From c1b12ea706feb3cd7cbfd001323b543d69a671bf Mon Sep 17 00:00:00 2001 From: Gavriil Sitnikov Date: Wed, 9 Mar 2016 01:15:32 +0300 Subject: [PATCH] navigation added --- .../navigation/AbstractBaseActivity.java | 29 +-- .../components/navigation/BaseActivity.java | 39 ++++ .../navigation/FragmentNavigation.java | 216 ++++++++++++++++++ .../SimpleViewControllerFragment.java | 51 +++++ .../components/navigation/ViewController.java | 75 ++++-- .../navigation/ViewControllerActivity.java | 35 +++ .../navigation/ViewControllerFragment.java | 72 +++--- .../navigation/ViewControllerNavigation.java | 162 +++++++++++++ 8 files changed, 597 insertions(+), 82 deletions(-) create mode 100644 src/main/java/ru/touchin/roboswag/components/navigation/BaseActivity.java create mode 100644 src/main/java/ru/touchin/roboswag/components/navigation/FragmentNavigation.java create mode 100644 src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java create mode 100644 src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerActivity.java create mode 100644 src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerNavigation.java diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java b/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java index 07f1309..bd1ca9e 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java @@ -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 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; diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/BaseActivity.java b/src/main/java/ru/touchin/roboswag/components/navigation/BaseActivity.java new file mode 100644 index 0000000..682968d --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/navigation/BaseActivity.java @@ -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); + } + +} diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/FragmentNavigation.java b/src/main/java/ru/touchin/roboswag/components/navigation/FragmentNavigation.java new file mode 100644 index 0000000..101279d --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/navigation/FragmentNavigation.java @@ -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 fragmentClass, + @Nullable final Fragment targetFragment, + @Nullable final Bundle args, + @Nullable final String backStackTag, + @Nullable final Func1 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 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 fragmentClass) { + addToStack(fragmentClass, null, null, null, null); + } + + public void push(@NonNull final Class fragmentClass, + @NonNull final Bundle args) { + addToStack(fragmentClass, null, args, null, null); + } + + public void push(@NonNull final Class fragmentClass, + @NonNull final Func1 transactionSetup) { + addToStack(fragmentClass, null, null, null, transactionSetup); + } + + public void push(@NonNull final Class fragmentClass, + @Nullable final Bundle args, + @Nullable final Func1 transactionSetup) { + addToStack(fragmentClass, null, args, null, transactionSetup); + } + + public void pushForResult(@NonNull final Class fragmentClass, + @NonNull final Fragment targetFragment) { + addToStack(fragmentClass, targetFragment, null, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); + } + + public void pushForResult(@NonNull final Class 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 fragmentClass, + @NonNull final Fragment targetFragment, + @NonNull final Func1 transactionSetup) { + addToStack(fragmentClass, targetFragment, null, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void pushForResult(@NonNull final Class fragmentClass, + @NonNull final Fragment targetFragment, + @Nullable final Bundle args, + @Nullable final Func1 transactionSetup) { + addToStack(fragmentClass, targetFragment, args, fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setAsTop(@NonNull final Class fragmentClass) { + addToStack(fragmentClass, null, null, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, null); + } + + public void setAsTop(@NonNull final Class fragmentClass, + @NonNull final Bundle args) { + addToStack(fragmentClass, null, args, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, null); + } + + public void setAsTop(@NonNull final Class fragmentClass, + @NonNull final Func1 transactionSetup) { + addToStack(fragmentClass, null, null, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setAsTop(@NonNull final Class fragmentClass, + @Nullable final Bundle args, + @Nullable final Func1 transactionSetup) { + addToStack(fragmentClass, null, args, fragmentClass.getName() + ';' + TOP_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setInitial(@NonNull final Class fragmentClass) { + setInitial(fragmentClass, null, null); + } + + public void setInitial(@NonNull final Class fragmentClass, + @NonNull final Bundle args) { + setInitial(fragmentClass, args, null); + } + + public void setInitial(@NonNull final Class fragmentClass, + @NonNull final Func1 transactionSetup) { + setInitial(fragmentClass, null, transactionSetup); + } + + public void setInitial(@NonNull final Class fragmentClass, + @Nullable final Bundle args, + @Nullable final Func1 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); + } + +} diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java new file mode 100644 index 0000000..a2d51e5 --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/navigation/SimpleViewControllerFragment.java @@ -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> + extends ViewControllerFragment { + + 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 viewControllerClass, + @Nullable final Serializable state) { + final Bundle result = ViewControllerFragment.createState(state); + result.putSerializable(VIEW_CONTROLLER_CLASS_EXTRA, viewControllerClass); + return result; + } + + private Class>> viewControllerClass; + + @NonNull + @Override + protected Class>> getViewControllerClass() { + return viewControllerClass; + } + + @SuppressWarnings("unchecked") + @Override + public void onCreate(@Nullable final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + viewControllerClass = (Class>>) getArguments().getSerializable(VIEW_CONTROLLER_CLASS_EXTRA); + } + +} diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java index 0b5a4b4..011cb0c 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java @@ -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> { +public class ViewController, + TFragment extends ViewControllerFragment> { + + private static final String SUPPORT_FRAGMENT_VIEW_STATE_EXTRA = "android:view_state"; @NonNull private final TLogicBridge logicBridge; @@ -45,13 +50,35 @@ public class ViewController creationContext, + public ViewController(@NonNull final CreationContext 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 getRestoreSavedStateObservable(@NonNull final CreationContext creationContext, + @Nullable final Bundle savedInstanceState) { + return Observable.just(savedInstanceState); } /** @@ -67,7 +94,7 @@ public class ViewController 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> { + public static class CreationContext, + TFragment extends ViewControllerFragment> { @NonNull private final TLogicBridge logicBridge; diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerActivity.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerActivity.java new file mode 100644 index 0000000..dd4bab7 --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerActivity.java @@ -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 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> 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 observeLogicBridge() { + return RxAndroidUtils.observeService(this, getLogicServiceClass()) + .map(service -> service != null ? service.getLogicBridge() : null); + } + +} diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java index 6abd528..fef1835 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewControllerFragment.java @@ -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 +public abstract class ViewControllerFragment> extends ViewFragment { private static final String VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA"; @@ -58,6 +57,7 @@ public abstract class ViewControllerFragment> 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>> 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 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> 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 extends FragmentNavigation { + + public ViewControllerNavigation(@NonNull final ViewControllerActivity context, + @NonNull final FragmentManager fragmentManager, + @IdRes final int containerViewId) { + super(context, fragmentManager, containerViewId); + } + + public void push(@NonNull final Class>> fragmentClass, + @NonNull final TState state) { + addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, null); + } + + public void push(@NonNull final Class>> fragmentClass, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + addToStack(fragmentClass, null, ViewControllerFragment.createState(state), null, transactionSetup); + } + + public void pushForResult(@NonNull final Class>> fragmentClass, + @NonNull final Fragment targetFragment, + @NonNull final TState state) { + addToStack(fragmentClass, targetFragment, ViewControllerFragment.createState(state), fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); + } + + public void pushForResult(@NonNull final Class>> fragmentClass, + @NonNull final Fragment targetFragment, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + addToStack(fragmentClass, targetFragment, ViewControllerFragment.createState(state), fragmentClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setAsTop(@NonNull final Class>> fragmentClass, + @NonNull final TState state) { + setAsTop(fragmentClass, ViewControllerFragment.createState(state), null); + } + + public void setAsTop(@NonNull final Class>> fragmentClass, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + setAsTop(fragmentClass, ViewControllerFragment.createState(state), transactionSetup); + } + + public void setInitial(@NonNull final Class>> fragmentClass, + @NonNull final TState state) { + setInitial(fragmentClass, ViewControllerFragment.createState(state), null); + } + + public void setInitial(@NonNull final Class>> fragmentClass, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + setInitial(fragmentClass, ViewControllerFragment.createState(state), transactionSetup); + } + + public void pushViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @NonNull final TState state) { + addViewControllerToStack(viewControllerClass, null, state, null, null); + } + + public void pushViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + addViewControllerToStack(viewControllerClass, null, state, null, transactionSetup); + } + + public void pushViewControllerForResult(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @NonNull final Fragment targetFragment, + @NonNull final TState state) { + addViewControllerToStack(viewControllerClass, targetFragment, state, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, null); + } + + public void pushViewControllerForResult(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @NonNull final Fragment targetFragment, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + addViewControllerToStack(viewControllerClass, targetFragment, state, viewControllerClass.getName() + ';' + WITH_TARGET_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setViewControllerAsTop(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @NonNull final TState state) { + addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, null); + } + + public void setViewControllerAsTop(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @Nullable final TState state, + @Nullable final Func1 transactionSetup) { + addViewControllerToStack(viewControllerClass, null, state, viewControllerClass.getName() + ' ' + TOP_FRAGMENT_TAG_MARK, transactionSetup); + } + + public void setInitialViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @NonNull final TState state) { + setInitialViewController(viewControllerClass, state, null); + } + + public void setInitialViewController(@NonNull final Class, + ? extends SimpleViewControllerFragment>>> viewControllerClass, + @Nullable final TState state, + @Nullable final Func1 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 void addViewControllerToStack( + @NonNull final Class, ?>> viewControllerClass, + @Nullable final Fragment targetFragment, + @Nullable final TState state, + @Nullable final String backStackTag, + @Nullable final Func1 transactionSetup) { + addToStack(SimpleViewControllerFragment.class, targetFragment, + SimpleViewControllerFragment.createState(viewControllerClass, state), backStackTag, transactionSetup); + } + +}