aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Ning <chineseperson5@gmail.com>2019-07-21 16:09:40 +0000
committerAlex Ning <chineseperson5@gmail.com>2019-07-21 16:09:40 +0000
commit2f15543f913da5c9100ce114f4268c0576b70a3e (patch)
tree656429d2b712ffa391c7e7eb6de633a7f3408bce
parent0d5cf54af5de84b35a10ec0b4b2e12dbe09715a0 (diff)
downloadinfinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar.gz
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar.bz2
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar.lz
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar.xz
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.tar.zst
infinity-for-reddit-2f15543f913da5c9100ce114f4268c0576b70a3e.zip
Add a ViewPager in ViewUserDetailActivity to display comments. Fixed searching posts without specifying subreddit will result in no posts. Use another api endpoint for fetching posts in ViewUserDetailActivity.
-rw-r--r--.idea/caches/build_file_checksums.serbin533 -> 533 bytes
-rw-r--r--.idea/caches/gradle_models.serbin254866 -> 254881 bytes
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java1
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSource.java200
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSourceFactory.java43
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentViewModel.java83
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingFragment.java149
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java284
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java27
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java19
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java20
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java7
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/SearchActivity.java9
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/SubredditListingRecyclerViewAdapter.java2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/UserListingRecyclerViewAdapter.java2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java150
-rw-r--r--app/src/main/res/layout/activity_view_user_detail.xml20
-rw-r--r--app/src/main/res/layout/fragment_comments_listing.xml48
-rw-r--r--app/src/main/res/layout/item_load_comments_failed_placeholder.xml2
-rw-r--r--app/src/main/res/values/strings.xml2
22 files changed, 1020 insertions, 52 deletions
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 35e47bf8..1c28698e 100644
--- a/.idea/caches/build_file_checksums.ser
+++ b/.idea/caches/build_file_checksums.ser
Binary files differ
diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser
index 226d995d..cce3e832 100644
--- a/.idea/caches/gradle_models.ser
+++ b/.idea/caches/gradle_models.ser
Binary files differ
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
index 87c4f254..79aed4ef 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
@@ -24,4 +24,5 @@ interface AppComponent {
void inject(PostVideoActivity postVideoActivity);
void inject(FlairBottomSheetFragment flairBottomSheetFragment);
void inject(RulesActivity rulesActivity);
+ void inject(CommentsListingFragment commentsListingFragment);
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java
index 3bb3ef10..d6af8c03 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java
@@ -442,7 +442,7 @@ class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVie
((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments);
}
} else if(holder instanceof LoadMoreCommentsFailedViewHolder) {
- ((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.post_load_comments_failed);
+ ((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.load_comments_failed);
}
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSource.java
new file mode 100644
index 00000000..acda274a
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSource.java
@@ -0,0 +1,200 @@
+package ml.docilealligator.infinityforreddit;
+
+import android.os.AsyncTask;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.MutableLiveData;
+import androidx.paging.PageKeyedDataSource;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+public class CommentDataSource extends PageKeyedDataSource<String, CommentData> {
+ interface OnCommentFetchedCallback {
+ void hasComment();
+ void noComment();
+ }
+
+ private Retrofit retrofit;
+ private Locale locale;
+ private String username;
+ private OnCommentFetchedCallback onCommentFetchedCallback;
+
+ private MutableLiveData<NetworkState> paginationNetworkStateLiveData;
+ private MutableLiveData<NetworkState> initialLoadStateLiveData;
+
+ private LoadInitialParams<String> initialParams;
+ private LoadInitialCallback<String, CommentData> initialCallback;
+ private LoadParams<String> params;
+ private LoadCallback<String, CommentData> callback;
+
+ CommentDataSource(Retrofit retrofit, Locale locale, String username, OnCommentFetchedCallback onCommentFetchedCallback) {
+ this.retrofit = retrofit;
+ this.locale = locale;
+ this.username = username;
+ paginationNetworkStateLiveData = new MutableLiveData();
+ initialLoadStateLiveData = new MutableLiveData();
+ this.onCommentFetchedCallback = onCommentFetchedCallback;
+ }
+
+ MutableLiveData getPaginationNetworkStateLiveData() {
+ return paginationNetworkStateLiveData;
+ }
+
+ MutableLiveData getInitialLoadStateLiveData() {
+ return initialLoadStateLiveData;
+ }
+
+ void retry() {
+ loadInitial(initialParams, initialCallback);
+ }
+
+ void retryLoadingMore() {
+ loadAfter(params, callback);
+ }
+
+ @Override
+ public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull LoadInitialCallback<String, CommentData> callback) {
+ initialParams = params;
+ initialCallback = callback;
+
+ RedditAPI api = retrofit.create(RedditAPI.class);
+ Call<String> bestPost = api.getUserComments(username, null);
+ bestPost.enqueue(new Callback<String>() {
+ @Override
+ public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
+ if(response.isSuccessful()) {
+ new ParseCommentAsyncTask(response.body(), locale, new ParseCommentAsyncTask.ParseCommentAsyncTaskListener() {
+ @Override
+ public void parseSuccessful(ArrayList<CommentData> comments, String after) {
+ if(comments.size() == 0) {
+ onCommentFetchedCallback.noComment();
+ } else {
+ onCommentFetchedCallback.hasComment();
+ }
+
+ callback.onResult(comments, null, after);
+ initialLoadStateLiveData.postValue(NetworkState.LOADED);
+ }
+
+ @Override
+ public void parseFailed() {
+ Log.i("Comments fetch error", "Error parsing data");
+ initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ }).execute();
+ } else {
+ Log.i("Comments fetch error", "Error parsing data");
+ initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
+ Log.i("Comments fetch error", "Error parsing data");
+ initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ });
+ }
+
+ @Override
+ public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, CommentData> callback) {
+
+ }
+
+ @Override
+ public void loadAfter(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, CommentData> callback) {
+ this.params = params;
+ this.callback = callback;
+
+ RedditAPI api = retrofit.create(RedditAPI.class);
+ Call<String> bestPost = api.getUserComments(username, params.key);
+ bestPost.enqueue(new Callback<String>() {
+ @Override
+ public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
+ if(response.isSuccessful()) {
+ new ParseCommentAsyncTask(response.body(), locale, new ParseCommentAsyncTask.ParseCommentAsyncTaskListener() {
+ @Override
+ public void parseSuccessful(ArrayList<CommentData> comments, String after) {
+ if(after == null || after.equals("") || after.equals("null")) {
+ callback.onResult(comments, null);
+ } else {
+ callback.onResult(comments, after);
+ }
+ paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
+ }
+
+ @Override
+ public void parseFailed() {
+ Log.i("Comments fetch error", "Error parsing data");
+ paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ }).execute();
+ } else {
+ paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
+ paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
+ }
+ });
+ }
+
+ private static class ParseCommentAsyncTask extends AsyncTask<Void, ArrayList<CommentData>, ArrayList<CommentData>> {
+ private String response;
+ private String after;
+ private Locale locale;
+ private ParseCommentAsyncTaskListener parseCommentAsyncTaskListener;
+
+ interface ParseCommentAsyncTaskListener {
+ void parseSuccessful(ArrayList<CommentData> comments, String after);
+ void parseFailed();
+ }
+
+ ParseCommentAsyncTask(String response, Locale locale, ParseCommentAsyncTaskListener parseCommentAsyncTaskListener) {
+ this.response = response;
+ this.locale = locale;
+ this.parseCommentAsyncTaskListener = parseCommentAsyncTaskListener;
+ }
+
+ @Override
+ protected ArrayList<CommentData> doInBackground(Void... voids) {
+ try {
+ JSONObject data = new JSONObject(response).getJSONObject(JSONUtils.DATA_KEY);
+ JSONArray commentsJSONArray = data.getJSONArray(JSONUtils.CHILDREN_KEY);
+ ArrayList<CommentData> comments = new ArrayList<>();
+ for(int i = 0; i < commentsJSONArray.length(); i++) {
+ JSONObject commentJSON = commentsJSONArray.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
+ comments.add(ParseComment.parseSingleComment(commentJSON, 0, locale));
+ }
+ after = data.getString(JSONUtils.AFTER_KEY);
+ return comments;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(ArrayList<CommentData> commentData) {
+ super.onPostExecute(commentData);
+ if(commentData != null) {
+ parseCommentAsyncTaskListener.parseSuccessful(commentData, after);
+ } else {
+ parseCommentAsyncTaskListener.parseFailed();
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSourceFactory.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSourceFactory.java
new file mode 100644
index 00000000..ac43a9c2
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentDataSourceFactory.java
@@ -0,0 +1,43 @@
+package ml.docilealligator.infinityforreddit;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.MutableLiveData;
+import androidx.paging.DataSource;
+
+import java.util.Locale;
+
+import retrofit2.Retrofit;
+
+class CommentDataSourceFactory extends DataSource.Factory {
+ private Retrofit retrofit;
+ private Locale locale;
+ private String username;
+ private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
+
+ private CommentDataSource commentDataSource;
+ private MutableLiveData<CommentDataSource> commentDataSourceLiveData;
+
+ CommentDataSourceFactory(Retrofit retrofit, Locale locale, String username, CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
+ this.retrofit = retrofit;
+ this.locale = locale;
+ this.username = username;
+ commentDataSourceLiveData = new MutableLiveData<>();
+ this.onCommentFetchedCallback = onCommentFetchedCallback;
+ }
+
+ @NonNull
+ @Override
+ public DataSource create() {
+ commentDataSource = new CommentDataSource(retrofit, locale, username, onCommentFetchedCallback);
+ commentDataSourceLiveData.postValue(commentDataSource);
+ return commentDataSource;
+ }
+
+ public MutableLiveData<CommentDataSource> getCommentDataSourceLiveData() {
+ return commentDataSourceLiveData;
+ }
+
+ CommentDataSource getCommentDataSource() {
+ return commentDataSource;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentViewModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentViewModel.java
new file mode 100644
index 00000000..87fca11d
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentViewModel.java
@@ -0,0 +1,83 @@
+package ml.docilealligator.infinityforreddit;
+
+import androidx.annotation.NonNull;
+import androidx.arch.core.util.Function;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.Transformations;
+import androidx.lifecycle.ViewModel;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.paging.LivePagedListBuilder;
+import androidx.paging.PagedList;
+
+import java.util.Locale;
+
+import retrofit2.Retrofit;
+
+public class CommentViewModel extends ViewModel {
+ private CommentDataSourceFactory commentDataSourceFactory;
+ private LiveData<NetworkState> paginationNetworkState;
+ private LiveData<NetworkState> initialLoadingState;
+ private LiveData<PagedList<CommentData>> comments;
+
+ public CommentViewModel(Retrofit retrofit, Locale locale, String username,
+ CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
+ commentDataSourceFactory = new CommentDataSourceFactory(retrofit, locale, username, onCommentFetchedCallback);
+
+ initialLoadingState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceLiveData(),
+ (Function<CommentDataSource, LiveData<NetworkState>>) CommentDataSource::getInitialLoadStateLiveData);
+ paginationNetworkState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceLiveData(),
+ (Function<CommentDataSource, LiveData<NetworkState>>) CommentDataSource::getPaginationNetworkStateLiveData);
+ PagedList.Config pagedListConfig =
+ (new PagedList.Config.Builder())
+ .setEnablePlaceholders(false)
+ .setPageSize(25)
+ .build();
+
+ comments = (new LivePagedListBuilder(commentDataSourceFactory, pagedListConfig)).build();
+ }
+
+ LiveData<PagedList<CommentData>> getComments() {
+ return comments;
+ }
+
+ LiveData<NetworkState> getPaginationNetworkState() {
+ return paginationNetworkState;
+ }
+
+ LiveData<NetworkState> getInitialLoadingState() {
+ return initialLoadingState;
+ }
+
+ void refresh() {
+ commentDataSourceFactory.getCommentDataSource().invalidate();
+ }
+
+ void retry() {
+ commentDataSourceFactory.getCommentDataSource().retry();
+ }
+
+ void retryLoadingMore() {
+ commentDataSourceFactory.getCommentDataSource().retryLoadingMore();
+ }
+
+ public static class Factory extends ViewModelProvider.NewInstanceFactory {
+ private Retrofit retrofit;
+ private Locale locale;
+ private String username;
+ private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
+
+ public Factory(Retrofit retrofit, Locale locale, String username,
+ CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
+ this.retrofit = retrofit;
+ this.locale = locale;
+ this.username = username;
+ this.onCommentFetchedCallback = onCommentFetchedCallback;
+ }
+
+ @NonNull
+ @Override
+ public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+ return (T) new CommentViewModel(retrofit, locale, username, onCommentFetchedCallback);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingFragment.java
new file mode 100644
index 00000000..5371d220
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingFragment.java
@@ -0,0 +1,149 @@
+package ml.docilealligator.infinityforreddit;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestManager;
+import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import retrofit2.Retrofit;
+
+
+/**
+ * A simple {@link Fragment} subclass.
+ */
+public class CommentsListingFragment extends Fragment implements FragmentCommunicator {
+
+ static final String EXTRA_USERNAME_KEY = "ENK";
+
+ @BindView(R.id.coordinator_layout_comments_listing_fragment) CoordinatorLayout mCoordinatorLayout;
+ @BindView(R.id.recycler_view_comments_listing_fragment) RecyclerView mCommentRecyclerView;
+ @BindView(R.id.progress_bar_comments_listing_fragment) CircleProgressBar mProgressBar;
+ @BindView(R.id.fetch_comments_info_linear_layout_comments_listing_fragment) LinearLayout mFetchCommentInfoLinearLayout;
+ @BindView(R.id.fetch_comments_info_image_view_comments_listing_fragment) ImageView mFetchCommentInfoImageView;
+ @BindView(R.id.fetch_comments_info_text_view_comments_listing_fragment) TextView mFetchCommentInfoTextView;
+
+ private RequestManager mGlide;
+
+ private Activity activity;
+
+ private CommentsListingRecyclerViewAdapter mAdapter;
+
+ CommentViewModel mCommentViewModel;
+
+ @Inject
+ @Named("no_oauth")
+ Retrofit mRetrofit;
+
+ @Inject @Named("oauth")
+ Retrofit mOauthRetrofit;
+
+ @Inject @Named("auth_info")
+ SharedPreferences mSharedPreferences;
+
+ public CommentsListingFragment() {
+ // Required empty public constructor
+ }
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_comments_listing, container, false);
+
+ ((Infinity) activity.getApplication()).getmAppComponent().inject(this);
+
+ ButterKnife.bind(this, rootView);
+
+ mGlide = Glide.with(activity);
+
+ mCommentRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
+
+ CommentViewModel.Factory factory;
+ mAdapter = new CommentsListingRecyclerViewAdapter(activity, mOauthRetrofit,
+ mSharedPreferences, () -> mCommentViewModel.retryLoadingMore());
+
+ String username = getArguments().getString(EXTRA_USERNAME_KEY);
+
+ factory = new CommentViewModel.Factory(mRetrofit, getResources().getConfiguration().locale,
+ username, new CommentDataSource.OnCommentFetchedCallback() {
+ @Override
+ public void hasComment() {
+ mFetchCommentInfoLinearLayout.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void noComment() {
+ mFetchCommentInfoLinearLayout.setOnClickListener(view -> {
+ //Do nothing
+ });
+ showErrorView(R.string.no_posts);
+ }
+ });
+
+ mCommentRecyclerView.setAdapter(mAdapter);
+
+ mCommentViewModel = ViewModelProviders.of(this, factory).get(CommentViewModel.class);
+ mCommentViewModel.getComments().observe(this, comments -> mAdapter.submitList(comments));
+
+ mCommentViewModel.getInitialLoadingState().observe(this, networkState -> {
+ if(networkState.getStatus().equals(NetworkState.Status.SUCCESS)) {
+ mProgressBar.setVisibility(View.GONE);
+ } else if(networkState.getStatus().equals(NetworkState.Status.FAILED)) {
+ mFetchCommentInfoLinearLayout.setOnClickListener(view -> mCommentViewModel.retry());
+ showErrorView(R.string.load_posts_error);
+ } else {
+ mFetchCommentInfoLinearLayout.setVisibility(View.GONE);
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+ });
+
+ mCommentViewModel.getPaginationNetworkState().observe(this, networkState -> {
+ mAdapter.setNetworkState(networkState);
+ });
+
+ return rootView;
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ this.activity = (Activity) context;
+ }
+
+ @Override
+ public void refresh() {
+ mCommentViewModel.refresh();
+ }
+
+ private void showErrorView(int stringResId) {
+ mProgressBar.setVisibility(View.GONE);
+ if(activity != null && isAdded()) {
+ mFetchCommentInfoLinearLayout.setVisibility(View.VISIBLE);
+ mFetchCommentInfoTextView.setText(stringResId);
+ mGlide.load(R.drawable.load_post_error_indicator).into(mFetchCommentInfoImageView);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java
new file mode 100644
index 00000000..8075c245
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java
@@ -0,0 +1,284 @@
+package ml.docilealligator.infinityforreddit;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.cardview.widget.CardView;
+import androidx.core.content.ContextCompat;
+import androidx.paging.PagedListAdapter;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
+
+import CustomView.CustomMarkwonView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import retrofit2.Retrofit;
+
+class CommentsListingRecyclerViewAdapter extends PagedListAdapter<CommentData, RecyclerView.ViewHolder> {
+ private Context mContext;
+ private Retrofit mOauthRetrofit;
+ private SharedPreferences mSharedPreferences;
+
+ private static final int VIEW_TYPE_DATA = 0;
+ private static final int VIEW_TYPE_ERROR = 1;
+ private static final int VIEW_TYPE_LOADING = 2;
+
+ private NetworkState networkState;
+ private RetryLoadingMoreCallback mRetryLoadingMoreCallback;
+
+ interface RetryLoadingMoreCallback {
+ void retryLoadingMore();
+ }
+
+ protected CommentsListingRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, SharedPreferences sharedPreferences,
+ RetryLoadingMoreCallback retryLoadingMoreCallback) {
+ super(DIFF_CALLBACK);
+ mContext = context;
+ mOauthRetrofit = oauthRetrofit;
+ mSharedPreferences = sharedPreferences;
+ mRetryLoadingMoreCallback = retryLoadingMoreCallback;
+ }
+
+ private static final DiffUtil.ItemCallback<CommentData> DIFF_CALLBACK = new DiffUtil.ItemCallback<CommentData>() {
+ @Override
+ public boolean areItemsTheSame(@NonNull CommentData CommentData, @NonNull CommentData t1) {
+ return CommentData.getId().equals(t1.getId());
+ }
+
+ @Override
+ public boolean areContentsTheSame(@NonNull CommentData CommentData, @NonNull CommentData t1) {
+ return CommentData.getCommentContent().equals(t1.getCommentContent());
+ }
+ };
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ if(viewType == VIEW_TYPE_DATA) {
+ CardView cardView = (CardView) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false);
+ 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 {
+ RelativeLayout relativeLayout = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.item_footer_loading, parent, false);
+ return new LoadingViewHolder(relativeLayout);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ if(holder instanceof DataViewHolder) {
+ CommentData comment = getItem(holder.getAdapterPosition());
+
+ String authorPrefixed = "u/" + comment.getAuthor();
+ ((DataViewHolder) holder).authorTextView.setText(authorPrefixed);
+
+ ((DataViewHolder) holder).commentTimeTextView.setText(comment.getCommentTime());
+
+ ((DataViewHolder) holder).commentMarkdownView.setMarkdown(comment.getCommentContent(), mContext);
+ ((DataViewHolder) holder).scoreTextView.setText(Integer.toString(comment.getScore()));
+
+ switch (comment.getVoteType()) {
+ case 1:
+ ((DataViewHolder) holder).upvoteButton
+ .setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
+ break;
+ case 2:
+ ((DataViewHolder) holder).downvoteButton
+ .setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
+ break;
+ }
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ // Reached at the end
+ if (hasExtraRow() && position == getItemCount() - 1) {
+ if (networkState.getStatus() == NetworkState.Status.LOADING) {
+ return VIEW_TYPE_LOADING;
+ } else {
+ return VIEW_TYPE_ERROR;
+ }
+ } else {
+ return VIEW_TYPE_DATA;
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ if(hasExtraRow()) {
+ return super.getItemCount() + 1;
+ }
+ return super.getItemCount();
+ }
+
+ private boolean hasExtraRow() {
+ return networkState != null && networkState.getStatus() != NetworkState.Status.SUCCESS;
+ }
+
+ void setNetworkState(NetworkState newNetworkState) {
+ NetworkState previousState = this.networkState;
+ boolean previousExtraRow = hasExtraRow();
+ this.networkState = newNetworkState;
+ boolean newExtraRow = hasExtraRow();
+ if (previousExtraRow != newExtraRow) {
+ if (previousExtraRow) {
+ notifyItemRemoved(super.getItemCount());
+ } else {
+ notifyItemInserted(super.getItemCount());
+ }
+ } else if (newExtraRow && !previousState.equals(newNetworkState)) {
+ notifyItemChanged(getItemCount() - 1);
+ }
+ }
+
+ class DataViewHolder extends RecyclerView.ViewHolder {
+ @BindView(R.id.vertical_block_item_post_comment) View verticalBlock;
+ @BindView(R.id.author_text_view_item_post_comment) TextView authorTextView;
+ @BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView;
+ @BindView(R.id.comment_markdown_view_item_post_comment) CustomMarkwonView commentMarkdownView;
+ @BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton;
+ @BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView;
+ @BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton;
+ @BindView(R.id.share_button_item_post_comment) ImageView shareButton;
+ @BindView(R.id.reply_button_item_post_comment) ImageView replyButton;
+
+ DataViewHolder(View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+
+ verticalBlock.setVisibility(View.GONE);
+
+ authorTextView.setOnClickListener(view -> {
+ Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
+ intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, getItem(getAdapterPosition()).getAuthor());
+ mContext.startActivity(intent);
+ });
+
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) shareButton.getLayoutParams();
+ lp.addRule(RelativeLayout.ALIGN_PARENT_END);
+ lp.setMarginEnd(0);
+ shareButton.setLayoutParams(lp);
+
+ shareButton.setOnClickListener(view -> {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
+ String extraText = getItem(getAdapterPosition()).getPermalink();
+ intent.putExtra(Intent.EXTRA_TEXT, extraText);
+ mContext.startActivity(Intent.createChooser(intent, "Share"));
+ });
+
+ replyButton.setVisibility(View.GONE);
+
+ upvoteButton.setOnClickListener(view -> {
+ int previousVoteType = getItem(getAdapterPosition()).getVoteType();
+ String newVoteType;
+
+ downvoteButton.clearColorFilter();
+
+ if(previousVoteType != CommentData.VOTE_TYPE_UPVOTE) {
+ //Not upvoted before
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_UPVOTE);
+ newVoteType = RedditUtils.DIR_UPVOTE;
+ upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
+ } else {
+ //Upvoted before
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
+ newVoteType = RedditUtils.DIR_UNVOTE;
+ upvoteButton.clearColorFilter();
+ }
+
+ scoreTextView.setText(Integer.toString(getItem(getAdapterPosition()).getScore() + getItem(getAdapterPosition()).getVoteType()));
+
+ VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
+ @Override
+ public void onVoteThingSuccess(int position) {
+ if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) {
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_UPVOTE);
+ upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
+ } else {
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
+ upvoteButton.clearColorFilter();
+ }
+
+ downvoteButton.clearColorFilter();
+ scoreTextView.setText(Integer.toString(getItem(getAdapterPosition()).getScore() + getItem(getAdapterPosition()).getVoteType()));
+ }
+
+ @Override
+ public void onVoteThingFail(int position) { }
+ }, getItem(getAdapterPosition()).getFullName(), newVoteType, getAdapterPosition());
+ });
+
+ downvoteButton.setOnClickListener(view -> {
+ int previousVoteType = getItem(getAdapterPosition()).getVoteType();
+ String newVoteType;
+
+ upvoteButton.clearColorFilter();
+
+ if(previousVoteType != CommentData.VOTE_TYPE_DOWNVOTE) {
+ //Not downvoted before
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE);
+ newVoteType = RedditUtils.DIR_DOWNVOTE;
+ downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
+ } else {
+ //Downvoted before
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
+ newVoteType = RedditUtils.DIR_UNVOTE;
+ downvoteButton.clearColorFilter();
+ }
+
+ scoreTextView.setText(Integer.toString(getItem(getAdapterPosition()).getScore() + getItem(getAdapterPosition()).getVoteType()));
+
+ VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
+ @Override
+ public void onVoteThingSuccess(int position1) {
+ if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) {
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE);
+ downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
+ } else {
+ getItem(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
+ downvoteButton.clearColorFilter();
+ }
+
+ upvoteButton.clearColorFilter();
+ scoreTextView.setText(Integer.toString(getItem(getAdapterPosition()).getScore() + getItem(getAdapterPosition()).getVoteType()));
+ }
+
+ @Override
+ public void onVoteThingFail(int position1) { }
+ }, getItem(getAdapterPosition()).getFullName(), newVoteType, getAdapterPosition());
+ });
+ }
+ }
+
+ class ErrorViewHolder extends RecyclerView.ViewHolder {
+ @BindView(R.id.error_text_view_item_footer_error) TextView errorTextView;
+ @BindView(R.id.retry_button_item_footer_error) Button retryButton;
+
+ ErrorViewHolder(View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+ errorTextView.setText(R.string.load_comments_failed);
+ retryButton.setOnClickListener(view -> mRetryLoadingMoreCallback.retryLoadingMore());
+ }
+ }
+
+ class LoadingViewHolder extends RecyclerView.ViewHolder {
+ LoadingViewHolder(@NonNull View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java
index 7f92697a..9240ccd3 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java
@@ -5,25 +5,20 @@ package ml.docilealligator.infinityforreddit;
*/
public class JSONUtils {
- public static final String DATA_KEY = "data";
+ static final String DATA_KEY = "data";
static final String AFTER_KEY = "after";
- static final String MODHASH_KEY = "modhash";
static final String CHILDREN_KEY = "children";
static final String COUNT_KEY = "count";
static final String TITLE_KEY = "title";
- public static final String NAME_KEY = "name";
+ static final String NAME_KEY = "name";
static final String SUBREDDIT_NAME_PREFIX_KEY = "subreddit_name_prefixed";
static final String SELFTEXT_HTML_KEY = "selftext_html";
static final String AUTHOR_KEY = "author";
- static final String DOMAIN_KEY = "domain";
static final String LINK_FLAIR_TEXT_KEY = "link_flair_text";
- static final String NUM_CROSSPOST_KEY = "num_crossposts";
- static final String CAN_MOD_POST_KEY = "can_mod_post";
static final String SCORE_KEY = "score";
static final String LIKES_KEY = "likes";
static final String NSFW_KEY = "over_18";
static final String GILDED_KEY = "gilded";
- static final String POST_HINT_KEY = "post_hint";
static final String PERMALINK_KEY = "permalink";
static final String CREATED_UTC_KEY = "created_utc";
static final String PREVIEW_KEY = "preview";
@@ -37,12 +32,10 @@ public class JSONUtils {
static final String URL_KEY = "url";
static final String MEDIA_KEY = "media";
static final String REDDIT_VIDEO_KEY = "reddit_video";
- static final String FALLBACK_URL_KEY = "fallback_url";
static final String DASH_URL_KEY = "dash_url";
static final String IS_VIDEO_KEY = "is_video";
static final String CROSSPOST_PARENT_LIST = "crosspost_parent_list";
static final String REDDIT_VIDEO_PREVIEW_KEY = "reddit_video_preview";
- static final String IS_REDDIT_MEDIA_DOMAIN = "is_reddit_media_domain";
static final String STICKIED_KEY = "stickied";
static final String BODY_HTML_KEY = "body_html";
static final String COLLAPSED_KEY = "collapsed";
@@ -51,24 +44,22 @@ public class JSONUtils {
static final String DEPTH_KEY = "depth";
static final String ID_KEY = "id";
static final String SCORE_HIDDEN_KEY = "score_hidden";
- public static final String SUBREDDIT_KEY = "subreddit";
- public static final String BANNER_IMG_KEY = "banner_img";
+ static final String SUBREDDIT_KEY = "subreddit";
+ static final String BANNER_IMG_KEY = "banner_img";
static final String BANNER_BACKGROUND_IMAGE_KEY = "banner_background_image";
- public static final String ICON_IMG_KEY = "icon_img";
+ static final String ICON_IMG_KEY = "icon_img";
static final String COMMUNITY_ICON_KEY = "community_icon";
- public static final String LINK_KARMA_KEY = "link_karma";
- public static final String COMMENT_KARMA_KEY = "comment_karma";
+ static final String LINK_KARMA_KEY = "link_karma";
+ static final String COMMENT_KARMA_KEY = "comment_karma";
static final String DISPLAY_NAME = "display_name";
static final String SUBREDDIT_TYPE_KEY = "subreddit_type";
static final String SUBREDDIT_TYPE_VALUE_USER = "user";
static final String SUBSCRIBERS_KEY = "subscribers";
static final String PUBLIC_DESCRIPTION_KEY = "public_description";
static final String ACTIVE_USER_COUNT_KEY = "active_user_count";
- public static final String IS_GOLD_KEY = "is_gold";
- public static final String IS_FRIEND_KEY = "is_friend";
- static final String KIND_KEY = "kind";
+ static final String IS_GOLD_KEY = "is_gold";
+ static final String IS_FRIEND_KEY = "is_friend";
static final String JSON_KEY = "json";
- static final String THINGS_KEY = "things";
static final String PARENT_ID_KEY = "parent_id";
static final String ERRORS_KEY = "errors";
static final String ARGS_KEY = "args";
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java
index 97170b5b..cb6b8acc 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java
@@ -211,7 +211,7 @@ class ParseComment {
}
}
- private static CommentData parseSingleComment(JSONObject singleCommentData, int depth, Locale locale) throws JSONException {
+ static CommentData parseSingleComment(JSONObject singleCommentData, int depth, Locale locale) throws JSONException {
String id = singleCommentData.getString(JSONUtils.ID_KEY);
String fullName = singleCommentData.getString(JSONUtils.NAME_KEY);
String author = singleCommentData.getString(JSONUtils.AUTHOR_KEY);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java
index 817fd7c8..a2146668 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParsePost.java
@@ -90,15 +90,8 @@ class ParsePost {
return null;
}
- String kind = allData.getJSONObject(0).getString(JSONUtils.KIND_KEY);
- if(kind.equals("t3")) {
- //It's a post
- JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY);
- post = parseBasicData(data, locale, -1);
- } else {
- parseFailed = true;
- return null;
- }
+ JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY);
+ post = parseBasicData(data, locale, -1);
} else {
//Posts listing
int size;
@@ -109,12 +102,8 @@ class ParsePost {
}
for(int i = 0; i < size; i++) {
- String kind = allData.getJSONObject(i).getString(JSONUtils.KIND_KEY);
- if(kind.equals("t3")) {
- //It's a post
- JSONObject data = allData.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
- newPosts.add(parseBasicData(data, locale, i));
- }
+ JSONObject data = allData.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
+ newPosts.add(parseBasicData(data, locale, i));
}
}
} catch (JSONException e) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java
index 84bf4c88..2f5c882e 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java
@@ -190,7 +190,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) {
- callback.onResult(newPosts, lastItem);
+ if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) {
+ callback.onResult(newPosts, null);
+ } else {
+ callback.onResult(newPosts, lastItem);
+ }
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
}
@@ -265,7 +269,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) {
- callback.onResult(newPosts, lastItem);
+ if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) {
+ callback.onResult(newPosts, null);
+ } else {
+ callback.onResult(newPosts, lastItem);
+ }
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
}
@@ -378,7 +386,7 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
Call<String> getPost;
if(subredditName == null) {
- getPost = api.searchPosts(subredditName, null, RedditUtils.getOAuthHeader(accessToken));
+ getPost = api.searchPosts(query, null, RedditUtils.getOAuthHeader(accessToken));
} else {
getPost = api.searchPostsInSpecificSubreddit(subredditName, query, null, RedditUtils.getOAuthHeader(accessToken));
}
@@ -438,7 +446,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) {
- callback.onResult(newPosts, lastItem);
+ if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) {
+ callback.onResult(newPosts, null);
+ } else {
+ callback.onResult(newPosts, lastItem);
+ }
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java
index 4efc649f..d8a86141 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java
@@ -48,13 +48,16 @@ public interface RedditAPI {
Call<String> getSubredditBestPosts(@Path("subredditName") String subredditName, @Query("after") String lastItem,
@HeaderMap Map<String, String> headers);
- @GET("user/{userName}.json?raw_json=1&limit=25")
- Call<String> getUserBestPosts(@Path("userName") String userName, @Query("after") String lastItem,
+ @GET("user/{username}/submitted.json?raw_json=1&limit=25")
+ Call<String> getUserBestPosts(@Path("username") String username, @Query("after") String lastItem,
@HeaderMap Map<String, String> headers);
@GET("user/{username}/about.json?raw_json=1")
Call<String> getUserData(@Path("username") String username);
+ @GET("user/{username}/comments.json?raw_json=1")
+ Call<String> getUserComments(@Path("username") String username, @Query("after") String after);
+
@FormUrlEncoded
@POST("api/subscribe")
Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SearchActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SearchActivity.java
index 3600bd27..725b50a0 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/SearchActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SearchActivity.java
@@ -4,6 +4,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -99,6 +100,14 @@ public class SearchActivity extends AppCompatActivity {
}
@Override
+ protected void onStart() {
+ super.onStart();
+ simpleSearchView.showSearch(false);
+ simpleSearchView.getSearchEditText().requestFocus();
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ }
+
+ @Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (simpleSearchView.onActivityResult(requestCode, resultCode, data)) {
return;
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditListingRecyclerViewAdapter.java
index 6adaecef..4de52062 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditListingRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditListingRecyclerViewAdapter.java
@@ -208,7 +208,7 @@ public class SubredditListingRecyclerViewAdapter extends PagedListAdapter<Subred
super(itemView);
ButterKnife.bind(this, itemView);
retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore());
- errorTextView.setText(R.string.post_load_comments_failed);
+ errorTextView.setText(R.string.load_comments_failed);
}
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/UserListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/UserListingRecyclerViewAdapter.java
index a67f7415..aa722fc6 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/UserListingRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/UserListingRecyclerViewAdapter.java
@@ -208,7 +208,7 @@ public class UserListingRecyclerViewAdapter extends PagedListAdapter<UserData, R
super(itemView);
ButterKnife.bind(this, itemView);
retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore());
- errorTextView.setText(R.string.post_load_comments_failed);
+ errorTextView.setText(R.string.load_comments_failed);
}
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java
index b08f0831..66e6257f 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java
@@ -15,7 +15,10 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.ViewModelProviders;
+import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
@@ -24,6 +27,7 @@ import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar;
+import com.google.android.material.tabs.TabLayout;
import javax.inject.Inject;
import javax.inject.Named;
@@ -48,7 +52,9 @@ public class ViewUserDetailActivity extends AppCompatActivity {
private static final String IS_IN_LAZY_MODE_STATE = "IILMS";
@BindView(R.id.coordinator_layout_view_user_detail_activity) CoordinatorLayout coordinatorLayout;
+ @BindView(R.id.view_pager_view_user_detail_activity) ViewPager viewPager;
@BindView(R.id.appbar_layout_view_user_detail) AppBarLayout appBarLayout;
+ @BindView(R.id.tab_layout_view_user_detail_activity) TabLayout tabLayout;
@BindView(R.id.collapsing_toolbar_layout_view_user_detail_activity) CollapsingToolbarLayout collapsingToolbarLayout;
@BindView(R.id.banner_image_view_view_user_detail_activity) GifImageView bannerImageView;
@BindView(R.id.icon_gif_image_view_view_user_detail_activity) GifImageView iconGifImageView;
@@ -56,6 +62,8 @@ public class ViewUserDetailActivity extends AppCompatActivity {
@BindView(R.id.subscribe_user_chip_view_user_detail_activity) Chip subscribeUserChip;
@BindView(R.id.karma_text_view_view_user_detail_activity) TextView karmaTextView;
+ private SectionsPagerAdapter sectionsPagerAdapter;
+
private Fragment mFragment;
private SubscribedUserDao subscribedUserDao;
private RequestManager glide;
@@ -66,6 +74,8 @@ public class ViewUserDetailActivity extends AppCompatActivity {
private String userName;
private boolean subscriptionReady = false;
private boolean isInLazyMode = false;
+ private int colorPrimary;
+ private int white;
@Inject
@Named("no_oauth")
@@ -108,6 +118,29 @@ public class ViewUserDetailActivity extends AppCompatActivity {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams();
params.topMargin = statusBarHeight;
+ sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
+ viewPager.setAdapter(sectionsPagerAdapter);
+ viewPager.setOffscreenPageLimit(2);
+ tabLayout.setupWithViewPager(viewPager);
+
+ colorPrimary = getResources().getColor(R.color.colorPrimary);
+ white = getResources().getColor(android.R.color.white);
+
+ appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
+ @Override
+ void onStateChanged(AppBarLayout appBarLayout, State state) {
+ if(state == State.EXPANDED) {
+ tabLayout.setTabTextColors(colorPrimary, colorPrimary);
+ tabLayout.setSelectedTabIndicatorColor(colorPrimary);
+ tabLayout.setBackgroundColor(white);
+ } else if(state == State.COLLAPSED) {
+ tabLayout.setTabTextColors(white, white);
+ tabLayout.setSelectedTabIndicatorColor(white);
+ tabLayout.setBackgroundColor(colorPrimary);
+ }
+ }
+ });
+
subscribedUserDao = SubscribedUserRoomDatabase.getDatabase(this).subscribedUserDao();
glide = Glide.with(this);
@@ -238,23 +271,23 @@ public class ViewUserDetailActivity extends AppCompatActivity {
});
if(savedInstanceState == null) {
- mFragment = new PostFragment();
+ /*mFragment = new PostFragment();
Bundle bundle = new Bundle();
bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName);
bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER);
mFragment.setArguments(bundle);
- getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_user_detail_activity, mFragment).commit();
+ getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_user_detail_activity, mFragment).commit();*/
} else {
- mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE_KEY);
+ /*mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE_KEY);
if(mFragment == null) {
mFragment = new PostFragment();
Bundle bundle = new Bundle();
bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName);
bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER);
mFragment.setArguments(bundle);
- }
+ }*/
isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE);
- getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_user_detail_activity, mFragment).commit();
+ //getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_user_detail_activity, mFragment).commit();
}
}
@@ -321,13 +354,51 @@ public class ViewUserDetailActivity extends AppCompatActivity {
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode);
- getSupportFragmentManager().putFragment(outState, FRAGMENT_OUT_STATE_KEY, mFragment);
+ //getSupportFragmentManager().putFragment(outState, FRAGMENT_OUT_STATE_KEY, mFragment);
}
private void makeSnackbar(int resId) {
Snackbar.make(coordinatorLayout, resId, Snackbar.LENGTH_SHORT).show();
}
+ public abstract static class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
+ // State
+ public enum State {
+ EXPANDED,
+ COLLAPSED,
+ IDLE
+ }
+
+ private State mCurrentState = State.IDLE;
+
+ @Override
+ public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
+ if (i == 0) {
+ if (mCurrentState != State.EXPANDED) {
+ onStateChanged(appBarLayout, State.EXPANDED);
+ }
+ mCurrentState = State.EXPANDED;
+ } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
+ if (mCurrentState != State.COLLAPSED) {
+ onStateChanged(appBarLayout, State.COLLAPSED);
+ }
+ mCurrentState = State.COLLAPSED;
+ } else {
+ if (mCurrentState != State.IDLE) {
+ onStateChanged(appBarLayout, State.IDLE);
+ }
+ mCurrentState = State.IDLE;
+ }
+ }
+
+ /**
+ * Notifies on state change
+ * @param appBarLayout Layout
+ * @param state Collapse state
+ */
+ abstract void onStateChanged(AppBarLayout appBarLayout, State state);
+ }
+
private static class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> {
private UserDao userDao;
@@ -344,4 +415,71 @@ public class ViewUserDetailActivity extends AppCompatActivity {
return null;
}
}
+
+ private class SectionsPagerAdapter extends FragmentPagerAdapter {
+ private PostFragment postFragment;
+ private CommentsListingFragment commentsListingFragment;
+
+ SectionsPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @NonNull
+ @Override
+ public Fragment getItem(int position) {
+ if (position == 0) {
+ PostFragment fragment = new PostFragment();
+ Bundle bundle = new Bundle();
+ bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER);
+ bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+ CommentsListingFragment fragment = new CommentsListingFragment();
+ Bundle bundle = new Bundle();
+ bundle.putString(CommentsListingFragment.EXTRA_USERNAME_KEY, userName);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case 0:
+ return "Posts";
+ case 1:
+ return "Comments";
+ }
+ return null;
+ }
+
+ @NonNull
+ @Override
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ Fragment fragment = (Fragment) super.instantiateItem(container, position);
+ switch (position) {
+ case 0:
+ postFragment = (PostFragment) fragment;
+ break;
+ case 1:
+ commentsListingFragment = (CommentsListingFragment) fragment;
+ break;
+ }
+ return fragment;
+ }
+
+ public void refresh() {
+ if(postFragment != null) {
+ ((FragmentCommunicator) postFragment).refresh();
+ }
+ if(commentsListingFragment != null) {
+ ((FragmentCommunicator) commentsListingFragment).refresh();
+ }
+ }
+ }
}
diff --git a/app/src/main/res/layout/activity_view_user_detail.xml b/app/src/main/res/layout/activity_view_user_detail.xml
index fac8a2ca..67beecd2 100644
--- a/app/src/main/res/layout/activity_view_user_detail.xml
+++ b/app/src/main/res/layout/activity_view_user_detail.xml
@@ -7,6 +7,12 @@
android:id="@+id/coordinator_layout_view_user_detail_activity"
tools:context=".ViewUserDetailActivity">
+ <androidx.viewpager.widget.ViewPager
+ android:id="@+id/view_pager_view_user_detail_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:layout_behavior="@string/appbar_scrolling_view_behavior" />
+
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout_view_user_detail"
android:layout_width="match_parent"
@@ -94,8 +100,20 @@
</com.google.android.material.appbar.CollapsingToolbarLayout>
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tab_layout_view_user_detail_activity"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ app:layout_scrollFlags="scroll|enterAlways"
+ app:tabGravity="fill"
+ app:tabMode="fixed"
+ app:tabIndicatorHeight="3dp"
+ app:tabRippleColor="?attr/colorControlHighlight"
+ app:tabUnboundedRipple="false" />
+
</com.google.android.material.appbar.AppBarLayout>
- <include layout="@layout/content_view_user_detail" />
+ <!--<include layout="@layout/content_view_user_detail" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_comments_listing.xml b/app/src/main/res/layout/fragment_comments_listing.xml
new file mode 100644
index 00000000..bac6f507
--- /dev/null
+++ b/app/src/main/res/layout/fragment_comments_listing.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/coordinator_layout_comments_listing_fragment"
+ tools:context="ml.docilealligator.infinityforreddit.CommentsListingFragment">
+
+ <com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar
+ android:id="@+id/progress_bar_comments_listing_fragment"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp"
+ app:mlpb_progress_stoke_width="3dp"
+ app:mlpb_progress_color="@color/colorAccent"
+ app:mlpb_background_color="@color/circularProgressBarBackground"
+ android:layout_gravity="center_horizontal"/>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/recycler_view_comments_listing_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <LinearLayout
+ android:id="@+id/fetch_comments_info_linear_layout_comments_listing_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:visibility="gone">
+
+ <ImageView
+ android:id="@+id/fetch_comments_info_image_view_comments_listing_fragment"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/fetch_comments_info_text_view_comments_listing_fragment"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:gravity="center" />
+
+ </LinearLayout>
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_load_comments_failed_placeholder.xml b/app/src/main/res/layout/item_load_comments_failed_placeholder.xml
index d81cdb97..f699efd0 100644
--- a/app/src/main/res/layout/item_load_comments_failed_placeholder.xml
+++ b/app/src/main/res/layout/item_load_comments_failed_placeholder.xml
@@ -15,6 +15,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:text="@string/post_load_comments_failed"/>
+ android:text="@string/load_comments_failed"/>
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ba9c2924..76e3f626 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -33,7 +33,7 @@
<string name="no_storage_permission">No storage permission to save this file</string>
<string name="load_posts_failed">Error loading posts</string>
- <string name="post_load_comments_failed">Error loading comments</string>
+ <string name="load_comments_failed">Error loading comments</string>
<string name="retry">Retry</string>
<string name="comments">Comments</string>
<string name="no_comments_yet">No comments yet. Write a comment?</string>