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.

This commit is contained in:
Alex Ning 2019-07-22 00:09:40 +08:00
parent 0d5cf54af5
commit 2f15543f91
22 changed files with 1020 additions and 52 deletions

Binary file not shown.

View File

@ -24,4 +24,5 @@ interface AppComponent {
void inject(PostVideoActivity postVideoActivity); void inject(PostVideoActivity postVideoActivity);
void inject(FlairBottomSheetFragment flairBottomSheetFragment); void inject(FlairBottomSheetFragment flairBottomSheetFragment);
void inject(RulesActivity rulesActivity); void inject(RulesActivity rulesActivity);
void inject(CommentsListingFragment commentsListingFragment);
} }

View File

@ -442,7 +442,7 @@ class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVie
((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments); ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments);
} }
} else if(holder instanceof LoadMoreCommentsFailedViewHolder) { } else if(holder instanceof LoadMoreCommentsFailedViewHolder) {
((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.post_load_comments_failed); ((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.load_comments_failed);
} }
} }

View File

@ -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();
}
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -5,25 +5,20 @@ package ml.docilealligator.infinityforreddit;
*/ */
public class JSONUtils { 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 AFTER_KEY = "after";
static final String MODHASH_KEY = "modhash";
static final String CHILDREN_KEY = "children"; static final String CHILDREN_KEY = "children";
static final String COUNT_KEY = "count"; static final String COUNT_KEY = "count";
static final String TITLE_KEY = "title"; 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 SUBREDDIT_NAME_PREFIX_KEY = "subreddit_name_prefixed";
static final String SELFTEXT_HTML_KEY = "selftext_html"; static final String SELFTEXT_HTML_KEY = "selftext_html";
static final String AUTHOR_KEY = "author"; 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 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 SCORE_KEY = "score";
static final String LIKES_KEY = "likes"; static final String LIKES_KEY = "likes";
static final String NSFW_KEY = "over_18"; static final String NSFW_KEY = "over_18";
static final String GILDED_KEY = "gilded"; static final String GILDED_KEY = "gilded";
static final String POST_HINT_KEY = "post_hint";
static final String PERMALINK_KEY = "permalink"; static final String PERMALINK_KEY = "permalink";
static final String CREATED_UTC_KEY = "created_utc"; static final String CREATED_UTC_KEY = "created_utc";
static final String PREVIEW_KEY = "preview"; static final String PREVIEW_KEY = "preview";
@ -37,12 +32,10 @@ public class JSONUtils {
static final String URL_KEY = "url"; static final String URL_KEY = "url";
static final String MEDIA_KEY = "media"; static final String MEDIA_KEY = "media";
static final String REDDIT_VIDEO_KEY = "reddit_video"; 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 DASH_URL_KEY = "dash_url";
static final String IS_VIDEO_KEY = "is_video"; static final String IS_VIDEO_KEY = "is_video";
static final String CROSSPOST_PARENT_LIST = "crosspost_parent_list"; static final String CROSSPOST_PARENT_LIST = "crosspost_parent_list";
static final String REDDIT_VIDEO_PREVIEW_KEY = "reddit_video_preview"; 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 STICKIED_KEY = "stickied";
static final String BODY_HTML_KEY = "body_html"; static final String BODY_HTML_KEY = "body_html";
static final String COLLAPSED_KEY = "collapsed"; static final String COLLAPSED_KEY = "collapsed";
@ -51,24 +44,22 @@ public class JSONUtils {
static final String DEPTH_KEY = "depth"; static final String DEPTH_KEY = "depth";
static final String ID_KEY = "id"; static final String ID_KEY = "id";
static final String SCORE_HIDDEN_KEY = "score_hidden"; static final String SCORE_HIDDEN_KEY = "score_hidden";
public static final String SUBREDDIT_KEY = "subreddit"; static final String SUBREDDIT_KEY = "subreddit";
public static final String BANNER_IMG_KEY = "banner_img"; static final String BANNER_IMG_KEY = "banner_img";
static final String BANNER_BACKGROUND_IMAGE_KEY = "banner_background_image"; 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"; static final String COMMUNITY_ICON_KEY = "community_icon";
public static final String LINK_KARMA_KEY = "link_karma"; static final String LINK_KARMA_KEY = "link_karma";
public static final String COMMENT_KARMA_KEY = "comment_karma"; static final String COMMENT_KARMA_KEY = "comment_karma";
static final String DISPLAY_NAME = "display_name"; static final String DISPLAY_NAME = "display_name";
static final String SUBREDDIT_TYPE_KEY = "subreddit_type"; static final String SUBREDDIT_TYPE_KEY = "subreddit_type";
static final String SUBREDDIT_TYPE_VALUE_USER = "user"; static final String SUBREDDIT_TYPE_VALUE_USER = "user";
static final String SUBSCRIBERS_KEY = "subscribers"; static final String SUBSCRIBERS_KEY = "subscribers";
static final String PUBLIC_DESCRIPTION_KEY = "public_description"; static final String PUBLIC_DESCRIPTION_KEY = "public_description";
static final String ACTIVE_USER_COUNT_KEY = "active_user_count"; static final String ACTIVE_USER_COUNT_KEY = "active_user_count";
public static final String IS_GOLD_KEY = "is_gold"; static final String IS_GOLD_KEY = "is_gold";
public static final String IS_FRIEND_KEY = "is_friend"; static final String IS_FRIEND_KEY = "is_friend";
static final String KIND_KEY = "kind";
static final String JSON_KEY = "json"; static final String JSON_KEY = "json";
static final String THINGS_KEY = "things";
static final String PARENT_ID_KEY = "parent_id"; static final String PARENT_ID_KEY = "parent_id";
static final String ERRORS_KEY = "errors"; static final String ERRORS_KEY = "errors";
static final String ARGS_KEY = "args"; static final String ARGS_KEY = "args";

View File

@ -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 id = singleCommentData.getString(JSONUtils.ID_KEY);
String fullName = singleCommentData.getString(JSONUtils.NAME_KEY); String fullName = singleCommentData.getString(JSONUtils.NAME_KEY);
String author = singleCommentData.getString(JSONUtils.AUTHOR_KEY); String author = singleCommentData.getString(JSONUtils.AUTHOR_KEY);

View File

@ -90,15 +90,8 @@ class ParsePost {
return null; return null;
} }
String kind = allData.getJSONObject(0).getString(JSONUtils.KIND_KEY); JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY);
if(kind.equals("t3")) { post = parseBasicData(data, locale, -1);
//It's a post
JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY);
post = parseBasicData(data, locale, -1);
} else {
parseFailed = true;
return null;
}
} else { } else {
//Posts listing //Posts listing
int size; int size;
@ -109,12 +102,8 @@ class ParsePost {
} }
for(int i = 0; i < size; i++) { for(int i = 0; i < size; i++) {
String kind = allData.getJSONObject(i).getString(JSONUtils.KIND_KEY); JSONObject data = allData.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
if(kind.equals("t3")) { newPosts.add(parseBasicData(data, locale, i));
//It's a post
JSONObject data = allData.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
newPosts.add(parseBasicData(data, locale, i));
}
} }
} }
} catch (JSONException e) { } catch (JSONException e) {

View File

@ -190,7 +190,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() { ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override @Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) { 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); paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
} }
@ -265,7 +269,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() { ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override @Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) { 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); paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
} }
@ -378,7 +386,7 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
Call<String> getPost; Call<String> getPost;
if(subredditName == null) { if(subredditName == null) {
getPost = api.searchPosts(subredditName, null, RedditUtils.getOAuthHeader(accessToken)); getPost = api.searchPosts(query, null, RedditUtils.getOAuthHeader(accessToken));
} else { } else {
getPost = api.searchPostsInSpecificSubreddit(subredditName, query, null, RedditUtils.getOAuthHeader(accessToken)); 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() { ParsePost.parsePosts(response.body(), locale, -1, new ParsePost.ParsePostsListingListener() {
@Override @Override
public void onParsePostsListingSuccess(ArrayList<Post> newPosts, String lastItem) { 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); paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
} }

View File

@ -48,13 +48,16 @@ public interface RedditAPI {
Call<String> getSubredditBestPosts(@Path("subredditName") String subredditName, @Query("after") String lastItem, Call<String> getSubredditBestPosts(@Path("subredditName") String subredditName, @Query("after") String lastItem,
@HeaderMap Map<String, String> headers); @HeaderMap Map<String, String> headers);
@GET("user/{userName}.json?raw_json=1&limit=25") @GET("user/{username}/submitted.json?raw_json=1&limit=25")
Call<String> getUserBestPosts(@Path("userName") String userName, @Query("after") String lastItem, Call<String> getUserBestPosts(@Path("username") String username, @Query("after") String lastItem,
@HeaderMap Map<String, String> headers); @HeaderMap Map<String, String> headers);
@GET("user/{username}/about.json?raw_json=1") @GET("user/{username}/about.json?raw_json=1")
Call<String> getUserData(@Path("username") String username); 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 @FormUrlEncoded
@POST("api/subscribe") @POST("api/subscribe")
Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);

View File

@ -4,6 +4,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@ -98,6 +99,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 @Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (simpleSearchView.onActivityResult(requestCode, resultCode, data)) { if (simpleSearchView.onActivityResult(requestCode, resultCode, data)) {

View File

@ -208,7 +208,7 @@ public class SubredditListingRecyclerViewAdapter extends PagedListAdapter<Subred
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore()); retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore());
errorTextView.setText(R.string.post_load_comments_failed); errorTextView.setText(R.string.load_comments_failed);
} }
} }

