navigation added
This commit is contained in:
parent
165c9232e6
commit
c1b12ea706
|
|
@ -51,7 +51,7 @@ import rx.subjects.PublishSubject;
|
|||
* TODO: fill description
|
||||
*/
|
||||
@SuppressWarnings({"PMD.GodClass", "PMD.TooManyMethods"})
|
||||
public abstract class AbstractBaseActivity extends AppCompatActivity
|
||||
public abstract class AbstractBaseActivity extends BaseActivity
|
||||
implements FragmentManager.OnBackStackChangedListener,
|
||||
OnFragmentStartedListener {
|
||||
|
||||
|
|
@ -67,8 +67,6 @@ public abstract class AbstractBaseActivity extends AppCompatActivity
|
|||
private String requestedPermission;
|
||||
private final PublishSubject<PermissionState> requestPermissionsEvent = PublishSubject.create();
|
||||
|
||||
private final Handler postHandler = new Handler();
|
||||
|
||||
/* Returns id of main fragments container where navigation-node fragments should be */
|
||||
protected int getFragmentContainerId() {
|
||||
throw new UnsupportedOperationException("Implement getFragmentContainerId method to use fragment managing");
|
||||
|
|
@ -322,24 +320,6 @@ public abstract class AbstractBaseActivity extends AppCompatActivity
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
postHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
/* Hides device keyboard */
|
||||
public void hideSoftInput() {
|
||||
if (getCurrentFocus() != null) {
|
||||
final InputMethodManager inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
|
||||
final View mainFragmentContainer = findViewById(getFragmentContainerId());
|
||||
if (mainFragmentContainer != null) {
|
||||
mainFragmentContainer.requestFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void popBackStackToTopFragment() {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
final int stackSize = fragmentManager.getBackStackEntryCount();
|
||||
|
|
@ -353,13 +333,6 @@ public abstract class AbstractBaseActivity extends AppCompatActivity
|
|||
fragmentManager.popBackStackImmediate(currentFragmentName, 0);
|
||||
}
|
||||
|
||||
/* Shows device keyboard */
|
||||
public void showSoftInput(@NonNull final View view) {
|
||||
view.requestFocus();
|
||||
final InputMethodManager inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Typeface getToolbarTitleTypeface(@NonNull final AbstractBaseActivity activity) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 08/03/2016.
|
||||
* TODO: fill description
|
||||
*/
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
|
||||
/**
|
||||
* Hides device keyboard that is showing over {@link Activity}.
|
||||
* Do not use it if keyboard is over {@link android.app.Dialog} - it won't work as they have different {@link Activity#getWindow()}.
|
||||
*/
|
||||
public void hideSoftInput() {
|
||||
if (getCurrentFocus() == null) {
|
||||
return;
|
||||
}
|
||||
final InputMethodManager inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
|
||||
getWindow().getDecorView().requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows device keyboard over {@link Activity} and focuses {@link View}.
|
||||
* Do not use it if keyboard is over {@link android.app.Dialog} - it won't work as they have different {@link Activity#getWindow()}.
|
||||
* @param view View to get focus for input from keyboard.
|
||||
*/
|
||||
public void showSoftInput(@NonNull final View view) {
|
||||
view.requestFocus();
|
||||
final InputMethodManager inputManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
|
||||
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
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 ru.touchin.roboswag.core.log.Lc;
|
||||
import rx.functions.Func1;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* Navigation which is controlling using {@link android.support.v4.app.FragmentManager} as controller.
|
||||
*/
|
||||
public class FragmentNavigation {
|
||||
|
||||
protected static final String TOP_FRAGMENT_TAG_MARK = "TOP_FRAGMENT";
|
||||
protected static final String WITH_TARGET_FRAGMENT_TAG_MARK = "FRAGMENT_WITH_TARGET";
|
||||
|
||||
@NonNull
|
||||
private final Context context;
|
||||
@NonNull
|
||||
private final FragmentManager fragmentManager;
|
||||
@IdRes
|
||||
private final int containerViewId;
|
||||
|
||||
public FragmentNavigation(@NonNull final Context context, @NonNull final FragmentManager fragmentManager, @IdRes final int containerViewId) {
|
||||
this.context = context;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.containerViewId = containerViewId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public FragmentManager getFragmentManager() {
|
||||
return fragmentManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@SuppressLint("CommitTransaction")
|
||||
protected void addToStack(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@Nullable final Fragment targetFragment,
|
||||
@Nullable final Bundle args,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
if (fragmentManager.isDestroyed()) {
|
||||
Lc.assertion("FragmentManager is destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
final Fragment fragment = Fragment.instantiate(context, fragmentClass.getName(), args);
|
||||
if (targetFragment != null) {
|
||||
fragment.setTargetFragment(targetFragment, 0);
|
||||
}
|
||||
|
||||
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
|
||||
.replace(containerViewId, fragment, null)
|
||||
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
|
||||
.addToBackStack(backStackTag);
|
||||
if (transactionSetup != null) {
|
||||
transactionSetup.call(fragmentTransaction).commit();
|
||||
} else {
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean back() {
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean backTo(@NonNull final Func1<FragmentManager.BackStackEntry, Boolean> condition) {
|
||||
final int stackSize = fragmentManager.getBackStackEntryCount();
|
||||
Integer id = null;
|
||||
for (int i = stackSize - 2; i >= 0; i--) {
|
||||
final FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
|
||||
id = backStackEntry.getId();
|
||||
if (condition.call(backStackEntry)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id != null) {
|
||||
fragmentManager.popBackStackImmediate(id, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean up() {
|
||||
return backTo(backStackEntry -> backStackEntry.getName().endsWith(TOP_FRAGMENT_TAG_MARK));
|
||||
}
|
||||
|
||||
public void push(@NonNull final Class<? extends Fragment> fragmentClass) {
|
||||
addToStack(fragmentClass, null, null, null, null);
|
||||
}
|
||||
|
||||
public void push(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Bundle args) {
|
||||
addToStack(fragmentClass, null, args, null, null);
|
||||
}
|
||||
|
||||
public void push(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, null, null, transactionSetup);
|
||||
}
|
||||
|
||||
public void push(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@Nullable final Bundle args,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, args, null, transactionSetup);
|
||||
}
|
||||
|
||||
public void pushForResult(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Fragment targetFragment) {
|
||||
addToStack(fragmentClass, targetFragment, null, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public void pushForResult(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final Bundle args) {
|
||||
addToStack(fragmentClass, targetFragment, args, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public void pushForResult(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, targetFragment, null, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public void pushForResult(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@Nullable final Bundle args,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, targetFragment, args, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public void setAsTop(@NonNull final Class<? extends Fragment> fragmentClass) {
|
||||
addToStack(fragmentClass, null, null, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public void setAsTop(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Bundle args) {
|
||||
addToStack(fragmentClass, null, args, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public void setAsTop(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, null, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public void setAsTop(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@Nullable final Bundle args,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, args, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public void setInitial(@NonNull final Class<? extends Fragment> fragmentClass) {
|
||||
setInitial(fragmentClass, null, null);
|
||||
}
|
||||
|
||||
public void setInitial(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Bundle args) {
|
||||
setInitial(fragmentClass, args, null);
|
||||
}
|
||||
|
||||
public void setInitial(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@NonNull final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
setInitial(fragmentClass, null, transactionSetup);
|
||||
}
|
||||
|
||||
public void setInitial(@NonNull final Class<? extends Fragment> fragmentClass,
|
||||
@Nullable final Bundle args,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
if (fragmentManager.isDestroyed()) {
|
||||
Lc.assertion("FragmentManager is destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fragmentManager.getBackStackEntryCount() > 0) {
|
||||
fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
}
|
||||
|
||||
setAsTop(fragmentClass, args, transactionSetup);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* TODO: fill description
|
||||
*/
|
||||
public class SimpleViewControllerFragment<TState extends Serializable, TLogicBridge, TActivity extends ViewControllerActivity<TLogicBridge>>
|
||||
extends ViewControllerFragment<TState, TLogicBridge, 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 Class<? extends ViewController> viewControllerClass,
|
||||
@Nullable final Serializable state) {
|
||||
final Bundle result = ViewControllerFragment.createState(state);
|
||||
result.putSerializable(VIEW_CONTROLLER_CLASS_EXTRA, viewControllerClass);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Class<? extends ViewController<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TState, TLogicBridge, TActivity>>> viewControllerClass;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Class<? extends ViewController<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TState, TLogicBridge, TActivity>>> getViewControllerClass() {
|
||||
return viewControllerClass;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewControllerClass = (Class<? extends ViewController<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TState, TLogicBridge, TActivity>>>) getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,22 +20,27 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.io.Serializable;
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Class to control view of specific fragment, activity and application by logic bridge.
|
||||
* [phase 1]
|
||||
*/
|
||||
public class ViewController<TState extends Serializable,
|
||||
TLogicBridge,
|
||||
TActivity extends AppCompatActivity,
|
||||
TFragment extends ViewControllerFragment<TState, TLogicBridge, TActivity>> {
|
||||
public class ViewController<TLogicBridge,
|
||||
TActivity extends ViewControllerActivity<TLogicBridge>,
|
||||
TFragment extends ViewControllerFragment<?, TLogicBridge, TActivity>> {
|
||||
|
||||
private static final String SUPPORT_FRAGMENT_VIEW_STATE_EXTRA = "android:view_state";
|
||||
|
||||
@NonNull
|
||||
private final TLogicBridge logicBridge;
|
||||
|
|
@ -45,13 +50,35 @@ public class ViewController<TState extends Serializable,
|
|||
private final TFragment fragment;
|
||||
@NonNull
|
||||
private final ViewGroup container;
|
||||
@NonNull
|
||||
private final Subscription savedStateSubscription;
|
||||
|
||||
public ViewController(@NonNull final CreationContext<TState, TLogicBridge, TActivity, TFragment> creationContext,
|
||||
public ViewController(@NonNull final CreationContext<TLogicBridge, TActivity, TFragment> creationContext,
|
||||
@Nullable final Bundle savedInstanceState) {
|
||||
this.logicBridge = creationContext.logicBridge;
|
||||
this.activity = creationContext.activity;
|
||||
this.fragment = creationContext.fragment;
|
||||
this.container = creationContext.container;
|
||||
|
||||
savedStateSubscription = getRestoreSavedStateObservable(creationContext, savedInstanceState)
|
||||
.filter(savedState -> savedState != null)
|
||||
.first()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onRestoreSavedState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link Observable} which will be used to get a moment when controller should restore it's state.
|
||||
* It will be waits for first non-null {@link Bundle} that contains saved state.
|
||||
*
|
||||
* @param creationContext Context passed into {@link ViewController} constructor.
|
||||
* @param savedInstanceState Saved state of {@link ViewController}.
|
||||
* @return {@link Observable} to get restore time to.
|
||||
*/
|
||||
@NonNull
|
||||
protected Observable<Bundle> getRestoreSavedStateObservable(@NonNull final CreationContext<TLogicBridge, TActivity, TFragment> creationContext,
|
||||
@Nullable final Bundle savedInstanceState) {
|
||||
return Observable.just(savedInstanceState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,7 +94,7 @@ public class ViewController<TState extends Serializable,
|
|||
/**
|
||||
* Returns view's activity.
|
||||
*
|
||||
* @return Returns activity.
|
||||
* @return Returns activity;
|
||||
*/
|
||||
@NonNull
|
||||
public TActivity getActivity() {
|
||||
|
|
@ -87,24 +114,40 @@ public class ViewController<TState extends Serializable,
|
|||
/**
|
||||
* Returns view instantiated in {@link #getFragment} fragment attached to {@link #getActivity} activity.
|
||||
*
|
||||
* @return Returns view.
|
||||
* @return Returns view;
|
||||
*/
|
||||
@NonNull
|
||||
public ViewGroup getContainer() {
|
||||
public View getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
//do nothing
|
||||
/**
|
||||
* Called when savedInstanceState is ready to be restored.
|
||||
*
|
||||
* @param savedInstanceState Saved state.
|
||||
*/
|
||||
protected void onRestoreSavedState(@NonNull final Bundle savedInstanceState) {
|
||||
final SparseArray<Parcelable> viewStates = savedInstanceState.getSparseParcelableArray(SUPPORT_FRAGMENT_VIEW_STATE_EXTRA);
|
||||
if (viewStates != null) {
|
||||
container.restoreHierarchyState(viewStates);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
savedStateSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class to simplify constructor override.
|
||||
*/
|
||||
public static class CreationContext<TState extends Serializable,
|
||||
TLogicBridge,
|
||||
TActivity extends AppCompatActivity,
|
||||
TFragment extends ViewControllerFragment<TState, TLogicBridge, TActivity>> {
|
||||
public static class CreationContext<TLogicBridge,
|
||||
TActivity extends ViewControllerActivity<TLogicBridge>,
|
||||
TFragment extends ViewControllerFragment<?, TLogicBridge, TActivity>> {
|
||||
|
||||
@NonNull
|
||||
private final TLogicBridge logicBridge;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import ru.touchin.roboswag.components.services.LogicService;
|
||||
import ru.touchin.roboswag.core.utils.android.RxAndroidUtils;
|
||||
import rx.Observable;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* TODO: fill description
|
||||
*/
|
||||
public abstract class ViewControllerActivity<TLogicBridge> extends BaseActivity {
|
||||
|
||||
/**
|
||||
* It should return specific Service class where from this fragment should get interface to logic.
|
||||
*
|
||||
* @return Returns class of specific LogicService.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<? extends LogicService<TLogicBridge>> getLogicServiceClass();
|
||||
|
||||
/**
|
||||
* Returns {@link Observable} which will connect to {@link LogicService} and get object of {@link TLogicBridge} type from it.
|
||||
*
|
||||
* @return {@link Observable} which will provide changes of object of type {@link TLogicBridge};
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<TLogicBridge> observeLogicBridge() {
|
||||
return RxAndroidUtils.observeService(this, getLogicServiceClass())
|
||||
.map(service -> service != null ? service.getLogicBridge() : null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ import android.content.Context;
|
|||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
|
@ -33,21 +32,21 @@ import android.widget.FrameLayout;
|
|||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import ru.touchin.roboswag.components.services.LogicService;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import ru.touchin.roboswag.core.utils.android.RxAndroidUtils;
|
||||
import rx.Observable;
|
||||
import rx.Scheduler;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.exceptions.OnErrorThrowable;
|
||||
import rx.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Fragment that creates {@link ViewController} between {@link #onViewCreated} and {@link #onDestroyView}.
|
||||
* [phase 1]
|
||||
* Fragment instantiated in specific activity of {@link TActivity} type that is holding {@link ViewController} inside.
|
||||
*/
|
||||
public abstract class ViewControllerFragment<TState extends Serializable, TLogicBridge, TActivity extends AppCompatActivity>
|
||||
public abstract class ViewControllerFragment<TState extends Serializable, TLogicBridge, TActivity extends ViewControllerActivity<TLogicBridge>>
|
||||
extends ViewFragment<TActivity> {
|
||||
|
||||
private static final String VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA";
|
||||
|
|
@ -58,6 +57,7 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
* @param state State to use into ViewController.
|
||||
* @return Returns bundle with state inside.
|
||||
*/
|
||||
@NonNull
|
||||
public static Bundle createState(@Nullable final Serializable state) {
|
||||
final Bundle result = new Bundle();
|
||||
result.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
|
|
@ -69,6 +69,7 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
private final Scheduler backgroundScheduler = RxAndroidUtils.createLooperScheduler();
|
||||
@Nullable
|
||||
private ViewController viewController;
|
||||
@Nullable
|
||||
private Subscription viewControllerSubscription;
|
||||
private TState state;
|
||||
|
||||
|
|
@ -82,31 +83,23 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* It should return specific Service class where from this fragment should get interface to logic.
|
||||
*
|
||||
* @return Returns class of specific LogicService.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<? extends LogicService<TLogicBridge>> getLogicServiceClass();
|
||||
|
||||
/**
|
||||
* It should return specific ViewController class to control instantiated view by logic bridge after activity creation.
|
||||
*
|
||||
* @return Returns class of specific ViewController.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<? extends ViewController<TState, TLogicBridge, TActivity,
|
||||
protected abstract Class<? extends ViewController<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TState, TLogicBridge, TActivity>>> getViewControllerClass();
|
||||
|
||||
// need throwable for app stability
|
||||
@SuppressWarnings({"PMD.AvoidCatchingThrowable", "unchecked"})
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getContext() == null) {
|
||||
Lc.assertion("Context is null in onCreate");
|
||||
return;
|
||||
}
|
||||
|
||||
state = savedInstanceState != null
|
||||
|
|
@ -114,26 +107,26 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
: (getArguments() != null ? (TState) getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA) : null);
|
||||
|
||||
viewControllerSubscription = Observable
|
||||
.combineLatest(RxAndroidUtils.observeService(getContext(), getLogicServiceClass())
|
||||
.map(service -> service != null ? service.getLogicBridge() : null)
|
||||
.combineLatest(activitySubject
|
||||
.switchMap(activity -> activity != null ? activity.observeLogicBridge() : Observable.just(null))
|
||||
.distinctUntilChanged()
|
||||
.observeOn(backgroundScheduler),
|
||||
activitySubject.distinctUntilChanged().observeOn(backgroundScheduler),
|
||||
viewSubject.distinctUntilChanged().observeOn(backgroundScheduler),
|
||||
(logicBridge, activity, view) -> {
|
||||
if (activity == null || view == null || logicBridge == null) {
|
||||
if (logicBridge == null || activity == null || view == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ViewController.CreationContext<? extends Serializable, TLogicBridge, TActivity,
|
||||
final ViewController.CreationContext<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TState, TLogicBridge, TActivity>> creationContext
|
||||
= new ViewController.CreationContext<>(logicBridge, activity, this, view.first);
|
||||
if (getViewControllerClass().getConstructors().length > 1) {
|
||||
Lc.assertion("There should be single constructor for " + getViewControllerClass());
|
||||
return null;
|
||||
if (getViewControllerClass().getConstructors().length != 1) {
|
||||
throw OnErrorThrowable
|
||||
.from(new ShouldNotHappenException("There should be single constructor for " + getViewControllerClass()));
|
||||
}
|
||||
final Constructor<?> constructor = getViewControllerClass().getConstructors()[0];
|
||||
try {
|
||||
final Constructor<?> constructor = getViewControllerClass().getConstructors()[0];
|
||||
switch (constructor.getParameterTypes().length) {
|
||||
case 2:
|
||||
return (ViewController) constructor.newInstance(creationContext, view.second);
|
||||
|
|
@ -143,13 +136,12 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
Lc.assertion("Wrong constructor parameters count: " + constructor.getParameterTypes().length);
|
||||
return null;
|
||||
}
|
||||
} catch (final Throwable throwable) {
|
||||
Lc.assertion(throwable);
|
||||
return null;
|
||||
} catch (final Exception exception) {
|
||||
throw OnErrorThrowable.from(exception);
|
||||
}
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onViewControllerChanged);
|
||||
.subscribe(this::onViewControllerChanged, Lc::assertion);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
@ -181,22 +173,23 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
if (this.viewController == null) {
|
||||
return;
|
||||
}
|
||||
if (getView() instanceof PlaceholderView) {
|
||||
((PlaceholderView) getView()).removeAllViews();
|
||||
((PlaceholderView) getView())
|
||||
.addView(this.viewController.getContainer(), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
} else {
|
||||
if (getView() == null || !(getView() instanceof PlaceholderView)) {
|
||||
Lc.assertion("View of fragment should be PlaceholderView");
|
||||
}
|
||||
((PlaceholderView) getView()).removeAllViews();
|
||||
((PlaceholderView) getView())
|
||||
.addView(this.viewController.getContainer(), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
viewController.getActivity().supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle stateToSave) {
|
||||
super.onSaveInstanceState(stateToSave);
|
||||
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
if (viewController != null) {
|
||||
stateToSave.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
viewController.onSaveInstanceState(savedInstanceState);
|
||||
savedInstanceState.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state);
|
||||
} else if (getArguments() != null && getArguments().containsKey(VIEW_CONTROLLER_STATE_EXTRA)) {
|
||||
stateToSave.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA));
|
||||
savedInstanceState.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +201,10 @@ public abstract class ViewControllerFragment<TState extends Serializable, TLogic
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
viewControllerSubscription.unsubscribe();
|
||||
if (viewControllerSubscription != null) {
|
||||
viewControllerSubscription.unsubscribe();
|
||||
viewControllerSubscription = null;
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
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 java.io.Serializable;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import rx.functions.Func1;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 07/03/2016.
|
||||
* TODO: fill description
|
||||
*/
|
||||
public class ViewControllerNavigation<TLogicBridge> extends FragmentNavigation {
|
||||
|
||||
public ViewControllerNavigation(@NonNull final ViewControllerActivity<TLogicBridge> context,
|
||||
@NonNull final FragmentManager fragmentManager,
|
||||
@IdRes final int containerViewId) {
|
||||
super(context, fragmentManager, containerViewId);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void push(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void push(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushForResult(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final TState state) {
|
||||
addToStack(fragmentClass, targetFragment, ViewControllerFragment.createState(state), fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushForResult(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(fragmentClass, targetFragment, ViewControllerFragment.createState(state), fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setAsTop(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
setAsTop(fragmentClass, ViewControllerFragment.createState(state), null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setAsTop(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
setAsTop(fragmentClass, ViewControllerFragment.createState(state), transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setInitial(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@NonNull final TState state) {
|
||||
setInitial(fragmentClass, ViewControllerFragment.createState(state), null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setInitial(@NonNull final Class<? extends ViewControllerFragment<TState, TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>>> fragmentClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
setInitial(fragmentClass, ViewControllerFragment.createState(state), transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushViewController(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, null, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushViewController(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushViewControllerForResult(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@NonNull final TState state) {
|
||||
addViewControllerToStack(viewControllerClass, targetFragment, state, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void pushViewControllerForResult(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@NonNull final Fragment targetFragment,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addViewControllerToStack(viewControllerClass, targetFragment, state, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setViewControllerAsTop(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setViewControllerAsTop(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, transactionSetup);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setInitialViewController(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@NonNull final TState state) {
|
||||
setInitialViewController(viewControllerClass, state, null);
|
||||
}
|
||||
|
||||
public <TState extends Serializable> void setInitialViewController(@NonNull final Class<? extends ViewController<TLogicBridge,
|
||||
? extends ViewControllerActivity<TLogicBridge>,
|
||||
? extends SimpleViewControllerFragment<TState, TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>>>> viewControllerClass,
|
||||
@Nullable final TState state,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
if (getFragmentManager().isDestroyed()) {
|
||||
Lc.assertion("FragmentManager is destroyed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (getFragmentManager().getBackStackEntryCount() > 0) {
|
||||
getFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||
}
|
||||
|
||||
setViewControllerAsTop(viewControllerClass, state, transactionSetup);
|
||||
}
|
||||
|
||||
protected <TState extends Serializable> void addViewControllerToStack(
|
||||
@NonNull final Class<? extends ViewController<TLogicBridge, ? extends ViewControllerActivity<TLogicBridge>, ?>> viewControllerClass,
|
||||
@Nullable final Fragment targetFragment,
|
||||
@Nullable final TState state,
|
||||
@Nullable final String backStackTag,
|
||||
@Nullable final Func1<FragmentTransaction, FragmentTransaction> transactionSetup) {
|
||||
addToStack(SimpleViewControllerFragment.class, targetFragment,
|
||||
SimpleViewControllerFragment.createState(viewControllerClass, state), backStackTag, transactionSetup);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue