From b7e1d92c7e45ee1b14ff53baebeb8af8dc6bbb5d Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Sat, 29 Dec 2018 13:38:18 +0800 Subject: Error handling for loading posts now works again. Don't show refresh button as an icon. Rewrite some code. --- .../infinityforreddit/NetworkState.java | 4 +- .../infinityforreddit/PostDataSource.java | 78 ++++---- .../infinityforreddit/PostDataSourceFactory.java | 34 ++-- .../infinityforreddit/PostFragment.java | 34 ++-- .../infinityforreddit/PostRecyclerViewAdapter.java | 196 ++++++++++----------- .../infinityforreddit/PostViewModel.java | 39 ++-- app/src/main/res/layout/item_footer_error.xml | 28 +++ app/src/main/res/layout/item_footer_loading.xml | 15 ++ .../main/res/layout/item_footer_progress_bar.xml | 47 ----- app/src/main/res/menu/main_activity.xml | 2 +- 10 files changed, 239 insertions(+), 238 deletions(-) create mode 100644 app/src/main/res/layout/item_footer_error.xml create mode 100644 app/src/main/res/layout/item_footer_loading.xml delete mode 100644 app/src/main/res/layout/item_footer_progress_bar.xml (limited to 'app') diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java index 495f54c2..4e741025 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java @@ -2,7 +2,7 @@ package ml.docilealligator.infinityforreddit; class NetworkState { public enum Status{ - RUNNING, + LOADING, SUCCESS, FAILED } @@ -21,7 +21,7 @@ class NetworkState { static { LOADED=new NetworkState(Status.SUCCESS,"Success"); - LOADING=new NetworkState(Status.RUNNING,"Running"); + LOADING=new NetworkState(Status.LOADING,"Loading"); } public Status getStatus() { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java index 9409de52..87c65fad 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java @@ -19,16 +19,21 @@ class PostDataSource extends PageKeyedDataSource { private boolean isBestPost; private String subredditName; - private MutableLiveData networkState; - private MutableLiveData initialLoading; + private MutableLiveData paginationNetworkStateLiveData; + private MutableLiveData initialLoadStateLiveData; + + private LoadInitialParams initialParams; + private LoadInitialCallback initialCallback; + private LoadParams params; + private LoadCallback callback; PostDataSource(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { this.retrofit = retrofit; this.accessToken = accessToken; this.locale = locale; this.isBestPost = isBestPost; - networkState = new MutableLiveData(); - initialLoading = new MutableLiveData(); + paginationNetworkStateLiveData = new MutableLiveData(); + initialLoadStateLiveData = new MutableLiveData(); } @@ -37,22 +42,24 @@ class PostDataSource extends PageKeyedDataSource { this.locale = locale; this.isBestPost = isBestPost; this.subredditName = subredditName; - networkState = new MutableLiveData(); - initialLoading = new MutableLiveData(); + paginationNetworkStateLiveData = new MutableLiveData(); + initialLoadStateLiveData = new MutableLiveData(); } - MutableLiveData getNetworkState() { - return networkState; + MutableLiveData getPaginationNetworkStateLiveData() { + return paginationNetworkStateLiveData; } - MutableLiveData getInitialLoading() { - return initialLoading; + MutableLiveData getInitialLoadStateLiveData() { + return initialLoadStateLiveData; } @Override public void loadInitial(@NonNull LoadInitialParams params, @NonNull final LoadInitialCallback callback) { - initialLoading.postValue(NetworkState.LOADING); - networkState.postValue(NetworkState.LOADING); + initialParams = params; + initialCallback = callback; + + initialLoadStateLiveData.postValue(NetworkState.LOADING); if(isBestPost) { RedditAPI api = retrofit.create(RedditAPI.class); @@ -67,26 +74,25 @@ class PostDataSource extends PageKeyedDataSource { @Override public void onParsePostSuccess(ArrayList newPosts, String lastItem) { callback.onResult(newPosts, null, lastItem); - initialLoading.postValue(NetworkState.LOADED); - networkState.postValue(NetworkState.LOADED); + initialLoadStateLiveData.postValue(NetworkState.LOADED); } @Override public void onParsePostFail() { Log.i("Post fetch error", "Error parsing data"); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); } }); } else { Log.i("Post fetch error", response.message()); - initialLoading.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); } } @Override public void onFailure(Call call, Throwable t) { String errorMessage = t == null ? "unknown error" : t.getMessage(); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); } }); } else { @@ -101,26 +107,25 @@ class PostDataSource extends PageKeyedDataSource { @Override public void onParsePostSuccess(ArrayList newPosts, String lastItem) { callback.onResult(newPosts, null, lastItem); - initialLoading.postValue(NetworkState.LOADED); - networkState.postValue(NetworkState.LOADED); + initialLoadStateLiveData.postValue(NetworkState.LOADED); } @Override public void onParsePostFail() { Log.i("Post fetch error", "Error parsing data"); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); } }); } else { Log.i("Post fetch error", response.message()); - initialLoading.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); } } @Override public void onFailure(Call call, Throwable t) { String errorMessage = t == null ? "unknown error" : t.getMessage(); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); } }); } @@ -133,7 +138,10 @@ class PostDataSource extends PageKeyedDataSource { @Override public void loadAfter(@NonNull LoadParams params, @NonNull final LoadCallback callback) { - networkState.postValue(NetworkState.LOADING); + this.params = params; + this.callback = callback; + + paginationNetworkStateLiveData.postValue(NetworkState.LOADING); if(isBestPost) { RedditAPI api = retrofit.create(RedditAPI.class); @@ -147,24 +155,25 @@ class PostDataSource extends PageKeyedDataSource { @Override public void onParsePostSuccess(ArrayList newPosts, String lastItem) { callback.onResult(newPosts, lastItem); - networkState.postValue(NetworkState.LOADED); + paginationNetworkStateLiveData.postValue(NetworkState.LOADED); } @Override public void onParsePostFail() { Log.i("Best post", "Error parsing data"); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); } }); } else { Log.i("best post", response.message()); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); } } @Override public void onFailure(Call call, Throwable t) { String errorMessage = t == null ? "unknown error" : t.getMessage(); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); } }); } else { @@ -178,26 +187,35 @@ class PostDataSource extends PageKeyedDataSource { @Override public void onParsePostSuccess(ArrayList newPosts, String lastItem) { callback.onResult(newPosts, lastItem); - networkState.postValue(NetworkState.LOADED); + paginationNetworkStateLiveData.postValue(NetworkState.LOADED); } @Override public void onParsePostFail() { Log.i("Best post", "Error parsing data"); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data")); } }); } else { - Log.i("best post", response.message()); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); + Log.i("Best post", response.message()); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); } } @Override public void onFailure(Call call, Throwable t) { String errorMessage = t == null ? "unknown error" : t.getMessage(); - networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); } }); } } + + void retry() { + loadInitial(initialParams, initialCallback); + } + + void retryLoadingMore() { + loadAfter(params, callback); + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java index db05e0e0..27c01fff 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java @@ -11,40 +11,48 @@ class PostDataSourceFactory extends DataSource.Factory { private Retrofit retrofit; private String accessToken; private Locale locale; - private boolean isBestPost; private String subredditName; - private MutableLiveData mutableLiveData; + private PostDataSource postDataSource; + private MutableLiveData postDataSourceLiveData; PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { this.retrofit = retrofit; this.accessToken = accessToken; this.locale = locale; - this.isBestPost = isBestPost; - mutableLiveData = new MutableLiveData<>(); + postDataSourceLiveData = new MutableLiveData<>(); + + if(isBestPost) { + postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost); + } else { + postDataSource = new PostDataSource(retrofit, locale, isBestPost, subredditName); + } } PostDataSourceFactory(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) { this.retrofit = retrofit; this.locale = locale; - this.isBestPost = isBestPost; - mutableLiveData = new MutableLiveData<>(); this.subredditName = subredditName; - } + postDataSourceLiveData = new MutableLiveData<>(); - @Override - public DataSource create() { - PostDataSource postDataSource; if(isBestPost) { postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost); } else { postDataSource = new PostDataSource(retrofit, locale, isBestPost, subredditName); } - mutableLiveData.postValue(postDataSource); + } + + @Override + public DataSource create() { + postDataSourceLiveData.postValue(postDataSource); return postDataSource; } - public MutableLiveData getMutableLiveData() { - return mutableLiveData; + public MutableLiveData getPostDataSourceLiveData() { + return postDataSourceLiveData; + } + + PostDataSource getPostDataSource() { + return postDataSource; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java index f7dd68ef..c4e10e45 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java @@ -11,6 +11,7 @@ import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -98,24 +99,15 @@ public class PostFragment extends Fragment implements FragmentCommunicator { if(!mIsBestPost) { mSubredditName = getArguments().getString(SUBREDDIT_NAME_KEY); } else { - /*mFetchPostErrorLinearLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if(mIsBestPost) { - fetchBestPost(); - } else { - fetchPost(); - } - } - });*/ + mFetchPostErrorLinearLayout.setOnClickListener(view -> mPostViewModel.retry()); } if(mIsBestPost) { mAdapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, - mSharedPreferences, mIsBestPost); + mSharedPreferences, mIsBestPost, () -> mPostViewModel.retryLoadingMore()); } else { mAdapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit, - mSharedPreferences, mIsBestPost); + mSharedPreferences, mIsBestPost, () -> mPostViewModel.retryLoadingMore()); } mPostRecyclerView.setAdapter(mAdapter); @@ -132,16 +124,23 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } mPostViewModel = ViewModelProviders.of(this, factory).get(PostViewModel.class); mPostViewModel.getPosts().observe(this, posts -> mAdapter.submitList(posts)); + mPostViewModel.getInitialLoadingState().observe(this, networkState -> { if(networkState.getStatus().equals(NetworkState.Status.SUCCESS)) { mProgressBar.setVisibility(View.GONE); } else if(networkState.getStatus().equals(NetworkState.Status.FAILED)) { showErrorView(); } else { + mFetchPostErrorLinearLayout.setVisibility(View.GONE); mProgressBar.setVisibility(View.VISIBLE); } }); + mPostViewModel.getPaginationNetworkState().observe(this, networkState -> { + Log.i("networkstate", networkState.getStatus().toString()); + mAdapter.setNetworkState(networkState); + }); + return rootView; } @@ -159,16 +158,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } } else { Snackbar snackbar = Snackbar.make(mCoordinatorLayout, "Error getting post", Snackbar.LENGTH_INDEFINITE); - snackbar.setAction(R.string.retry, new View.OnClickListener() { - @Override - public void onClick(View view) { - /*if (mIsBestPost) { - fetchBestPost(); - } else { - fetchPost(); - }*/ - } - }); + snackbar.setAction(R.string.retry, view -> mPostViewModel.retry()); snackbar.show(); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java index 9ec8b83b..f9c3332c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java @@ -21,7 +21,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; @@ -36,8 +35,6 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; -import java.util.List; - import CustomView.AspectRatioGifImageView; import SubredditDatabase.SubredditDao; import SubredditDatabase.SubredditRoomDatabase; @@ -57,16 +54,22 @@ class PostRecyclerViewAdapter extends PagedListAdapter payloads) { - onBindViewHolder(holder, position); - } - @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { if(holder instanceof DataViewHolder) { @@ -129,40 +131,37 @@ class PostRecyclerViewAdapter extends PagedListAdapter 0) { - if(!iconImageUrl.equals("")) { - glide.load(iconImageUrl) - .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) - .error(glide.load(R.drawable.subreddit_default_icon)) - .listener(new RequestListener() { - @Override - public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - return false; + iconImageUrl -> { + if(mContext != null && getItemCount() > 0) { + if(!iconImageUrl.equals("")) { + glide.load(iconImageUrl) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .error(glide.load(R.drawable.subreddit_default_icon)) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + if(resource instanceof Animatable) { + //This is a gif + //((Animatable) resource).start(); + ((DataViewHolder) holder).subredditIconGifImageView.startAnimation(); } + return false; + } + }) + .into(((DataViewHolder) holder).subredditIconGifImageView); + } else { + glide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .into(((DataViewHolder) holder).subredditIconGifImageView); + } - @Override - public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { - if(resource instanceof Animatable) { - //This is a gif - //((Animatable) resource).start(); - ((DataViewHolder) holder).subredditIconGifImageView.startAnimation(); - } - return false; - } - }) - .into(((DataViewHolder) holder).subredditIconGifImageView); - } else { - glide.load(R.drawable.subreddit_default_icon) - .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) - .into(((DataViewHolder) holder).subredditIconGifImageView); - } - - if(holder.getAdapterPosition() >= 0) { - post.setSubredditIconUrl(iconImageUrl); - } + if(holder.getAdapterPosition() >= 0) { + post.setSubredditIconUrl(iconImageUrl); } } }).execute(); @@ -341,21 +340,18 @@ class PostRecyclerViewAdapter extends PagedListAdapter { + Intent intent = new Intent(mContext, ViewVideoActivity.class); + intent.setData(videoUri); + intent.putExtra(ViewVideoActivity.TITLE_KEY, title); + intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, post.isDashVideo()); + intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, post.isDownloadableGifOrVideo()); + if(post.isDownloadableGifOrVideo()) { + intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, post.getGifOrVideoDownloadUrl()); + intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName); + intent.putExtra(ViewVideoActivity.ID_KEY, id); } + mContext.startActivity(intent); }); break; case Post.NO_PREVIEW_LINK_TYPE: @@ -507,36 +503,6 @@ class PostRecyclerViewAdapter extends PagedListAdapter= getItemCount() ? VIEW_TYPE_LOADING : VIEW_TYPE_DATA); + // Reached at the end + if (hasExtraRow() && position == getItemCount() - 1) { + if (networkState.getStatus() == NetworkState.Status.LOADING) { + return VIEW_TYPE_LOADING; + } else { + return VIEW_TYPE_ERROR; + } + } else { + return VIEW_TYPE_DATA; + } + } + + @Override + public int getItemCount() { + if(hasExtraRow()) { + return super.getItemCount() + 1; + } + return super.getItemCount(); } private boolean hasExtraRow() { - return networkState != null && networkState != NetworkState.LOADED; + return networkState != null && networkState.getStatus() != NetworkState.Status.SUCCESS; } - public void setNetworkState(NetworkState newNetworkState) { + void setNetworkState(NetworkState newNetworkState) { NetworkState previousState = this.networkState; boolean previousExtraRow = hasExtraRow(); this.networkState = newNetworkState; boolean newExtraRow = hasExtraRow(); if (previousExtraRow != newExtraRow) { if (previousExtraRow) { - notifyItemRemoved(getItemCount()); + notifyItemRemoved(super.getItemCount()); } else { - notifyItemInserted(getItemCount()); + notifyItemInserted(super.getItemCount()); } - } else if (newExtraRow && previousState != newNetworkState) { + } else if (newExtraRow && !previousState.equals(newNetworkState)) { notifyItemChanged(getItemCount() - 1); } } @@ -626,12 +609,21 @@ class PostRecyclerViewAdapter extends PagedListAdapter retryLoadingMoreCallback.retryLoadingMore()); + } + } + + class LoadingViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.progress_bar_footer_progress_bar_item) ProgressBar progressBar; + + LoadingViewHolder(@NonNull View itemView) { super(itemView); ButterKnife.bind(this, itemView); } @@ -660,14 +652,6 @@ class PostRecyclerViewAdapter extends PagedListAdapter networkState; + private PostDataSource postDataSource; + private LiveData paginationNetworkState; private LiveData initialLoadingState; private LiveData> posts; public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { - //executor = Executors.newFixedThreadPool(5); - PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, isBestPost); - initialLoadingState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), - dataSource -> dataSource.getInitialLoading()); - networkState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), - dataSource -> dataSource.getNetworkState()); + initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), + dataSource -> dataSource.getInitialLoadStateLiveData()); + paginationNetworkState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), + dataSource -> dataSource.getPaginationNetworkStateLiveData()); PagedList.Config pagedListConfig = (new PagedList.Config.Builder()) .setEnablePlaceholders(false) @@ -35,17 +32,16 @@ public class PostViewModel extends ViewModel { .build(); posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build(); + postDataSource = postDataSourceFactory.getPostDataSource(); } public PostViewModel(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) { - //executor = Executors.newFixedThreadPool(5); - PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, locale, isBestPost, subredditName); - initialLoadingState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), - dataSource -> dataSource.getInitialLoading()); - networkState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), - dataSource -> dataSource.getNetworkState()); + initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), + dataSource -> dataSource.getInitialLoadStateLiveData()); + paginationNetworkState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(), + dataSource -> dataSource.getPaginationNetworkStateLiveData()); PagedList.Config pagedListConfig = (new PagedList.Config.Builder()) @@ -54,20 +50,29 @@ public class PostViewModel extends ViewModel { .build(); posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build(); + postDataSource = postDataSourceFactory.getPostDataSource(); } LiveData> getPosts() { return posts; } - LiveData getNetworkState() { - return networkState; + LiveData getPaginationNetworkState() { + return paginationNetworkState; } public LiveData getInitialLoadingState() { return initialLoadingState; } + void retry() { + postDataSource.retry(); + } + + void retryLoadingMore() { + postDataSource.retryLoadingMore(); + } + public static class Factory extends ViewModelProvider.NewInstanceFactory { private Retrofit retrofit; private String accessToken; diff --git a/app/src/main/res/layout/item_footer_error.xml b/app/src/main/res/layout/item_footer_error.xml new file mode 100644 index 00000000..bd653604 --- /dev/null +++ b/app/src/main/res/layout/item_footer_error.xml @@ -0,0 +1,28 @@ + + + + + +