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 7f8cb96..d7f09f5 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseActivity.java @@ -168,7 +168,7 @@ public abstract class AbstractBaseActivity extends AppCompatActivity } @Override - public void onFragmentStarted(@NonNull final AbstractBaseFragment fragment) { + public void onFragmentStarted(@NonNull final Fragment fragment) { hideSoftInput(); } diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseFragment.java b/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseFragment.java index 610e0bc..e8c5c76 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseFragment.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/AbstractBaseFragment.java @@ -106,7 +106,7 @@ public abstract class AbstractBaseFragment> { + @NonNull + private final TState state; @NonNull private final TLogicBridge logicBridge; @NonNull @@ -40,16 +46,25 @@ public class ViewController creationContext, + public ViewController(@NonNull final CreationContext creationContext, @Nullable final Bundle savedInstanceState) { + this.state = creationContext.state; this.logicBridge = creationContext.logicBridge; this.activity = creationContext.activity; this.fragment = creationContext.fragment; - this.view = creationContext.view; + this.container = creationContext.container; + } + + /** + * Returns specific object which contains state of ViewController. + * + * @return Object of TState type. + */ + @NonNull + public TState getState() { + return state; } /** @@ -65,7 +80,7 @@ public class ViewController> { + @NonNull + private final TState state; @NonNull private final TLogicBridge logicBridge; @NonNull @@ -110,16 +128,18 @@ public class ViewController extends ViewFragment { + private static final String VIEW_CONTROLLER_STATE_EXTRA = "VIEW_CONTROLLER_STATE_EXTRA"; + + /** + * Creates {@link Bundle} which will store state. + * + * @param state State to use into ViewController. + * @return Returns bundle with state inside. + */ + public static Bundle createState(@NonNull final Serializable state) { + final Bundle result = new Bundle(); + result.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, state); + return result; + } + private final BehaviorSubject activitySubject = BehaviorSubject.create(); - private final BehaviorSubject> viewSubject = BehaviorSubject.create(); + private final BehaviorSubject> viewSubject = BehaviorSubject.create(); + private final Scheduler backgroundScheduler = RxAndroidUtils.createLooperScheduler(); @Nullable private ViewController viewController; - @Nullable private Subscription viewControllerSubscription; /** @@ -53,7 +76,7 @@ public abstract class ViewControllerFragment> getLogicServiceClass(); + protected abstract Class> getLogicServiceClass(); /** * It should return specific ViewController class to control instantiated view by logic bridge after activity creation. @@ -61,7 +84,7 @@ public abstract class ViewControllerFragment>> getViewControllerClass(); // need throwable for app stability @@ -70,39 +93,73 @@ public abstract class ViewControllerFragment service != null ? service.getLogicBridge() : null) - .distinctUntilChanged(), - (activity, view, logicBridge) -> { - if (activity == null || view == null || logicBridge == null) { - return null; - } - - final ViewController.CreationContext> creationContext - = new ViewController.CreationContext<>(logicBridge, activity, this, view.first); - if (getViewControllerClass().getConstructors().length == 1) { - try { - return (ViewController) getViewControllerClass().getConstructors()[0].newInstance(creationContext, view.second); - } catch (Throwable throwable) { - Lc.assertion(throwable); - } - } else { - Lc.assertion("There should be single constructor for " + getViewControllerClass()); - } - return null; - }).subscribe(this::onViewControllerChanged); - } else { - Lc.assertion("Context is null in onCreate."); + if (getContext() == null) { + Lc.assertion("Context is null in onCreate"); } + + viewControllerSubscription = Observable + .combineLatest(Observable.create(subscriber -> { + final Serializable state = savedInstanceState != null + ? savedInstanceState.getSerializable(VIEW_CONTROLLER_STATE_EXTRA) + : (getArguments() != null ? getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA) : null); + if (state != null) { + subscriber.onNext(state); + } else { + Lc.assertion("State should be stored into arguments or savedInstanceState"); + } + subscriber.onCompleted(); + }).subscribeOn(backgroundScheduler), + RxAndroidUtils.observeService(getContext(), getLogicServiceClass()) + .map(service -> service != null ? service.getLogicBridge() : null) + .distinctUntilChanged() + .observeOn(backgroundScheduler), + activitySubject.distinctUntilChanged().observeOn(backgroundScheduler), + viewSubject.distinctUntilChanged().observeOn(backgroundScheduler), + (state, logicBridge, activity, view) -> { + if (activity == null || view == null || logicBridge == null) { + return null; + } + + final ViewController.CreationContext> creationContext + = new ViewController.CreationContext<>(state, logicBridge, activity, this, view.first); + if (getViewControllerClass().getConstructors().length > 1) { + Lc.assertion("There should be single constructor for " + getViewControllerClass()); + return null; + } + try { + final Constructor constructor = getViewControllerClass().getConstructors()[0]; + switch (constructor.getParameterTypes().length) { + case 2: + return (ViewController) constructor.newInstance(creationContext, view.second); + case 3: + return (ViewController) constructor.newInstance(this, creationContext, view.second); + default: + Lc.assertion("Wrong constructor parameters count: " + constructor.getParameterTypes().length); + return null; + } + } catch (final Throwable throwable) { + Lc.assertion(throwable); + return null; + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::onViewControllerChanged); + } + + @Deprecated + @NonNull + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, + @Nullable final ViewGroup container, + @Nullable final Bundle savedInstanceState) { + return new PlaceholderView(inflater.getContext()); } @Override - public void onViewCreated(final View view, @Nullable final Bundle savedInstanceState) { + public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - //TODO... + viewSubject.onNext(new Pair<>(new FrameLayout(view.getContext()), savedInstanceState)); } @Override @@ -116,6 +173,26 @@ public abstract class ViewControllerFragment extends Fragment { @@ -67,24 +67,23 @@ public abstract class ViewFragment extends } } - @Deprecated @NonNull @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { - throw new IllegalStateException("Method onCreateView() should be override."); + throw new IllegalStateException("Method onCreateView() should be overridden"); } @Deprecated @Override public void onActivityCreated(@Nullable final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - if (getView() != null && getBaseActivity() != null) { - onActivityCreated(getView(), getBaseActivity(), savedInstanceState); - } else { + if (getView() == null || getBaseActivity() == null) { Lc.assertion("View and activity shouldn't be null"); + return; } + onActivityCreated(getView(), getBaseActivity(), savedInstanceState); } /** @@ -99,11 +98,11 @@ public abstract class ViewFragment extends } private void callMethodAfterInstantiation(@NonNull final Action2 action) { - if (getView() != null && getBaseActivity() != null) { - action.call(getView(), getBaseActivity()); - } else { + if (getView() == null || getBaseActivity() == null) { Lc.assertion("View and activity shouldn't be null"); + return; } + action.call(getView(), getBaseActivity()); } @Deprecated @@ -120,7 +119,11 @@ public abstract class ViewFragment extends * @param activity Activity which fragment attached to. */ protected void onStart(@NonNull final View view, @NonNull final TActivity activity) { - //do nothing + if (getParentFragment() instanceof OnFragmentStartedListener) { + ((OnFragmentStartedListener) getParentFragment()).onFragmentStarted(this); + } else if (activity instanceof OnFragmentStartedListener) { + ((OnFragmentStartedListener) activity).onFragmentStarted(this); + } } @Deprecated @@ -177,11 +180,11 @@ public abstract class ViewFragment extends @Deprecated @Override public void onDestroyView() { - if (getView() != null) { - onDestroyView(getView()); - } else { + if (getView() == null) { Lc.assertion("View shouldn't be null"); + return; } + onDestroyView(getView()); super.onDestroyView(); } diff --git a/src/main/java/ru/touchin/roboswag/components/services/LogicService.java b/src/main/java/ru/touchin/roboswag/components/services/LogicService.java index d63157f..f2ff35b 100644 --- a/src/main/java/ru/touchin/roboswag/components/services/LogicService.java +++ b/src/main/java/ru/touchin/roboswag/components/services/LogicService.java @@ -10,18 +10,24 @@ import ru.touchin.roboswag.core.utils.android.ServiceBinder; * Created by Gavriil Sitnikov on 10/01/2016. * Service which holds interface to all application's logic objects and methods. * Any part of application should interact with some part of logic via this interface. - * If it is Service, Activity, Fragment or iew then it should bind itself to that service first then get service and logic bridge from IBinder. + * If it is Service, Activity, Fragment or view then it should bind itself to that service first then get service and logic bridge from IBinder. * If it is BroadcastReceiver then it should start service which can bind to that service or just send some intent to that service. + * [phase 1] */ public abstract class LogicService extends IntentService { private final TLogicBridge logicBridge; - protected LogicService(final String name) { - super(name); + protected LogicService() { + super("LogicService"); this.logicBridge = createLogicBridge(); } + @Override + protected void onHandleIntent(final Intent intent) { + // do nothing + } + /** * Creates object which will provide all logic methods and objects of application. * Any other activity, fragment or service should bind to that service to get logic bridge and start interact with application's logic. diff --git a/src/main/java/ru/touchin/roboswag/components/utils/Typefaces.java b/src/main/java/ru/touchin/roboswag/components/utils/Typefaces.java index d28c42d..51bd1ac 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/Typefaces.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/Typefaces.java @@ -34,7 +34,7 @@ import java.util.List; import java.util.Map; /** - * Created by Gavriil Sitnikov on 18/07/2014. [phase 1] + * Created by Gavriil Sitnikov on 18/07/2014. * Manager for typefaces stored in assets 'fonts' folder. */ public final class Typefaces {