Error handling for loading posts now works again. Don't show refresh button as an icon. Rewrite some code.

This commit is contained in:
Alex Ning 2018-12-29 13:38:18 +08:00
parent 93a9ad9ece
commit b7e1d92c7e
14 changed files with 251 additions and 299 deletions

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="imageWizard">
<value>
<PersistentState />
</value>
</entry>
<entry key="vectorWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="vectorAssetStep">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipartAsset">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/home/alex/Android%20Studio/plugins/android/lib/android.jar!/images/material_design_icons/alert/ic_error_outline_black_24dp.xml" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="assetSourceType" value="FILE" />
<entry key="color" value="ffffff" />
<entry key="outputName" value="ic_pin_outline" />
<entry key="sourceFile" value="$USER_HOME$/Downloads/if_pin-outline_216358.svg" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

Binary file not shown.

8
.idea/misc.xml generated
View File

@ -5,22 +5,26 @@
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables"> <option name="myNullables">
<value> <value>
<list size="5"> <list size="7">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" /> <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" /> <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" /> <item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" /> <item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" /> <item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
</list> </list>
</value> </value>
</option> </option>
<option name="myNotNulls"> <option name="myNotNulls">
<value> <value>
<list size="4"> <list size="6">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" /> <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" /> <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" /> <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" /> <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
</list> </list>
</value> </value>
</option> </option>

2
.idea/vcs.xml generated
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="" vcs="Git" />
</component> </component>
</project> </project>

View File

@ -2,7 +2,7 @@ package ml.docilealligator.infinityforreddit;
class NetworkState { class NetworkState {
public enum Status{ public enum Status{
RUNNING, LOADING,
SUCCESS, SUCCESS,
FAILED FAILED
} }
@ -21,7 +21,7 @@ class NetworkState {
static { static {
LOADED=new NetworkState(Status.SUCCESS,"Success"); LOADED=new NetworkState(Status.SUCCESS,"Success");
LOADING=new NetworkState(Status.RUNNING,"Running"); LOADING=new NetworkState(Status.LOADING,"Loading");
} }
public Status getStatus() { public Status getStatus() {

View File

@ -19,16 +19,21 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
private boolean isBestPost; private boolean isBestPost;
private String subredditName; private String subredditName;
private MutableLiveData networkState; private MutableLiveData<NetworkState> paginationNetworkStateLiveData;
private MutableLiveData initialLoading; private MutableLiveData<NetworkState> initialLoadStateLiveData;
private LoadInitialParams<String> initialParams;
private LoadInitialCallback<String, Post> initialCallback;
private LoadParams<String> params;
private LoadCallback<String, Post> callback;
PostDataSource(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { PostDataSource(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) {
this.retrofit = retrofit; this.retrofit = retrofit;
this.accessToken = accessToken; this.accessToken = accessToken;
this.locale = locale; this.locale = locale;
this.isBestPost = isBestPost; this.isBestPost = isBestPost;
networkState = new MutableLiveData(); paginationNetworkStateLiveData = new MutableLiveData();
initialLoading = new MutableLiveData(); initialLoadStateLiveData = new MutableLiveData();
} }
@ -37,22 +42,24 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
this.locale = locale; this.locale = locale;
this.isBestPost = isBestPost; this.isBestPost = isBestPost;
this.subredditName = subredditName; this.subredditName = subredditName;
networkState = new MutableLiveData(); paginationNetworkStateLiveData = new MutableLiveData();
initialLoading = new MutableLiveData(); initialLoadStateLiveData = new MutableLiveData();
} }
MutableLiveData getNetworkState() { MutableLiveData getPaginationNetworkStateLiveData() {
return networkState; return paginationNetworkStateLiveData;
} }
MutableLiveData getInitialLoading() { MutableLiveData getInitialLoadStateLiveData() {
return initialLoading; return initialLoadStateLiveData;
} }
@Override @Override
public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull final LoadInitialCallback<String, Post> callback) { public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull final LoadInitialCallback<String, Post> callback) {
initialLoading.postValue(NetworkState.LOADING); initialParams = params;
networkState.postValue(NetworkState.LOADING); initialCallback = callback;
initialLoadStateLiveData.postValue(NetworkState.LOADING);
if(isBestPost) { if(isBestPost) {
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
@ -67,26 +74,25 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
@Override @Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
callback.onResult(newPosts, null, lastItem); callback.onResult(newPosts, null, lastItem);
initialLoading.postValue(NetworkState.LOADED); initialLoadStateLiveData.postValue(NetworkState.LOADED);
networkState.postValue(NetworkState.LOADED);
} }
@Override @Override
public void onParsePostFail() { public void onParsePostFail() {
Log.i("Post fetch error", "Error parsing data"); Log.i("Post fetch error", "Error parsing data");
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
} }
}); });
} else { } else {
Log.i("Post fetch error", response.message()); Log.i("Post fetch error", response.message());
initialLoading.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
} }
} }
@Override @Override
public void onFailure(Call<String> call, Throwable t) { public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage(); 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 { } else {
@ -101,26 +107,25 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
@Override @Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
callback.onResult(newPosts, null, lastItem); callback.onResult(newPosts, null, lastItem);
initialLoading.postValue(NetworkState.LOADED); initialLoadStateLiveData.postValue(NetworkState.LOADED);
networkState.postValue(NetworkState.LOADED);
} }
@Override @Override
public void onParsePostFail() { public void onParsePostFail() {
Log.i("Post fetch error", "Error parsing data"); Log.i("Post fetch error", "Error parsing data");
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
} }
}); });
} else { } else {
Log.i("Post fetch error", response.message()); Log.i("Post fetch error", response.message());
initialLoading.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
} }
} }
@Override @Override
public void onFailure(Call<String> call, Throwable t) { public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage(); 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<String, Post> {
@Override @Override
public void loadAfter(@NonNull LoadParams<String> params, @NonNull final LoadCallback<String, Post> callback) { public void loadAfter(@NonNull LoadParams<String> params, @NonNull final LoadCallback<String, Post> callback) {
networkState.postValue(NetworkState.LOADING); this.params = params;
this.callback = callback;
paginationNetworkStateLiveData.postValue(NetworkState.LOADING);
if(isBestPost) { if(isBestPost) {
RedditAPI api = retrofit.create(RedditAPI.class); RedditAPI api = retrofit.create(RedditAPI.class);
@ -147,24 +155,25 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
@Override @Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
callback.onResult(newPosts, lastItem); callback.onResult(newPosts, lastItem);
networkState.postValue(NetworkState.LOADED); paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
} }
@Override @Override
public void onParsePostFail() { public void onParsePostFail() {
Log.i("Best post", "Error parsing data"); Log.i("Best post", "Error parsing data");
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
} }
}); });
} else { } else {
Log.i("best post", response.message()); 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 @Override
public void onFailure(Call<String> call, Throwable t) { public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage(); 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 { } else {
@ -178,26 +187,35 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
@Override @Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
callback.onResult(newPosts, lastItem); callback.onResult(newPosts, lastItem);
networkState.postValue(NetworkState.LOADED); paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
} }
@Override @Override
public void onParsePostFail() { public void onParsePostFail() {
Log.i("Best post", "Error parsing data"); Log.i("Best post", "Error parsing data");
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
} }
}); });
} else { } else {
Log.i("best post", response.message()); 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 @Override
public void onFailure(Call<String> call, Throwable t) { public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage(); 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);
}
} }

View File

@ -11,40 +11,48 @@ class PostDataSourceFactory extends DataSource.Factory {
private Retrofit retrofit; private Retrofit retrofit;
private String accessToken; private String accessToken;
private Locale locale; private Locale locale;
private boolean isBestPost;
private String subredditName; private String subredditName;
private MutableLiveData<PostDataSource> mutableLiveData; private PostDataSource postDataSource;
private MutableLiveData<PostDataSource> postDataSourceLiveData;
PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) {
this.retrofit = retrofit; this.retrofit = retrofit;
this.accessToken = accessToken; this.accessToken = accessToken;
this.locale = locale; this.locale = locale;
this.isBestPost = isBestPost; postDataSourceLiveData = new MutableLiveData<>();
mutableLiveData = new MutableLiveData<>();
}
PostDataSourceFactory(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) {
this.retrofit = retrofit;
this.locale = locale;
this.isBestPost = isBestPost;
mutableLiveData = new MutableLiveData<>();
this.subredditName = subredditName;
}
@Override
public DataSource create() {
PostDataSource postDataSource;
if(isBestPost) { if(isBestPost) {
postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost); postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost);
} else { } else {
postDataSource = new PostDataSource(retrofit, locale, isBestPost, subredditName); postDataSource = new PostDataSource(retrofit, locale, isBestPost, subredditName);
} }
mutableLiveData.postValue(postDataSource); }
PostDataSourceFactory(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) {
this.retrofit = retrofit;
this.locale = locale;
this.subredditName = subredditName;
postDataSourceLiveData = new MutableLiveData<>();
if(isBestPost) {
postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost);
} else {
postDataSource = new PostDataSource(retrofit, locale, isBestPost, subredditName);
}
}
@Override
public DataSource create() {
postDataSourceLiveData.postValue(postDataSource);
return postDataSource; return postDataSource;
} }
public MutableLiveData<PostDataSource> getMutableLiveData() { public MutableLiveData<PostDataSource> getPostDataSourceLiveData() {
return mutableLiveData; return postDataSourceLiveData;
}
PostDataSource getPostDataSource() {
return postDataSource;
} }
} }

View File

@ -11,6 +11,7 @@ import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -98,24 +99,15 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
if(!mIsBestPost) { if(!mIsBestPost) {
mSubredditName = getArguments().getString(SUBREDDIT_NAME_KEY); mSubredditName = getArguments().getString(SUBREDDIT_NAME_KEY);
} else { } else {
/*mFetchPostErrorLinearLayout.setOnClickListener(new View.OnClickListener() { mFetchPostErrorLinearLayout.setOnClickListener(view -> mPostViewModel.retry());
@Override
public void onClick(View view) {
if(mIsBestPost) {
fetchBestPost();
} else {
fetchPost();
}
}
});*/
} }
if(mIsBestPost) { if(mIsBestPost) {
mAdapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, mAdapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit,
mSharedPreferences, mIsBestPost); mSharedPreferences, mIsBestPost, () -> mPostViewModel.retryLoadingMore());
} else { } else {
mAdapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit, mAdapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit,
mSharedPreferences, mIsBestPost); mSharedPreferences, mIsBestPost, () -> mPostViewModel.retryLoadingMore());
} }
mPostRecyclerView.setAdapter(mAdapter); mPostRecyclerView.setAdapter(mAdapter);
@ -132,16 +124,23 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
} }
mPostViewModel = ViewModelProviders.of(this, factory).get(PostViewModel.class); mPostViewModel = ViewModelProviders.of(this, factory).get(PostViewModel.class);
mPostViewModel.getPosts().observe(this, posts -> mAdapter.submitList(posts)); mPostViewModel.getPosts().observe(this, posts -> mAdapter.submitList(posts));
mPostViewModel.getInitialLoadingState().observe(this, networkState -> { mPostViewModel.getInitialLoadingState().observe(this, networkState -> {
if(networkState.getStatus().equals(NetworkState.Status.SUCCESS)) { if(networkState.getStatus().equals(NetworkState.Status.SUCCESS)) {
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
} else if(networkState.getStatus().equals(NetworkState.Status.FAILED)) { } else if(networkState.getStatus().equals(NetworkState.Status.FAILED)) {
showErrorView(); showErrorView();
} else { } else {
mFetchPostErrorLinearLayout.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
} }
}); });
mPostViewModel.getPaginationNetworkState().observe(this, networkState -> {
Log.i("networkstate", networkState.getStatus().toString());
mAdapter.setNetworkState(networkState);
});
return rootView; return rootView;
} }
@ -159,16 +158,7 @@ public class PostFragment extends Fragment implements FragmentCommunicator {
} }
} else { } else {
Snackbar snackbar = Snackbar.make(mCoordinatorLayout, "Error getting post", Snackbar.LENGTH_INDEFINITE); Snackbar snackbar = Snackbar.make(mCoordinatorLayout, "Error getting post", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, new View.OnClickListener() { snackbar.setAction(R.string.retry, view -> mPostViewModel.retry());
@Override
public void onClick(View view) {
/*if (mIsBestPost) {
fetchBestPost();
} else {
fetchPost();
}*/
}
});
snackbar.show(); snackbar.show();
} }
} }

View File

@ -21,7 +21,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; 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.RequestOptions;
import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.Target;
import java.util.List;
import CustomView.AspectRatioGifImageView; import CustomView.AspectRatioGifImageView;
import SubredditDatabase.SubredditDao; import SubredditDatabase.SubredditDao;
import SubredditDatabase.SubredditRoomDatabase; import SubredditDatabase.SubredditRoomDatabase;
@ -57,16 +54,22 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
private SharedPreferences mSharedPreferences; private SharedPreferences mSharedPreferences;
private RequestManager glide; private RequestManager glide;
private SubredditDao subredditDao; private SubredditDao subredditDao;
private boolean isLoadingMorePostSuccess = true;
private boolean canStartActivity = true; private boolean canStartActivity = true;
private boolean hasMultipleSubreddits; private boolean hasMultipleSubreddits;
private static final int VIEW_TYPE_DATA = 0; private static final int VIEW_TYPE_DATA = 0;
private static final int VIEW_TYPE_LOADING = 1; private static final int VIEW_TYPE_ERROR = 1;
private static final int VIEW_TYPE_LOADING = 2;
private NetworkState networkState; private NetworkState networkState;
private RetryLoadingMoreCallback retryLoadingMoreCallback;
PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, boolean hasMultipleSubreddits) { interface RetryLoadingMoreCallback {
void retryLoadingMore();
}
PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, boolean hasMultipleSubreddits,
RetryLoadingMoreCallback retryLoadingMoreCallback) {
super(DIFF_CALLBACK); super(DIFF_CALLBACK);
if(context != null) { if(context != null) {
mContext = context; mContext = context;
@ -75,6 +78,7 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
this.hasMultipleSubreddits = hasMultipleSubreddits; this.hasMultipleSubreddits = hasMultipleSubreddits;
glide = Glide.with(mContext.getApplicationContext()); glide = Glide.with(mContext.getApplicationContext());
subredditDao = SubredditRoomDatabase.getDatabase(mContext.getApplicationContext()).subredditDao(); subredditDao = SubredditRoomDatabase.getDatabase(mContext.getApplicationContext()).subredditDao();
this.retryLoadingMoreCallback = retryLoadingMoreCallback;
} }
} }
@ -100,17 +104,15 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
if(viewType == VIEW_TYPE_DATA) { if(viewType == VIEW_TYPE_DATA) {
CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post, parent, false); CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post, parent, false);
return new DataViewHolder(cardView); return new DataViewHolder(cardView);
} else if(viewType == VIEW_TYPE_ERROR) {
RelativeLayout relativeLayout = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_footer_error, parent, false);
return new ErrorViewHolder(relativeLayout);
} else { } else {
LinearLayout linearLayout = (LinearLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_footer_progress_bar, parent, false); RelativeLayout relativeLayout = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_footer_loading, parent, false);
return new LoadingViewHolder(linearLayout); return new LoadingViewHolder(relativeLayout);
} }
} }
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
onBindViewHolder(holder, position);
}
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
if(holder instanceof DataViewHolder) { if(holder instanceof DataViewHolder) {
@ -129,40 +131,37 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
if(post.getSubredditIconUrl() == null) { if(post.getSubredditIconUrl() == null) {
new LoadSubredditIconAsyncTask(subredditDao, subredditName, new LoadSubredditIconAsyncTask(subredditDao, subredditName,
new LoadSubredditIconAsyncTask.LoadSubredditIconAsyncTaskListener() { iconImageUrl -> {
@Override if(mContext != null && getItemCount() > 0) {
public void loadIconSuccess(String iconImageUrl) { if(!iconImageUrl.equals("")) {
if(mContext != null && getItemCount() > 0) { glide.load(iconImageUrl)
if(!iconImageUrl.equals("")) { .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
glide.load(iconImageUrl) .error(glide.load(R.drawable.subreddit_default_icon))
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) .listener(new RequestListener<Drawable>() {
.error(glide.load(R.drawable.subreddit_default_icon)) @Override
.listener(new RequestListener<Drawable>() { public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
@Override return false;
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { }
return false;
}
@Override @Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
if(resource instanceof Animatable) { if(resource instanceof Animatable) {
//This is a gif //This is a gif
//((Animatable) resource).start(); //((Animatable) resource).start();
((DataViewHolder) holder).subredditIconGifImageView.startAnimation(); ((DataViewHolder) holder).subredditIconGifImageView.startAnimation();
}
return false;
} }
}) return false;
.into(((DataViewHolder) holder).subredditIconGifImageView); }
} else { })
glide.load(R.drawable.subreddit_default_icon) .into(((DataViewHolder) holder).subredditIconGifImageView);
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) } else {
.into(((DataViewHolder) holder).subredditIconGifImageView); glide.load(R.drawable.subreddit_default_icon)
} .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(((DataViewHolder) holder).subredditIconGifImageView);
}
if(holder.getAdapterPosition() >= 0) { if(holder.getAdapterPosition() >= 0) {
post.setSubredditIconUrl(iconImageUrl); post.setSubredditIconUrl(iconImageUrl);
}
} }
} }
}).execute(); }).execute();
@ -341,21 +340,18 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
((DataViewHolder) holder).typeTextView.setText("VIDEO"); ((DataViewHolder) holder).typeTextView.setText("VIDEO");
final Uri videoUri = Uri.parse(post.getVideoUrl()); final Uri videoUri = Uri.parse(post.getVideoUrl());
((DataViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() { ((DataViewHolder) holder).imageView.setOnClickListener(view -> {
@Override Intent intent = new Intent(mContext, ViewVideoActivity.class);
public void onClick(View view) { intent.setData(videoUri);
Intent intent = new Intent(mContext, ViewVideoActivity.class); intent.putExtra(ViewVideoActivity.TITLE_KEY, title);
intent.setData(videoUri); intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, post.isDashVideo());
intent.putExtra(ViewVideoActivity.TITLE_KEY, title); intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, post.isDownloadableGifOrVideo());
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, post.isDashVideo()); if(post.isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, post.isDownloadableGifOrVideo()); intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, post.getGifOrVideoDownloadUrl());
if(post.isDownloadableGifOrVideo()) { intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName);
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, post.getGifOrVideoDownloadUrl()); intent.putExtra(ViewVideoActivity.ID_KEY, id);
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, subredditName);
intent.putExtra(ViewVideoActivity.ID_KEY, id);
}
mContext.startActivity(intent);
} }
mContext.startActivity(intent);
}); });
break; break;
case Post.NO_PREVIEW_LINK_TYPE: case Post.NO_PREVIEW_LINK_TYPE:
@ -507,36 +503,6 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
} }
}); });
} }
} else if(holder instanceof LoadingViewHolder) {
((LoadingViewHolder) holder).retryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//mPaginationSynchronizer.getPaginationRetryNotifier().retry();
((LoadingViewHolder) holder).progressBar.setVisibility(View.VISIBLE);
((LoadingViewHolder) holder).relativeLayout.setVisibility(View.GONE);
}
});
PaginationNotifier mPaginationNotifier = new PaginationNotifier() {
@Override
public void LoadMorePostSuccess() {
isLoadingMorePostSuccess = true;
}
@Override
public void LoadMorePostFail() {
((LoadingViewHolder) holder).progressBar.setVisibility(View.GONE);
((LoadingViewHolder) holder).relativeLayout.setVisibility(View.VISIBLE);
isLoadingMorePostSuccess = false;
}
};
/*mPaginationSynchronizer.setPaginationNotifier(mPaginationNotifier);
if(!mPaginationSynchronizer.isLoadingMorePostsSuccess()) {
((LoadingViewHolder) holder).progressBar.setVisibility(View.GONE);
((LoadingViewHolder) holder).relativeLayout.setVisibility(View.VISIBLE);
}*/
} }
} }
@ -575,25 +541,42 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
return (position >= 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() { 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; NetworkState previousState = this.networkState;
boolean previousExtraRow = hasExtraRow(); boolean previousExtraRow = hasExtraRow();
this.networkState = newNetworkState; this.networkState = newNetworkState;
boolean newExtraRow = hasExtraRow(); boolean newExtraRow = hasExtraRow();
if (previousExtraRow != newExtraRow) { if (previousExtraRow != newExtraRow) {
if (previousExtraRow) { if (previousExtraRow) {
notifyItemRemoved(getItemCount()); notifyItemRemoved(super.getItemCount());
} else { } else {
notifyItemInserted(getItemCount()); notifyItemInserted(super.getItemCount());
} }
} else if (newExtraRow && previousState != newNetworkState) { } else if (newExtraRow && !previousState.equals(newNetworkState)) {
notifyItemChanged(getItemCount() - 1); notifyItemChanged(getItemCount() - 1);
} }
} }
@ -626,12 +609,21 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
} }
} }
class LoadingViewHolder extends RecyclerView.ViewHolder { class ErrorViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.progress_bar_footer_progress_bar_item) ProgressBar progressBar;
@BindView(R.id.relative_layout_footer_progress_bar_item) RelativeLayout relativeLayout; @BindView(R.id.relative_layout_footer_progress_bar_item) RelativeLayout relativeLayout;
@BindView(R.id.retry_button_footer_progress_bar_item) Button retryButton; @BindView(R.id.retry_button_footer_progress_bar_item) Button retryButton;
LoadingViewHolder(View itemView) { ErrorViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore());
}
}
class LoadingViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.progress_bar_footer_progress_bar_item) ProgressBar progressBar;
LoadingViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
} }
@ -660,14 +652,6 @@ class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHo
((DataViewHolder) holder).noPreviewLinkImageView.setVisibility(View.GONE); ((DataViewHolder) holder).noPreviewLinkImageView.setVisibility(View.GONE);
((DataViewHolder) holder).upvoteButton.clearColorFilter(); ((DataViewHolder) holder).upvoteButton.clearColorFilter();
((DataViewHolder) holder).downvoteButton.clearColorFilter(); ((DataViewHolder) holder).downvoteButton.clearColorFilter();
} else if(holder instanceof LoadingViewHolder) {
if(isLoadingMorePostSuccess) {
((LoadingViewHolder) holder).relativeLayout.setVisibility(View.GONE);
((LoadingViewHolder) holder).progressBar.setVisibility(View.VISIBLE);
} else {
((LoadingViewHolder) holder).relativeLayout.setVisibility(View.VISIBLE);
((LoadingViewHolder) holder).progressBar.setVisibility(View.GONE);
}
} }
} }
} }

