Add a feature which is refreshing the posts by clicking the refresh button. Minor bugs fixed. Rewrite some code.

This commit is contained in:
Alex Ning 2018-09-24 17:03:57 +08:00
parent a7d4485fc1
commit bfb311d75f
13 changed files with 223 additions and 88 deletions

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="vectorWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="vectorAssetStep">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="clipartAsset">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/home/alex/Android%20Studio/plugins/android/lib/android.jar!/images/material_design_icons/navigation/ic_refresh_black_24dp.xml" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
<option name="values">
<map>
<entry key="color" value="ffffff" />
<entry key="outputName" value="ic_refresh_white_24dp" />
<entry key="sourceFile" value="$USER_HOME$" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@ -0,0 +1,5 @@
package ml.docilealligator.infinityforreddit;
interface FragmentCommunicator {
void refresh();
}

View File

@ -16,6 +16,8 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@ -55,6 +57,8 @@ public class MainActivity extends AppCompatActivity {
private boolean mFetchUserInfoSuccess;
private boolean mInsertSuccess;
private FragmentCommunicator mFragmentCommunicator;
private SubscribedSubredditViewModel mSubscribedSubredditViewModel;
private SubscribedUserViewModel mSubscribedUserViewModel;
@ -254,6 +258,24 @@ public class MainActivity extends AppCompatActivity {
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_activity, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh_main_activity:
if(mFragment instanceof FragmentCommunicator) {
((FragmentCommunicator) mFragment).refresh();
}
return true;
}
return false;
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);

View File

