Migration to AAC lifecycle, simplification of some logic
This commit is contained in:
parent
44af99f9cf
commit
9b1275ceec
|
|
@ -1,4 +1,5 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion compileSdk
|
||||
|
|
@ -16,6 +17,8 @@ android {
|
|||
dependencies {
|
||||
api project(':libraries:core')
|
||||
|
||||
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
compileOnly "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
compileOnly "com.android.support:design:$supportLibraryVersion"
|
||||
compileOnly "com.android.support:recyclerview-v7:$supportLibraryVersion"
|
||||
|
|
|
|||
|
|
@ -19,46 +19,35 @@
|
|||
|
||||
package ru.touchin.roboswag.components.adapters;
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
|
||||
/**
|
||||
* Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders.
|
||||
* Default {@link #getItemViewType} is generating on construction of object.
|
||||
*
|
||||
* @param <TViewHolder> Type of {@link BindableViewHolder} of delegate.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
//TooManyMethods: it's ok
|
||||
public abstract class AdapterDelegate<TViewHolder extends BindableViewHolder> implements LifecycleBindable {
|
||||
public abstract class AdapterDelegate<TViewHolder extends BindableViewHolder> {
|
||||
|
||||
private final int defaultItemViewType = ViewCompat.generateViewId();
|
||||
@NonNull
|
||||
private final LifecycleBindable parentLifecycleBindable;
|
||||
private final int defaultItemViewType;
|
||||
private final LifecycleOwner lifecycleOwner;
|
||||
|
||||
public AdapterDelegate(@NonNull final LifecycleBindable parentLifecycleBindable) {
|
||||
this.parentLifecycleBindable = parentLifecycleBindable;
|
||||
this.defaultItemViewType = UiUtils.OfViews.generateViewId();
|
||||
public AdapterDelegate(@NonNull final LifecycleOwner lifecycleOwner) {
|
||||
this.lifecycleOwner = lifecycleOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent {@link LifecycleBindable} that this delegate created from (e.g. Activity or ViewController).
|
||||
* Returns parent {@link LifecycleOwner} that this delegate created from (e.g. Activity, Fragment or ViewController).
|
||||
*
|
||||
* @return Parent {@link LifecycleBindable}.
|
||||
* @return Parent {@link LifecycleOwner}.
|
||||
*/
|
||||
@NonNull
|
||||
public LifecycleBindable getParentLifecycleBindable() {
|
||||
return parentLifecycleBindable;
|
||||
public LifecycleOwner getLifecycleOwner() {
|
||||
return lifecycleOwner;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -79,184 +68,4 @@ public abstract class AdapterDelegate<TViewHolder extends BindableViewHolder> im
|
|||
@NonNull
|
||||
public abstract TViewHolder onCreateViewHolder(@NonNull final ViewGroup parent);
|
||||
|
||||
@SuppressWarnings("CPD-START")
|
||||
//CPD: it is same as in other implementation based on BaseLifecycleBindable
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
return parentLifecycleBindable.untilStop(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return parentLifecycleBindable.untilStop(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilStop(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return parentLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
return parentLifecycleBindable.untilStop(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return parentLifecycleBindable.untilStop(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
return parentLifecycleBindable.untilStop(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return parentLifecycleBindable.untilStop(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
return parentLifecycleBindable.untilStop(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return parentLifecycleBindable.untilStop(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilStop(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
return parentLifecycleBindable.untilDestroy(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return parentLifecycleBindable.untilDestroy(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return parentLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
return parentLifecycleBindable.untilDestroy(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return parentLifecycleBindable.untilDestroy(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
return parentLifecycleBindable.untilDestroy(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return parentLifecycleBindable.untilDestroy(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
return parentLifecycleBindable.untilDestroy(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return parentLifecycleBindable.untilDestroy(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return parentLifecycleBindable.untilDestroy(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,307 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.adapters;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 12/8/2016.
|
||||
* ViewHolder that implements {@link LifecycleBindable} and uses parent bindable object as bridge (Activity, ViewController etc.).
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public class BindableViewHolder extends RecyclerView.ViewHolder implements LifecycleBindable {
|
||||
|
||||
@NonNull
|
||||
private final LifecycleBindable baseLifecycleBindable;
|
||||
|
||||
public BindableViewHolder(@NonNull final LifecycleBindable baseLifecycleBindable, @NonNull final View itemView) {
|
||||
super(itemView);
|
||||
this.baseLifecycleBindable = baseLifecycleBindable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a child view with the given id. If this view has the given id, return this view.
|
||||
*
|
||||
* @param id The id to search for;
|
||||
* @return The view that has the given id in the hierarchy.
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends View> T findViewById(@IdRes final int id) {
|
||||
final T viewById = (T) itemView.findViewById(id);
|
||||
if (viewById == null) {
|
||||
throw new ShouldNotHappenException("No view for id=" + itemView.getResources().getResourceName(id));
|
||||
}
|
||||
return viewById;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string value associated with a particular resource ID. It
|
||||
* will be stripped of any styled text information.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return String The string data associated with the resource.
|
||||
*/
|
||||
@NonNull
|
||||
public String getString(@StringRes final int resId) {
|
||||
return itemView.getResources().getString(resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string value associated with a particular resource ID. It
|
||||
* will be stripped of any styled text information.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @param formatArgs The format arguments that will be used for substitution.
|
||||
* @return String The string data associated with the resource.
|
||||
*/
|
||||
@NonNull
|
||||
public String getString(@StringRes final int resId, @Nullable final Object... formatArgs) {
|
||||
return itemView.getResources().getString(resId, formatArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color value associated with a particular resource ID.
|
||||
* Starting in {@link android.os.Build.VERSION_CODES#M}, the returned
|
||||
* color will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return int A single color value in the form 0xAARRGGBB.
|
||||
*/
|
||||
@ColorInt
|
||||
public int getColor(@ColorRes final int resId) {
|
||||
return ContextCompat.getColor(itemView.getContext(), resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable object associated with a particular resource ID.
|
||||
* Starting in {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the
|
||||
* returned drawable will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return Drawable An object that can be used to draw this resource.
|
||||
*/
|
||||
@NonNull
|
||||
public Drawable getDrawable(@DrawableRes final int resId) {
|
||||
return ContextCompat.getDrawable(itemView.getContext(), resId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-START")
|
||||
//CPD: it's ok as it's LifecycleBindable
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilStop(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilStop(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilStop(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilStop(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilDestroy(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilDestroy(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilDestroy(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-END")
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.adapters
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Created by Denis Karmyshakov 14.03.2018.
|
||||
* ViewHolder that implements {@link LifecycleOwner} and uses parent lifecycle
|
||||
* object as bridge ([android.app.Activity], [android.support.v4.app.Fragment] etc.).
|
||||
*/
|
||||
open class BindableViewHolder(
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
itemView: View
|
||||
) : RecyclerView.ViewHolder(itemView), LifecycleOwner by lifecycleOwner
|
||||
|
|
@ -1,24 +1,23 @@
|
|||
package ru.touchin.roboswag.components.adapters;
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
|
||||
/**
|
||||
* Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders.
|
||||
* Such delegates are creating and binding ViewHolders for specific items.
|
||||
* Default {@link #getItemViewType} is generating on construction of object.
|
||||
*
|
||||
* @param <TViewHolder> Type of {@link BindableViewHolder} of delegate;
|
||||
* @param <TItem> Type of items to bind to {@link BindableViewHolder}s.
|
||||
* @param <TViewHolder> Type of {@link LifecycleOwner} of delegate;
|
||||
* @param <TItem> Type of items to bind to {@link LifecycleOwner}s.
|
||||
*/
|
||||
public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder, TItem> extends AdapterDelegate<TViewHolder> {
|
||||
|
||||
public ItemAdapterDelegate(@NonNull final LifecycleBindable parentLifecycleBindable) {
|
||||
super(parentLifecycleBindable);
|
||||
public ItemAdapterDelegate(@NonNull final LifecycleOwner lifecycleOwner) {
|
||||
super(lifecycleOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,8 +60,12 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
|
|||
* @param positionInAdapter Position of item in adapter;
|
||||
* @param positionInCollection Position of item in collection that contains item;
|
||||
*/
|
||||
public abstract void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item,
|
||||
final int positionInAdapter, final int positionInCollection);
|
||||
public abstract void onBindViewHolder(
|
||||
@NonNull final TViewHolder holder,
|
||||
@NonNull final TItem item,
|
||||
final int positionInAdapter,
|
||||
final int positionInCollection
|
||||
);
|
||||
|
||||
/**
|
||||
* Binds item with payloads to created by this object ViewHolder.
|
||||
|
|
@ -73,8 +76,13 @@ public abstract class ItemAdapterDelegate<TViewHolder extends BindableViewHolder
|
|||
* @param positionInAdapter Position of item in adapter;
|
||||
* @param positionInCollection Position of item in collection that contains item;
|
||||
*/
|
||||
public void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item, @NonNull final List<Object> payloads,
|
||||
final int positionInAdapter, final int positionInCollection) {
|
||||
public void onBindViewHolder(
|
||||
@NonNull final TViewHolder holder,
|
||||
@NonNull final TItem item,
|
||||
@NonNull final List<Object> payloads,
|
||||
final int positionInAdapter,
|
||||
final int positionInCollection
|
||||
) {
|
||||
//do nothing by default
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,697 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.adapters;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.functions.BiConsumer;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.observables.collections.ObservableCollection;
|
||||
import ru.touchin.roboswag.core.observables.collections.ObservableList;
|
||||
import ru.touchin.roboswag.core.observables.collections.changes.Change;
|
||||
import ru.touchin.roboswag.core.observables.collections.changes.ChangePayloadProducer;
|
||||
import ru.touchin.roboswag.core.observables.collections.changes.CollectionChanges;
|
||||
import ru.touchin.roboswag.core.observables.collections.changes.SameItemsPredicate;
|
||||
import ru.touchin.roboswag.core.observables.collections.loadable.LoadingMoreList;
|
||||
import ru.touchin.roboswag.core.utils.Optional;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 20/11/2015.
|
||||
* Adapter based on {@link ObservableCollection} and providing some useful features like:
|
||||
* - item-based binding method;
|
||||
* - delegates by {@link AdapterDelegate} over itemViewType logic;
|
||||
* - item click listener setup by {@link #setOnItemClickListener(OnItemClickListener)};
|
||||
* - allows to inform about footers/headers by overriding base create/bind methods and {@link #getHeadersCount()} plus {@link #getFootersCount()};
|
||||
* - by default it is pre-loading items for collections like {@link ru.touchin.roboswag.core.observables.collections.loadable.LoadingMoreList}.
|
||||
*
|
||||
* @param <TItem> Type of items to bind to ViewHolders;
|
||||
* @param <TItemViewHolder> Type of ViewHolders to show items.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "PMD.TooManyMethods"})
|
||||
//TooManyMethods: it's ok
|
||||
public abstract class ObservableCollectionAdapter<TItem, TItemViewHolder extends BindableViewHolder>
|
||||
extends RecyclerView.Adapter<BindableViewHolder> {
|
||||
|
||||
private static final int PRE_LOADING_COUNT = 20;
|
||||
|
||||
private static boolean inDebugMode;
|
||||
|
||||
/**
|
||||
* Enables debugging features like checking concurrent delegates.
|
||||
*/
|
||||
public static void setInDebugMode() {
|
||||
inDebugMode = true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final BehaviorSubject<Optional<ObservableCollection<TItem>>> observableCollectionSubject
|
||||
= BehaviorSubject.createDefault(new Optional<>(null));
|
||||
@NonNull
|
||||
private final BehaviorSubject<Boolean> moreAutoLoadingRequested = BehaviorSubject.create();
|
||||
@NonNull
|
||||
private final LifecycleBindable lifecycleBindable;
|
||||
@Nullable
|
||||
private Object onItemClickListener;
|
||||
private int lastUpdatedChangeNumber = -1;
|
||||
|
||||
@NonNull
|
||||
private final ObservableList<TItem> innerCollection = new ObservableList<>();
|
||||
private boolean anyChangeApplied;
|
||||
private long itemClickDelayMillis;
|
||||
@NonNull
|
||||
private final List<RecyclerView> attachedRecyclerViews = new LinkedList<>();
|
||||
@NonNull
|
||||
private final List<AdapterDelegate<? extends BindableViewHolder>> delegates = new ArrayList<>();
|
||||
|
||||
public ObservableCollectionAdapter(@NonNull final LifecycleBindable lifecycleBindable) {
|
||||
super();
|
||||
this.lifecycleBindable = lifecycleBindable;
|
||||
lifecycleBindable.untilDestroy(innerCollection.observeChanges(), this::onItemsChanged);
|
||||
lifecycleBindable.untilDestroy(observableCollectionSubject
|
||||
.switchMap(optional -> {
|
||||
final ObservableCollection<TItem> collection = optional.get();
|
||||
if (collection instanceof ObservableList) {
|
||||
innerCollection.setDiffUtilsSource((ObservableList<TItem>) collection);
|
||||
} else {
|
||||
innerCollection.setDiffUtilsSource(null);
|
||||
}
|
||||
return collection != null ? collection.observeItems() : Observable.just(Collections.emptyList());
|
||||
}), innerCollection::set);
|
||||
lifecycleBindable.untilDestroy(createMoreAutoLoadingObservable());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Observable createMoreAutoLoadingObservable() {
|
||||
return observableCollectionSubject
|
||||
.switchMap(collectionOptional -> {
|
||||
final ObservableCollection<TItem> collection = collectionOptional.get();
|
||||
if (!(collection instanceof LoadingMoreList)) {
|
||||
return Observable.empty();
|
||||
}
|
||||
return moreAutoLoadingRequested
|
||||
.distinctUntilChanged()
|
||||
.switchMap(requested -> {
|
||||
if (!requested) {
|
||||
return Observable.empty();
|
||||
}
|
||||
final int size = collection.size();
|
||||
return ((LoadingMoreList<?, ?, ?>) collection)
|
||||
.loadRange(size, size + PRE_LOADING_COUNT)
|
||||
.onErrorReturnItem(new ArrayList<>())
|
||||
.toObservable()
|
||||
.doOnComplete(() -> moreAutoLoadingRequested.onNext(false));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if any change of source collection applied to adapter.
|
||||
* It's important to not show some footers or headers before first change have applied.
|
||||
*
|
||||
* @return True id any change applied.
|
||||
*/
|
||||
public boolean isAnyChangeApplied() {
|
||||
return anyChangeApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(@NonNull final RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
attachedRecyclerViews.add(recyclerView);
|
||||
}
|
||||
|
||||
private boolean anyRecyclerViewShown() {
|
||||
for (final RecyclerView recyclerView : attachedRecyclerViews) {
|
||||
if (recyclerView.isShown()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(@NonNull final RecyclerView recyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView);
|
||||
attachedRecyclerViews.remove(recyclerView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parent {@link LifecycleBindable} (Activity/ViewController etc.).
|
||||
*
|
||||
* @return Parent {@link LifecycleBindable}.
|
||||
*/
|
||||
@NonNull
|
||||
public LifecycleBindable getLifecycleBindable() {
|
||||
return lifecycleBindable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ObservableCollection} which provides items and it's changes.
|
||||
*
|
||||
* @return Inner {@link ObservableCollection}.
|
||||
*/
|
||||
@Nullable
|
||||
public ObservableCollection<TItem> getObservableCollection() {
|
||||
return observableCollectionSubject.getValue().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to observe {@link ObservableCollection} which provides items and it's changes.
|
||||
*
|
||||
* @return Observable of inner {@link ObservableCollection}.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<Optional<ObservableCollection<TItem>>> observeObservableCollection() {
|
||||
return observableCollectionSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link ObservableCollection} which will provide items and it's changes.
|
||||
*
|
||||
* @param observableCollection Inner {@link ObservableCollection}.
|
||||
*/
|
||||
public void setObservableCollection(@Nullable final ObservableCollection<TItem> observableCollection) {
|
||||
this.observableCollectionSubject.onNext(new Optional<>(observableCollection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply sets items.
|
||||
*
|
||||
* @param items Items to set.
|
||||
*/
|
||||
public void setItems(@NonNull final Collection<TItem> items) {
|
||||
setObservableCollection(new ObservableList<>(items));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when collection changes.
|
||||
*
|
||||
* @param collectionChanges Changes of collection.
|
||||
*/
|
||||
protected void onItemsChanged(@NonNull final CollectionChanges<TItem> collectionChanges) {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
Lc.assertion("Items changes called on not main thread");
|
||||
return;
|
||||
}
|
||||
if (!anyChangeApplied || !anyRecyclerViewShown()) {
|
||||
anyChangeApplied = true;
|
||||
refreshUpdate();
|
||||
return;
|
||||
}
|
||||
if (collectionChanges.getNumber() != innerCollection.getChangesCount()
|
||||
|| collectionChanges.getNumber() != lastUpdatedChangeNumber + 1) {
|
||||
if (lastUpdatedChangeNumber < collectionChanges.getNumber()) {
|
||||
refreshUpdate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
notifyAboutChanges(collectionChanges.getChanges());
|
||||
lastUpdatedChangeNumber = innerCollection.getChangesCount();
|
||||
}
|
||||
|
||||
private void refreshUpdate() {
|
||||
notifyDataSetChanged();
|
||||
lastUpdatedChangeNumber = innerCollection.getChangesCount();
|
||||
}
|
||||
|
||||
private void notifyAboutChanges(@NonNull final Collection<Change> changes) {
|
||||
for (final Change change : changes) {
|
||||
if (change instanceof Change.Inserted) {
|
||||
final Change.Inserted castedChange = (Change.Inserted) change;
|
||||
notifyItemRangeInserted(castedChange.getPosition() + getHeadersCount(), castedChange.getCount());
|
||||
} else if (change instanceof Change.Removed) {
|
||||
if (getItemCount() - getHeadersCount() == 0) {
|
||||
//TODO: bug of recyclerview?
|
||||
notifyDataSetChanged();
|
||||
} else {
|
||||
final Change.Removed castedChange = (Change.Removed) change;
|
||||
notifyItemRangeRemoved(castedChange.getPosition() + getHeadersCount(), castedChange.getCount());
|
||||
}
|
||||
} else if (change instanceof Change.Moved) {
|
||||
final Change.Moved castedChange = (Change.Moved) change;
|
||||
notifyItemMoved(castedChange.getFromPosition() + getHeadersCount(), castedChange.getToPosition() + getHeadersCount());
|
||||
} else if (change instanceof Change.Changed) {
|
||||
final Change.Changed castedChange = (Change.Changed) change;
|
||||
notifyItemRangeChanged(
|
||||
castedChange.getPosition() + getHeadersCount(),
|
||||
castedChange.getCount(),
|
||||
castedChange.getPayload());
|
||||
} else {
|
||||
Lc.assertion("Not supported " + change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns headers count goes before items.
|
||||
*
|
||||
* @return Headers count.
|
||||
*/
|
||||
protected int getHeadersCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns footers count goes after items and headers.
|
||||
*
|
||||
* @return Footers count.
|
||||
*/
|
||||
protected int getFootersCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of added delegates.
|
||||
*
|
||||
* @return List of {@link AdapterDelegate}.
|
||||
*/
|
||||
@NonNull
|
||||
public List<AdapterDelegate<? extends BindableViewHolder>> getDelegates() {
|
||||
return Collections.unmodifiableList(delegates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link ItemAdapterDelegate} to adapter.
|
||||
*
|
||||
* @param delegate Delegate to add.
|
||||
*/
|
||||
public void addDelegate(@NonNull final ItemAdapterDelegate<? extends TItemViewHolder, ? extends TItem> delegate) {
|
||||
addDelegateInternal(delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link PositionAdapterDelegate} to adapter.
|
||||
*
|
||||
* @param delegate Delegate to add.
|
||||
*/
|
||||
public void addDelegate(@NonNull final PositionAdapterDelegate<? extends BindableViewHolder> delegate) {
|
||||
addDelegateInternal(delegate);
|
||||
}
|
||||
|
||||
private void addDelegateInternal(@NonNull final AdapterDelegate<? extends BindableViewHolder> delegate) {
|
||||
if (inDebugMode) {
|
||||
for (final AdapterDelegate addedDelegate : delegates) {
|
||||
if (addedDelegate.getItemViewType() == delegate.getItemViewType()) {
|
||||
Lc.assertion("AdapterDelegate with viewType=" + delegate.getItemViewType() + " already added");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
delegates.add(delegate);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link AdapterDelegate} from adapter.
|
||||
*
|
||||
* @param delegate Delegate to remove.
|
||||
*/
|
||||
public void removeDelegate(@NonNull final AdapterDelegate<? extends BindableViewHolder> delegate) {
|
||||
delegates.remove(delegate);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void checkDelegates(@Nullable final AdapterDelegate alreadyPickedDelegate, @NonNull final AdapterDelegate currentDelegate) {
|
||||
if (alreadyPickedDelegate != null) {
|
||||
throw new ShouldNotHappenException("Concurrent delegates: " + currentDelegate + " and " + alreadyPickedDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
private int getItemPositionInCollection(final int positionInAdapter) {
|
||||
final int shiftedPosition = positionInAdapter - getHeadersCount();
|
||||
return shiftedPosition >= 0 && shiftedPosition < innerCollection.size() ? shiftedPosition : -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ModifiedCyclomaticComplexity", "PMD.StdCyclomaticComplexity", "PMD.NPathComplexity"})
|
||||
//Complexity: because of debug code
|
||||
@Override
|
||||
public int getItemViewType(final int positionInAdapter) {
|
||||
AdapterDelegate delegateOfViewType = null;
|
||||
final int positionInCollection = getItemPositionInCollection(positionInAdapter);
|
||||
final TItem item = positionInCollection >= 0 ? innerCollection.get(positionInCollection) : null;
|
||||
for (final AdapterDelegate<?> delegate : delegates) {
|
||||
if (delegate instanceof ItemAdapterDelegate) {
|
||||
if (item != null && ((ItemAdapterDelegate) delegate).isForViewType(item, positionInAdapter, positionInCollection)) {
|
||||
checkDelegates(delegateOfViewType, delegate);
|
||||
delegateOfViewType = delegate;
|
||||
if (!inDebugMode) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (delegate instanceof PositionAdapterDelegate) {
|
||||
if (((PositionAdapterDelegate) delegate).isForViewType(positionInAdapter)) {
|
||||
checkDelegates(delegateOfViewType, delegate);
|
||||
delegateOfViewType = delegate;
|
||||
if (!inDebugMode) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Lc.assertion("Delegate of type " + delegate.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
return delegateOfViewType != null ? delegateOfViewType.getItemViewType() : super.getItemViewType(positionInAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int positionInAdapter) {
|
||||
final LongContainer result = new LongContainer();
|
||||
tryDelegateAction(positionInAdapter,
|
||||
(itemAdapterDelegate, positionInCollection) ->
|
||||
result.value = itemAdapterDelegate.getItemId(innerCollection.get(positionInCollection),
|
||||
positionInAdapter, positionInCollection),
|
||||
positionAdapterDelegate -> result.value = positionAdapterDelegate.getItemId(positionInAdapter),
|
||||
(positionInCollection) -> result.value = super.getItemId(positionInAdapter));
|
||||
return result.value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.CyclomaticComplexity")
|
||||
private void tryDelegateAction(final int positionInAdapter,
|
||||
@NonNull final BiConsumer<ItemAdapterDelegate, Integer> itemAdapterDelegateAction,
|
||||
@NonNull final Consumer<PositionAdapterDelegate> positionAdapterDelegateAction,
|
||||
@NonNull final Consumer<Integer> defaultAction) {
|
||||
final int viewType = getItemViewType(positionInAdapter);
|
||||
final int positionInCollection = getItemPositionInCollection(positionInAdapter);
|
||||
for (final AdapterDelegate<?> delegate : delegates) {
|
||||
if (delegate instanceof ItemAdapterDelegate) {
|
||||
if (positionInCollection >= 0 && viewType == delegate.getItemViewType()) {
|
||||
try {
|
||||
itemAdapterDelegateAction.accept((ItemAdapterDelegate) delegate, positionInCollection);
|
||||
} catch (final Exception exception) {
|
||||
Lc.assertion(exception);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (delegate instanceof PositionAdapterDelegate) {
|
||||
if (viewType == delegate.getItemViewType()) {
|
||||
try {
|
||||
positionAdapterDelegateAction.accept((PositionAdapterDelegate) delegate);
|
||||
} catch (final Exception exception) {
|
||||
Lc.assertion(exception);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Lc.assertion("Delegate of type " + delegate.getClass());
|
||||
}
|
||||
}
|
||||
try {
|
||||
defaultAction.accept(positionInCollection);
|
||||
} catch (final Exception exception) {
|
||||
Lc.assertion(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return getHeadersCount() + innerCollection.size() + getFootersCount();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BindableViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
for (final AdapterDelegate<?> delegate : delegates) {
|
||||
if (delegate.getItemViewType() == viewType) {
|
||||
return delegate.onCreateViewHolder(parent);
|
||||
}
|
||||
}
|
||||
throw new ShouldNotHappenException("Add some AdapterDelegate or override this method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final BindableViewHolder holder, final int positionInAdapter) {
|
||||
lastUpdatedChangeNumber = innerCollection.getChangesCount();
|
||||
|
||||
tryDelegateAction(positionInAdapter,
|
||||
(itemAdapterDelegate, positionInCollection) -> {
|
||||
bindItemViewHolder(itemAdapterDelegate, holder, innerCollection.get(positionInCollection),
|
||||
null, positionInAdapter, positionInCollection);
|
||||
updateMoreAutoLoadingRequest(positionInCollection);
|
||||
},
|
||||
positionAdapterDelegate -> positionAdapterDelegate.onBindViewHolder(holder, positionInAdapter),
|
||||
(positionInCollection) -> {
|
||||
if (positionInCollection >= 0) {
|
||||
bindItemViewHolder(null, holder, innerCollection.get(positionInCollection), null, positionInAdapter, positionInCollection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final BindableViewHolder holder, final int positionInAdapter, @NonNull final List<Object> payloads) {
|
||||
super.onBindViewHolder(holder, positionInAdapter, payloads);
|
||||
tryDelegateAction(positionInAdapter,
|
||||
(itemAdapterDelegate, positionInCollection) -> {
|
||||
bindItemViewHolder(itemAdapterDelegate, holder, innerCollection.get(positionInCollection),
|
||||
payloads, positionInAdapter, positionInCollection);
|
||||
updateMoreAutoLoadingRequest(positionInCollection);
|
||||
},
|
||||
positionAdapterDelegate -> positionAdapterDelegate.onBindViewHolder(holder, positionInAdapter),
|
||||
(positionInCollection) -> {
|
||||
if (positionInCollection >= 0) {
|
||||
bindItemViewHolder(null, holder, innerCollection.get(positionInCollection),
|
||||
payloads, positionInAdapter, positionInCollection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void bindItemViewHolder(@Nullable final ItemAdapterDelegate<TItemViewHolder, TItem> itemAdapterDelegate,
|
||||
@NonNull final BindableViewHolder holder, @NonNull final TItem item, @Nullable final List<Object> payloads,
|
||||
final int positionInAdapter, final int positionInCollection) {
|
||||
final TItemViewHolder itemViewHolder;
|
||||
try {
|
||||
itemViewHolder = (TItemViewHolder) holder;
|
||||
} catch (final ClassCastException exception) {
|
||||
Lc.assertion(exception);
|
||||
return;
|
||||
}
|
||||
updateClickListener(holder, item, positionInAdapter, positionInCollection);
|
||||
if (itemAdapterDelegate != null) {
|
||||
if (payloads == null) {
|
||||
itemAdapterDelegate.onBindViewHolder(itemViewHolder, item, positionInAdapter, positionInCollection);
|
||||
} else {
|
||||
itemAdapterDelegate.onBindViewHolder(itemViewHolder, item, payloads, positionInAdapter, positionInCollection);
|
||||
}
|
||||
} else {
|
||||
if (payloads == null) {
|
||||
onBindItemToViewHolder(itemViewHolder, positionInAdapter, item);
|
||||
} else {
|
||||
onBindItemToViewHolder(itemViewHolder, positionInAdapter, item, payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateClickListener(@NonNull final BindableViewHolder holder, @NonNull final TItem item,
|
||||
final int positionInAdapter, final int positionInCollection) {
|
||||
if (onItemClickListener != null && !isOnClickListenerDisabled(item, positionInAdapter, positionInCollection)) {
|
||||
UiUtils.setOnRippleClickListener(holder.itemView,
|
||||
() -> {
|
||||
if (onItemClickListener instanceof OnItemClickListener) {
|
||||
((OnItemClickListener) onItemClickListener).onItemClicked(item);
|
||||
} else if (onItemClickListener instanceof OnItemWithPositionClickListener) {
|
||||
((OnItemWithPositionClickListener) onItemClickListener).onItemClicked(item, positionInAdapter, positionInCollection);
|
||||
} else {
|
||||
Lc.assertion("Unexpected onItemClickListener type " + onItemClickListener);
|
||||
}
|
||||
},
|
||||
itemClickDelayMillis);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMoreAutoLoadingRequest(final int positionInCollection) {
|
||||
if (positionInCollection > innerCollection.size() - PRE_LOADING_COUNT) {
|
||||
return;
|
||||
}
|
||||
moreAutoLoadingRequested.onNext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to bind item (from {@link #getObservableCollection()}) to item-specific ViewHolder.
|
||||
* It is not calling for headers and footer which counts are returned by {@link #getHeadersCount()} and @link #getFootersCount()}.
|
||||
* You don't need to override this method if you have delegates for every view type.
|
||||
*
|
||||
* @param holder ViewHolder to bind item to;
|
||||
* @param positionInAdapter Position of ViewHolder (NOT item!);
|
||||
* @param item Item returned by position (WITH HEADER OFFSET!).
|
||||
*/
|
||||
protected void onBindItemToViewHolder(@NonNull final TItemViewHolder holder, final int positionInAdapter, @NonNull final TItem item) {
|
||||
// do nothing by default - let delegates do it
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to bind item (from {@link #getObservableCollection()}) to item-specific ViewHolder with payloads.
|
||||
* It is not calling for headers and footer which counts are returned by {@link #getHeadersCount()} and @link #getFootersCount()}.
|
||||
*
|
||||
* @param holder ViewHolder to bind item to;
|
||||
* @param positionInAdapter Position of ViewHolder in adapter (NOT item!);
|
||||
* @param item Item returned by position (WITH HEADER OFFSET!);
|
||||
* @param payloads Payloads.
|
||||
*/
|
||||
protected void onBindItemToViewHolder(@NonNull final TItemViewHolder holder, final int positionInAdapter, @NonNull final TItem item,
|
||||
@NonNull final List<Object> payloads) {
|
||||
// do nothing by default - let delegates do it
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TItem getItem(final int positionInAdapter) {
|
||||
final int positionInCollection = getItemPositionInCollection(positionInAdapter);
|
||||
return positionInCollection >= 0 ? innerCollection.get(positionInCollection) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets item click listener.
|
||||
*
|
||||
* @param onItemClickListener Item click listener.
|
||||
*/
|
||||
public void setOnItemClickListener(@Nullable final OnItemClickListener<TItem> onItemClickListener) {
|
||||
this.setOnItemClickListener(onItemClickListener, UiUtils.RIPPLE_EFFECT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets item click listener.
|
||||
*
|
||||
* @param onItemClickListener Item click listener;
|
||||
* @param itemClickDelayMillis Delay of calling click listener.
|
||||
*/
|
||||
public void setOnItemClickListener(@Nullable final OnItemClickListener<TItem> onItemClickListener, final long itemClickDelayMillis) {
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
this.itemClickDelayMillis = itemClickDelayMillis;
|
||||
refreshUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets item click listener.
|
||||
*
|
||||
* @param onItemClickListener Item click listener.
|
||||
*/
|
||||
public void setOnItemClickListener(@Nullable final OnItemWithPositionClickListener<TItem> onItemClickListener) {
|
||||
this.setOnItemClickListener(onItemClickListener, UiUtils.RIPPLE_EFFECT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets item click listener.
|
||||
*
|
||||
* @param onItemClickListener Item click listener;
|
||||
* @param itemClickDelayMillis Delay of calling click listener.
|
||||
*/
|
||||
public void setOnItemClickListener(@Nullable final OnItemWithPositionClickListener<TItem> onItemClickListener, final long itemClickDelayMillis) {
|
||||
this.onItemClickListener = onItemClickListener;
|
||||
this.itemClickDelayMillis = itemClickDelayMillis;
|
||||
refreshUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if click listening disabled or not for specific item.
|
||||
*
|
||||
* @param item Item to check click availability;
|
||||
* @param positionInAdapter Position of clicked item in adapter (with headers);
|
||||
* @param positionInCollection Position of clicked item in inner collection;
|
||||
* @return True if click listener enabled for such item.
|
||||
*/
|
||||
public boolean isOnClickListenerDisabled(@NonNull final TItem item, final int positionInAdapter, final int positionInCollection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable diff utils algorithm in collection changes.
|
||||
*
|
||||
* @param detectMoves The flag that determines whether the {@link Change.Moved} changes will be generated or not;
|
||||
* @param sameItemsPredicate Predicate for the determination of the same elements;
|
||||
* @param changePayloadProducer Function that calculate change payload when items the same but contents are different.
|
||||
*/
|
||||
public void enableDiffUtils(final boolean detectMoves,
|
||||
@NonNull final SameItemsPredicate<TItem> sameItemsPredicate,
|
||||
@Nullable final ChangePayloadProducer<TItem> changePayloadProducer) {
|
||||
innerCollection.enableDiffUtils(detectMoves, sameItemsPredicate, changePayloadProducer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable diff utils algorithm.
|
||||
*/
|
||||
public void disableDiffUtils() {
|
||||
innerCollection.disableDiffUtils();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enabled flag of diff utils.
|
||||
*
|
||||
* @return true if diff utils is enabled.
|
||||
*/
|
||||
public boolean diffUtilsIsEnabled() {
|
||||
return innerCollection.diffUtilsIsEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to simply add item click listener.
|
||||
*
|
||||
* @param <TItem> Type of item
|
||||
*/
|
||||
public interface OnItemClickListener<TItem> {
|
||||
|
||||
/**
|
||||
* Calls when item have clicked.
|
||||
*
|
||||
* @param item Clicked item.
|
||||
*/
|
||||
void onItemClicked(@NonNull TItem item);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to simply add item click listener based on item position in adapter and collection.
|
||||
*
|
||||
* @param <TItem> Type of item
|
||||
*/
|
||||
public interface OnItemWithPositionClickListener<TItem> {
|
||||
|
||||
/**
|
||||
* Calls when item have clicked.
|
||||
*
|
||||
* @param item Clicked item;
|
||||
* @param positionInAdapter Position of clicked item in adapter (with headers);
|
||||
* @param positionInCollection Position of clicked item in inner collection.
|
||||
*/
|
||||
void onItemClicked(@NonNull TItem item, final int positionInAdapter, final int positionInCollection);
|
||||
|
||||
}
|
||||
|
||||
private class LongContainer {
|
||||
|
||||
private long value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
package ru.touchin.roboswag.components.adapters;
|
||||
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
|
||||
/**
|
||||
* Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders.
|
||||
* Such delegates are creating and binding ViewHolders by position in adapter.
|
||||
|
|
@ -16,8 +15,8 @@ import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
|||
*/
|
||||
public abstract class PositionAdapterDelegate<TViewHolder extends BindableViewHolder> extends AdapterDelegate<TViewHolder> {
|
||||
|
||||
public PositionAdapterDelegate(@NonNull final LifecycleBindable parentLifecycleBindable) {
|
||||
super(parentLifecycleBindable);
|
||||
public PositionAdapterDelegate(@NonNull final LifecycleOwner lifecycleOwner) {
|
||||
super(lifecycleOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Ilia Kurtov on 13/04/2016.
|
||||
* Basic state of {@link ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment}.
|
||||
* This object is saving as serializable in {@link android.os.Bundle} at {@link Fragment#onSaveInstanceState(Bundle)} point.
|
||||
* Also this object is passing into {@link Fragment#getArguments()} on fragment instantiation.
|
||||
* Do NOT store such object in fields outside of it's {@link ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment}:
|
||||
* 1) it should be used as state of fragment but not state of other fragments or parts of logic;
|
||||
* 2) if you want to modify such object then you should pass it's fragment as {@link Fragment#getTargetFragment()};
|
||||
* 3) if you are using {@link ViewControllerNavigation} then just use ***ForResult methods to pass target;
|
||||
* 4) as it is serializable object then all initialization logic (like binding) should NOT be in constructor. Use {@link #onCreate()} method.
|
||||
*/
|
||||
@SuppressWarnings("PMD.AbstractClassWithoutAbstractMethod")
|
||||
//AbstractClassWithoutAbstractMethod: objects of this class actually shouldn't exist
|
||||
public abstract class AbstractState implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Calls right after construction. All inner object's instantiation logic should be in this method.
|
||||
* Do NOT do some instantiation logic in constructor except fields setup.
|
||||
*/
|
||||
public void onCreate() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,39 +19,27 @@
|
|||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.arch.lifecycle.Lifecycle;
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.arch.lifecycle.LifecycleRegistry;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.utils.BaseLifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
|
|
@ -60,20 +48,16 @@ import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
|||
* @param <TActivity> Type of activity where such {@link ViewController} could be;
|
||||
* @param <TFragment> Type of fragment where such {@link ViewController} could be;
|
||||
*/
|
||||
@SuppressWarnings({"PMD.TooManyMethods", "PMD.ExcessivePublicCount"})
|
||||
public class ViewController<TActivity extends ViewControllerActivity<?>,
|
||||
TFragment extends ViewControllerFragment<?, TActivity>>
|
||||
implements LifecycleBindable {
|
||||
public class ViewController<TActivity extends FragmentActivity, TFragment extends ViewControllerFragment<?, TActivity>> implements LifecycleOwner {
|
||||
|
||||
@NonNull
|
||||
private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
|
||||
@NonNull
|
||||
private final TActivity activity;
|
||||
@NonNull
|
||||
private final TFragment fragment;
|
||||
@NonNull
|
||||
private final ViewGroup container;
|
||||
@NonNull
|
||||
private final BaseLifecycleBindable baseLifecycleBindable = new BaseLifecycleBindable();
|
||||
private boolean destroyed;
|
||||
|
||||
@SuppressWarnings({"unchecked", "PMD.UnusedFormalParameter"})
|
||||
//UnusedFormalParameter: savedInstanceState could be used by children
|
||||
|
|
@ -83,6 +67,12 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
this.container = creationContext.container;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Lifecycle getLifecycle() {
|
||||
return lifecycleRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns activity where {@link ViewController} could be.
|
||||
*
|
||||
|
|
@ -114,37 +104,6 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if {@link ViewController} destroyed or not.
|
||||
*
|
||||
* @return True if it is destroyed.
|
||||
*/
|
||||
public final boolean isDestroyed() {
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a localized string from the application's package's default string table.
|
||||
*
|
||||
* @param resId Resource id for the string
|
||||
*/
|
||||
@NonNull
|
||||
public final String getString(@StringRes final int resId) {
|
||||
return getActivity().getString(resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a localized formatted string from the application's package's default string table, substituting the format arguments as defined in
|
||||
* {@link java.util.Formatter} and {@link java.lang.String#format}.
|
||||
*
|
||||
* @param resId Resource id for the format string
|
||||
* @param formatArgs The format arguments that will be used for substitution.
|
||||
*/
|
||||
@NonNull
|
||||
public final String getString(@StringRes final int resId, @NonNull final Object... formatArgs) {
|
||||
return getActivity().getString(resId, formatArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view controller content from a layout resource.
|
||||
* This layout is placed directly into the container's ({@link #getContainer()}) view hierarchy.
|
||||
|
|
@ -189,39 +148,8 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
* @return The view that has the given id in the hierarchy.
|
||||
*/
|
||||
@NonNull
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends View> T findViewById(@IdRes final int id) {
|
||||
final T viewById = (T) getContainer().findViewById(id);
|
||||
if (viewById == null) {
|
||||
throw new ShouldNotHappenException("No view for id=" + getActivity().getResources().getResourceName(id));
|
||||
}
|
||||
return viewById;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color value associated with a particular resource ID.
|
||||
* Starting in {@link android.os.Build.VERSION_CODES#M}, the returned
|
||||
* color will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return int A single color value in the form 0xAARRGGBB.
|
||||
*/
|
||||
@ColorInt
|
||||
public int getColor(@ColorRes final int resId) {
|
||||
return getActivity().getColorCompat(resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a drawable object associated with a particular resource ID.
|
||||
* Starting in {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the
|
||||
* returned drawable will be styled for the specified Context's theme.
|
||||
*
|
||||
* @param resId The resource id to search for data;
|
||||
* @return Drawable An object that can be used to draw this resource.
|
||||
*/
|
||||
@NonNull
|
||||
public Drawable getDrawable(@DrawableRes final int resId) {
|
||||
return getActivity().getDrawableCompat(resId);
|
||||
public final <T extends View> T findViewById(@IdRes final int id) {
|
||||
return getContainer().findViewById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -231,28 +159,28 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
* @param menu The options menu in which you place your items;
|
||||
* @param inflater Helper to inflate menu items.
|
||||
*/
|
||||
public void onConfigureNavigation(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls right after construction of {@link ViewController}.
|
||||
* Happens at {@link ViewControllerFragment#onActivityCreated(View, ViewControllerActivity, Bundle)}.
|
||||
* Happens at {@link ViewControllerFragment#onActivityCreated(Bundle)}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onCreate() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onCreate();
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when {@link ViewController} have started.
|
||||
* Happens at {@link ViewControllerFragment#onStart(View, ViewControllerActivity)}.
|
||||
* Happens at {@link ViewControllerFragment#onStart()}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onStart() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onStart();
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -265,12 +193,12 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
|
||||
/**
|
||||
* Calls when {@link ViewController} have resumed.
|
||||
* Happens at {@link ViewControllerFragment#onResume(View, ViewControllerActivity)}.
|
||||
* Happens at {@link ViewControllerFragment#onResume()}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onResume() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onResume();
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -284,11 +212,12 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
|
||||
/**
|
||||
* Calls when {@link ViewController} have paused.
|
||||
* Happens at {@link ViewControllerFragment#onPause(View, ViewControllerActivity)}.
|
||||
* Happens at {@link ViewControllerFragment#onPause()}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onPause() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -298,7 +227,6 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
*/
|
||||
@CallSuper
|
||||
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||
baseLifecycleBindable.onSaveInstanceState();
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
}
|
||||
|
||||
|
|
@ -312,30 +240,29 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
|
||||
/**
|
||||
* Calls when {@link ViewController} have stopped.
|
||||
* Happens at {@link ViewControllerFragment#onStop(View, ViewControllerActivity)}.
|
||||
* Happens at {@link ViewControllerFragment#onStop()}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onStop() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onStop();
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when {@link ViewController} have destroyed.
|
||||
* Happens usually at {@link ViewControllerFragment#onDestroyView(View)}. In some cases at {@link ViewControllerFragment#onDestroy()}.
|
||||
* Happens usually at {@link ViewControllerFragment#onDestroyView()}. In some cases at {@link ViewControllerFragment#onDestroy()}.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onDestroy() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onDestroy();
|
||||
destroyed = true;
|
||||
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from parent fragment.
|
||||
*/
|
||||
public void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||
// Do nothing
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -348,200 +275,23 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilStop(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilStop(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilStop(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilStop(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilDestroy(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilDestroy(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilDestroy(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-END")
|
||||
/*
|
||||
* Helper class to simplify constructor override.
|
||||
*/
|
||||
public static class CreationContext {
|
||||
|
||||
@NonNull
|
||||
private final ViewControllerActivity activity;
|
||||
private final FragmentActivity activity;
|
||||
@NonNull
|
||||
private final ViewControllerFragment fragment;
|
||||
@NonNull
|
||||
private final ViewGroup container;
|
||||
|
||||
public CreationContext(@NonNull final ViewControllerActivity activity,
|
||||
@NonNull final ViewControllerFragment fragment,
|
||||
@NonNull final ViewGroup container) {
|
||||
public CreationContext(
|
||||
@NonNull final FragmentActivity activity,
|
||||
@NonNull final ViewControllerFragment fragment,
|
||||
@NonNull final ViewGroup container
|
||||
) {
|
||||
this.activity = activity;
|
||||
this.fragment = fragment;
|
||||
this.container = container;
|
||||
|
|
@ -549,4 +299,4 @@ public class ViewController<TActivity extends ViewControllerActivity<?>,
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,504 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
|
||||
import io.reactivex.functions.Function;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.SimpleViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.StatelessTargetedViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.StatelessViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.TargetedViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Navigation based on {@link ViewController}s which are creating by {@link Fragment}s.
|
||||
* So basically it is just {@link FragmentNavigation} where most of fragments should be inherited from {@link ViewControllerFragment}.
|
||||
*
|
||||
* @param <TActivity> Type of activity where {@link ViewController}s should be showed.
|
||||
*/
|
||||
public class ViewControllerNavigation<TActivity extends ViewControllerActivity<?>> extends FragmentNavigation {
|
||||
|
||||
public ViewControllerNavigation(@NonNull final Context context,
|
||||
@NonNull final FragmentManager fragmentManager,
|
||||
@IdRes final int containerViewId) {
|
||||
super(context, fragmentManager, containerViewId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void push(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
addToStack(fragmentClass, null, true, ViewControllerFragment.createState(state), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack with specific transaction setup.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void push(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, true, ViewControllerFragment.createState(state), null, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack with specific target fragment.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param targetFragment Target fragment to be set as {@link Fragment#getTargetFragment()} of instantiated {@link Fragment};
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void pushForResult(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final TState state) {
|
||||
addToStack(fragmentClass, targetFragment, true, ViewControllerFragment.createState(state),
|
||||
fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack with specific target fragment and specific transaction setup.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param targetFragment Target fragment to be set as {@link Fragment#getTargetFragment()} of instantiated {@link Fragment};
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void pushForResult(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, targetFragment, true, ViewControllerFragment.createState(state),
|
||||
fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate.
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setAsTop(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
setAsTop(fragmentClass, ViewControllerFragment.createState(state), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewControllerFragment} on top of stack with specific transaction setup
|
||||
* and with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate.
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setAsTop(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
setAsTop(fragmentClass, ViewControllerFragment.createState(state), transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewControllerFragment} on top of stack.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setInitial(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
setInitial(fragmentClass, ViewControllerFragment.createState(state), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewControllerFragment} on top of stack with specific transaction setup.
|
||||
*
|
||||
* @param fragmentClass Class of {@link ViewControllerFragment} to instantiate;
|
||||
* @param state Specific {@link AbstractState} of {@link ViewControllerFragment};
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setInitial(@NonNull final Class<? extends ViewControllerFragment<TState, TActivity>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
setInitial(fragmentClass, ViewControllerFragment.createState(state), transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed.
|
||||
*/
|
||||
public void pushViewController(@NonNull final Class<? extends ViewController<TActivity,
|
||||
StatelessViewControllerFragment<TActivity>>> viewControllerClass) {
|
||||
addStatelessViewControllerToStack(viewControllerClass, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link ViewControllerFragment#getState()}.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void pushViewController(@NonNull final Class<? extends ViewController<TActivity,
|
||||
SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;.
|
||||
*/
|
||||
public void pushViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, StatelessViewControllerFragment<TActivity>>> viewControllerClass,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addStatelessViewControllerToStack(viewControllerClass, null, null, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link ViewControllerFragment#getState()} and with specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void pushViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} without adding to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed.
|
||||
*/
|
||||
public void pushSingleViewController(@NonNull final Class<? extends ViewController<TActivity,
|
||||
StatelessViewControllerFragment<TActivity>>> viewControllerClass) {
|
||||
addToStack(StatelessViewControllerFragment.class, null, false, StatelessViewControllerFragment.createState(viewControllerClass), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} without adding to stack and with specific {@link ViewControllerFragment#getState()}.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void pushSingleViewController(@NonNull final Class<? extends ViewController<TActivity,
|
||||
SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass, @NonNull final TState state) {
|
||||
addToStack(SimpleViewControllerFragment.class, null, false, SimpleViewControllerFragment.createState(viewControllerClass, state), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link StatelessTargetedViewControllerFragment#getTarget()}.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
|
||||
* @param <TTargetFragment> Type of target fragment.
|
||||
*/
|
||||
public <TTargetState extends AbstractState,
|
||||
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
StatelessTargetedViewControllerFragment<TTargetState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TTargetFragment targetFragment) {
|
||||
addTargetedStatelessViewControllerToStack(viewControllerClass, targetFragment,
|
||||
viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link StatelessTargetedViewControllerFragment#getTarget()} and transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
|
||||
* @param <TTargetFragment> Type of target fragment.
|
||||
*/
|
||||
public <TTargetState extends AbstractState,
|
||||
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
StatelessTargetedViewControllerFragment<TTargetState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TTargetFragment targetFragment,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addTargetedStatelessViewControllerToStack(viewControllerClass, targetFragment,
|
||||
viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific with specific {@link ViewControllerFragment#getState()}
|
||||
* and with specific {@link TargetedViewControllerFragment#getTarget()}.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param <TState> Type of state of fragment;
|
||||
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
|
||||
* @param <TTargetFragment> Type of target fragment.
|
||||
*/
|
||||
@SuppressWarnings("CPD-START")
|
||||
public <TState extends AbstractState, TTargetState extends AbstractState,
|
||||
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
TargetedViewControllerFragment<TState, TTargetState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TTargetFragment targetFragment,
|
||||
@NonNull final TState state) {
|
||||
addTargetedViewControllerToStack(viewControllerClass, targetFragment, state,
|
||||
viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link ViewControllerFragment#getState()}
|
||||
* and with specific {@link TargetedViewControllerFragment#getTarget()} and transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment;
|
||||
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
|
||||
* @param <TTargetFragment> Type of target fragment.
|
||||
*/
|
||||
@SuppressWarnings("CPD-END")
|
||||
public <TState extends AbstractState, TTargetState extends AbstractState,
|
||||
TTargetFragment extends ViewControllerFragment<? extends TTargetState, TActivity>> void pushViewControllerForResult(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
TargetedViewControllerFragment<TState, TTargetState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TTargetFragment targetFragment,
|
||||
@NonNull final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addTargetedViewControllerToStack(viewControllerClass, targetFragment, state,
|
||||
viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed.
|
||||
*/
|
||||
public void setViewControllerAsTop(
|
||||
@NonNull final Class<? extends ViewController<TActivity, StatelessViewControllerFragment<TActivity>>> viewControllerClass) {
|
||||
addStatelessViewControllerToStack(viewControllerClass, null, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link ViewControllerFragment#getState()}
|
||||
* and with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setViewControllerAsTop(
|
||||
@NonNull final Class<? extends ViewController<TActivity, SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific transaction setup
|
||||
* and with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info.
|
||||
*/
|
||||
public void setViewControllerAsTop(
|
||||
@NonNull final Class<? extends ViewController<TActivity, StatelessViewControllerFragment<TActivity>>> viewControllerClass,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addStatelessViewControllerToStack(viewControllerClass, null, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes {@link ViewController} on top of stack with specific {@link ViewControllerFragment#getState()} and with specific transaction setup
|
||||
* and with {@link #TOP_FRAGMENT_TAG_MARK} tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setViewControllerAsTop(
|
||||
@NonNull final Class<? extends ViewController<TActivity, SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewController} on top of stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
*/
|
||||
public void setInitialViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, StatelessViewControllerFragment<TActivity>>> viewControllerClass) {
|
||||
beforeSetInitialActions();
|
||||
setViewControllerAsTop(viewControllerClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewController} on top of stack
|
||||
* with specific {@link ViewControllerFragment#getState()}.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setInitialViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
setInitialViewController(viewControllerClass, state, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewController} on top of stack with specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
*/
|
||||
public void setInitialViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, StatelessViewControllerFragment<TActivity>>> viewControllerClass,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
beforeSetInitialActions();
|
||||
setViewControllerAsTop(viewControllerClass, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all {@link Fragment}s and places new initial {@link ViewController} on top of stack
|
||||
* with specific {@link ViewControllerFragment#getState()} and specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
public <TState extends AbstractState> void setInitialViewController(
|
||||
@NonNull final Class<? extends ViewController<TActivity, SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final TState state,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
beforeSetInitialActions();
|
||||
setViewControllerAsTop(viewControllerClass, state, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method to push stateless {@link ViewControllerFragment} to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param backStackTag Tag of {@link ViewControllerFragment} in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info.
|
||||
*/
|
||||
protected void addStatelessViewControllerToStack(
|
||||
@NonNull final Class<? extends ViewController<TActivity, ? extends StatelessViewControllerFragment<TActivity>>> viewControllerClass,
|
||||
@Nullable final Fragment targetFragment,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(StatelessViewControllerFragment.class, targetFragment, true,
|
||||
StatelessViewControllerFragment.createState(viewControllerClass), backStackTag, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method to push stateful {@link ViewControllerFragment} with target to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param backStackTag Tag of {@link ViewControllerFragment} in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
* @param <TTargetState> Type of state of target fragment. State is using to affect on that fragment;
|
||||
*/
|
||||
protected <TState extends AbstractState, TTargetState extends AbstractState> void addTargetedViewControllerToStack(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
? extends TargetedViewControllerFragment<TState, TTargetState, TActivity>>> viewControllerClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final TState state,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(TargetedViewControllerFragment.class, targetFragment, true,
|
||||
TargetedViewControllerFragment.createState(viewControllerClass, state), backStackTag, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method to push stateless {@link ViewControllerFragment} with target to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param backStackTag Tag of {@link ViewControllerFragment} in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
protected <TState extends AbstractState> void addTargetedStatelessViewControllerToStack(
|
||||
@NonNull final Class<? extends ViewController<TActivity,
|
||||
? extends StatelessTargetedViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(StatelessTargetedViewControllerFragment.class, targetFragment, true,
|
||||
StatelessTargetedViewControllerFragment.createState(viewControllerClass), backStackTag, transactionSetup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method to push stateful {@link ViewControllerFragment} to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} to be pushed;
|
||||
* @param targetFragment {@link ViewControllerFragment} to be set as target;
|
||||
* @param state {@link AbstractState} of {@link ViewController}'s fragment;
|
||||
* @param backStackTag Tag of {@link ViewControllerFragment} in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param <TState> Type of state of fragment.
|
||||
*/
|
||||
protected <TState extends AbstractState> void addViewControllerToStack(
|
||||
@NonNull final Class<? extends ViewController<TActivity, ? extends SimpleViewControllerFragment<TState, TActivity>>> viewControllerClass,
|
||||
@Nullable final Fragment targetFragment,
|
||||
@NonNull final TState state,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Function<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(SimpleViewControllerFragment.class, targetFragment, true,
|
||||
SimpleViewControllerFragment.createState(viewControllerClass, state), backStackTag, transactionSetup);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import android.support.annotation.IdRes
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v4.app.FragmentTransaction
|
||||
|
||||
import io.reactivex.functions.Function
|
||||
import ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Navigation based on [ViewController]s which are creating by [Fragment]s.
|
||||
* So basically it is just [FragmentNavigation] where most of fragments should be inherited from [ViewControllerFragment].
|
||||
*
|
||||
* @param TActivity Type of activity where [ViewController]s should be showed.
|
||||
*/
|
||||
open class ViewControllerNavigation<TActivity : FragmentActivity>(
|
||||
context: Context,
|
||||
fragmentManager: FragmentManager,
|
||||
@IdRes containerViewId: Int
|
||||
) : FragmentNavigation(context, fragmentManager, containerViewId) {
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState] and with specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> pushViewController(
|
||||
viewControllerClass: Class<out ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>,
|
||||
state: TState,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>? = null
|
||||
) {
|
||||
addViewControllerToStack(viewControllerClass, null, true, state, null, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] without adding to stack and with specific [ViewControllerFragment.getState].
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> pushSingleViewController(
|
||||
viewControllerClass: Class<out ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>,
|
||||
state: TState,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>? = null
|
||||
) {
|
||||
addViewControllerToStack(viewControllerClass, null, false, state, null, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState]
|
||||
* and with specific [TTargetFragment] and transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param targetFragment [ViewControllerFragment] to be set as target;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment;
|
||||
* @param TTargetFragment Type of target fragment.
|
||||
*/
|
||||
fun <TState : Parcelable, TTargetFragment : Fragment> pushViewControllerForResult(
|
||||
viewControllerClass: Class<out ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>,
|
||||
state: TState,
|
||||
targetFragment: TTargetFragment,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>? = null
|
||||
) {
|
||||
addViewControllerToStack(
|
||||
viewControllerClass,
|
||||
targetFragment,
|
||||
true,
|
||||
state,
|
||||
viewControllerClass.name + ';'.toString() + FragmentNavigation.WITH_TARGET_FRAGMENT_TAG_MARK,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes [ViewController] on top of stack with specific [ViewControllerFragment.getState] and with specific transaction setup
|
||||
* and with [.TOP_FRAGMENT_TAG_MARK] tag used for simple up/back navigation.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> setViewControllerAsTop(
|
||||
viewControllerClass: Class<out ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>,
|
||||
state: TState,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>? = null
|
||||
) {
|
||||
addViewControllerToStack(
|
||||
viewControllerClass,
|
||||
null,
|
||||
true,
|
||||
state,
|
||||
viewControllerClass.name + ';'.toString() + FragmentNavigation.TOP_FRAGMENT_TAG_MARK,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops all [Fragment]s and places new initial [ViewController] on top of stack
|
||||
* with specific [ViewControllerFragment.getState] and specific transaction setup.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
fun <TState : Parcelable> setInitialViewController(
|
||||
viewControllerClass: Class<out ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>,
|
||||
state: TState,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>? = null
|
||||
) {
|
||||
beforeSetInitialActions()
|
||||
setViewControllerAsTop(viewControllerClass, state, transactionSetup)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method to push stateful [ViewControllerFragment] to stack.
|
||||
*
|
||||
* @param viewControllerClass Class of [ViewController] to be pushed;
|
||||
* @param targetFragment [ViewControllerFragment] to be set as target;
|
||||
* @param state [Parcelable] of [ViewController]'s fragment;
|
||||
* @param backStackTag Tag of [ViewControllerFragment] in back stack;
|
||||
* @param transactionSetup Function to setup transaction before commit. It is useful to specify transition animations or additional info;
|
||||
* @param TState Type of state of fragment.
|
||||
*/
|
||||
protected fun <TState : Parcelable> addViewControllerToStack(
|
||||
viewControllerClass: Class<out ViewController<TActivity, out ViewControllerFragment<TState, TActivity>>>,
|
||||
targetFragment: Fragment?,
|
||||
addToStack: Boolean,
|
||||
state: TState,
|
||||
backStackTag: String?,
|
||||
transactionSetup: Function<FragmentTransaction, FragmentTransaction>?
|
||||
) {
|
||||
addToStack(
|
||||
ViewControllerFragment::class.java,
|
||||
targetFragment,
|
||||
addToStack,
|
||||
ViewControllerFragment.args(viewControllerClass, state),
|
||||
backStackTag,
|
||||
transactionSetup
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -35,130 +35,52 @@ import android.view.inputmethod.InputMethodManager;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import ru.touchin.roboswag.components.utils.BaseLifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.utils.Optional;
|
||||
import ru.touchin.roboswag.core.utils.pairs.HalfNullablePair;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 08/03/2016.
|
||||
* Base activity to use in components repository.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public abstract class BaseActivity extends AppCompatActivity
|
||||
implements LifecycleBindable {
|
||||
|
||||
private static final String ACTIVITY_RESULT_CODE_EXTRA = "ACTIVITY_RESULT_CODE_EXTRA";
|
||||
private static final String ACTIVITY_RESULT_DATA_EXTRA = "ACTIVITY_RESULT_DATA_EXTRA";
|
||||
public abstract class BaseActivity extends AppCompatActivity {
|
||||
|
||||
@NonNull
|
||||
private final ArrayList<OnBackPressedListener> onBackPressedListeners = new ArrayList<>();
|
||||
@NonNull
|
||||
private final BaseLifecycleBindable baseLifecycleBindable = new BaseLifecycleBindable();
|
||||
private boolean resumed;
|
||||
|
||||
@NonNull
|
||||
private final BehaviorSubject<Optional<HalfNullablePair<Integer, Intent>>> lastActivityResult
|
||||
= BehaviorSubject.createDefault(new Optional<HalfNullablePair<Integer, Intent>>(null));
|
||||
|
||||
/**
|
||||
* Returns if activity resumed.
|
||||
*
|
||||
* @return True if resumed.
|
||||
*/
|
||||
public boolean isActuallyResumed() {
|
||||
return resumed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onCreate();
|
||||
restoreLastActivityResult(savedInstanceState);
|
||||
}
|
||||
|
||||
private void restoreLastActivityResult(@Nullable final Bundle savedInstanceState) {
|
||||
if (savedInstanceState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastActivityResult.onNext(new Optional<>(new HalfNullablePair<>(savedInstanceState.getInt(ACTIVITY_RESULT_CODE_EXTRA),
|
||||
savedInstanceState.getParcelable(ACTIVITY_RESULT_DATA_EXTRA))));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, @Nullable final Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this) + " requestCode: " + requestCode + "; resultCode: " + resultCode);
|
||||
if (resultCode == RESULT_OK) {
|
||||
lastActivityResult.onNext(new Optional<>(new HalfNullablePair<>(requestCode, data)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observes activity result by request code coming from {@link #onActivityResult(int, int, Intent)}
|
||||
*
|
||||
* @param requestCode Unique code to identify activity result;
|
||||
* @return {@link Observable} which will emit data (Intents) from other activities (endlessly).
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<Intent> observeActivityResult(final int requestCode) {
|
||||
return lastActivityResult
|
||||
.concatMap(optional -> {
|
||||
final HalfNullablePair<Integer, Intent> activityResult = optional.get();
|
||||
if (activityResult == null || activityResult.getFirst() != requestCode) {
|
||||
return Observable.empty();
|
||||
}
|
||||
return Observable.just(activityResult.getSecond() != null ? activityResult.getSecond() : new Intent())
|
||||
.doOnNext(result -> lastActivityResult.onNext(new Optional<>(null)));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
resumed = true;
|
||||
baseLifecycleBindable.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
resumed = false;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull final Bundle stateToSave) {
|
||||
super.onSaveInstanceState(stateToSave);
|
||||
baseLifecycleBindable.onSaveInstanceState();
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
final HalfNullablePair<Integer, Intent> activityResult = lastActivityResult.getValue().get();
|
||||
if (activityResult != null) {
|
||||
stateToSave.putInt(ACTIVITY_RESULT_CODE_EXTRA, activityResult.getFirst());
|
||||
if (activityResult.getSecond() != null) {
|
||||
stateToSave.putParcelable(ACTIVITY_RESULT_DATA_EXTRA, activityResult.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -170,14 +92,12 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||
@Override
|
||||
protected void onStop() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
UiUtils.UI_LIFECYCLE_LC_GROUP.i(Lc.getCodePoint(this));
|
||||
baseLifecycleBindable.onDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +149,7 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||
* @param resId The resource id to search for data;
|
||||
* @return Drawable An object that can be used to draw this resource.
|
||||
*/
|
||||
@NonNull
|
||||
@Nullable
|
||||
public Drawable getDrawableCompat(@DrawableRes final int resId) {
|
||||
return ContextCompat.getDrawable(this, resId);
|
||||
}
|
||||
|
|
@ -257,187 +177,6 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-START")
|
||||
//CPD: it's ok as it's LifecycleBindable
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilStop(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilStop(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilStop(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilStop(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilDestroy(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilDestroy(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilDestroy(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CPD-END")
|
||||
/*
|
||||
* Interface to be implemented for someone who want to intercept device back button pressing event.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation.activities;
|
||||
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import ru.touchin.roboswag.components.utils.Logic;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Activity which is containing specific {@link Logic}
|
||||
* to support navigation based on {@link ru.touchin.roboswag.components.navigation.ViewController}s.
|
||||
*
|
||||
* @param <TLogic> Type of application's {@link Logic}.
|
||||
*/
|
||||
public abstract class ViewControllerActivity<TLogic extends Logic> extends BaseActivity {
|
||||
|
||||
//it is needed to hold strong reference to logic
|
||||
private TLogic reference;
|
||||
|
||||
/**
|
||||
* It should return specific class where all logic will be.
|
||||
*
|
||||
* @return Returns class of specific {@link Logic}.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<TLogic> getLogicClass();
|
||||
|
||||
/**
|
||||
* Returns (and creates if needed) application's logic.
|
||||
*
|
||||
* @return Object which represents application's logic.
|
||||
*/
|
||||
@NonNull
|
||||
public TLogic getLogic() {
|
||||
synchronized (ViewControllerActivity.class) {
|
||||
if (reference == null) {
|
||||
reference = Logic.getInstance(this, getLogicClass());
|
||||
}
|
||||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
// use {@link #reconfigureNavigation}
|
||||
public void invalidateOptionsMenu() {
|
||||
super.invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
// use {@link #reconfigureNavigation}
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
super.supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates navigation and calls {@link #onConfigureNavigation} for all navigation elements.
|
||||
*/
|
||||
public void reconfigureNavigation() {
|
||||
super.supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
// use {@link #onConfigureNavigation}
|
||||
public boolean onCreateOptionsMenu(@NonNull final Menu menu) {
|
||||
onConfigureNavigation(menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when activity configuring ActionBar, Toolbar, Sidebar, AppBar etc.
|
||||
* It is calling before it's {@link ru.touchin.roboswag.components.navigation.ViewController}'s.
|
||||
*
|
||||
* @param menu The options menu in which you place your menu items.
|
||||
*/
|
||||
public void onConfigureNavigation(@NonNull final Menu menu) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends View> T findViewById(@IdRes final int id) {
|
||||
final T viewById = super.findViewById(id);
|
||||
if (viewById == null) {
|
||||
throw new ShouldNotHappenException("No view for id=" + getResources().getResourceName(id));
|
||||
}
|
||||
return viewById;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.touchin.roboswag.components.navigation.AbstractState;
|
||||
import ru.touchin.roboswag.components.navigation.ViewController;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Simple {@link ViewControllerFragment} which is using by {@link ru.touchin.roboswag.components.navigation.ViewControllerNavigation}.
|
||||
*
|
||||
* @param <TState> Type of object which is representing it's fragment state;
|
||||
* @param <TActivity> Type of {@link ViewControllerActivity} where fragment could be attached to.
|
||||
*/
|
||||
public class SimpleViewControllerFragment<TState extends AbstractState, TActivity extends ViewControllerActivity<?>>
|
||||
extends ViewControllerFragment<TState, TActivity> {
|
||||
|
||||
private static final String VIEW_CONTROLLER_CLASS_EXTRA = "VIEW_CONTROLLER_CLASS_EXTRA";
|
||||
|
||||
/**
|
||||
* Creates {@link Bundle} which will store state and {@link ViewController}'s class.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} which will be instantiated inside this fragment;
|
||||
* @param state State to use into {@link ViewController};
|
||||
* @return Returns {@link Bundle} with state inside.
|
||||
*/
|
||||
@NonNull
|
||||
public static Bundle createState(@NonNull final Class<? extends ViewController> viewControllerClass,
|
||||
@NonNull final AbstractState state) {
|
||||
final Bundle result = createState(state);
|
||||
result.putSerializable(VIEW_CONTROLLER_CLASS_EXTRA, viewControllerClass);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Class<? extends ViewController<TActivity,
|
||||
? extends ViewControllerFragment<TState, TActivity>>> viewControllerClass;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends ViewController<TActivity,
|
||||
? extends ViewControllerFragment<TState, TActivity>>> getViewControllerClass() {
|
||||
return viewControllerClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isStateRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewControllerClass = (Class<? extends ViewController<TActivity,
|
||||
? extends ViewControllerFragment<TState, TActivity>>>) getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA);
|
||||
}
|
||||
|
||||
protected static class DefaultState extends AbstractState {
|
||||
// just default implementation
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.components.navigation.AbstractState;
|
||||
import ru.touchin.roboswag.components.navigation.ViewController;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 11/04/2016.
|
||||
* Simple {@link ViewControllerFragment} with no state and with attached {@link #getTargetFragment()}
|
||||
* which is using by {@link ru.touchin.roboswag.components.navigation.ViewControllerNavigation}.
|
||||
*
|
||||
* @param <TActivity> Type of {@link ViewControllerActivity} where fragment could be attached to.
|
||||
*/
|
||||
@SuppressWarnings("PMD.UseUtilityClass")
|
||||
//UseUtilityClass: PMD bug
|
||||
public class StatelessTargetedViewControllerFragment<TTargetState extends AbstractState,
|
||||
TActivity extends ViewControllerActivity<?>>
|
||||
extends TargetedViewControllerFragment<AbstractState, TTargetState, TActivity> {
|
||||
|
||||
/**
|
||||
* Creates {@link Bundle} which will store state and {@link ViewController}'s class.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} which will be instantiated inside this fragment;
|
||||
* @return Returns {@link Bundle} with state inside.
|
||||
*/
|
||||
@NonNull
|
||||
public static Bundle createState(@NonNull final Class<? extends ViewController> viewControllerClass) {
|
||||
return createState(viewControllerClass, new DefaultState());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isStateRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractState getState() {
|
||||
Lc.assertion("Trying to access to state of stateless fragment of " + getViewControllerClass());
|
||||
return super.getState();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.components.navigation.AbstractState;
|
||||
import ru.touchin.roboswag.components.navigation.ViewController;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 12/03/2016.
|
||||
* Simple {@link ViewControllerFragment} with no state which is using by {@link ru.touchin.roboswag.components.navigation.ViewControllerNavigation}.
|
||||
*
|
||||
* @param <TActivity> Type of {@link ViewControllerActivity} where fragment could be attached to.
|
||||
*/
|
||||
@SuppressWarnings("PMD.UseUtilityClass")
|
||||
//UseUtilityClass: PMD bug
|
||||
public class StatelessViewControllerFragment<TActivity extends ViewControllerActivity<?>>
|
||||
extends SimpleViewControllerFragment<AbstractState, TActivity> {
|
||||
|
||||
/**
|
||||
* Creates {@link Bundle} which will store state and {@link ViewController}'s class.
|
||||
*
|
||||
* @param viewControllerClass Class of {@link ViewController} which will be instantiated inside this fragment;
|
||||
* @return Returns {@link Bundle} with state inside.
|
||||
*/
|
||||
@NonNull
|
||||
public static Bundle createState(@NonNull final Class<? extends ViewController> viewControllerClass) {
|
||||
return createState(viewControllerClass, new DefaultState());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractState getState() {
|
||||
Lc.assertion("Trying to access to state of stateless fragment of " + getViewControllerClass());
|
||||
return super.getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isStateRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation.fragments;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.touchin.roboswag.components.navigation.AbstractState;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 11/04/2016.
|
||||
* Simple {@link ViewControllerFragment} with attached {@link #getTargetFragment()}
|
||||
* which is using by {@link ru.touchin.roboswag.components.navigation.ViewControllerNavigation}.
|
||||
*
|
||||
* @param <TState> Type of object which is representing it's fragment state;
|
||||
* @param <TActivity> Type of {@link ViewControllerActivity} where fragment could be attached to.
|
||||
*/
|
||||
public class TargetedViewControllerFragment<TState extends AbstractState,
|
||||
TTargetState extends AbstractState,
|
||||
TActivity extends ViewControllerActivity<?>>
|
||||
extends SimpleViewControllerFragment<TState, TActivity> {
|
||||
|
||||
/**
|
||||
* Returns specific {@link ViewControllerFragment} which is attached to this fragment as {@link #getTargetFragment()}.
|
||||
*
|
||||
* @return Target fragment.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@NonNull
|
||||
public ViewControllerFragment<TTargetState, TActivity> getTarget() {
|
||||
if (!(getTargetFragment() instanceof ViewControllerFragment)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
return (ViewControllerFragment<TTargetState, TActivity>) getTargetFragment();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,10 +24,11 @@ import android.content.Intent;
|
|||
import android.graphics.Canvas;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.InflateException;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
|
@ -36,33 +37,23 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import ru.touchin.roboswag.components.navigation.AbstractState;
|
||||
import ru.touchin.roboswag.components.navigation.ViewController;
|
||||
import ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.utils.Optional;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import ru.touchin.roboswag.core.utils.pairs.NullablePair;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Fragment instantiated in specific activity of {@link TActivity} type that is holding {@link ViewController} inside.
|
||||
*
|
||||
* @param <TState> Type of object which is representing it's fragment state;
|
||||
* @param <TActivity> Type of {@link ViewControllerActivity} where fragment could be attached to.
|
||||
* @param <TActivity> Type of {@link FragmentActivity} where fragment could be attached to.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public abstract class ViewControllerFragment<TState extends AbstractState, TActivity extends ViewControllerActivity<?>>
|
||||
extends ViewFragment<TActivity> {
|
||||
public abstract class ViewControllerFragment<TState extends Parcelable, TActivity extends FragmentActivity> extends ViewFragment<TActivity> {
|
||||
|
||||
private static final String VIEW_CONTROLLER_CLASS_EXTRA = "VIEW_CONTROLLER_CLASS_EXTRA";
|
||||
private static final String VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA";
|
||||
|
||||
private static boolean inDebugMode;
|
||||
|
|
@ -84,17 +75,16 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
ViewControllerFragment.acceptableUiCalculationTime = acceptableUiCalculationTime;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NonNull
|
||||
private static <T extends Serializable> T reserialize(@NonNull final T serializable) {
|
||||
private static <T extends Parcelable> T reserialize(@NonNull final T parcelable) {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
parcel.writeSerializable(serializable);
|
||||
parcel.writeParcelable(parcelable, 0);
|
||||
final byte[] serializableBytes = parcel.marshall();
|
||||
parcel.recycle();
|
||||
parcel = Parcel.obtain();
|
||||
parcel.unmarshall(serializableBytes, 0, serializableBytes.length);
|
||||
parcel.setDataPosition(0);
|
||||
final T result = (T) parcel.readSerializable();
|
||||
final T result = parcel.readParcelable(parcelable.getClass().getClassLoader());
|
||||
parcel.recycle();
|
||||
return result;
|
||||
}
|
||||
|
|
@ -106,32 +96,20 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
* @return Returns bundle with state inside.
|
||||
*/
|
||||
@NonNull
|
||||
public static Bundle createState(@Nullable final AbstractState state) {
|
||||
public static Bundle args(@NonNull final Class<? extends ViewController> viewControllerClass, @Nullable final Parcelable state) {
|
||||
final Bundle result = new Bundle();
|
||||
result.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
result.putSerializable(VIEW_CONTROLLER_CLASS_EXTRA, viewControllerClass);
|
||||
result.putParcelable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final BehaviorSubject<Optional<TActivity>> activitySubject = BehaviorSubject.create();
|
||||
@NonNull
|
||||
private final BehaviorSubject<NullablePair<PlaceholderView, Bundle>> viewSubject = BehaviorSubject.create();
|
||||
@Nullable
|
||||
private ViewController viewController;
|
||||
private Disposable viewControllerSubscription;
|
||||
private Class<ViewController<TActivity, ViewControllerFragment<TState, TActivity>>> viewControllerClass;
|
||||
private TState state;
|
||||
private boolean started;
|
||||
private boolean stateCreated;
|
||||
|
||||
private void tryCreateState(@Nullable final Context context) {
|
||||
if (!stateCreated && state != null && context != null) {
|
||||
state.onCreate();
|
||||
stateCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns specific {@link AbstractState} which contains state of fragment and it's {@link ViewController}.
|
||||
* Returns specific {@link Parcelable} which contains state of fragment and it's {@link ViewController}.
|
||||
*
|
||||
* @return Object represents state.
|
||||
*/
|
||||
|
|
@ -140,64 +118,37 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* It should return specific {@link ViewController} class to control instantiated view by logic after activity creation.
|
||||
*
|
||||
* @return Returns class of specific {@link ViewController}.
|
||||
*/
|
||||
@NonNull
|
||||
public abstract Class<? extends ViewController<TActivity,
|
||||
? extends ViewControllerFragment<TState, TActivity>>> getViewControllerClass();
|
||||
|
||||
/**
|
||||
* Returns if ViewControllerFragment requires state or not.
|
||||
*
|
||||
* @return true if state is required
|
||||
*/
|
||||
protected abstract boolean isStateRequired();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(!isChildFragment());
|
||||
|
||||
//noinspection unchecked
|
||||
viewControllerClass = (Class<ViewController<TActivity, ViewControllerFragment<TState, TActivity>>>)
|
||||
getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA);
|
||||
state = savedInstanceState != null
|
||||
? (TState) savedInstanceState.getSerializable(VIEW_CONTROLLER_STATE_EXTRA)
|
||||
: (getArguments() != null ? (TState) getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA) : null);
|
||||
? savedInstanceState.getParcelable(VIEW_CONTROLLER_STATE_EXTRA)
|
||||
: (getArguments() != null ? getArguments().getParcelable(VIEW_CONTROLLER_STATE_EXTRA) : null);
|
||||
if (state != null) {
|
||||
if (inDebugMode) {
|
||||
state = reserialize(state);
|
||||
}
|
||||
tryCreateState(getContext());
|
||||
} else if (isStateRequired()) {
|
||||
} else {
|
||||
Lc.assertion("State is required and null");
|
||||
}
|
||||
viewControllerSubscription = Observable
|
||||
.combineLatest(activitySubject.distinctUntilChanged(), viewSubject.distinctUntilChanged(),
|
||||
(activityOptional, viewInfo) -> {
|
||||
final TActivity activity = activityOptional.get();
|
||||
final PlaceholderView container = viewInfo.getFirst();
|
||||
if (activity == null || container == null) {
|
||||
return new Optional<ViewController>(null);
|
||||
}
|
||||
final ViewController newViewController = createViewController(activity, container, viewInfo.getSecond());
|
||||
newViewController.onCreate();
|
||||
return new Optional<>(newViewController);
|
||||
})
|
||||
.subscribe(this::onViewControllerChanged,
|
||||
throwable -> Lc.cutAssertion(throwable, InvocationTargetException.class, InflateException.class));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ViewController createViewController(@NonNull final TActivity activity, @NonNull final PlaceholderView view,
|
||||
@Nullable final Bundle savedInstanceState) {
|
||||
|
||||
if (getViewControllerClass().getConstructors().length != 1) {
|
||||
throw new ShouldNotHappenException("There should be single constructor for " + getViewControllerClass());
|
||||
private ViewController createViewController(
|
||||
@NonNull final FragmentActivity activity,
|
||||
@NonNull final PlaceholderView view,
|
||||
@Nullable final Bundle savedInstanceState
|
||||
) {
|
||||
if (viewControllerClass.getConstructors().length != 1) {
|
||||
throw new ShouldNotHappenException("There should be single constructor for " + viewControllerClass);
|
||||
}
|
||||
final Constructor<?> constructor = getViewControllerClass().getConstructors()[0];
|
||||
final Constructor<?> constructor = viewControllerClass.getConstructors()[0];
|
||||
final ViewController.CreationContext creationContext = new ViewController.CreationContext(activity, this, view);
|
||||
final long creationTime = inDebugMode ? SystemClock.elapsedRealtime() : 0;
|
||||
try {
|
||||
|
|
@ -209,7 +160,7 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
default:
|
||||
throw new ShouldNotHappenException("Wrong constructor parameters count: " + constructor.getParameterTypes().length);
|
||||
}
|
||||
} catch (final Exception exception) {
|
||||
} catch (@NonNull final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
} finally {
|
||||
checkCreationTime(creationTime);
|
||||
|
|
@ -220,46 +171,33 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
if (inDebugMode) {
|
||||
final long creationPeriod = SystemClock.elapsedRealtime() - creationTime;
|
||||
if (creationPeriod > acceptableUiCalculationTime) {
|
||||
UiUtils.UI_METRICS_LC_GROUP.w("Creation of %s took too much: %dms", getViewControllerClass(), creationPeriod);
|
||||
UiUtils.UI_METRICS_LC_GROUP.w("Creation of %s took too much: %dms", viewControllerClass, creationPeriod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull final Context context) {
|
||||
super.onAttach(context);
|
||||
tryCreateState(context);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@NonNull
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
@Nullable final ViewGroup container,
|
||||
@Nullable final Bundle savedInstanceState) {
|
||||
return new PlaceholderView(inflater.getContext(), getViewControllerClass().getName());
|
||||
public final View onCreateView(
|
||||
@NonNull final LayoutInflater inflater,
|
||||
@Nullable final ViewGroup container,
|
||||
@Nullable final Bundle savedInstanceState
|
||||
) {
|
||||
return new PlaceholderView(inflater.getContext(), viewControllerClass.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (view instanceof PlaceholderView) {
|
||||
viewSubject.onNext(new NullablePair<>((PlaceholderView) view, savedInstanceState));
|
||||
} else {
|
||||
Lc.assertion("View should be instanceof PlaceholderView");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(@NonNull final View view, @NonNull final TActivity activity, @Nullable final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(view, activity, savedInstanceState);
|
||||
activitySubject.onNext(new Optional<>(activity));
|
||||
public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
//noinspection ConstantConditions
|
||||
viewController = createViewController(requireActivity(), (PlaceholderView) getView(), savedInstanceState);
|
||||
viewController.onCreate();
|
||||
requireActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart(@NonNull final View view, @NonNull final TActivity activity) {
|
||||
super.onStart(view, activity);
|
||||
started = true;
|
||||
if (viewController != null) {
|
||||
viewController.onStart();
|
||||
}
|
||||
|
|
@ -289,23 +227,12 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when activity configuring ActionBar, Toolbar, Sidebar etc.
|
||||
* If it will be called or not depends on {@link #hasOptionsMenu()} and {@link #isMenuVisible()}.
|
||||
*
|
||||
* @param menu The options menu in which you place your items;
|
||||
* @param inflater Helper to inflate menu items.
|
||||
*/
|
||||
protected void onConfigureNavigation(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
if (viewController != null) {
|
||||
viewController.onConfigureNavigation(menu, inflater);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
onConfigureNavigation(menu, inflater);
|
||||
if (viewController != null) {
|
||||
viewController.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -313,19 +240,6 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
return (viewController != null && viewController.onOptionsItemSelected(item)) || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void onViewControllerChanged(@NonNull final Optional<ViewController> viewControllerOptional) {
|
||||
if (this.viewController != null) {
|
||||
this.viewController.onDestroy();
|
||||
}
|
||||
this.viewController = viewControllerOptional.get();
|
||||
if (this.viewController != null) {
|
||||
if (started) {
|
||||
this.viewController.onStart();
|
||||
}
|
||||
this.viewController.getActivity().reconfigureNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause(@NonNull final View view, @NonNull final TActivity activity) {
|
||||
super.onPause(view, activity);
|
||||
|
|
@ -340,7 +254,7 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
if (viewController != null) {
|
||||
viewController.onSaveInstanceState(savedInstanceState);
|
||||
}
|
||||
savedInstanceState.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
savedInstanceState.putParcelable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -353,7 +267,6 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
|
||||
@Override
|
||||
protected void onStop(@NonNull final View view, @NonNull final TActivity activity) {
|
||||
started = false;
|
||||
if (viewController != null) {
|
||||
viewController.onStop();
|
||||
}
|
||||
|
|
@ -361,25 +274,12 @@ public abstract class ViewControllerFragment<TState extends AbstractState, TActi
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroyView(@NonNull final View view) {
|
||||
viewSubject.onNext(new NullablePair<>(null, null));
|
||||
super.onDestroyView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
activitySubject.onNext(new Optional<>(null));
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
viewControllerSubscription.dispose();
|
||||
if (viewController != null && !viewController.isDestroyed()) {
|
||||
public void onDestroyView() {
|
||||
if (viewController != null) {
|
||||
viewController.onDestroy();
|
||||
viewController = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import android.support.annotation.CallSuper;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -39,8 +39,7 @@ import ru.touchin.roboswag.core.log.Lc;
|
|||
*
|
||||
* @param <TActivity> Type of activity which to such fragment could be attached.
|
||||
*/
|
||||
public abstract class ViewFragment<TActivity extends AppCompatActivity> extends Fragment
|
||||
implements OnFragmentStartedListener {
|
||||
public abstract class ViewFragment<TActivity extends FragmentActivity> extends Fragment implements OnFragmentStartedListener {
|
||||
|
||||
private boolean appeared;
|
||||
private boolean started;
|
||||
|
|
@ -88,27 +87,12 @@ public abstract class ViewFragment<TActivity extends AppCompatActivity> extends
|
|||
//do nothing
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (getView() == null || getBaseActivity() == null) {
|
||||
Lc.assertion("View and activity shouldn't be null");
|
||||
return;
|
||||
}
|
||||
onActivityCreated(getView(), getBaseActivity(), savedInstanceState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement of {@link #onActivityCreated} with non null activity as first parameter.
|
||||
*
|
||||
* @param view Instantiated view.
|
||||
* @param activity Activity which fragment attached to.
|
||||
* @param savedInstanceState If the fragment is being re-created from a previous saved state, this is the state.
|
||||
*/
|
||||
@CallSuper
|
||||
public void onActivityCreated(@NonNull final View view, @NonNull final TActivity activity, @Nullable final Bundle savedInstanceState) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
private void callMethodAfterInstantiation(@NonNull final BiConsumer<View, TActivity> action) {
|
||||
|
|
@ -243,25 +227,4 @@ public abstract class ViewFragment<TActivity extends AppCompatActivity> extends
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (getView() == null) {
|
||||
Lc.assertion("View shouldn't be null");
|
||||
return;
|
||||
}
|
||||
onDestroyView(getView());
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement of {@link #onDestroyView} with non null activity as first parameter.
|
||||
*
|
||||
* @param view Instantiated view.
|
||||
*/
|
||||
@CallSuper
|
||||
protected void onDestroyView(@NonNull final View view) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.utils;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.internal.functions.Functions;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 18/04/16.
|
||||
* Simple implementation of {@link LifecycleBindable}. Could be used to not implement interface but use such object inside.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public class BaseLifecycleBindable implements LifecycleBindable {
|
||||
|
||||
private static final String UNTIL_DESTROY_METHOD = "untilDestroy";
|
||||
private static final String UNTIL_STOP_METHOD = "untilStop";
|
||||
|
||||
@NonNull
|
||||
private final BehaviorSubject<Boolean> isCreatedSubject = BehaviorSubject.create();
|
||||
@NonNull
|
||||
private final BehaviorSubject<Boolean> isStartedSubject = BehaviorSubject.create();
|
||||
@NonNull
|
||||
private final BehaviorSubject<Boolean> isInAfterSaving = BehaviorSubject.createDefault(false);
|
||||
|
||||
/**
|
||||
* Call it on parent's onCreate method.
|
||||
*/
|
||||
public void onCreate() {
|
||||
isCreatedSubject.onNext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it on parent's onStart method.
|
||||
*/
|
||||
public void onStart() {
|
||||
isStartedSubject.onNext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it on parent's onResume method.
|
||||
* It is needed as sometimes onSaveInstanceState() calling after onPause() with no onStop call. So lifecycle object going in stopped state.
|
||||
* In that case onResume will be called after onSaveInstanceState so lifecycle object is becoming started.
|
||||
*/
|
||||
public void onResume() {
|
||||
isInAfterSaving.onNext(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it on parent's onSaveInstanceState method.
|
||||
*/
|
||||
public void onSaveInstanceState() {
|
||||
isInAfterSaving.onNext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it on parent's onStop method.
|
||||
*/
|
||||
public void onStop() {
|
||||
isStartedSubject.onNext(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call it on parent's onDestroy method.
|
||||
*/
|
||||
public void onDestroy() {
|
||||
isCreatedSubject.onNext(false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(observable, Functions.emptyConsumer(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD), Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(observable, onNextAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD), Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return untilStop(observable, onNextAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return until(observable, isStartedSubject.map(started -> !started)
|
||||
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)),
|
||||
onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(single, Functions.emptyConsumer(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(single, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(single.toObservable(), isStartedSubject.map(started -> !started)
|
||||
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)),
|
||||
onSuccessAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(completable, Functions.EMPTY_ACTION, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(completable, onCompletedAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(completable.toObservable(), isStartedSubject.map(started -> !started)
|
||||
.delay(item -> isInAfterSaving.filter(inAfterSaving -> !inAfterSaving)),
|
||||
Functions.emptyConsumer(), onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(maybe, Functions.emptyConsumer(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilStop(maybe, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(maybe.toObservable(), isStartedSubject.map(started -> !started), onSuccessAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(observable, Functions.emptyConsumer(),
|
||||
getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD), Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(observable, onNextAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD), Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return untilDestroy(observable, onNextAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return until(observable, isCreatedSubject.map(created -> !created), onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(single, Functions.emptyConsumer(), getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(single, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(single.toObservable(), isCreatedSubject.map(created -> !created), onSuccessAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(completable, Functions.EMPTY_ACTION, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(completable, onCompletedAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(completable.toObservable(), isCreatedSubject.map(created -> !created),
|
||||
Functions.emptyConsumer(), onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(maybe, Functions.emptyConsumer(), getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
final String codePoint = Lc.getCodePoint(this, 2);
|
||||
return untilDestroy(maybe, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return until(maybe.toObservable(), isCreatedSubject.map(created -> !created), onSuccessAction, onErrorAction, Functions.EMPTY_ACTION);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private <T> Disposable until(@NonNull final Observable<T> observable,
|
||||
@NonNull final Observable<Boolean> conditionSubject,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
final Observable<T> actualObservable;
|
||||
if (onNextAction == Functions.emptyConsumer() && onErrorAction == (Consumer) Functions.emptyConsumer()
|
||||
&& onCompletedAction == Functions.EMPTY_ACTION) {
|
||||
actualObservable = observable;
|
||||
} else {
|
||||
actualObservable = observable.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnComplete(onCompletedAction)
|
||||
.doOnNext(onNextAction)
|
||||
.doOnError(onErrorAction);
|
||||
}
|
||||
|
||||
return isCreatedSubject.firstOrError()
|
||||
.flatMapObservable(created -> created ? actualObservable : Observable.empty())
|
||||
.takeUntil(conditionSubject.filter(condition -> condition))
|
||||
.onErrorResumeNext(throwable -> {
|
||||
if (throwable instanceof RuntimeException) {
|
||||
Lc.assertion(throwable);
|
||||
}
|
||||
return Observable.empty();
|
||||
})
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Consumer<Throwable> getActionThrowableForAssertion(@NonNull final String codePoint, @NonNull final String method) {
|
||||
return throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on " + method + " at " + codePoint, throwable));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,391 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.utils;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.CompletableEmitter;
|
||||
import io.reactivex.Emitter;
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.MaybeEmitter;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleEmitter;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 15/04/16.
|
||||
* Interface that should be implemented by lifecycle-based elements ({@link android.app.Activity}, {@link android.support.v4.app.Fragment} etc.)
|
||||
* to not manually manage subscriptions.
|
||||
* Use {@link #untilStop(Observable)} method to subscribe to observable where you want and unsubscribe onStop.
|
||||
* Use {@link #untilDestroy(Observable)} method to subscribe to observable where you want and unsubscribe onDestroy.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public interface LifecycleBindable {
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the observable.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onStop;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which will unsubscribes from observable onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Observable<T> observable);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the observable and calls onNextAction on every emitted item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onStop;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which will unsubscribes from observable onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Observable<T> observable, @NonNull Consumer<T> onNextAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the observable and calls onNextAction and onErrorAction on observable events.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onStop;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link Emitter#onError(Throwable)} throwable;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which will unsubscribes from observable onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Observable<T> observable, @NonNull Consumer<T> onNextAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the observable and calls onNextAction, onErrorAction and onCompletedAction on observable events.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onStop;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link Emitter#onError(Throwable)} throwable;
|
||||
* @param onCompletedAction Action which will raise at {@link Emitter#onComplete()} on completion of observable;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source observable to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Observable<T> observable,
|
||||
@NonNull Consumer<T> onNextAction, @NonNull Consumer<Throwable> onErrorAction, @NonNull Action onCompletedAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the single.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onStop;
|
||||
* @param <T> Type of emitted by single item;
|
||||
* @return {@link Disposable} which will unsubscribes from single onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Single<T> single);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the single and calls onSuccessAction on the emitted item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onStop;
|
||||
* @param onSuccessAction Action which will raise on every {@link SingleEmitter#onSuccess(Object)} item;
|
||||
* @param <T> Type of emitted by single item;
|
||||
* @return {@link Disposable} which will unsubscribes from single onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Single<T> single, @NonNull Consumer<T> onSuccessAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the single and calls onSuccessAction and onErrorAction on single events.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onStop;
|
||||
* @param onSuccessAction Action which will raise on every {@link SingleEmitter#onSuccess(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link SingleEmitter#onError(Throwable)} throwable;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source single to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Single<T> single, @NonNull Consumer<T> onSuccessAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the completable.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onStop;
|
||||
* @return {@link Disposable} which will unsubscribes from completable onStop.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilStop(@NonNull Completable completable);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the completable and calls onCompletedAction on completable item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onStop;
|
||||
* @param onCompletedAction Action which will raise at {@link CompletableEmitter#onComplete()} on completion of observable;
|
||||
* @return {@link Disposable} which is wrapping source completable to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilStop(@NonNull Completable completable, @NonNull Action onCompletedAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the completable and calls onCompletedAction and onErrorAction on completable item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onStop;
|
||||
* @param onCompletedAction Action which will raise at {@link CompletableEmitter#onComplete()} on completion of observable;
|
||||
* @param onErrorAction Action which will raise on every {@link CompletableEmitter#onError(Throwable)} throwable;
|
||||
* @return {@link Disposable} which is wrapping source completable to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilStop(@NonNull Completable completable, @NonNull Action onCompletedAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the maybe.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onStop;
|
||||
* @return {@link Disposable} which will unsubscribes from completable onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Maybe<T> maybe);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the maybe and calls onCompletedAction on maybe item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onStop;
|
||||
* @param onSuccessAction Action which will raise at {@link MaybeEmitter#onSuccess(Object)} ()} on completion of observable;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Maybe<T> maybe, @NonNull Consumer<T> onSuccessAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onStop.
|
||||
* It is automatically subscribing to the maybe and calls onCompletedAction and onErrorAction on maybe item.
|
||||
* Usually it is using to stop requests/execution while element is off or to not do illegal actions after onStop like fragment's stack changing.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onStop;
|
||||
* @param onSuccessAction Action which will raise at {@link MaybeEmitter#onSuccess(Object)} ()} on completion of observable;
|
||||
* @param onErrorAction Action which will raise on every {@link MaybeEmitter#onError(Throwable)} throwable;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onStop.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilStop(@NonNull Maybe<T> maybe, @NonNull Consumer<T> onSuccessAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the observable.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onDestroy;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Observable<T> observable);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the observable and calls onNextAction on every emitted item.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onDestroy;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source observable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Observable<T> observable, @NonNull Consumer<T> onNextAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the observable and calls onNextAction and onErrorAction on observable events.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onDestroy;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link Emitter#onError(Throwable)} throwable;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source observable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Observable<T> observable, @NonNull Consumer<T> onNextAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the observable and calls onNextAction, onErrorAction and onCompletedAction on observable events.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable {@link Observable} to subscribe until onDestroy;
|
||||
* @param onNextAction Action which will raise on every {@link Emitter#onNext(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link Emitter#onError(Throwable)} throwable;
|
||||
* @param onCompletedAction Action which will raise at {@link Emitter#onComplete()} on completion of observable;
|
||||
* @param <T> Type of emitted by observable items;
|
||||
* @return {@link Disposable} which is wrapping source observable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Observable<T> observable,
|
||||
@NonNull Consumer<T> onNextAction, @NonNull Consumer<Throwable> onErrorAction, @NonNull Action onCompletedAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the single.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onDestroy;
|
||||
* @param <T> Type of emitted by single items;
|
||||
* @return {@link Disposable} which is wrapping source single to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Single<T> single);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the single and calls onSuccessAction on every emitted item.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every {@link SingleEmitter#onSuccess(Object)} item;
|
||||
* @param <T> Type of emitted by single items;
|
||||
* @return {@link Disposable} which is wrapping source single to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Single<T> single, @NonNull Consumer<T> onSuccessAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the single and calls onSuccessAction and onErrorAction on single events.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single {@link Single} to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every {@link SingleEmitter#onSuccess(Object)} item;
|
||||
* @param onErrorAction Action which will raise on every {@link SingleEmitter#onError(Throwable)} throwable;
|
||||
* @param <T> Type of emitted by single items;
|
||||
* @return {@link Disposable} which is wrapping source single to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Single<T> single, @NonNull Consumer<T> onSuccessAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the completable.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onDestroy;
|
||||
* @return {@link Disposable} which is wrapping source completable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilDestroy(@NonNull Completable completable);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the completable and calls onCompletedAction on completable item.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onDestroy;
|
||||
* @param onCompletedAction Action which will raise on every {@link CompletableEmitter#onComplete()} item;
|
||||
* @return {@link Disposable} which is wrapping source single to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilDestroy(@NonNull Completable completable, @NonNull Action onCompletedAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the completable and calls onCompletedAction and onErrorAction on completable events.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onDestroy;
|
||||
* @param onCompletedAction Action which will raise on every {@link CompletableEmitter#onComplete()} item;
|
||||
* @param onErrorAction Action which will raise on every {@link CompletableEmitter#onError(Throwable)} throwable;
|
||||
* @return {@link Disposable} which is wrapping source completable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
Disposable untilDestroy(@NonNull Completable completable, @NonNull Action onCompletedAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the maybe.
|
||||
* Don't forget to process errors if maybe can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onDestroy;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Maybe<T> maybe);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the maybe and calls onCompletedAction on maybe item.
|
||||
* Don't forget to process errors if maybe can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every {@link MaybeEmitter#onSuccess(Object)} ()} item;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Maybe<T> maybe, @NonNull Consumer<T> onSuccessAction);
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the maybe and calls onSuccessAction and onErrorAction on maybe events.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param maybe {@link Maybe} to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every {@link MaybeEmitter#onSuccess(Object)} ()} item;
|
||||
* @param onErrorAction Action which will raise on every {@link MaybeEmitter#onError(Throwable)} throwable;
|
||||
* @return {@link Disposable} which is wrapping source maybe to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
<T> Disposable untilDestroy(@NonNull Maybe<T> maybe, @NonNull Consumer<T> onSuccessAction, @NonNull Consumer<Throwable> onErrorAction);
|
||||
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 24/03/16.
|
||||
* Base class representing application's logic.
|
||||
* In specific application it should be child of it (usually one) which contains all methods/objects related to logic.
|
||||
* It should contains interface to work with API/preferences/database/file system/system parameters etc.
|
||||
* Be sure that all objects/instances/services created to represents logic are not getting a lot of time to be instantiated, if they take a lot time
|
||||
* for instantiation then it is wrong logic and it should be moved into asynchronous operations via {@link Observable} or so.
|
||||
* Also it shouldn't create massive data objects and a lot of objects instantly. Basically it should just create bunch of interfaces inside
|
||||
* which will allows to access to some logic methods.
|
||||
* In fact it is similar to dependency injection pattern but with full control of instantiation and only one single instance of {@link Logic} per app.
|
||||
* If you want to use it then just create getter in {@link android.app.Service}/{@link android.app.Activity}/{@link android.content.BroadcastReceiver}
|
||||
* or any else context-based elements and do not forget to store reference to {@link Logic} into field because else it will be consumed by GC.
|
||||
* Sample of {@link Logic} using is in {@link ru.touchin.roboswag.components.navigation.activities.ViewControllerActivity}.
|
||||
* NOTE: Ideally creation of logic should be asynchronous and stored in specific {@link android.app.Service} so it should be accessed
|
||||
* asynchronously via {@link Observable} or so. But in fact it requires {@link android.app.Service} plus more complex methods to access to logic.
|
||||
* So currently it is more simple to access via simple bridge based on singletons stored into {@link WeakReference} because anyway instantiation of
|
||||
* logic have to be as fast as it can. If it's not then it is just a bug and problem of optimization.
|
||||
*/
|
||||
public class Logic {
|
||||
|
||||
private static final Map<Class<? extends Logic>, WeakReference<Logic>> LOGIC_INSTANCES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Returns instance of {@link Logic} depends on class. There should be no more than one instance per class.
|
||||
*
|
||||
* @param context Context of application where this {@link Logic} related to;
|
||||
* @param logicClass Class of {@link Logic};
|
||||
* @param <T> Type of class of {@link Logic};
|
||||
* @return Instance of {@link Logic}.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "PMD.SingletonClassReturningNewInstance"})
|
||||
//SingletonClassReturningNewInstance: it is OK to create instance every time if WeakReference have died
|
||||
@NonNull
|
||||
public static <T extends Logic> T getInstance(@NonNull final Context context, @NonNull final Class<T> logicClass) {
|
||||
T result;
|
||||
synchronized (LOGIC_INSTANCES) {
|
||||
final WeakReference<Logic> reference = LOGIC_INSTANCES.get(logicClass);
|
||||
result = reference != null ? (T) reference.get() : null;
|
||||
if (result == null) {
|
||||
result = constructLogic(context.getApplicationContext(), logicClass);
|
||||
LOGIC_INSTANCES.put(logicClass, new WeakReference<>(result));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Logic> T constructLogic(@NonNull final Context context, @NonNull final Class<T> logicClass) {
|
||||
if (logicClass.getConstructors().length != 1 || logicClass.getConstructors()[0].getParameterTypes().length != 1) {
|
||||
throw new ShouldNotHappenException("There should be only one public constructor(Context) for class " + logicClass);
|
||||
}
|
||||
final Constructor<?> constructor = logicClass.getConstructors()[0];
|
||||
try {
|
||||
return (T) constructor.newInstance(context);
|
||||
} catch (final Exception exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private final Context context;
|
||||
|
||||
public Logic(@NonNull final Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link android.app.Application}'s context.
|
||||
*
|
||||
* @return Context (possibly application).
|
||||
*/
|
||||
@NonNull
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,13 +21,14 @@ package ru.touchin.roboswag.components.utils;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.arch.lifecycle.Lifecycle;
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
|
@ -41,11 +42,8 @@ import android.view.View;
|
|||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import ru.touchin.roboswag.components.navigation.activities.BaseActivity;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.log.LcGroup;
|
||||
|
||||
|
|
@ -130,9 +128,11 @@ public final class UiUtils {
|
|||
}
|
||||
|
||||
final Runnable runnable = () -> {
|
||||
final Context context = targetView.getContext();
|
||||
if (targetView.getWindowVisibility() != View.VISIBLE
|
||||
|| !targetView.hasWindowFocus()
|
||||
|| (targetView.getContext() instanceof BaseActivity && !((BaseActivity) targetView.getContext()).isActuallyResumed())) {
|
||||
|| (context instanceof LifecycleOwner
|
||||
&& !((LifecycleOwner) context).getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED))) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
|
@ -292,35 +292,6 @@ public final class UiUtils {
|
|||
*/
|
||||
public static class OfViews {
|
||||
|
||||
private static final int GENERATED_ID_THRESHOLD = 0x00FFFFFF;
|
||||
private static final AtomicInteger NEXT_GENERATED_ID = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* Generates unique ID for view. See android {@link View#generateViewId()}.
|
||||
*
|
||||
* @return Unique ID.
|
||||
*/
|
||||
@IdRes
|
||||
public static int generateViewId() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return View.generateViewId();
|
||||
}
|
||||
int result = 0;
|
||||
boolean isGenerated = false;
|
||||
while (!isGenerated) {
|
||||
result = NEXT_GENERATED_ID.get();
|
||||
// aapt-generated IDs have the high byte nonzero; clamp to the range under that.
|
||||
int newValue = result + 1;
|
||||
if (newValue > GENERATED_ID_THRESHOLD) {
|
||||
newValue = 1; // Roll over to 1, not 0.
|
||||
}
|
||||
if (NEXT_GENERATED_ID.compareAndSet(result, newValue)) {
|
||||
isGenerated = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string representation of {@link View}'s ID.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package ru.touchin.roboswag.components.utils.destroyable
|
||||
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
/**
|
||||
* Created by Oksana Pokrovskaya on 7/03/18.
|
||||
* Simple implementation of [Destroyable]. Could be used to not implement interface but use such object inside.
|
||||
*/
|
||||
open class BaseDestroyable : Destroyable {
|
||||
|
||||
private val subscriptions = CompositeDisposable()
|
||||
|
||||
/**
|
||||
* Call it on parent's onDestroy method.
|
||||
*/
|
||||
fun onDestroy() = subscriptions.dispose()
|
||||
|
||||
override fun <T> untilDestroy(
|
||||
observable: Observable<T>,
|
||||
onNextAction: (T) -> Unit,
|
||||
onErrorAction: (Throwable) -> Unit,
|
||||
onCompletedAction: () -> Unit
|
||||
): Disposable = observable
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(onNextAction, onErrorAction, onCompletedAction)
|
||||
.also { subscriptions.add(it) }
|
||||
|
||||
override fun <T> untilDestroy(
|
||||
single: Single<T>,
|
||||
onSuccessAction: (T) -> Unit,
|
||||
onErrorAction: (Throwable) -> Unit
|
||||
): Disposable = single
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(onSuccessAction, onErrorAction)
|
||||
.also { subscriptions.add(it) }
|
||||
|
||||
override fun untilDestroy(
|
||||
completable: Completable,
|
||||
onCompletedAction: () -> Unit,
|
||||
onErrorAction: (Throwable) -> Unit
|
||||
): Disposable = completable
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(onCompletedAction, onErrorAction)
|
||||
.also { subscriptions.add(it) }
|
||||
|
||||
override fun <T> untilDestroy(
|
||||
maybe: Maybe<T>,
|
||||
onSuccessAction: (T) -> Unit,
|
||||
onErrorAction: (Throwable) -> Unit,
|
||||
onCompletedAction: () -> Unit
|
||||
): Disposable = maybe
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(onSuccessAction, onErrorAction, onCompletedAction)
|
||||
.also { subscriptions.add(it) }
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package ru.touchin.roboswag.components.utils.destroyable
|
||||
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.internal.functions.Functions
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException
|
||||
|
||||
/**
|
||||
* Created by Oksana Pokrovskaya on 7/03/18.
|
||||
* Interface that should be implemented by ([android.arch.lifecycle.ViewModel] etc.)
|
||||
* to not manually manage subscriptions.
|
||||
* Use [.untilDestroy] method to subscribe to observable where you want and unsubscribe onDestroy.
|
||||
*/
|
||||
interface Destroyable {
|
||||
|
||||
companion object {
|
||||
private fun getActionThrowableForAssertion(codePoint: String, method: String = "untilDestroy"): (Throwable) -> Unit = { throwable ->
|
||||
Lc.assertion(ShouldNotHappenException("Unexpected error on $method at $codePoint", throwable))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that observable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the observable and calls onNextAction and onErrorAction on observable events.
|
||||
* Don't forget to process errors if observable can emit them.
|
||||
*
|
||||
* @param observable [Observable] to subscribe until onDestroy;
|
||||
* @param onNextAction Action which will raise on every [io.reactivex.Emitter.onNext] item;
|
||||
* @param onErrorAction Action which will raise on every [io.reactivex.Emitter.onError] throwable;
|
||||
* @param T Type of emitted by observable items;
|
||||
* @return [Disposable] which is wrapping source observable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
fun <T> untilDestroy(
|
||||
observable: Observable<T>,
|
||||
onNextAction: (T) -> Unit = Functions.emptyConsumer<T>()::accept,
|
||||
onErrorAction: (Throwable) -> Unit = getActionThrowableForAssertion(Lc.getCodePoint(this, 2)),
|
||||
onCompletedAction: () -> Unit = Functions.EMPTY_ACTION::run
|
||||
): Disposable
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that single won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the single and calls onSuccessAction and onErrorAction on single events.
|
||||
* Don't forget to process errors if single can emit them.
|
||||
*
|
||||
* @param single [Single] to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every [io.reactivex.SingleEmitter.onSuccess] item;
|
||||
* @param onErrorAction Action which will raise on every [io.reactivex.SingleEmitter.onError] throwable;
|
||||
* @param T Type of emitted by single items;
|
||||
* @return [Disposable] which is wrapping source single to unsubscribe from it onDestroy.
|
||||
*/
|
||||
fun <T> untilDestroy(
|
||||
single: Single<T>,
|
||||
onSuccessAction: (T) -> Unit = Functions.emptyConsumer<T>()::accept,
|
||||
onErrorAction: (Throwable) -> Unit = getActionThrowableForAssertion(Lc.getCodePoint(this, 2))
|
||||
): Disposable
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that completable won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the completable and calls onCompletedAction and onErrorAction on completable events.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable [Completable] to subscribe until onDestroy;
|
||||
* @param onCompletedAction Action which will raise on every [io.reactivex.CompletableEmitter.onComplete] item;
|
||||
* @param onErrorAction Action which will raise on every [io.reactivex.CompletableEmitter.onError] throwable;
|
||||
* @return [Disposable] which is wrapping source completable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
fun untilDestroy(
|
||||
completable: Completable,
|
||||
onCompletedAction: () -> Unit = Functions.EMPTY_ACTION::run,
|
||||
onErrorAction: (Throwable) -> Unit = getActionThrowableForAssertion(Lc.getCodePoint(this, 2))
|
||||
): Disposable
|
||||
|
||||
/**
|
||||
* Method should be used to guarantee that maybe won't be subscribed after onDestroy.
|
||||
* It is automatically subscribing to the maybe and calls onSuccessAction and onErrorAction on maybe events.
|
||||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param maybe [Maybe] to subscribe until onDestroy;
|
||||
* @param onSuccessAction Action which will raise on every [io.reactivex.MaybeEmitter.onSuccess] ()} item;
|
||||
* @param onErrorAction Action which will raise on every [io.reactivex.MaybeEmitter.onError] throwable;
|
||||
* @return [Disposable] which is wrapping source maybe to unsubscribe from it onDestroy.
|
||||
*/
|
||||
fun <T> untilDestroy(
|
||||
maybe: Maybe<T>,
|
||||
onSuccessAction: (T) -> Unit = Functions.emptyConsumer<T>()::accept,
|
||||
onErrorAction: (Throwable) -> Unit = getActionThrowableForAssertion(Lc.getCodePoint(this, 2)),
|
||||
onCompletedAction: () -> Unit = Functions.EMPTY_ACTION::run
|
||||
): Disposable
|
||||
|
||||
}
|
||||
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Point;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import ru.touchin.roboswag.components.R;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 01/07/14.
|
||||
* FrameLayout that holds specific aspect ratio sizes.
|
||||
* For example if aspect ratio equals 1.0 then this view will layout as square.
|
||||
*/
|
||||
public class AspectRatioFrameLayout extends FrameLayout {
|
||||
|
||||
private static final float DEFAULT_ASPECT_RATIO = 1.0f;
|
||||
private static final float EPSILON = 0.0000001f;
|
||||
|
||||
private float aspectRatio;
|
||||
private boolean wrapToContent;
|
||||
|
||||
public AspectRatioFrameLayout(@NonNull final Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AspectRatioFrameLayout(@NonNull final Context context, @Nullable final AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AspectRatioFrameLayout(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
if (attrs == null) {
|
||||
wrapToContent = false;
|
||||
aspectRatio = DEFAULT_ASPECT_RATIO;
|
||||
} else {
|
||||
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.AspectRatioFrameLayout);
|
||||
wrapToContent = typedArray.getBoolean(R.styleable.AspectRatioFrameLayout_wrapToContent, false);
|
||||
aspectRatio = typedArray.getFloat(R.styleable.AspectRatioFrameLayout_aspectRatio, DEFAULT_ASPECT_RATIO);
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns aspect ratio of layout */
|
||||
public float getAspectRatio() {
|
||||
return aspectRatio;
|
||||
}
|
||||
|
||||
/* Sets aspect ratio of layout */
|
||||
public void setAspectRatio(final float aspectRatio) {
|
||||
if (Math.abs(aspectRatio - this.aspectRatio) < EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.aspectRatio = aspectRatio;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/* Returns if layout is wrapping to content but holds aspect ratio */
|
||||
|
||||
/**
|
||||
* Returns if layout is wrapping to content but holds aspect ratio.
|
||||
* If it is true it means that minimum size of view will equals to maximum size of it's child (biggest width or height) depends on aspect ratio.
|
||||
* Else maximum size of view will equals to minimum available size which parent could give to this view depends on aspect ratio.
|
||||
*
|
||||
* @return True if wrapping to content.
|
||||
*/
|
||||
public boolean isWrapToContent() {
|
||||
return wrapToContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if layout is wrapping to content but holds aspect ratio.
|
||||
*
|
||||
* @param wrapToContent True if wrapping to content.
|
||||
*/
|
||||
public void setWrapToContent(final boolean wrapToContent) {
|
||||
if (wrapToContent == this.wrapToContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.wrapToContent = wrapToContent;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private void setMeasuredDimensionWithAspectOfLesser(final int measuredWidth, final int measuredHeight) {
|
||||
final float heightBasedOnMw = measuredWidth / aspectRatio;
|
||||
if (heightBasedOnMw > measuredHeight) {
|
||||
setMeasuredDimension((int) (measuredHeight * aspectRatio), measuredHeight);
|
||||
} else {
|
||||
setMeasuredDimension(measuredWidth, (int) heightBasedOnMw);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMeasuredDimensionWithAspectOfHigher(final int measuredWidth, final int measuredHeight) {
|
||||
final float heightBasedOnMw = measuredWidth / aspectRatio;
|
||||
if (heightBasedOnMw < measuredHeight) {
|
||||
setMeasuredDimension((int) (measuredHeight * aspectRatio), measuredHeight);
|
||||
} else {
|
||||
setMeasuredDimension(measuredWidth, (int) heightBasedOnMw);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Point measureWrapChildren(final int widthMeasureSpec, final int heightMeasureSpec) {
|
||||
final Point result = new Point();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
final View child = getChildAt(i);
|
||||
child.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (result.x < child.getMeasuredWidth()) {
|
||||
result.x = child.getMeasuredWidth();
|
||||
}
|
||||
if (result.y < child.getMeasuredHeight()) {
|
||||
result.y = child.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
|
||||
if (wrapToContent) {
|
||||
final Point bounds = measureWrapChildren(widthMeasureSpec, heightMeasureSpec);
|
||||
width = widthMode == MeasureSpec.UNSPECIFIED ? bounds.x : Math.min(bounds.x, width);
|
||||
height = heightMode == MeasureSpec.UNSPECIFIED ? bounds.y : Math.min(bounds.y, height);
|
||||
}
|
||||
|
||||
if (widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
measureBothUnspecified(width, height);
|
||||
} else {
|
||||
measureOnlyUnspecifiedWidth(width, height);
|
||||
}
|
||||
} else if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
measureOnlyUnspecifiedHeight(width, height);
|
||||
} else {
|
||||
measureBothSpecified(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private void measureBothSpecified(final int width, final int height) {
|
||||
if (wrapToContent) {
|
||||
setMeasuredDimensionWithAspectOfHigher(width, height);
|
||||
} else {
|
||||
setMeasuredDimensionWithAspectOfLesser(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private void measureOnlyUnspecifiedHeight(final int width, final int height) {
|
||||
if (wrapToContent) {
|
||||
measureWrapToContent(width, height);
|
||||
} else {
|
||||
setMeasuredDimension(width, (int) (width / aspectRatio));
|
||||
}
|
||||
}
|
||||
|
||||
private void measureWrapToContent(final int width, final int height) {
|
||||
if (width < (int) (height * aspectRatio)) {
|
||||
setMeasuredDimension((int) (height * aspectRatio), height);
|
||||
} else {
|
||||
setMeasuredDimension(width, (int) (width / aspectRatio));
|
||||
}
|
||||
}
|
||||
|
||||
private void measureOnlyUnspecifiedWidth(final int width, final int height) {
|
||||
if (wrapToContent) {
|
||||
measureWrapToContent(width, height);
|
||||
} else {
|
||||
setMeasuredDimension((int) (height * aspectRatio), height);
|
||||
}
|
||||
}
|
||||
|
||||
private void measureBothUnspecified(final int width, final int height) {
|
||||
if (wrapToContent) {
|
||||
setMeasuredDimensionWithAspectOfHigher(width, height);
|
||||
} else {
|
||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
setMeasuredDimensionWithAspectOfLesser(metrics.widthPixels, metrics.heightPixels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(final boolean changed, final int left, final int top, final int right, final int bottom) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
final View child = getChildAt(i);
|
||||
final ViewGroup.LayoutParams lp = child.getLayoutParams();
|
||||
final int widthMeasureSpec;
|
||||
final int heightMeasureSpec;
|
||||
final int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
|
||||
final int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
|
||||
switch (lp.width) {
|
||||
case ViewGroup.LayoutParams.MATCH_PARENT:
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
|
||||
break;
|
||||
case ViewGroup.LayoutParams.WRAP_CONTENT:
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
|
||||
break;
|
||||
default:
|
||||
widthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (lp.height) {
|
||||
case ViewGroup.LayoutParams.MATCH_PARENT:
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
|
||||
break;
|
||||
case ViewGroup.LayoutParams.WRAP_CONTENT:
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
|
||||
break;
|
||||
default:
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
|
||||
break;
|
||||
}
|
||||
|
||||
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,325 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
* This file is part of RoboSwag library.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.views;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.AttrRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import ru.touchin.roboswag.components.utils.BaseLifecycleBindable;
|
||||
import ru.touchin.roboswag.components.utils.LifecycleBindable;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Action;
|
||||
import io.reactivex.functions.Consumer;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 18/05/17.
|
||||
* FrameLayout that realizes LifecycleBindable interface.
|
||||
*/
|
||||
@SuppressWarnings({"CPD-START", "PMD.TooManyMethods"})
|
||||
public class LifecycleView extends FrameLayout implements LifecycleBindable {
|
||||
|
||||
@NonNull
|
||||
private final BaseLifecycleBindable baseLifecycleBindable;
|
||||
private boolean created;
|
||||
private boolean started;
|
||||
|
||||
public LifecycleView(@NonNull final Context context) {
|
||||
super(context);
|
||||
baseLifecycleBindable = new BaseLifecycleBindable();
|
||||
}
|
||||
|
||||
public LifecycleView(@NonNull final Context context, @Nullable final AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
baseLifecycleBindable = new BaseLifecycleBindable();
|
||||
}
|
||||
|
||||
public LifecycleView(@NonNull final Context context, @Nullable final AttributeSet attrs, @AttrRes final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
baseLifecycleBindable = new BaseLifecycleBindable();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
onCreate();
|
||||
if (!started && getWindowSystemUiVisibility() == VISIBLE) {
|
||||
onStart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when view attached to window and ready to use.
|
||||
*/
|
||||
protected void onCreate() {
|
||||
created = true;
|
||||
baseLifecycleBindable.onCreate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when view's window showed or state restored.
|
||||
*/
|
||||
protected void onStart() {
|
||||
started = true;
|
||||
baseLifecycleBindable.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(@NonNull final Parcelable state) {
|
||||
super.onRestoreInstanceState(state);
|
||||
if (created && !started) {
|
||||
onStart();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
started = false;
|
||||
baseLifecycleBindable.onSaveInstanceState();
|
||||
return super.onSaveInstanceState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when view's window hided or state saved.
|
||||
*/
|
||||
protected void onStop() {
|
||||
started = false;
|
||||
baseLifecycleBindable.onStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls when view detached from window.
|
||||
*/
|
||||
protected void onDestroy() {
|
||||
if (started) {
|
||||
onStop();
|
||||
}
|
||||
created = false;
|
||||
baseLifecycleBindable.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
onDestroy();
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onWindowVisibilityChanged(final int visibility) {
|
||||
super.onWindowVisibilityChanged(visibility);
|
||||
if (visibility == VISIBLE) {
|
||||
if (created && !started) {
|
||||
baseLifecycleBindable.onStart();
|
||||
}
|
||||
} else if (started) {
|
||||
baseLifecycleBindable.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilStop(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilStop(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilStop(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilStop(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilStop(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilStop(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilStop(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable) {
|
||||
return baseLifecycleBindable.untilDestroy(observable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable, @NonNull final Consumer<T> onNextAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Observable<T> observable,
|
||||
@NonNull final Consumer<T> onNextAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction,
|
||||
@NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single) {
|
||||
return baseLifecycleBindable.untilDestroy(single);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Single<T> single,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable) {
|
||||
return baseLifecycleBindable.untilDestroy(completable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable, @NonNull final Action onCompletedAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Disposable untilDestroy(@NonNull final Completable completable,
|
||||
@NonNull final Action onCompletedAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe, @NonNull final Consumer<T> onSuccessAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onSuccessAction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T> Disposable untilDestroy(@NonNull final Maybe<T> maybe,
|
||||
@NonNull final Consumer<T> onSuccessAction,
|
||||
@NonNull final Consumer<Throwable> onErrorAction) {
|
||||
return baseLifecycleBindable.untilDestroy(maybe, onSuccessAction, onErrorAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,11 +19,6 @@
|
|||
<attr name="isMultiline" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="AspectRatioFrameLayout">
|
||||
<attr name="aspectRatio" format="float" />
|
||||
<attr name="wrapToContent" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="MaterialLoadingBar">
|
||||
<attr name="strokeWidth" format="dimension"/>
|
||||
<attr name="color" format="color"/>
|
||||
|
|
@ -31,4 +26,4 @@
|
|||
<attr name="materialLoadingBarStyle" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue