diff options
author | Alex Ning <chineseperson5@gmail.com> | 2018-12-27 03:29:02 +0000 |
---|---|---|
committer | Alex Ning <chineseperson5@gmail.com> | 2018-12-27 03:29:02 +0000 |
commit | 45f67457fa6bf49fdf2648e1dc3a3802beac41b4 (patch) | |
tree | 30ecbc7539372376cdc73ccdea44ad214f7ef17b | |
parent | 60b659e651b4d8e7d9ca26b17ba8990497022ed1 (diff) | |
download | infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar.gz infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar.bz2 infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar.lz infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar.xz infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.tar.zst infinity-for-reddit-45f67457fa6bf49fdf2648e1dc3a3802beac41b4.zip |
Use Android Paging Library to load and display best posts. Loading best posts in a specific subreddit is broken. Fixed a bug which is PostViewModel's data becoming null after the app restart. Add notch support for Android Pie.
Diffstat (limited to '')
13 files changed, 389 insertions, 520 deletions
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser Binary files differindex a7bbc0e3..dd278ac4 100644 --- a/.idea/caches/build_file_checksums.ser +++ b/.idea/caches/build_file_checksums.ser diff --git a/.idea/misc.xml b/.idea/misc.xml index dc345694..cc51e58e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -25,7 +25,7 @@ </value> </option> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> <component name="ProjectType"> diff --git a/app/build.gradle b/app/build.gradle index 317de2a4..c9d61af9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,6 +16,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + } } repositories { @@ -66,4 +70,5 @@ dependencies { annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' implementation 'com.github.santalu:aspect-ratio-imageview:1.0.6' implementation 'com.felipecsl:gifimageview:2.2.0' + implementation "android.arch.paging:runtime:1.0.1" } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java new file mode 100644 index 00000000..495f54c2 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/NetworkState.java @@ -0,0 +1,34 @@ +package ml.docilealligator.infinityforreddit; + +class NetworkState { + public enum Status{ + RUNNING, + SUCCESS, + FAILED + } + + + private final Status status; + private final String msg; + + static final NetworkState LOADED; + static final NetworkState LOADING; + + NetworkState(Status status, String msg) { + this.status = status; + this.msg = msg; + } + + static { + LOADED=new NetworkState(Status.SUCCESS,"Success"); + LOADING=new NetworkState(Status.RUNNING,"Running"); + } + + public Status getStatus() { + return status; + } + + public String getMsg() { + return msg; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java new file mode 100644 index 00000000..41ba65d1 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java @@ -0,0 +1,124 @@ +package ml.docilealligator.infinityforreddit; + +import android.arch.lifecycle.MutableLiveData; +import android.arch.paging.PageKeyedDataSource; +import android.support.annotation.NonNull; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Locale; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Retrofit; + +class PostDataSource extends PageKeyedDataSource<String, Post> { + private Retrofit retrofit; + private String accessToken; + private Locale locale; + private boolean isBestPost; + + //private MutableLiveData networkState; + private MutableLiveData initialLoading; + + 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(); + + } + + /*public MutableLiveData getNetworkState() { + return networkState; + }*/ + + public MutableLiveData getInitialLoading() { + return initialLoading; + } + + @Override + public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull final LoadInitialCallback<String, Post> callback) { + initialLoading.postValue(NetworkState.LOADING); + //networkState.postValue(NetworkState.LOADING); + + RedditAPI api = retrofit.create(RedditAPI.class); + + Call<String> bestPost = api.getBestPost(null, RedditUtils.getOAuthHeader(accessToken)); + bestPost.enqueue(new Callback<String>() { + @Override + public void onResponse(Call<String> call, retrofit2.Response<String> response) { + if (response.isSuccessful()) { + ParsePost.parsePost(response.body(), locale, + new ParsePost.ParsePostListener() { + @Override + public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { + callback.onResult(newPosts, null, lastItem); + initialLoading.postValue(NetworkState.LOADED); + //networkState.postValue(NetworkState.LOADED); + } + + @Override + public void onParsePostFail() { + Log.i("Post fetch error", "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())); + } + } + + @Override + public void onFailure(Call<String> call, Throwable t) { + String errorMessage = t == null ? "unknown error" : t.getMessage(); + //networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + } + }); + } + + @Override + public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, Post> callback) { + + } + + @Override + public void loadAfter(@NonNull LoadParams<String> params, @NonNull final LoadCallback<String, Post> callback) { + //networkState.postValue(NetworkState.LOADING); + + RedditAPI api = retrofit.create(RedditAPI.class); + Call<String> bestPost = api.getBestPost(params.key, RedditUtils.getOAuthHeader(accessToken)); + + bestPost.enqueue(new Callback<String>() { + @Override + public void onResponse(Call<String> call, retrofit2.Response<String> response) { + if(response.isSuccessful()) { + ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() { + @Override + public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { + callback.onResult(newPosts, lastItem); + //networkState.postValue(NetworkState.LOADED); + } + + @Override + public void onParsePostFail() { + Log.i("Best post", "Error parsing data"); + } + }); + } else { + Log.i("best post", response.message()); + //networkState.postValue(new NetworkState(NetworkState.Status.FAILED, response.message())); + } + } + + @Override + public void onFailure(Call<String> call, Throwable t) { + String errorMessage = t == null ? "unknown error" : t.getMessage(); + //networkState.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage)); + } + }); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java new file mode 100644 index 00000000..20cda5ca --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSourceFactory.java @@ -0,0 +1,37 @@ +package ml.docilealligator.infinityforreddit; + +import android.arch.lifecycle.MutableLiveData; +import android.arch.paging.DataSource; +import android.arch.paging.PageKeyedDataSource; + +import java.util.Locale; + +import retrofit2.Retrofit; + +class PostDataSourceFactory extends DataSource.Factory { + private Retrofit retrofit; + private String accessToken; + private Locale locale; + private boolean isBestPost; + + private MutableLiveData<PageKeyedDataSource<String, Post>> mutableLiveData; + + PostDataSourceFactory(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { + this.retrofit = retrofit; + this.accessToken = accessToken; + this.locale = locale; + this.isBestPost = isBestPost; + mutableLiveData = new MutableLiveData<>(); + } + + @Override + public DataSource create() { + PostDataSource postDataSource = new PostDataSource(retrofit, accessToken, locale, isBestPost); + mutableLiveData.postValue(postDataSource); + return postDataSource; + } + + public MutableLiveData<PageKeyedDataSource<String, Post>> getMutableLiveData() { + return mutableLiveData; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java index e3a2ba5a..52c92813 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostFragment.java @@ -1,19 +1,15 @@ package ml.docilealligator.infinityforreddit; -import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.design.widget.CoordinatorLayout; -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; @@ -21,15 +17,9 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; -import com.bumptech.glide.Glide; - -import java.util.ArrayList; - import javax.inject.Inject; import javax.inject.Named; -import retrofit2.Call; -import retrofit2.Callback; import retrofit2.Retrofit; @@ -53,9 +43,6 @@ public class PostFragment extends Fragment implements FragmentCommunicator { private LinearLayout mFetchPostErrorLinearLayout; private ImageView mFetchPostErrorImageView; - private String mLastItem; - private PaginationSynchronizer mPaginationSynchronizer; - private boolean mIsBestPost; private String mSubredditName; @@ -77,14 +64,6 @@ public class PostFragment extends Fragment implements FragmentCommunicator { } @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(LAST_ITEM_STATE, mLastItem); - outState.putBoolean(LOADING_STATE_STATE, mPaginationSynchronizer.isLoading()); - outState.putBoolean(LOAD_SUCCESS_STATE, mPaginationSynchronizer.isLoadingMorePostsSuccess()); - } - - @Override public void onResume() { super.onResume(); if(mPostRecyclerView.getAdapter() != null) { @@ -117,10 +96,11 @@ public class PostFragment extends Fragment implements FragmentCommunicator { });*/ mIsBestPost = getArguments().getBoolean(IS_BEST_POST_KEY); + if(!mIsBestPost) { mSubredditName = getArguments().getString(SUBREDDIT_NAME_KEY); } else { - mFetchPostErrorLinearLayout.setOnClickListener(new View.OnClickListener() { + /*mFetchPostErrorLinearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(mIsBestPost) { @@ -129,159 +109,35 @@ public class PostFragment extends Fragment implements FragmentCommunicator { fetchPost(); } } - }); + });*/ } - mPaginationSynchronizer = new PaginationSynchronizer(); - mPaginationSynchronizer.addLastItemSynchronizer(new LastItemSynchronizer() { - @Override - public void lastItemChanged(String lastItem) { - mLastItem = lastItem; - } - }); - - mPostViewModel = ViewModelProviders.of(this).get(PostViewModel.class); - mPostViewModel.getPosts().observe(this, new Observer<ArrayList<Post>>() { - @Override - public void onChanged(@Nullable ArrayList<Post> posts) { - if(posts == null) { - Log.i("datachange", Integer.toString(0)); - } else { - Log.i("datachange", Integer.toString(posts.size())); - mAdapter.changeDataSet(posts); - } - } - }); - if(mIsBestPost) { mAdapter = new PostRecyclerViewAdapter(getActivity(), mOauthRetrofit, - mSharedPreferences, mPaginationSynchronizer, mIsBestPost); - - mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( - getActivity(), mOauthRetrofit, mPostViewModel, mLinearLayoutManager, - mLastItem, mPaginationSynchronizer, mSubredditName, mIsBestPost, - mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadingMorePostsSuccess(), - getResources().getConfiguration().locale)); + mSharedPreferences, mIsBestPost); } else { mAdapter = new PostRecyclerViewAdapter(getActivity(), mRetrofit, - mSharedPreferences, mPaginationSynchronizer, mIsBestPost); - - mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( - getActivity(), mRetrofit, mPostViewModel, mLinearLayoutManager, - mLastItem, mPaginationSynchronizer, mSubredditName, mIsBestPost, - mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadingMorePostsSuccess(), - getResources().getConfiguration().locale)); + mSharedPreferences, mIsBestPost); } mPostRecyclerView.setAdapter(mAdapter); - if(savedInstanceState != null && savedInstanceState.containsKey(LAST_ITEM_STATE)) { - mLastItem = savedInstanceState.getString(LAST_ITEM_STATE); - - mPaginationSynchronizer.notifyLastItemChanged(mLastItem); - mPaginationSynchronizer.setLoadSuccess(savedInstanceState.getBoolean(LOAD_SUCCESS_STATE)); - mPaginationSynchronizer.setLoadingState(savedInstanceState.getBoolean(LOADING_STATE_STATE)); - - mProgressBar.setVisibility(View.GONE); - } else { - if(mIsBestPost) { - fetchBestPost(); - } else { - fetchPost(); - } - } - - return rootView; - } - - private void fetchBestPost() { - mFetchPostErrorLinearLayout.setVisibility(View.GONE); - mProgressBar.setVisibility(View.VISIBLE); - - RedditAPI api = mOauthRetrofit.create(RedditAPI.class); - String accessToken = getActivity().getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); - Call<String> bestPost = api.getBestPost(mLastItem, RedditUtils.getOAuthHeader(accessToken)); - bestPost.enqueue(new Callback<String>() { - @Override - public void onResponse(Call<String> call, retrofit2.Response<String> response) { - if(getActivity() != null) { - if(response.isSuccessful()) { - ParsePost.parsePost(response.body(), getResources().getConfiguration().locale, - new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { - if(isAdded() && getActivity() != null) { - mLastItem = lastItem; - mPaginationSynchronizer.notifyLastItemChanged(lastItem); - mPostViewModel.setPosts(newPosts); - mProgressBar.setVisibility(View.GONE); - } - } - @Override - public void onParsePostFail() { - Log.i("Post fetch error", "Error parsing data"); - showErrorView(); - } - }); - } else { - Log.i("Post fetch error", response.message()); - showErrorView(); - } - } - } + PostViewModel.Factory factory = new PostViewModel.Factory(mOauthRetrofit, accessToken, + getResources().getConfiguration().locale, mIsBestPost); + mPostViewModel = ViewModelProviders.of(this, factory).get(PostViewModel.class); + mPostViewModel.getPosts().observe(this, posts -> mAdapter.submitList(posts)); - @Override - public void onFailure(Call<String> call, Throwable t) { - showErrorView(); - } - }); + return rootView; } - private void fetchPost() { - mFetchPostErrorLinearLayout.setVisibility(View.GONE); - mProgressBar.setVisibility(View.VISIBLE); - - RedditAPI api = mRetrofit.create(RedditAPI.class); - Call<String> getPost = api.getPost(mSubredditName, mLastItem); - getPost.enqueue(new Callback<String>() { - @Override - public void onResponse(Call<String> call, retrofit2.Response<String> response) { - if(getActivity() != null) { - if(response.isSuccessful()) { - ParsePost.parsePost(response.body(), getResources().getConfiguration().locale, - new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { - if(isAdded() && getActivity() != null) { - mLastItem = lastItem; - mPaginationSynchronizer.notifyLastItemChanged(lastItem); - mPostViewModel.setPosts(newPosts); - mProgressBar.setVisibility(View.GONE); - } - } - - @Override - public void onParsePostFail() { - Log.i("Post fetch error", "Error parsing data"); - showErrorView(); - } - }); - } else { - Log.i("Post fetch error", response.message()); - showErrorView(); - } - } - } + @Override + public void refresh() { - @Override - public void onFailure(Call<String> call, Throwable t) { - showErrorView(); - } - }); } + /* private void showErrorView() { mProgressBar.setVisibility(View.GONE); if(mIsBestPost) { @@ -303,32 +159,5 @@ public class PostFragment extends Fragment implements FragmentCommunicator { }); snackbar.show(); } - } - - @Override - public void refresh() { - mLastItem = null; - mPostRecyclerView.clearOnScrollListeners(); - mPostRecyclerView.getRecycledViewPool().clear(); - - mPostViewModel.setPosts(null); - - if(mIsBestPost) { - mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( - getActivity(), mOauthRetrofit, mPostViewModel, mLinearLayoutManager, - mLastItem, mPaginationSynchronizer, mSubredditName, mIsBestPost, - mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadingMorePostsSuccess(), - getResources().getConfiguration().locale)); - - fetchBestPost(); - } else { - mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( - getActivity(), mRetrofit, mPostViewModel, mLinearLayoutManager, - mLastItem, mPaginationSynchronizer, mSubredditName, mIsBestPost, - mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadingMorePostsSuccess(), - getResources().getConfiguration().locale)); - - fetchPost(); - } - } + }*/ }
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java deleted file mode 100644 index 0c11e305..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostPaginationScrollListener.java +++ /dev/null @@ -1,197 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.util.Log; -import android.widget.Toast; - -import java.util.ArrayList; -import java.util.Locale; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Retrofit; - -/** - * Created by alex on 3/12/18. - */ - -class PostPaginationScrollListener extends RecyclerView.OnScrollListener { - private Context mContext; - private Retrofit mRetrofit; - private PostViewModel mPostViewModel; - private LinearLayoutManager mLayoutManager; - private PaginationSynchronizer mPaginationSynchronizer; - - private String mSubredditName; - private boolean isBestPost; - private boolean isLoading; - private boolean loadSuccess; - private Locale locale; - private String mLastItem; - - PostPaginationScrollListener(Context context, Retrofit retrofit, PostViewModel postViewModel, - LinearLayoutManager layoutManager, String lastItem, - PaginationSynchronizer paginationSynchronizer, final String subredditName, - final boolean isBestPost, boolean isLoading, boolean loadSuccess, Locale locale) { - if(context != null) { - mContext = context; - mRetrofit = retrofit; - mPostViewModel = postViewModel; - mLayoutManager = layoutManager; - mLastItem = lastItem; - mPaginationSynchronizer = paginationSynchronizer; - mSubredditName = subredditName; - this.isBestPost = isBestPost; - this.isLoading = isLoading; - this.loadSuccess = loadSuccess; - this.locale = locale; - - PaginationRetryNotifier paginationRetryNotifier = new PaginationRetryNotifier() { - @Override - public void retry() { - if (isBestPost) { - fetchBestPost(); - } else { - fetchPost(subredditName); - } - } - }; - mPaginationSynchronizer.setPaginationRetryNotifier(paginationRetryNotifier); - mPaginationSynchronizer.addLastItemSynchronizer(new LastItemSynchronizer() { - @Override - public void lastItemChanged(String lastItem) { - mLastItem = lastItem; - } - }); - } - } - - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if(!isLoading && loadSuccess) { - int visibleItemCount = mLayoutManager.getChildCount(); - int totalItemCount = mLayoutManager.getItemCount(); - int firstVisibleItemPosition = mLayoutManager.findFirstVisibleItemPosition(); - - if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { - if(isBestPost) { - fetchBestPost(); - } else { - fetchPost(mSubredditName); - } - } - } - } - - - private void fetchBestPost() { - isLoading = true; - loadSuccess = false; - mPaginationSynchronizer.setLoadingState(true); - - RedditAPI api = mRetrofit.create(RedditAPI.class); - - String accessToken = mContext.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) - .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); - Call<String> bestPost = api.getBestPost(mLastItem, RedditUtils.getOAuthHeader(accessToken)); - bestPost.enqueue(new Callback<String>() { - @Override - public void onResponse(Call<String> call, retrofit2.Response<String> response) { - if(response.isSuccessful()) { - ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { - if(mPostViewModel != null) { - mPostViewModel.addPosts(newPosts); - - mLastItem = lastItem; - mPaginationSynchronizer.notifyLastItemChanged(lastItem); - - isLoading = false; - loadSuccess = true; - mPaginationSynchronizer.setLoadingState(false); - mPaginationSynchronizer.loadSuccess(true); - } - } - - @Override - public void onParsePostFail() { - Toast.makeText(mContext, "Error parsing data", Toast.LENGTH_SHORT).show(); - Log.i("Best post", "Error parsing data"); - loadFailed(); - } - }); - } else { - Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); - Log.i("best post", response.message()); - loadFailed(); - } - } - - @Override - public void onFailure(Call<String> call, Throwable t) { - loadFailed(); - } - }); - } - - private void fetchPost(final String subredditName) { - isLoading = true; - loadSuccess = false; - mPaginationSynchronizer.setLoadingState(true); - - RedditAPI api = mRetrofit.create(RedditAPI.class); - Call<String> getPost = api.getPost(subredditName, mLastItem); - getPost.enqueue(new Callback<String>() { - @Override - public void onResponse(Call<String> call, retrofit2.Response<String> response) { - if(response.isSuccessful()) { - ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() { - @Override - public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) { - if(mPostViewModel != null) { - mPostViewModel.addPosts(newPosts); - - mLastItem = lastItem; - mPaginationSynchronizer.notifyLastItemChanged(lastItem); - - isLoading = false; - loadSuccess = true; - mPaginationSynchronizer.setLoadingState(false); - mPaginationSynchronizer.loadSuccess(true); - } - } - - @Override - public void onParsePostFail() { - Toast.makeText(mContext, "Error parsing data", Toast.LENGTH_SHORT).show(); - Log.i("Best post", "Error parsing data"); - loadFailed(); - } - }); - } else { - Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); - Log.i("best post", response.message()); - loadFailed(); - } - } - - @Override - public void onFailure(Call<String> call, Throwable t) { - Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); - loadFailed(); - } - }); - } - - private void loadFailed() { - isLoading = false; - loadSuccess = false; - mPaginationSynchronizer.setLoadingState(false); - mPaginationSynchronizer.loadSuccess(false); - } -}
\ No newline at end of file diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java index 66c29d65..2d6f54aa 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostRecyclerViewAdapter.java @@ -1,5 +1,6 @@ package ml.docilealligator.infinityforreddit; +import android.arch.paging.PagedListAdapter; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -11,6 +12,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.customtabs.CustomTabsIntent; import android.support.v4.content.ContextCompat; +import android.support.v7.util.DiffUtil; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.util.Log; @@ -34,7 +36,7 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; -import java.util.ArrayList; +import java.util.List; import CustomView.AspectRatioGifImageView; import butterknife.BindView; @@ -47,12 +49,10 @@ import retrofit2.Retrofit; * Created by alex on 2/25/18. */ -class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { - private ArrayList<Post> mPostData; +class PostRecyclerViewAdapter extends PagedListAdapter<Post, RecyclerView.ViewHolder> { private Context mContext; private Retrofit mOauthRetrofit; private SharedPreferences mSharedPreferences; - private PaginationSynchronizer mPaginationSynchronizer; private RequestManager glide; private SubredditDao subredditDao; private boolean isLoadingMorePostSuccess = true; @@ -62,21 +62,32 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold private static final int VIEW_TYPE_DATA = 0; private static final int VIEW_TYPE_LOADING = 1; - private int dataSize; + private NetworkState networkState; - PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, PaginationSynchronizer paginationSynchronizer, boolean hasMultipleSubreddits) { + PostRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences, boolean hasMultipleSubreddits) { + super(DIFF_CALLBACK); if(context != null) { mContext = context; mOauthRetrofit = oauthRetrofit; mSharedPreferences = sharedPreferences; - mPostData = new ArrayList<>(); - mPaginationSynchronizer = paginationSynchronizer; this.hasMultipleSubreddits = hasMultipleSubreddits; glide = Glide.with(mContext.getApplicationContext()); subredditDao = SubredditRoomDatabase.getDatabase(mContext.getApplicationContext()).subredditDao(); } } + static final DiffUtil.ItemCallback<Post> DIFF_CALLBACK = new DiffUtil.ItemCallback<Post>() { + @Override + public boolean areItemsTheSame(@NonNull Post post, @NonNull Post t1) { + return post.getId().equals(t1.getId()); + } + + @Override + public boolean areContentsTheSame(@NonNull Post post, @NonNull Post t1) { + return post.getTitle().equals(t1.getTitle()); + } + }; + void setCanStartActivity(boolean canStartActivity) { this.canStartActivity = canStartActivity; } @@ -94,26 +105,32 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold } @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) { + onBindViewHolder(holder, position); + } + + @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { if(holder instanceof DataViewHolder) { - if(mPostData.get(holder.getAdapterPosition()) == null) { + Post post = getItem(position); + if(post == null) { Log.i("is null", Integer.toString(holder.getAdapterPosition())); } else { - final String id = mPostData.get(holder.getAdapterPosition()).getFullName(); - final String subredditName = mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed(); - final String postTime = mPostData.get(holder.getAdapterPosition()).getPostTime(); - final String title = mPostData.get(holder.getAdapterPosition()).getTitle(); - final String permalink = mPostData.get(holder.getAdapterPosition()).getPermalink(); - int voteType = mPostData.get(holder.getAdapterPosition()).getVoteType(); - int gilded = mPostData.get(holder.getAdapterPosition()).getGilded(); - boolean nsfw = mPostData.get(holder.getAdapterPosition()).isNSFW(); - - if(mPostData.get(holder.getAdapterPosition()).getSubredditIconUrl() == null) { + final String id = post.getFullName(); + final String subredditName = post.getSubredditNamePrefixed(); + final String postTime = post.getPostTime(); + final String title = post.getTitle(); + final String permalink = post.getPermalink(); + int voteType = post.getVoteType(); + int gilded = post.getGilded(); + boolean nsfw = post.isNSFW(); + + if(post.getSubredditIconUrl() == null) { new LoadSubredditIconAsyncTask(subredditDao, subredditName, new LoadSubredditIconAsyncTask.LoadSubredditIconAsyncTaskListener() { @Override public void loadIconSuccess(String iconImageUrl) { - if(mContext != null && !mPostData.isEmpty()) { + if(mContext != null && getItemCount() > 0) { if(!iconImageUrl.equals("")) { glide.load(iconImageUrl) .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) @@ -142,13 +159,13 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold } if(holder.getAdapterPosition() >= 0) { - mPostData.get(holder.getAdapterPosition()).setSubredditIconUrl(iconImageUrl); + post.setSubredditIconUrl(iconImageUrl); } } } }).execute(); - } else if(!mPostData.get(position).getSubredditIconUrl().equals("")) { - glide.load(mPostData.get(position).getSubredditIconUrl()) + } else if(!post.getSubredditIconUrl().equals("")) { + glide.load(post.getSubredditIconUrl()) .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) .error(glide.load(R.drawable.subreddit_default_icon)) .listener(new RequestListener<Drawable>() { @@ -181,7 +198,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold canStartActivity = false; Intent intent = new Intent(mContext, ViewPostDetailActivity.class); intent.putExtra(ViewPostDetailActivity.EXTRA_TITLE, title); - intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, mPostData.get(holder.getAdapterPosition())); + intent.putExtra(ViewPostDetailActivity.EXTRA_POST_DATA, post); mContext.startActivity(intent); } } @@ -194,9 +211,9 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold canStartActivity = false; Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, - mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed().substring(2)); + post.getSubredditNamePrefixed().substring(2)); intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, - mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed()); + post.getSubredditNamePrefixed()); intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false); mContext.startActivity(intent); } @@ -212,9 +229,9 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold canStartActivity = false; Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, - mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed().substring(2)); + post.getSubredditNamePrefixed().substring(2)); intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, - mPostData.get(holder.getAdapterPosition()).getSubredditNamePrefixed()); + post.getSubredditNamePrefixed()); intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, false); mContext.startActivity(intent); } @@ -222,7 +239,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold }); ((DataViewHolder) holder).postTimeTextView.setText(postTime); ((DataViewHolder) holder).titleTextView.setText(title); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore())); if(gilded > 0) { ((DataViewHolder) holder).gildedImageView.setVisibility(View.VISIBLE); @@ -247,29 +264,29 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold break; } - if(mPostData.get(position).getPostType() != Post.TEXT_TYPE && mPostData.get(position).getPostType() != Post.NO_PREVIEW_LINK_TYPE) { + if(post.getPostType() != Post.TEXT_TYPE && post.getPostType() != Post.NO_PREVIEW_LINK_TYPE) { ((DataViewHolder) holder).relativeLayout.setVisibility(View.VISIBLE); ((DataViewHolder) holder).progressBar.setVisibility(View.VISIBLE); ((DataViewHolder) holder).imageView.setVisibility(View.VISIBLE); ((DataViewHolder) holder).imageView - .setRatio((float) mPostData.get(position).getPreviewHeight() / mPostData.get(position).getPreviewWidth()); - loadImage(holder, mPostData.get(holder.getAdapterPosition())); + .setRatio((float) post.getPreviewHeight() / post.getPreviewWidth()); + loadImage(holder, post); } - if(!hasMultipleSubreddits && mPostData.get(position).isStickied()) { + if(!hasMultipleSubreddits && post.isStickied()) { ((DataViewHolder) holder).stickiedPostImageView.setVisibility(View.VISIBLE); glide.load(R.drawable.thumbtack).into(((DataViewHolder) holder).stickiedPostImageView); } - if(mPostData.get(holder.getAdapterPosition()).isCrosspost()) { + if(post.isCrosspost()) { ((DataViewHolder) holder).crosspostImageView.setVisibility(View.VISIBLE); } - switch (mPostData.get(position).getPostType()) { + switch (post.getPostType()) { case Post.IMAGE_TYPE: ((DataViewHolder) holder).typeTextView.setText("IMAGE"); - final String imageUrl = mPostData.get(position).getUrl(); + final String imageUrl = post.getUrl(); ((DataViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -293,24 +310,24 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold builder.addDefaultShareMenuItem(); builder.setToolbarColor(mContext.getResources().getColor(R.color.colorPrimary)); CustomTabsIntent customTabsIntent = builder.build(); - customTabsIntent.launchUrl(mContext, Uri.parse(mPostData.get(holder.getAdapterPosition()).getUrl())); + customTabsIntent.launchUrl(mContext, Uri.parse(post.getUrl())); } }); break; case Post.GIF_VIDEO_TYPE: ((DataViewHolder) holder).typeTextView.setText("GIF"); - final Uri gifVideoUri = Uri.parse(mPostData.get(position).getVideoUrl()); + final Uri gifVideoUri = Uri.parse(post.getVideoUrl()); ((DataViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext, ViewVideoActivity.class); intent.setData(gifVideoUri); intent.putExtra(ViewVideoActivity.TITLE_KEY, title); - intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(holder.getAdapterPosition()).isDashVideo()); - intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()); - if(mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()) { - intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(holder.getAdapterPosition()).getGifOrVideoDownloadUrl()); + 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); } @@ -321,17 +338,17 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold case Post.VIDEO_TYPE: ((DataViewHolder) holder).typeTextView.setText("VIDEO"); - final Uri videoUri = Uri.parse(mPostData.get(position).getVideoUrl()); + final Uri videoUri = Uri.parse(post.getVideoUrl()); ((DataViewHolder) holder).imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext, ViewVideoActivity.class); intent.setData(videoUri); intent.putExtra(ViewVideoActivity.TITLE_KEY, title); - intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPostData.get(holder.getAdapterPosition()).isDashVideo()); - intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()); - if(mPostData.get(holder.getAdapterPosition()).isDownloadableGifOrVideo()) { - intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPostData.get(holder.getAdapterPosition()).getGifOrVideoDownloadUrl()); + 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); } @@ -341,7 +358,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold break; case Post.NO_PREVIEW_LINK_TYPE: ((DataViewHolder) holder).typeTextView.setText("LINK"); - final String noPreviewLinkUrl = mPostData.get(position).getUrl(); + final String noPreviewLinkUrl = post.getUrl(); ((DataViewHolder) holder).noPreviewLinkImageView.setVisibility(View.VISIBLE); ((DataViewHolder) holder).noPreviewLinkImageView.setOnClickListener(new View.OnClickListener() { @Override @@ -371,19 +388,19 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold if (((DataViewHolder) holder).upvoteButton.getColorFilter() == null) { ((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); if(isDownvotedBefore) { - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 2)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() + 2)); } else { - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 1)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() + 1)); } VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { - mPostData.get(position).setVoteType(1); + post.setVoteType(1); if(isDownvotedBefore) { - mPostData.get(position).setScore(mPostData.get(position).getScore() + 2); + post.setScore(post.getScore() + 2); } else { - mPostData.get(position).setScore(mPostData.get(position).getScore() + 1); + post.setScore(post.getScore() + 1); } } @@ -391,28 +408,28 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold public void onVoteThingFail(int position) { Toast.makeText(mContext, "Cannot upvote this post", Toast.LENGTH_SHORT).show(); ((DataViewHolder) holder).upvoteButton.clearColorFilter(); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore())); ((DataViewHolder) holder).downvoteButton.setColorFilter(downvoteButtonColorFilter); } }, id, RedditUtils.DIR_UPVOTE, holder.getAdapterPosition()); } else { //Upvoted before ((DataViewHolder) holder).upvoteButton.clearColorFilter(); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 1)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() - 1)); VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { - mPostData.get(position).setVoteType(0); - mPostData.get(position).setScore(mPostData.get(position).getScore() - 1); + post.setVoteType(0); + post.setScore(post.getScore() - 1); } @Override public void onVoteThingFail(int position) { Toast.makeText(mContext, "Cannot unvote this post", Toast.LENGTH_SHORT).show(); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore() + 1)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() + 1)); ((DataViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - mPostData.get(position).setScore(mPostData.get(position).getScore() + 1); + post.setScore(post.getScore() + 1); } }, id, RedditUtils.DIR_UNVOTE, holder.getAdapterPosition()); } @@ -429,19 +446,19 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold if (((DataViewHolder) holder).downvoteButton.getColorFilter() == null) { ((DataViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); if (isUpvotedBefore) { - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 2)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() - 2)); } else { - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() - 1)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() - 1)); } VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { - mPostData.get(position).setVoteType(-1); + post.setVoteType(-1); if(isUpvotedBefore) { - mPostData.get(position).setScore(mPostData.get(position).getScore() - 2); + post.setScore(post.getScore() - 2); } else { - mPostData.get(position).setScore(mPostData.get(position).getScore() - 1); + post.setScore(post.getScore() - 1); } } @@ -449,28 +466,28 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold public void onVoteThingFail(int position) { Toast.makeText(mContext, "Cannot downvote this post", Toast.LENGTH_SHORT).show(); ((DataViewHolder) holder).downvoteButton.clearColorFilter(); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore())); ((DataViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); } }, id, RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition()); } else { //Down voted before ((DataViewHolder) holder).downvoteButton.clearColorFilter(); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(holder.getAdapterPosition()).getScore() + 1)); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore() + 1)); VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { @Override public void onVoteThingSuccess(int position) { - mPostData.get(position).setVoteType(0); - mPostData.get(position).setScore(mPostData.get(position).getScore()); + post.setVoteType(0); + post.setScore(post.getScore()); } @Override public void onVoteThingFail(int position) { Toast.makeText(mContext, "Cannot unvote this post", Toast.LENGTH_SHORT).show(); ((DataViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(mPostData.get(position).getScore())); - mPostData.get(position).setScore(mPostData.get(position).getScore()); + ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(post.getScore())); + post.setScore(post.getScore()); } }, id, RedditUtils.DIR_UNVOTE, holder.getAdapterPosition()); } @@ -492,7 +509,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold ((LoadingViewHolder) holder).retryButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - mPaginationSynchronizer.getPaginationRetryNotifier().retry(); + //mPaginationSynchronizer.getPaginationRetryNotifier().retry(); ((LoadingViewHolder) holder).progressBar.setVisibility(View.VISIBLE); ((LoadingViewHolder) holder).relativeLayout.setVisibility(View.GONE); } @@ -512,12 +529,12 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold } }; - mPaginationSynchronizer.setPaginationNotifier(mPaginationNotifier); + /*mPaginationSynchronizer.setPaginationNotifier(mPaginationNotifier); if(!mPaginationSynchronizer.isLoadingMorePostsSuccess()) { ((LoadingViewHolder) holder).progressBar.setVisibility(View.GONE); ((LoadingViewHolder) holder).relativeLayout.setVisibility(View.VISIBLE); - } + }*/ } } @@ -553,27 +570,30 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold imageRequestBuilder.into(((DataViewHolder) holder).imageView); } } - @Override - public int getItemCount() { - if(mPostData == null || mPostData.isEmpty()) { - return 0; - } - return mPostData.size() + 1; - } @Override public int getItemViewType(int position) { - return (position >= mPostData.size() ? VIEW_TYPE_LOADING : VIEW_TYPE_DATA); + return (position >= getItemCount() ? VIEW_TYPE_LOADING : VIEW_TYPE_DATA); } - void changeDataSet(ArrayList<Post> posts) { - mPostData = posts; - if(dataSize == 0 || posts.size() <= dataSize) { - notifyDataSetChanged(); - } else { - notifyItemRangeInserted(dataSize, posts.size() - dataSize); + private boolean hasExtraRow() { + return networkState != null && networkState != NetworkState.LOADED; + } + + public void setNetworkState(NetworkState newNetworkState) { + NetworkState previousState = this.networkState; + boolean previousExtraRow = hasExtraRow(); + this.networkState = newNetworkState; + boolean newExtraRow = hasExtraRow(); + if (previousExtraRow != newExtraRow) { + if (previousExtraRow) { + notifyItemRemoved(getItemCount()); + } else { + notifyItemInserted(getItemCount()); + } + } else if (newExtraRow && previousState != newNetworkState) { + notifyItemChanged(getItemCount() - 1); } - dataSize = posts.size(); } class DataViewHolder extends RecyclerView.ViewHolder { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostViewModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostViewModel.java index af6c1f31..0be971eb 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostViewModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostViewModel.java @@ -1,30 +1,66 @@ package ml.docilealligator.infinityforreddit; import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.ViewModel; +import android.arch.lifecycle.ViewModelProvider; +import android.arch.paging.LivePagedListBuilder; +import android.arch.paging.PageKeyedDataSource; +import android.arch.paging.PagedList; +import android.support.annotation.NonNull; -import java.util.ArrayList; +import java.util.Locale; +import java.util.concurrent.Executor; + +import retrofit2.Retrofit; public class PostViewModel extends ViewModel { - private MutableLiveData<ArrayList<Post>> posts = new MutableLiveData<>(); + private Executor executor; + LiveData<NetworkState> networkState; + LiveData<PagedList<Post>> posts; + LiveData<PageKeyedDataSource<String, Post>> liveDataSource; - LiveData<ArrayList<Post>> getPosts() { - if(posts == null) { - setPosts(new ArrayList<Post>()); - } - return posts; + public PostViewModel(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { + //executor = Executors.newFixedThreadPool(5); + + PostDataSourceFactory postDataSourceFactory = new PostDataSourceFactory(retrofit, accessToken, locale, isBestPost); + /*networkState = Transformations.switchMap(postDataSourceFactory.getMutableLiveData(), + (Function<PostDataSource, LiveData<NetworkState>>) PostDataSource::getNetworkState);*/ + liveDataSource = postDataSourceFactory.getMutableLiveData(); + + PagedList.Config pagedListConfig = + (new PagedList.Config.Builder()) + .setEnablePlaceholders(false) + .setPageSize(25) + .build(); + + posts = (new LivePagedListBuilder(postDataSourceFactory, pagedListConfig)).build(); } - void setPosts(ArrayList<Post> posts) { - this.posts.postValue(posts); + LiveData<PagedList<Post>> getPosts() { + return posts; } - void addPosts(ArrayList<Post> newPosts) { - ArrayList<Post> posts = this.posts.getValue(); - if(posts != null) { - posts.addAll(newPosts); - this.posts.postValue(posts); + /*public LiveData<NetworkState> getNetworkState() { + return networkState; + }*/ + + public static class Factory extends ViewModelProvider.NewInstanceFactory { + private Retrofit retrofit; + private String accessToken; + private Locale locale; + private boolean isBestPost; + + public Factory(Retrofit retrofit, String accessToken, Locale locale, boolean isBestPost) { + this.retrofit = retrofit; + this.accessToken = accessToken; + this.locale = locale; + this.isBestPost = isBestPost; + } + + @NonNull + @Override + public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { + return (T) new PostViewModel(retrofit, accessToken, locale, isBestPost); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index 27d152d1..6c8f209e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -321,40 +321,6 @@ public class ViewPostDetailActivity extends AppCompatActivity { } queryComment(); - /*final Observable<Integer> observable = Observable.create( - new ObservableOnSubscribe<Integer>() { - @Override - public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { - emitter.onNext(mPost.getVoteType()); - emitter.onComplete(); - Log.i("asdasdf", "adasdfasdf"); - Toast.makeText(ViewPostDetailActivity.this, "observable", Toast.LENGTH_SHORT).show(); - } - } - ); - - final Observer observer = new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(Object o) { - - } - - @Override - public void onError(Throwable e) { - - } - - @Override - public void onComplete() { - Toast.makeText(ViewPostDetailActivity.this, "complete", Toast.LENGTH_SHORT).show(); - } - };*/ - mUpvoteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { diff --git a/app/src/main/res/values-v28/styles.xml b/app/src/main/res/values-v28/styles.xml new file mode 100644 index 00000000..7b88cdf3 --- /dev/null +++ b/app/src/main/res/values-v28/styles.xml @@ -0,0 +1,12 @@ +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> + <!-- Customize your theme here. --> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> + </style> + +</resources> diff --git a/build.gradle b/build.gradle index 35d0051f..8a7b6fa0 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,9 @@ allprojects { google() jcenter() maven { url 'https://jitpack.io' } + maven { url 'https://dl.bintray.com/sysdata/maven' } + maven { url 'http://repo.pageturner-reader.org' } + mavenCentral() } } |