/* * Copyright 2015 Hannes Dorfmann. * * 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 com.hannesdorfmann.mosby3.mvp.lce; import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.hannesdorfmann.mosby3.mvp.MvpActivity; import com.hannesdorfmann.mosby3.mvp.MvpPresenter; import com.hannesdorfmann.mosby3.mvp.lce.R; /** * A {@link MvpActivity} that implements {@link MvpLceView} which gives you 3 options: * <ul> * <li>Display a loading view: A view with <b>R.id.loadingView</b> must be specified in your * inflated xml layout</li> * <li>Display a error view: A <b>TextView</b> with <b>R.id.errorView</b> must be declared in your * inflated xml layout</li> * <li>Display content view: A view with <b>R.id.contentView</b> must be specified in your * inflated * xml layout</li> * </ul> * * @param <CV> The type of the content view with the id = R.id.contentView. Can be any kind of * android view widget like ListView, RecyclerView, ScrollView or a simple layout like Framelayout * etc. (everything that extends from android.view.View) * @param <M> The underlying data model that will be displayed with this view * @param <V> The View interface that must be implemented by this view. You can use {@link * MvpLceView}, but if you want to add more methods you have to provide your own view interface * that * extends from {@link MvpLceView} * @param <P> The type of the Presenter. Must extend from {@link MvpPresenter} */ public abstract class MvpLceActivity<CV extends View, M, V extends MvpLceView<M>, P extends MvpPresenter<V>> extends MvpActivity<V, P> implements MvpLceView<M> { protected View loadingView; protected CV contentView; protected TextView errorView; @CallSuper @Override public void onContentChanged() { super.onContentChanged(); loadingView = createLoadingView(); contentView = createContentView(); errorView = createErrorView(); if (loadingView == null) { throw new NullPointerException( "Loading view is null! Have you specified a loading view in your layout xml file?" + " You have to give your loading View the id R.id.loadingView"); } if (contentView == null) { throw new NullPointerException( "Content view is null! Have you specified a content view in your layout xml file?" + " You have to give your content View the id R.id.contentView"); } if (errorView == null) { throw new NullPointerException( "Error view is null! Have you specified an error view in your layout xml file?" + " You have to give your error View the id R.id.errorView"); } errorView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onErrorViewClicked(); } }); } /** * Create the loading view. Default is {@code findViewById(R.id.loadingView)} * @return the loading view */ @NonNull protected View createLoadingView() { return findViewById(R.id.loadingView); } /** * Create the content view. Default is {@code findViewById(R.id.contentView)} * @return the content view */ @NonNull protected CV createContentView() { return (CV) findViewById(R.id.contentView); } /** * Create the loading view. Default is {@code findViewById(R.id.errorView)} * @return the error view */ @NonNull protected TextView createErrorView(){ return (TextView) findViewById(R.id.errorView); } /** * Called if the error view has been clicked. To disable clicking on the errorView use * <code>errorView.setClickable(false)</code> */ protected void onErrorViewClicked() { loadData(false); } @Override public void showLoading(boolean pullToRefresh) { if (!pullToRefresh) { animateLoadingViewIn(); } // otherwise the pull to refresh widget will already display a loading animation } /** * Override this method if you want to provide your own animation for showing the loading view */ protected void animateLoadingViewIn() { LceAnimator.showLoading(loadingView, contentView, errorView); } @Override public void showContent() { animateContentViewIn(); } /** * Called to animate from loading view to content view */ protected void animateContentViewIn() { LceAnimator.showContent(loadingView, contentView, errorView); } /** * Get the error message for a certain Exception that will be shown on {@link * #showError(Throwable, boolean)} */ protected abstract String getErrorMessage(Throwable e, boolean pullToRefresh); /** * The default behaviour is to display a toast message as light error (i.e. pull-to-refresh * error). * Override this method if you want to display the light error in another way (like crouton). */ protected void showLightError(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public void showError(Throwable e, boolean pullToRefresh) { String errorMsg = getErrorMessage(e, pullToRefresh); if (pullToRefresh) { showLightError(errorMsg); } else { errorView.setText(errorMsg); animateErrorViewIn(); } } /** * Animates the error view in (instead of displaying content view / loading view) */ protected void animateErrorViewIn() { LceAnimator.showErrorView(loadingView, contentView, errorView); } }