@ -10,9 +10,10 @@ class PaginationSynchronizer implements Parcelable {
private PaginationRetryNotifier paginationRetryNotifier;
private LastItemSynchronizer lastItemSynchronizer;
PaginationSynchronizer() {
PaginationSynchronizer(LastItemSynchronizer lastItemSynchronizer) {
loadingState = false;
loadSuccess = true;
this. lastItemSynchronizer = lastItemSynchronizer;
}
protected PaginationSynchronizer(Parcel in) {

View File

@ -6,7 +6,6 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
@ -33,61 +32,36 @@ import retrofit2.converter.scalars.ScalarsConverterFactory;
/**
* A simple {@link Fragment} subclass.
*/
public class PostFragment extends Fragment {
public class PostFragment extends Fragment implements FragmentCommunicator {
static final String SUBREDDIT_NAME_KEY = "SNK";
static final String IS_BEST_POST_KEY = "IBPK";
private static final String PostDataParcelableState = "BPDPS";
private static final String lastItemState = "LIS";
private static final String paginationSynchronizerState = "PSS";
private CoordinatorLayout mCoordinatorLayout;
private RecyclerView mPostRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
private ProgressBar mProgressBar;
private ArrayList<PostData> mPostData;
private String mLastItem;
private PaginationSynchronizer mPaginationSynchronizer;
private PostRecyclerViewAdapter mAdapter;
private LinearLayout mFetchPostErrorLinearLayout;
private ImageView mFetchPostErrorImageView;
private ArrayList<PostData> mPostData;
private String mLastItem;
private PaginationSynchronizer mPaginationSynchronizer;
private boolean mIsBestPost;
private String mSubredditName;
private String PostDataParcelableState = "BPDPS";
private String lastItemState = "LIS";
private String paginationSynchronizerState = "PSS";
public PostFragment() {
// Required empty public constructor
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState != null) {
if(savedInstanceState.containsKey(PostDataParcelableState)) {
mPostData = savedInstanceState.getParcelableArrayList(PostDataParcelableState);
mLastItem = savedInstanceState.getString(lastItemState);
mAdapter = new PostRecyclerViewAdapter(getActivity(), mPostData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, mLastItem, mPostData,
mPaginationSynchronizer, mSubredditName, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale));
mProgressBar.setVisibility(View.GONE);
} else {
if(mIsBestPost) {
fetchBestPost(1);
} else {
fetchPost();
}
}
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if(mPostData != null) {
outState.putParcelableArrayList(PostDataParcelableState, mPostData);
outState.putString(lastItemState, mLastItem);
@ -98,13 +72,13 @@ public class PostFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
if(mAdapter != null) {
mAdapter.setCanStartActivity(true);
if(mPostRecyclerView.getAdapter() != null) {
((PostRecyclerViewAdapter) mPostRecyclerView.getAdapter()).setCanStartActivity(true);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_post, container, false);
@ -140,10 +114,25 @@ public class PostFragment extends Fragment {
});
}
if(savedInstanceState != null && savedInstanceState.getParcelable(paginationSynchronizerState) != null) {
if(savedInstanceState != null && savedInstanceState.containsKey(PostDataParcelableState)) {
mPostData = savedInstanceState.getParcelableArrayList(PostDataParcelableState);
mLastItem = savedInstanceState.getString(lastItemState);
mPaginationSynchronizer = savedInstanceState.getParcelable(paginationSynchronizerState);
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), mPostData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(adapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, adapter, mLastItem, mPostData,
mPaginationSynchronizer, mSubredditName, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale));
mProgressBar.setVisibility(View.GONE);
} else {
mPaginationSynchronizer = new PaginationSynchronizer();
mPaginationSynchronizer = new PaginationSynchronizer(new LastItemSynchronizer() {
@Override
public void lastItemChanged(String lastItem) {
mLastItem = lastItem;
}
});
if(mIsBestPost) {
fetchBestPost(1);
} else {
@ -151,14 +140,6 @@ public class PostFragment extends Fragment {
}
}
LastItemSynchronizer lastItemSynchronizer = new LastItemSynchronizer() {
@Override
public void lastItemChanged(String lastItem) {
mLastItem = lastItem;
}
};
mPaginationSynchronizer.setLastItemSynchronizer(lastItemSynchronizer);
return rootView;
}
@ -197,11 +178,11 @@ public class PostFragment extends Fragment {
if(isAdded() && getActivity() != null) {
mPostData = postData;
mLastItem = lastItem;
mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.setAdapter(adapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData,
getActivity(), mLinearLayoutManager, adapter, lastItem, postData,
mPaginationSynchronizer, mSubredditName, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale));
@ -269,11 +250,11 @@ public class PostFragment extends Fragment {
if(isAdded() && getActivity() != null) {
mPostData = postData;
mLastItem = lastItem;
mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
PostRecyclerViewAdapter adapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.setAdapter(adapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData,
getActivity(), mLinearLayoutManager, adapter, lastItem, postData,
mPaginationSynchronizer, mSubredditName, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale));
@ -304,8 +285,10 @@ public class PostFragment extends Fragment {
private void showErrorView() {
mProgressBar.setVisibility(View.GONE);
if(mIsBestPost) {
mFetchPostErrorLinearLayout.setVisibility(View.VISIBLE);
Glide.with(this).load(R.drawable.load_post_error_indicator).into(mFetchPostErrorImageView);
if(getActivity() != null && isAdded()) {
mFetchPostErrorLinearLayout.setVisibility(View.VISIBLE);
Glide.with(this).load(R.drawable.load_post_error_indicator).into(mFetchPostErrorImageView);
}
} else {
Snackbar snackbar = Snackbar.make(mCoordinatorLayout, "Error getting post", Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, new View.OnClickListener() {
@ -321,4 +304,29 @@ public class PostFragment extends Fragment {
snackbar.show();
}
}
@Override
public void refresh() {
mLastItem = null;
mPaginationSynchronizer = new PaginationSynchronizer(new LastItemSynchronizer() {
@Override
public void lastItemChanged(String lastItem) {
mLastItem = lastItem;
}
});
mPostRecyclerView.clearOnScrollListeners();
mPostRecyclerView.getRecycledViewPool().clear();
if(mPostData != null) {
mPostData.clear();
}
mPostData = null;
if(mPostRecyclerView.getAdapter() != null) {
(mPostRecyclerView.getAdapter()).notifyDataSetChanged();
}
if(mIsBestPost) {
fetchBestPost(1);
} else {
fetchPost();
}
}
}

View File

@ -117,14 +117,16 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
ParsePost.parsePost(response.body(), mPostData, locale, new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) {
mAdapter.notifyItemRangeInserted(mPostData.size(), postData.size());
mLastItem = lastItem;
mLastItemSynchronizer.lastItemChanged(mLastItem);
if(mAdapter != null) {
mAdapter.notifyItemRangeInserted(mPostData.size(), postData.size());
mLastItem = lastItem;
mLastItemSynchronizer.lastItemChanged(lastItem);
isLoading = false;
loadSuccess = true;
mPaginationSynchronizer.setLoading(false);
mPaginationSynchronizer.setLoadingState(true);
isLoading = false;
loadSuccess = true;
mPaginationSynchronizer.setLoading(false);
mPaginationSynchronizer.setLoadingState(true);
}
}
@Override
@ -188,14 +190,16 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
ParsePost.parsePost(response.body(), mPostData, locale, new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) {
mAdapter.notifyItemRangeInserted(mPostData.size(), postData.size());
mLastItem = lastItem;
mLastItemSynchronizer.lastItemChanged(mLastItem);
if(mAdapter != null) {
mAdapter.notifyItemRangeInserted(mPostData.size(), postData.size());
mLastItem = lastItem;
mLastItemSynchronizer.lastItemChanged(lastItem);
isLoading = false;
loadSuccess = true;
mPaginationSynchronizer.setLoading(false);
mPaginationSynchronizer.setLoadingState(true);
isLoading = false;
loadSuccess = true;
mPaginationSynchronizer.setLoading(false);
mPaginationSynchronizer.setLoadingState(true);
}
}
@Override

View File

@ -83,10 +83,10 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
if(holder instanceof DataViewHolder) {
if(mPostData.get(position) == null) {
Log.i("is null", Integer.toString(position));
if(mPostData.get(holder.getAdapterPosition()) == null) {
Log.i("is null", Integer.toString(holder.getAdapterPosition()));
} else {
final int adapterPosition = holder.getAdapterPosition();
final String id = mPostData.get(adapterPosition).getFullName();
@ -103,15 +103,17 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
new LoadSubredditIconAsyncTask.LoadSubredditIconAsyncTaskListener() {
@Override
public void loadIconSuccess(String iconImageUrl) {
if(!iconImageUrl.equals("")) {
Glide.with(mContext).load(iconImageUrl)
.into(((DataViewHolder) holder).subredditIconCircleImageView);
} else {
Glide.with(mContext).load(R.drawable.subreddit_default_icon)
.into(((DataViewHolder) holder).subredditIconCircleImageView);
}
if(mContext != null && !mPostData.isEmpty()) {
if(!iconImageUrl.equals("")) {
Glide.with(mContext).load(iconImageUrl)
.into(((DataViewHolder) holder).subredditIconCircleImageView);
} else {
Glide.with(mContext).load(R.drawable.subreddit_default_icon)
.into(((DataViewHolder) holder).subredditIconCircleImageView);
}
mPostData.get(adapterPosition).setSubredditIconUrl(iconImageUrl);
mPostData.get(adapterPosition).setSubredditIconUrl(iconImageUrl);
}
}
}).execute();
} else if(!mPostData.get(position).getSubredditIconUrl().equals("")) {
@ -253,7 +255,7 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
builder.addDefaultShareMenuItem();
builder.setToolbarColor(mContext.getResources().getColor(R.color.colorPrimary));
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(mContext, Uri.parse(mPostData.get(position).getUrl()));
customTabsIntent.launchUrl(mContext, Uri.parse(mPostData.get(holder.getAdapterPosition()).getUrl()));
}
});
break;
@ -482,6 +484,9 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
@Override
public int getItemCount() {
if(mPostData == null || mPostData.isEmpty()) {
return 0;
}
return mPostData.size() + 1;
}

View File

@ -37,11 +37,13 @@ class SubscribedSubredditRecyclerViewAdapter extends RecyclerView.Adapter<Recycl
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getName());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getId());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, true);
mContext.startActivity(intent);
if(viewHolder.getAdapterPosition() >= 0) {
Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getName());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_VALUE_KEY, mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getId());
intent.putExtra(ViewSubredditDetailActivity.EXTRA_QUERY_BY_ID_KEY, true);
mContext.startActivity(intent);
}
}
});
if(!mSubscribedSubredditData.get(i).getIconUrl().equals("")) {

View File

@ -11,6 +11,7 @@ import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -195,12 +196,22 @@ public class ViewSubredditDetailActivity extends AppCompatActivity {
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.view_subreddit_detail_activity, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.action_refresh_view_subreddit_detail_activity:
if(mFragment instanceof FragmentCommunicator) {
((FragmentCommunicator) mFragment).refresh();
}
}
return false;
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="ml.docilealligator.infinityforreddit.MainActivity">
<item
android:id="@+id/action_refresh_main_activity"
android:orderInCategory="1"
android:title="@string/action_refresh"
android:icon="@drawable/ic_refresh_white_24dp"
app:showAsAction="always" />
</menu>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="ml.docilealligator.infinityforreddit.ViewSubredditDetailActivity">
<item
android:id="@+id/action_refresh_view_subreddit_detail_activity"
android:orderInCategory="1"
android:title="@string/action_refresh"
android:icon="@drawable/ic_refresh_white_24dp"
app:showAsAction="always" />
</menu>

View File

@ -7,6 +7,7 @@
<string name="action_settings">Settings</string>
<string name="action_download">Download</string>
<string name="action_refresh">Refresh</string>
<string name="load_posts_error">Error loading posts.\nTap to retry.</string>