View File

@ -9,25 +9,22 @@ import android.arch.paging.PagedList;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.Executor;
import retrofit2.Retrofit; import retrofit2.Retrofit;
public class PostViewModel extends ViewModel { public class PostViewModel extends ViewModel {
private Executor executor; private PostDataSource postDataSource;
private LiveData<NetworkState> networkState; private LiveData<NetworkState> paginationNetworkState;
private LiveData<NetworkState> initialLoadingState; private LiveData<NetworkState> initialLoadingState;
private LiveData<PagedList<Post>> posts; private LiveData<PagedList<Post>> posts;
public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) {
//executor = Executors.newFixedThreadPool(5);
PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, isBestPost); PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, isBestPost);
initialLoadingState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(),
dataSource -> dataSource.getInitialLoading()); dataSource -> dataSource.getInitialLoadStateLiveData());
networkState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), paginationNetworkState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(),
dataSource -> dataSource.getNetworkState()); dataSource -> dataSource.getPaginationNetworkStateLiveData());
PagedList.Config pagedListConfig = PagedList.Config pagedListConfig =
(new PagedList.Config.Builder()) (new PagedList.Config.Builder())
.setEnablePlaceholders(false) .setEnablePlaceholders(false)
@ -35,17 +32,16 @@ public class PostViewModel extends ViewModel {
.build(); .build();
posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build(); posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build();
postDataSource = postDataSourceFactory.getPostDataSource();
} }
public PostViewModel(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) { public PostViewModel(Retrofit retrofit, Locale locale, boolean isBestPost, String subredditName) {
//executor = Executors.newFixedThreadPool(5);
PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, locale, isBestPost, subredditName); PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, locale, isBestPost, subredditName);
initialLoadingState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), initialLoadingState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(),
dataSource -> dataSource.getInitialLoading()); dataSource -> dataSource.getInitialLoadStateLiveData());
networkState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), paginationNetworkState = Transformations.switchMap(postDataSourceFactory.getPostDataSourceLiveData(),
dataSource -> dataSource.getNetworkState()); dataSource -> dataSource.getPaginationNetworkStateLiveData());
PagedList.Config pagedListConfig = PagedList.Config pagedListConfig =
(new PagedList.Config.Builder()) (new PagedList.Config.Builder())
@ -54,20 +50,29 @@ public class PostViewModel extends ViewModel {
.build(); .build();
posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build(); posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build();
postDataSource = postDataSourceFactory.getPostDataSource();
} }
LiveData<PagedList<Post>> getPosts() { LiveData<PagedList<Post>> getPosts() {
return posts; return posts;
} }
LiveData<NetworkState> getNetworkState() { LiveData<NetworkState> getPaginationNetworkState() {
return networkState; return paginationNetworkState;
} }
public LiveData<NetworkState> getInitialLoadingState() { public LiveData<NetworkState> getInitialLoadingState() {
return initialLoadingState; return initialLoadingState;
} }
void retry() {
postDataSource.retry();
}
void retryLoadingMore() {
postDataSource.retryLoadingMore();
}
public static class Factory extends ViewModelProvider.NewInstanceFactory { public static class Factory extends ViewModelProvider.NewInstanceFactory {
private Retrofit retrofit; private Retrofit retrofit;
private String accessToken; private String accessToken;

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relative_layout_footer_progress_bar_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@id/retry_button_footer_progress_bar_item"
android:text="@string/load_data_failed"
android:textSize="18sp" />
<Button
android:id="@+id/retry_button_footer_progress_bar_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:text="@string/retry" />
</RelativeLayout>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progress_bar_footer_progress_bar_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_centerHorizontal="true" />
</RelativeLayout>

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/linear_layout_footer_progress_bar_item"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress_bar_footer_progress_bar_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_gravity="center" />
<RelativeLayout
android:id="@+id/relative_layout_footer_progress_bar_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="@id/retry_button_footer_progress_bar_item"
android:layout_alignParentStart="true"
android:text="@string/load_data_failed"
android:textSize="18sp"
android:layout_centerVertical="true" />
<Button
android:id="@+id/retry_button_footer_progress_bar_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@color/colorAccent"
android:text="@string/retry" />
</RelativeLayout>
</LinearLayout>

View File

@ -8,5 +8,5 @@
android:orderInCategory="1" android:orderInCategory="1"
android:title="@string/action_refresh" android:title="@string/action_refresh"
android:icon="@drawable/ic_refresh_white_24dp" android:icon="@drawable/ic_refresh_white_24dp"
app:showAsAction="always" /> app:showAsAction="never" />
</menu> </menu>