View File

@ -208,7 +208,7 @@ public class UserListingRecyclerViewAdapter extends PagedListAdapter<UserData, R
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore()); retryButton.setOnClickListener(view -> retryLoadingMoreCallback.retryLoadingMore());
errorTextView.setText(R.string.post_load_comments_failed); errorTextView.setText(R.string.load_comments_failed);
} }
} }

View File

@ -15,7 +15,10 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager.widget.ViewPager;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager; 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.appbar.CollapsingToolbarLayout;
import com.google.android.material.chip.Chip; import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -48,7 +52,9 @@ public class ViewUserDetailActivity extends AppCompatActivity {
private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; private static final String IS_IN_LAZY_MODE_STATE = "IILMS";
@BindView(R.id.coordinator_layout_view_user_detail_activity) CoordinatorLayout coordinatorLayout; @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.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.collapsing_toolbar_layout_view_user_detail_activity) CollapsingToolbarLayout collapsingToolbarLayout;
@BindView(R.id.banner_image_view_view_user_detail_activity) GifImageView bannerImageView; @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; @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.subscribe_user_chip_view_user_detail_activity) Chip subscribeUserChip;
@BindView(R.id.karma_text_view_view_user_detail_activity) TextView karmaTextView; @BindView(R.id.karma_text_view_view_user_detail_activity) TextView karmaTextView;
private SectionsPagerAdapter sectionsPagerAdapter;
private Fragment mFragment; private Fragment mFragment;
private SubscribedUserDao subscribedUserDao; private SubscribedUserDao subscribedUserDao;
private RequestManager glide; private RequestManager glide;
@ -66,6 +74,8 @@ public class ViewUserDetailActivity extends AppCompatActivity {
private String userName; private String userName;
private boolean subscriptionReady = false; private boolean subscriptionReady = false;
private boolean isInLazyMode = false; private boolean isInLazyMode = false;
private int colorPrimary;
private int white;
@Inject @Inject
@Named("no_oauth") @Named("no_oauth")
@ -108,6 +118,29 @@ public class ViewUserDetailActivity extends AppCompatActivity {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams();
params.topMargin = statusBarHeight; 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(); subscribedUserDao = SubscribedUserRoomDatabase.getDatabase(this).subscribedUserDao();
glide = Glide.with(this); glide = Glide.with(this);
@ -238,23 +271,23 @@ public class ViewUserDetailActivity extends AppCompatActivity {
}); });
if(savedInstanceState == null) { if(savedInstanceState == null) {
mFragment = new PostFragment(); /*mFragment = new PostFragment();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName); bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName);
bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER); bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER);
mFragment.setArguments(bundle); 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 { } else {
mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE_KEY); /*mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE_KEY);
if(mFragment == null) { if(mFragment == null) {
mFragment = new PostFragment(); mFragment = new PostFragment();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName); bundle.putString(PostFragment.EXTRA_SUBREDDIT_NAME_KEY, userName);
bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER); bundle.putInt(PostFragment.EXTRA_POST_TYPE_KEY, PostDataSource.TYPE_USER);
mFragment.setArguments(bundle); mFragment.setArguments(bundle);
} }*/
isInLazyMode = savedInstanceState.getBoolean(IS_IN_LAZY_MODE_STATE); 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) { protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putBoolean(IS_IN_LAZY_MODE_STATE, isInLazyMode); 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) { private void makeSnackbar(int resId) {
Snackbar.make(coordinatorLayout, resId, Snackbar.LENGTH_SHORT).show(); 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 static class InsertUserDataAsyncTask extends AsyncTask<Void, Void, Void> {
private UserDao userDao; private UserDao userDao;
@ -344,4 +415,71 @@ public class ViewUserDetailActivity extends AppCompatActivity {
return null; 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();
}
}
}
} }

View File

@ -7,6 +7,12 @@
android:id="@+id/coordinator_layout_view_user_detail_activity" android:id="@+id/coordinator_layout_view_user_detail_activity"
tools:context=".ViewUserDetailActivity"> 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 <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_layout_view_user_detail" android:id="@+id/appbar_layout_view_user_detail"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -94,8 +100,20 @@
</com.google.android.material.appbar.CollapsingToolbarLayout> </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> </com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_view_user_detail" /> <!--<include layout="@layout/content_view_user_detail" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -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>

View File

@ -15,6 +15,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:text="@string/post_load_comments_failed"/> android:text="@string/load_comments_failed"/>
</LinearLayout> </LinearLayout>

View File

@ -33,7 +33,7 @@
<string name="no_storage_permission">No storage permission to save this file</string> <string name="no_storage_permission">No storage permission to save this file</string>
<string name="load_posts_failed">Error loading posts</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="retry">Retry</string>
<string name="comments">Comments</string> <string name="comments">Comments</string>
<string name="no_comments_yet">No comments yet. Write a comment?</string> <string name="no_comments_yet">No comments yet. Write a comment?</string>