view controllers fixed. now working
This commit is contained in:
parent
a0b9326ab2
commit
4df5862967
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public abstract class AbstractBaseFragment<TViewController extends AbstractBaseF
|
|||
protected abstract TViewController createViewController(@NonNull final View view, @Nullable final Bundle savedInstanceState);
|
||||
|
||||
@Override
|
||||
public void onFragmentStarted(@NonNull final AbstractBaseFragment fragment) {
|
||||
public void onFragmentStarted(@NonNull final Fragment fragment) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 08/10/2014.
|
||||
* Base interface to listen fragment changing
|
||||
|
|
@ -26,5 +29,6 @@ package ru.touchin.roboswag.components.navigation;
|
|||
public interface OnFragmentStartedListener {
|
||||
|
||||
/* Raises by fragment to notify that it is started */
|
||||
void onFragmentStarted(AbstractBaseFragment fragment);
|
||||
void onFragmentStarted(@NonNull Fragment fragment);
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov)
|
||||
*
|
||||
|
|
@ -25,14 +17,28 @@ import android.view.View;
|
|||
*
|
||||
*/
|
||||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 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<TLogicBridge,
|
||||
public class ViewController<TState extends Serializable,
|
||||
TLogicBridge,
|
||||
TActivity extends AppCompatActivity,
|
||||
TFragment extends ViewControllerFragment<TLogicBridge, TActivity>> {
|
||||
|
||||
@NonNull
|
||||
private final TState state;
|
||||
@NonNull
|
||||
private final TLogicBridge logicBridge;
|
||||
@NonNull
|
||||
|
|
@ -40,16 +46,25 @@ public class ViewController<TLogicBridge,
|
|||
@NonNull
|
||||
private final TFragment fragment;
|
||||
@NonNull
|
||||
private final View view;
|
||||
private final ViewGroup container;
|
||||
|
||||
//not completed yet
|
||||
@SuppressWarnings("PMD.UnusedFormalParameter")
|
||||
public ViewController(@NonNull final CreationContext<TLogicBridge, TActivity, TFragment> creationContext,
|
||||
public ViewController(@NonNull final CreationContext<TState, TLogicBridge, TActivity, TFragment> 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<TLogicBridge,
|
|||
/**
|
||||
* Returns view's activity.
|
||||
*
|
||||
* @return Returns activity;
|
||||
* @return Returns activity.
|
||||
*/
|
||||
@NonNull
|
||||
public TActivity getActivity() {
|
||||
|
|
@ -85,11 +100,11 @@ public class ViewController<TLogicBridge,
|
|||
/**
|
||||
* Returns view instantiated in {@link #getFragment} fragment attached to {@link #getActivity} activity.
|
||||
*
|
||||
* @return Returns view;
|
||||
* @return Returns view.
|
||||
*/
|
||||
@NonNull
|
||||
public View getView() {
|
||||
return view;
|
||||
public ViewGroup getContainer() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
|
|
@ -99,10 +114,13 @@ public class ViewController<TLogicBridge,
|
|||
/**
|
||||
* Class to simplify constructor override.
|
||||
*/
|
||||
public static class CreationContext<TLogicBridge,
|
||||
public static class CreationContext<TState extends Serializable,
|
||||
TLogicBridge,
|
||||
TActivity extends AppCompatActivity,
|
||||
TFragment extends ViewControllerFragment<TLogicBridge, TActivity>> {
|
||||
|
||||
@NonNull
|
||||
private final TState state;
|
||||
@NonNull
|
||||
private final TLogicBridge logicBridge;
|
||||
@NonNull
|
||||
|
|
@ -110,16 +128,18 @@ public class ViewController<TLogicBridge,
|
|||
@NonNull
|
||||
private final TFragment fragment;
|
||||
@NonNull
|
||||
private final View view;
|
||||
private final ViewGroup container;
|
||||
|
||||
public CreationContext(@NonNull final TLogicBridge logicBridge,
|
||||
public CreationContext(@NonNull final TState state,
|
||||
@NonNull final TLogicBridge logicBridge,
|
||||
@NonNull final TActivity activity,
|
||||
@NonNull final TFragment fragment,
|
||||
@NonNull final View view) {
|
||||
@NonNull final ViewGroup container) {
|
||||
this.state = state;
|
||||
this.logicBridge = logicBridge;
|
||||
this.activity = activity;
|
||||
this.fragment = fragment;
|
||||
this.view = view;
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,32 +19,55 @@
|
|||
|
||||
package ru.touchin.roboswag.components.navigation;
|
||||
|
||||
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;
|
||||
import android.view.ViewGroup;
|
||||
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.android.RxAndroidUtils;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Scheduler;
|
||||
import rx.Subscription;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* TODO: fill description
|
||||
* Fragment that creates {@link ViewController} between {@link #onViewCreated} and {@link #onDestroyView}.
|
||||
* [phase 1]
|
||||
*/
|
||||
public abstract class ViewControllerFragment<TLogicBridge, TActivity extends AppCompatActivity> extends ViewFragment<TActivity> {
|
||||
|
||||
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<TActivity> activitySubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Pair<View, Bundle>> viewSubject = BehaviorSubject.create();
|
||||
private final BehaviorSubject<Pair<ViewGroup, Bundle>> 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<TLogicBridge, TActivity extends App
|
|||
* @return Returns class of specific LogicService.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<LogicService<TLogicBridge>> getLogicServiceClass();
|
||||
protected abstract Class<? extends LogicService<TLogicBridge>> 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<TLogicBridge, TActivity extends App
|
|||
* @return Returns class of specific ViewController.
|
||||
*/
|
||||
@NonNull
|
||||
protected abstract Class<ViewController<TLogicBridge, TActivity,
|
||||
protected abstract Class<? extends ViewController<? extends Serializable, TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TLogicBridge, TActivity>>> getViewControllerClass();
|
||||
|
||||
// need throwable for app stability
|
||||
|
|
@ -70,39 +93,73 @@ public abstract class ViewControllerFragment<TLogicBridge, TActivity extends App
|
|||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getContext() != null) {
|
||||
viewControllerSubscription = Observable.combineLatest(activitySubject.distinctUntilChanged(), viewSubject.distinctUntilChanged(),
|
||||
RxAndroidUtils.observeService(getContext(), getLogicServiceClass())
|
||||
.map(service -> service != null ? service.getLogicBridge() : null)
|
||||
.distinctUntilChanged(),
|
||||
(activity, view, logicBridge) -> {
|
||||
if (activity == null || view == null || logicBridge == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ViewController.CreationContext<TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TLogicBridge, TActivity>> 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.<Serializable>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<? extends Serializable, TLogicBridge, TActivity,
|
||||
? extends ViewControllerFragment<TLogicBridge, TActivity>> 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<TLogicBridge, TActivity extends App
|
|||
this.viewController.onDestroy();
|
||||
}
|
||||
this.viewController = viewController;
|
||||
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 {
|
||||
Lc.assertion("View of fragment should be PlaceholderView");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull final Bundle stateToSave) {
|
||||
super.onSaveInstanceState(stateToSave);
|
||||
if (viewController != null) {
|
||||
stateToSave.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, viewController.getState());
|
||||
} else if (getArguments() != null && getArguments().containsKey(VIEW_CONTROLLER_STATE_EXTRA)) {
|
||||
stateToSave.putSerializable(VIEW_CONTROLLER_STATE_EXTRA, getArguments().getSerializable(VIEW_CONTROLLER_STATE_EXTRA));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -126,10 +203,7 @@ public abstract class ViewControllerFragment<TLogicBridge, TActivity extends App
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (viewControllerSubscription != null) {
|
||||
viewControllerSubscription.unsubscribe();
|
||||
viewControllerSubscription = null;
|
||||
}
|
||||
viewControllerSubscription.unsubscribe();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
|
|
@ -139,4 +213,12 @@ public abstract class ViewControllerFragment<TLogicBridge, TActivity extends App
|
|||
super.onDetach();
|
||||
}
|
||||
|
||||
private static class PlaceholderView extends FrameLayout {
|
||||
|
||||
public PlaceholderView(@NonNull final Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
|
||||
import rx.functions.Action2;
|
||||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 21/10/2015.
|
||||
* Fragment that have specific activity as a parent and can't be background.
|
||||
* [phase 1]
|
||||
*/
|
||||
public abstract class ViewFragment<TActivity extends AppCompatActivity> extends Fragment {
|
||||
|
||||
|
|
@ -67,24 +67,23 @@ public abstract class ViewFragment<TActivity extends AppCompatActivity> 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<TActivity extends AppCompatActivity> extends
|
|||
}
|
||||
|
||||
private void callMethodAfterInstantiation(@NonNull final Action2<View, TActivity> 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<TActivity extends AppCompatActivity> 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<TActivity extends AppCompatActivity> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<TLogicBridge> 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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue