Skip to content
This repository has been archived by the owner on Mar 16, 2021. It is now read-only.

Commit

Permalink
Merge pull request #47 from vRallev/feature/add-fragment-delegate
Browse files Browse the repository at this point in the history
Add fragment delegate
  • Loading branch information
StefMa authored Dec 16, 2016
2 parents a8a702e + 0e7a537 commit a255fc4
Show file tree
Hide file tree
Showing 4 changed files with 428 additions and 274 deletions.
Original file line number Diff line number Diff line change
@@ -1,62 +1,53 @@
package net.grandcentrix.thirtyinch;

import net.grandcentrix.thirtyinch.internal.DelegatedTiFragment;
import net.grandcentrix.thirtyinch.internal.InterceptableViewBinder;
import net.grandcentrix.thirtyinch.internal.TiFragmentDelegate;
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import net.grandcentrix.thirtyinch.callonmainthread.CallOnMainThreadInterceptor;
import net.grandcentrix.thirtyinch.distinctuntilchanged.DistinctUntilChangedInterceptor;
import net.grandcentrix.thirtyinch.internal.InterceptableViewBinder;
import net.grandcentrix.thirtyinch.internal.PresenterSavior;
import net.grandcentrix.thirtyinch.internal.PresenterViewBinder;
import net.grandcentrix.thirtyinch.internal.TiLoggingTagProvider;
import net.grandcentrix.thirtyinch.internal.TiPresenterProvider;
import net.grandcentrix.thirtyinch.internal.TiViewProvider;
import net.grandcentrix.thirtyinch.util.AndroidDeveloperOptions;
import net.grandcentrix.thirtyinch.util.AnnotationUtil;

import java.util.List;

public abstract class TiDialogFragment<P extends TiPresenter<V>, V extends TiView>
extends AppCompatDialogFragment implements TiPresenterProvider<P>, TiLoggingTagProvider,
extends AppCompatDialogFragment
implements DelegatedTiFragment, TiPresenterProvider<P>, TiLoggingTagProvider,
TiViewProvider<V>, InterceptableViewBinder<V> {

private static final String SAVED_STATE_PRESENTER_ID = "presenter_id";

private final String TAG = this.getClass().getSimpleName()
+ ":" + TiDialogFragment.class.getSimpleName()
+ "@" + Integer.toHexString(this.hashCode());

private volatile boolean mActivityStarted = false;

private P mPresenter;

private String mPresenterId;

private PresenterViewBinder<V> mViewBinder = new PresenterViewBinder<>(this);
private final TiFragmentDelegate<P, V> mDelegate =
new TiFragmentDelegate<>(this, this, this, this);

@NonNull
@Override
public Removable addBindViewInterceptor(@NonNull final BindViewInterceptor interceptor) {
return mViewBinder.addBindViewInterceptor(interceptor);
return mDelegate.addBindViewInterceptor(interceptor);
}

@Nullable
@Override
public V getInterceptedViewOf(@NonNull final BindViewInterceptor interceptor) {
return mViewBinder.getInterceptedViewOf(interceptor);
return mDelegate.getInterceptedViewOf(interceptor);
}

@NonNull
@Override
public List<BindViewInterceptor> getInterceptors(
@NonNull final Filter<BindViewInterceptor> predicate) {
return mViewBinder.getInterceptors(predicate);
return mDelegate.getInterceptors(predicate);
}

@Override
Expand All @@ -65,7 +56,7 @@ public String getLoggingTag() {
}

public P getPresenter() {
return mPresenter;
return mDelegate.getPresenter();
}

/**
Expand All @@ -74,144 +65,83 @@ public P getPresenter() {
*/
@Override
public void invalidateView() {
mViewBinder.invalidateView();
mDelegate.invalidateView();
}

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public boolean isDontKeepActivitiesEnabled() {
return AndroidDeveloperOptions.isDontKeepActivitiesEnabled(getActivity());
}

if (mPresenter == null && savedInstanceState != null) {
// recover with Savior
// this should always work.
final String recoveredPresenterId = savedInstanceState
.getString(SAVED_STATE_PRESENTER_ID);
if (recoveredPresenterId != null) {
TiLog.v(TAG, "try to recover Presenter with id: " + recoveredPresenterId);
//noinspection unchecked
mPresenter = (P) PresenterSavior.INSTANCE.recover(recoveredPresenterId);
if (mPresenter != null) {
// save recovered presenter with new id. No other instance of this activity,
// holding the presenter before, is now able to remove the reference to
// this presenter from the savior
PresenterSavior.INSTANCE.free(recoveredPresenterId);
mPresenterId = PresenterSavior.INSTANCE.safe(mPresenter);
}
TiLog.v(TAG, "recovered Presenter " + mPresenter);
}
}
@Override
public boolean isFragmentAdded() {
return isAdded();
}

if (mPresenter == null) {
mPresenter = providePresenter();
TiLog.v(TAG, "created Presenter: " + mPresenter);
final TiConfiguration config = mPresenter.getConfig();
if (config.shouldRetainPresenter() && config.useStaticSaviorToRetain()) {
mPresenterId = PresenterSavior.INSTANCE.safe(mPresenter);
}
mPresenter.create();
}
@Override
public boolean isFragmentDetached() {
return isDetached();
}

final TiConfiguration config = mPresenter.getConfig();
if (config.isCallOnMainThreadInterceptorEnabled()) {
addBindViewInterceptor(new CallOnMainThreadInterceptor());
}
@Override
public boolean isHostingActivityChangingConfigurations() {
return getActivity().isChangingConfigurations();
}

if (config.isDistinctUntilChangedInterceptorEnabled()) {
addBindViewInterceptor(new DistinctUntilChangedInterceptor());
}
@Override
public boolean isHostingActivityFinishing() {
return getActivity().isFinishing();
}

if (config.shouldRetainPresenter()) {
setRetainInstance(true);
}
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate_afterSuper(savedInstanceState);
}

