Skip to content

Commit d52964a

Browse files
mseroczynskisockeqwe
authored andcommitted
Added DialogFragment support (basic, LCE, ViewState) (sockeqwe#300)
* Added DialogFragment support (basic, LCE, ViewState) * Dialogs compatible with 3.0.0
1 parent 108289a commit d52964a

File tree

3 files changed

+431
-0
lines changed

3 files changed

+431
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package com.hannesdorfmann.mosby3.mvp.lce;
2+
3+
import android.os.Bundle;
4+
import android.support.annotation.CallSuper;
5+
import android.support.annotation.NonNull;
6+
import android.support.annotation.Nullable;
7+
import android.view.LayoutInflater;
8+
import android.view.View;
9+
import android.view.ViewGroup;
10+
import android.widget.TextView;
11+
import android.widget.Toast;
12+
import com.hannesdorfmann.mosby3.mvp.MvpDialogFragment;
13+
import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
14+
15+
/**
16+
* A {@link MvpDialogFragment} that implements {@link MvpLceView} which gives you 3 options:
17+
* <ul>
18+
* <li>Display a loading view: A view with <b>R.id.loadingView</b> must be specified in your
19+
* inflated xml layout</li>
20+
* <li>Display a error view: A <b>TextView</b> with <b>R.id.errorView</b> must be declared in your
21+
* inflated xml layout</li>
22+
* <li>Display content view: A view with <b>R.id.contentView</b> must be specified in your
23+
* inflated
24+
* xml layout</li>
25+
* </ul>
26+
*
27+
* @param <CV> The type of the content view with the id = R.id.contentView. Can be any kind of
28+
* android view widget like ListView, RecyclerView, ScrollView or a simple layout like Framelayout
29+
* etc. (everything that extends from android.view.View)
30+
* @param <M> The underlying data model that will be displayed with this view
31+
* @param <V> The View interface that must be implemented by this view. You can use {@link
32+
* MvpLceView}, but if you want to add more methods you have to provide your own view interface
33+
* that
34+
* extends from {@link MvpLceView}
35+
* @param <P> The type of the Presenter. Must extend from {@link MvpPresenter}
36+
* @author Hannes Dorfmann
37+
* @since 3.1.1
38+
*/
39+
public abstract class MvpLceDialogFragment<CV extends View, M, V extends MvpLceView<M>, P extends MvpPresenter<V>>
40+
extends MvpDialogFragment<V, P> implements MvpLceView<M> {
41+
42+
protected View loadingView;
43+
protected CV contentView;
44+
protected TextView errorView;
45+
46+
@CallSuper @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
47+
super.onViewCreated(view, savedInstanceState);
48+
49+
loadingView = createLoadingView(view);
50+
contentView = createContentView(view);
51+
errorView = createErrorView(view);
52+
53+
if (loadingView == null) {
54+
throw new NullPointerException(
55+
"Loading view is null! Have you specified a loading view in your layout xml file?"
56+
+ " You have to give your loading View the id R.id.loadingView");
57+
}
58+
59+
if (contentView == null) {
60+
throw new NullPointerException(
61+
"Content view is null! Have you specified a content view in your layout xml file?"
62+
+ " You have to give your content View the id R.id.contentView");
63+
}
64+
65+
if (errorView == null) {
66+
throw new NullPointerException(
67+
"Error view is null! Have you specified a content view in your layout xml file?"
68+
+ " You have to give your error View the id R.id.errorView");
69+
}
70+
71+
errorView.setOnClickListener(new View.OnClickListener() {
72+
@Override public void onClick(View v) {
73+
onErrorViewClicked();
74+
}
75+
});
76+
}
77+
78+
/**
79+
* Create the loading view. Default is {@code findViewById(R.id.loadingView)}
80+
*
81+
* @param view The main view returned from {@link #onCreateView(LayoutInflater, ViewGroup, * Bundle)}
82+
* @return the loading view
83+
*/
84+
@NonNull protected View createLoadingView(View view) {
85+
return view.findViewById(R.id.loadingView);
86+
}
87+
88+
/**
89+
* Create the content view. Default is {@code findViewById(R.id.contentView)}
90+
*
91+
* @param view The main view returned from {@link #onCreateView(LayoutInflater, ViewGroup, *
92+
* Bundle)}
93+
* @return the content view
94+
*/
95+
@NonNull protected CV createContentView(View view) {
96+
return (CV) view.findViewById(R.id.contentView);
97+
}
98+
99+
/**
100+
* Create the error view. Default is {@code findViewById(R.id.errorView)}
101+
*
102+
* @param view The main view returned from {@link #onCreateView(LayoutInflater, ViewGroup, *
103+
* Bundle)}
104+
* @return the error view
105+
*/
106+
@NonNull protected TextView createErrorView(View view) {
107+
return (TextView) view.findViewById(R.id.errorView);
108+
}
109+
110+
@Override public void showLoading(boolean pullToRefresh) {
111+
112+
if (!pullToRefresh) {
113+
animateLoadingViewIn();
114+
}
115+
116+
// otherwise the pull to refresh widget will already display a loading animation
117+
}
118+
119+
/**
120+
* Override this method if you want to provide your own animation for showing the loading view
121+
*/
122+
protected void animateLoadingViewIn() {
123+
LceAnimator.showLoading(loadingView, contentView, errorView);
124+
}
125+
126+
@Override public void showContent() {
127+
animateContentViewIn();
128+
}
129+
130+
/**
131+
* Called to animate from loading view to content view
132+
*/
133+
protected void animateContentViewIn() {
134+
LceAnimator.showContent(loadingView, contentView, errorView);
135+
}
136+
137+
/**
138+
* Get the error message for a certain Exception that will be shown on {@link
139+
* #showError(Throwable, boolean)}
140+
*/
141+
protected abstract String getErrorMessage(Throwable e, boolean pullToRefresh);
142+
143+
/**
144+
* The default behaviour is to display a toast message as light error (i.e. pull-to-refresh
145+
* error).
146+
* Override this method if you want to display the light error in another way (like crouton).
147+
*/
148+
protected void showLightError(String msg) {
149+
if (getActivity() != null) {
150+
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
151+
}
152+
}
153+
154+
/**
155+
* Called if the error view has been clicked. To disable clicking on the errorView use
156+
* <code>errorView.setClickable(false)</code>
157+
*/
158+
protected void onErrorViewClicked() {
159+
loadData(false);
160+
}
161+
162+
@Override
163+
public void showError(Throwable e, boolean pullToRefresh) {
164+
165+
String errorMsg = getErrorMessage(e, pullToRefresh);
166+
167+
if (pullToRefresh) {
168+
showLightError(errorMsg);
169+
} else {
170+
errorView.setText(errorMsg);
171+
animateErrorViewIn();
172+
}
173+
}
174+
175+
/**
176+
* Animates the error view in (instead of displaying content view / loading view)
177+
*/
178+
protected void animateErrorViewIn() {
179+
LceAnimator.showErrorView(loadingView, contentView, errorView);
180+
}
181+
182+
@Override
183+
public void onDestroyView() {
184+
super.onDestroyView();
185+
loadingView = null;
186+
contentView = null;
187+
errorView.setOnClickListener(null);
188+
errorView = null;
189+
}
190+
191+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.hannesdorfmann.mosby3.mvp.viewstate.lce;
2+
3+
import android.os.Bundle;
4+
import android.view.View;
5+
import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
6+
import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpDelegate;
7+
import com.hannesdorfmann.mosby3.mvp.delegate.FragmentMvpViewStateDelegateImpl;
8+
import com.hannesdorfmann.mosby3.mvp.delegate.MvpViewStateDelegateCallback;
9+
import com.hannesdorfmann.mosby3.mvp.lce.MvpLceDialogFragment;
10+
import com.hannesdorfmann.mosby3.mvp.lce.MvpLceView;
11+
import com.hannesdorfmann.mosby3.mvp.viewstate.ViewState;
12+
13+
/**
14+
* A {@link MvpLceDialogFragment} with {@link ViewState} support.
15+
*
16+
* @author Hannes Dorfmann
17+
* @since 3.1.1
18+
*/
19+
public abstract class MvpLceViewStateDialogFragment<CV extends View, M, V extends MvpLceView<M>, P extends MvpPresenter<V>>
20+
extends MvpLceDialogFragment<CV, M, V, P>
21+
implements MvpLceView<M>, MvpViewStateDelegateCallback<V, P, LceViewState<M, V>> {
22+
23+
/**
24+
* The viewstate will be instantiated by calling {@link #createViewState()} in {@link
25+
* #onViewCreated(View, Bundle)}. Don't instantiate it by hand.
26+
*/
27+
protected LceViewState<M, V> viewState;
28+
29+
/**
30+
* A flag that indicates if the viewstate tires to restore the view right now.
31+
*/
32+
private boolean restoringViewState = false;
33+
34+
@Override protected FragmentMvpDelegate<V, P> getMvpDelegate() {
35+
if (mvpDelegate == null) {
36+
mvpDelegate = new FragmentMvpViewStateDelegateImpl<>(this, this, true, true);
37+
}
38+
39+
return mvpDelegate;
40+
}
41+
42+
@Override public LceViewState<M, V> getViewState() {
43+
return viewState;
44+
}
45+
46+
@Override public void setViewState(LceViewState<M, V> viewState) {
47+
this.viewState = viewState;
48+
}
49+
50+
@Override public void showContent() {
51+
super.showContent();
52+
viewState.setStateShowContent(getData());
53+
}
54+
55+
@Override public void showError(Throwable e, boolean pullToRefresh) {
56+
super.showError(e, pullToRefresh);
57+
viewState.setStateShowError(e, pullToRefresh);
58+
}
59+
60+
@Override public void showLoading(boolean pullToRefresh) {
61+
super.showLoading(pullToRefresh);
62+
viewState.setStateShowLoading(pullToRefresh);
63+
}
64+
65+
@Override public void setRestoringViewState(boolean restoringViewState) {
66+
this.restoringViewState = restoringViewState;
67+
}
68+
@Override public boolean isRestoringViewState() {
69+
return restoringViewState;
70+
}
71+
72+
@Override public void onViewStateInstanceRestored(boolean instanceStateRetainedInMemory) {
73+
if (!instanceStateRetainedInMemory && viewState.isLoadingState()) {
74+
loadData(viewState.isPullToRefreshLoadingState());
75+
}
76+
}
77+
78+
@Override public void onNewViewStateInstance() {
79+
loadData(false);
80+
}
81+
82+
@Override protected void showLightError(String msg) {
83+
if (isRestoringViewState()) {
84+
return; // Do not display toast again while restoring viewstate
85+
}
86+
87+
super.showLightError(msg);
88+
}
89+
90+
/**
91+
* Get the data that has been set before in {@link #setData(Object)}
92+
* <p>
93+
* <b>It's necessary to return the same data as set before to ensure that {@link ViewState} works
94+
* correctly</b>
95+
* </p>
96+
*
97+
* @return The data
98+
*/
99+
public abstract M getData();
100+
}

0 commit comments

Comments
 (0)