@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
mViewBinder.invalidateView();
@Nullable final Bundle savedInstanceState) {
mDelegate.invalidateView();
return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onDestroy() {
super.onDestroy();
final FragmentActivity activity = getActivity();

boolean destroyPresenter = false;
if (activity.isFinishing()) {
// Probably a backpress and not a configuration change
// Activity will not be recreated and finally destroyed, also destroyed the presenter
destroyPresenter = true;
TiLog.v(TAG, "Activity is finishing, destroying presenter " + mPresenter);
}

final TiConfiguration config = mPresenter.getConfig();
if (!destroyPresenter &&
!config.shouldRetainPresenter()) {
// configuration says the presenter should not be retained, a new presenter instance
// will be created and the current presenter should be destroyed
destroyPresenter = true;
TiLog.v(TAG, "presenter configured as not retaining, destroying " + mPresenter);
}

if (!destroyPresenter &&
!config.useStaticSaviorToRetain()
&& AndroidDeveloperOptions.isDontKeepActivitiesEnabled(getActivity())) {
// configuration says the PresenterSavior should not be used. Retaining the presenter
// relays on the Activity nonConfigurationInstance which is always null when
// "don't keep activities" is enabled.
// a new presenter instance will be created and the current presenter should be destroyed
destroyPresenter = true;
TiLog.v(TAG, "the PresenterSavior is disabled and \"don\'t keep activities\" is "
+ "activated. The presenter can't be retained. Destroying " + mPresenter);
}

if (destroyPresenter) {
mPresenter.destroy();
PresenterSavior.INSTANCE.free(mPresenterId);
} else {
TiLog.v(TAG, "not destroying " + mPresenter
+ " which will be reused by the next Activity instance, recreating...");
}
mDelegate.onDestroy_afterSuper();
}

@Override
public void onDestroyView() {
mPresenter.detachView();
mDelegate.onDestroyView_beforeSuper();
super.onDestroyView();
}

@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SAVED_STATE_PRESENTER_ID, mPresenterId);
mDelegate.onSaveInstanceState_afterSuper(outState);
}

@Override
public void onStart() {
super.onStart();
mActivityStarted = true;

if (isUiPossible()) {
getActivity().getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
if (isUiPossible() && mActivityStarted) {
mViewBinder.bindView(mPresenter, TiDialogFragment.this);
}
}
});
}
mDelegate.onStart_afterSuper();
}

@Override
public void onStop() {
mActivityStarted = false;
mPresenter.detachView();
mDelegate.onStop_beforeSuper();
super.onStop();
}

@Override
public boolean postToMessageQueue(final Runnable runnable) {
return getActivity().getWindow().getDecorView().post(runnable);
}

/**
* the default implementation assumes that the fragment is the view and implements the {@link
* TiView} interface. Override this method for a different behaviour.
Expand All @@ -222,11 +152,11 @@ public void onStop() {
public V provideView() {

final Class<?> foundViewInterface = AnnotationUtil
.getInterfaceOfClassExtendingGivenInterface(this.getClass(), TiView.class);
.getInterfaceOfClassExtendingGivenInterface(getClass(), TiView.class);

if (foundViewInterface == null) {
throw new IllegalArgumentException(
"This Fragment doesn't implement a TiView interface. "
"This DialogFragment doesn't implement a TiView interface. "
+ "This is the default behaviour. Override provideView() to explicitly change this.");
} else {
if (foundViewInterface.getSimpleName().equals("TiView")) {
Expand All @@ -241,19 +171,19 @@ public V provideView() {
}
}

@Override
public void setFragmentRetainInstance(final boolean retain) {
setRetainInstance(retain);
}

@Override
public String toString() {
String presenter = getPresenter() == null ? "null" :
getPresenter().getClass().getSimpleName()
+ "@" + Integer.toHexString(getPresenter().hashCode());

return getClass().getSimpleName()
+ ":" + TiDialogFragment.class.getSimpleName()
+ "@" + Integer.toHexString(hashCode())
+ "{presenter=" + presenter + "}";
}

private boolean isUiPossible() {
return isAdded() && !isDetached();
}
}
Loading

0 comments on commit a255fc4

Please sign in to comment.