Browse Source

UnreadFragment improvements

pull/68/head
Ezerous 5 years ago
parent
commit
cad2497259
No known key found for this signature in database GPG Key ID: 262B2954BBA319E3
  1. 116
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java
  2. 120
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java
  3. 5
      app/src/main/res/drawable/ic_mark_as_read.xml
  4. 60
      app/src/main/res/layout/fragment_unread.xml
  5. 19
      app/src/main/res/layout/fragment_unread_empty_row.xml
  6. 17
      app/src/main/res/layout/fragment_unread_mark_read_row.xml
  7. 1
      app/src/main/res/values/strings.xml

116
app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java

@ -20,91 +20,50 @@ import timber.log.Timber;
class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<TopicSummary> unreadList; private final List<TopicSummary> unreadList;
private final UnreadFragment.UnreadFragmentInteractionListener mListener; private final UnreadFragment.UnreadFragmentInteractionListener mListener;
private final MarkReadInteractionListener markReadListener;
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_NADA = 1;
private final int VIEW_TYPE_MARK_READ = 2;
UnreadAdapter(@NonNull List<TopicSummary> topicSummaryList, UnreadAdapter(@NonNull List<TopicSummary> topicSummaryList,
BaseFragment.FragmentInteractionListener listener, BaseFragment.FragmentInteractionListener listener) {
MarkReadInteractionListener markReadInteractionListener) {
this.unreadList = topicSummaryList; this.unreadList = topicSummaryList;
mListener = (UnreadFragment.UnreadFragmentInteractionListener) listener; mListener = (UnreadFragment.UnreadFragmentInteractionListener) listener;
markReadListener = markReadInteractionListener;
}
@Override
public int getItemViewType(int position) {
if (unreadList.get(position).getLastPostDateTime() == null) return VIEW_TYPE_MARK_READ;
return unreadList.get(position).getTopicUrl() == null ? VIEW_TYPE_NADA : VIEW_TYPE_ITEM;
} }
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) { View view = LayoutInflater.from(parent.getContext())
View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.fragment_unread_row, parent, false);
.inflate(R.layout.fragment_unread_row, parent, false); return new ViewHolder(view);
return new ViewHolder(view);
} else if (viewType == VIEW_TYPE_NADA) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_unread_empty_row, parent, false);
return new EmptyViewHolder(view);
} else if (viewType == VIEW_TYPE_MARK_READ) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_unread_mark_read_row, parent, false);
return new MarkReadViewHolder(view);
}
return null;
} }
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
TopicSummary topicSummary = unreadList.get(holder.getAdapterPosition()); TopicSummary topicSummary = unreadList.get(holder.getAdapterPosition());
if (holder instanceof UnreadAdapter.EmptyViewHolder) { final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder;
final UnreadAdapter.EmptyViewHolder emptyViewHolder = (UnreadAdapter.EmptyViewHolder) holder;
emptyViewHolder.text.setText(topicSummary.getLastPostDateTime());
} else if (holder instanceof UnreadAdapter.ViewHolder) {
final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder;
viewHolder.mTitleView.setText(topicSummary.getSubject()); viewHolder.mTitleView.setText(topicSummary.getSubject());
if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){ if(BaseApplication.getInstance().isDisplayRelativeTimeEnabled()){
String timestamp = topicSummary.getLastPostTimestamp(); String timestamp = topicSummary.getLastPostTimestamp();
try{ try{
viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp));
}
catch(NumberFormatException e){
Timber.e(e, "Invalid number format: %s", timestamp);
viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());
}
} }
else catch(NumberFormatException e){
Timber.e(e, "Invalid number format: %s", timestamp);
viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());
}
}
else
viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());
viewHolder.mUserView.setText(topicSummary.getLastUser()); viewHolder.mUserView.setText(topicSummary.getLastUser());
viewHolder.topic = topicSummary; viewHolder.topic = topicSummary;
viewHolder.mView.setOnClickListener(v -> {
if (null != mListener) {
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mListener.onUnreadFragmentInteraction(viewHolder.topic); //?
}
});
} else if (holder instanceof UnreadAdapter.MarkReadViewHolder) {
final UnreadAdapter.MarkReadViewHolder markReadViewHolder = (UnreadAdapter.MarkReadViewHolder) holder;
markReadViewHolder.text.setText(unreadList.get(holder.getAdapterPosition()).getSubject());
markReadViewHolder.topic = unreadList.get(holder.getAdapterPosition());
markReadViewHolder.mView.setOnClickListener(v -> { viewHolder.mView.setOnClickListener(v -> {
if (null != mListener) { if (null != mListener) {
// Notify the active callbacks interface (the activity, if the // Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected. // fragment is attached to one) that an item has been selected.
markReadListener.onMarkReadInteraction(unreadList.get(holder.getAdapterPosition()).getTopicUrl()); mListener.onUnreadFragmentInteraction(viewHolder.topic); //?
} }
}); });
}
} }
@Override @Override
@ -127,29 +86,4 @@ class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
mDateTimeView = view.findViewById(R.id.dateTime); mDateTimeView = view.findViewById(R.id.dateTime);
} }
} }
private static class EmptyViewHolder extends RecyclerView.ViewHolder {
final TextView text;
EmptyViewHolder(View view) {
super(view);
text = view.findViewById(R.id.text);
}
}
private static class MarkReadViewHolder extends RecyclerView.ViewHolder {
final View mView;
final TextView text;
public TopicSummary topic;
MarkReadViewHolder(View view) {
super(view);
mView = view;
text = view.findViewById(R.id.mark_read);
}
}
interface MarkReadInteractionListener {
void onMarkReadInteraction(String markReadLinkUrl);
}
} }

120
app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java

@ -7,14 +7,18 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
@ -50,9 +54,13 @@ public class UnreadFragment extends BaseFragment {
private MaterialProgressBar progressBar; private MaterialProgressBar progressBar;
private SwipeRefreshLayout swipeRefreshLayout; private SwipeRefreshLayout swipeRefreshLayout;
private FloatingActionButton markAsReadFAB;
private TextView noUnreadTopicsTextView;
private UnreadAdapter unreadAdapter; private UnreadAdapter unreadAdapter;
private List<TopicSummary> topicSummaries; private List<TopicSummary> topicSummaries;
private String markAsReadUrl = "";
private int numberOfPages = 0; private int numberOfPages = 0;
private int loadedPages = 0; private int loadedPages = 0;
@ -103,15 +111,21 @@ public class UnreadFragment extends BaseFragment {
final View rootView = inflater.inflate(R.layout.fragment_unread, container, false); final View rootView = inflater.inflate(R.layout.fragment_unread, container, false);
// Set the adapter // Set the adapter
if (rootView instanceof RelativeLayout) { if (rootView instanceof CoordinatorLayout) {
progressBar = rootView.findViewById(R.id.progressBar); progressBar = rootView.findViewById(R.id.progressBar);
unreadAdapter = new UnreadAdapter(topicSummaries, noUnreadTopicsTextView = rootView.findViewById(R.id.no_unread_topics);
fragmentInteractionListener, markReadLinkUrl -> { markAsReadFAB = rootView.findViewById(R.id.unread_fab);
if (!markReadTask.isRunning() && !unreadTask.isRunning()) {
markReadTask = new MarkReadTask(); if(topicSummaries.isEmpty()){
markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markReadLinkUrl); hideMarkAsReadFAB();
} noUnreadTopicsTextView.setVisibility(View.VISIBLE);
}); }
else{
noUnreadTopicsTextView.setVisibility(View.INVISIBLE);
showMarkAsReadFAB();
}
unreadAdapter = new UnreadAdapter(topicSummaries, fragmentInteractionListener);
CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
@ -155,20 +169,56 @@ public class UnreadFragment extends BaseFragment {
void onUnreadFragmentInteraction(TopicSummary topicSummary); void onUnreadFragmentInteraction(TopicSummary topicSummary);
} }
private void showMarkAsReadFAB() {
markAsReadFAB.setOnClickListener(v -> {
if (!markReadTask.isRunning() && !unreadTask.isRunning())
showMarkAsReadConfirmationDialog();
});
markAsReadFAB.show();
markAsReadFAB.setTag(true);
}
private void hideMarkAsReadFAB() {
markAsReadFAB.setOnClickListener(null);
markAsReadFAB.hide();
markAsReadFAB.setTag(false);
}
private void showMarkAsReadConfirmationDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
builder.setTitle("Mark all as read");
builder.setMessage("Are you sure that you want to mark ALL topics as read?");
builder.setPositiveButton("Yep", (dialogInterface, i) -> {
markReadTask = new MarkReadTask();
markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl);
});
builder.setNegativeButton("Nope", (dialogInterface, i) -> {});
builder.create().show();
}
//---------------------------------------ASYNC TASK----------------------------------- //---------------------------------------ASYNC TASK-----------------------------------
private void onUnreadTaskStarted() { private void onUnreadTaskStarted() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
} }
private void onUnreadTaskFinished(int resultCode, ArrayList<TopicSummary> fetchedUnread) { private void onUnreadTaskFinished(int resultCode, UnreadTaskData unreadTaskData) {
if (resultCode == NetworkResultCodes.SUCCESSFUL) { if (resultCode == NetworkResultCodes.SUCCESSFUL) {
if(fetchedUnread!=null && !fetchedUnread.isEmpty()){ ArrayList<TopicSummary> fetchedUnread = unreadTaskData.getTopicSummaries();
if(!fetchedUnread.isEmpty()){
if(loadedPages==0) if(loadedPages==0)
topicSummaries.clear(); topicSummaries.clear();
topicSummaries.addAll(fetchedUnread); topicSummaries.addAll(fetchedUnread);
unreadAdapter.notifyDataSetChanged(); markAsReadUrl = unreadTaskData.getMarkAsReadUrl();
noUnreadTopicsTextView.setVisibility(View.INVISIBLE);
showMarkAsReadFAB();
}
else {
topicSummaries.clear();
hideMarkAsReadFAB();
noUnreadTopicsTextView.setVisibility(View.VISIBLE);
} }
unreadAdapter.notifyDataSetChanged();
loadedPages++; loadedPages++;
if (loadedPages < numberOfPages) { if (loadedPages < numberOfPages) {
unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished); unreadTask = new UnreadTask(this::onUnreadTaskStarted, this::onUnreadTaskFinished);
@ -191,18 +241,17 @@ public class UnreadFragment extends BaseFragment {
} }
} }
private class UnreadTask extends NewParseTask<ArrayList<TopicSummary>> { private class UnreadTask extends NewParseTask<UnreadTaskData> {
UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<UnreadTaskData> onParseTaskFinishedListener) {
UnreadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<ArrayList<TopicSummary>> onParseTaskFinishedListener) {
super(onTaskStartedListener, onParseTaskFinishedListener); super(onTaskStartedListener, onParseTaskFinishedListener);
} }
@Override @Override
protected ArrayList<TopicSummary> parse(Document document, Response response) throws ParseException { protected UnreadTaskData parse(Document document, Response response) throws ParseException {
Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)");
ArrayList<TopicSummary> fetchedTopicSummaries = new ArrayList<>(); ArrayList<TopicSummary> fetchedTopicSummaries = new ArrayList<>();
String markAsReadUrl="";
if (!unread.isEmpty()) { if (!unread.isEmpty()) {
//topicSummaries.clear();
for (Element row : unread) { for (Element row : unread) {
Elements information = row.select("td"); Elements information = row.select("td");
String link = information.last().select("a").first().attr("href"); String link = information.last().select("a").first().attr("href");
@ -222,7 +271,6 @@ public class UnreadFragment extends BaseFragment {
Element pagesElement = null, markRead = null; Element pagesElement = null, markRead = null;
if (topBar != null) { if (topBar != null) {
pagesElement = topBar.select("td.middletext").first(); pagesElement = topBar.select("td.middletext").first();
markRead = document.select("table:not(.bordercolor):not([width])").select("a") markRead = document.select("table:not(.bordercolor):not([width])").select("a")
.first(); .first();
} }
@ -236,26 +284,38 @@ public class UnreadFragment extends BaseFragment {
} }
if (markRead != null && loadedPages == numberOfPages - 1) if (markRead != null && loadedPages == numberOfPages - 1)
fetchedTopicSummaries.add(new TopicSummary(markRead.attr("href"), markRead.text(), null, markAsReadUrl = markRead.attr("href");
null));
} else { return new UnreadTaskData(fetchedTopicSummaries, markAsReadUrl);
String message = document.select("table.bordercolor[cellspacing=1]").first().text();
if (message.contains("No messages")) { //It's english
message = "No unread posts!";
} else { //It's greek
message = "Δεν υπάρχουν μη αναγνωσμένα μηνύματα!";
}
fetchedTopicSummaries.add(new TopicSummary(null, null, null, message));
} }
return fetchedTopicSummaries;
return new UnreadTaskData(new ArrayList<>(), markAsReadUrl);
} }
@Override @Override
protected int getResultCode(Response response, ArrayList<TopicSummary> data) { protected int getResultCode(Response response, UnreadTaskData data) {
return NetworkResultCodes.SUCCESSFUL; return NetworkResultCodes.SUCCESSFUL;
} }
} }
private class UnreadTaskData {
ArrayList<TopicSummary> topicSummaries;
String markAsReadUrl;
UnreadTaskData(ArrayList<TopicSummary> topicSummaries, String markAsReadUrl){
this.topicSummaries = topicSummaries;
this.markAsReadUrl = markAsReadUrl;
}
ArrayList<TopicSummary> getTopicSummaries() {
return topicSummaries;
}
String getMarkAsReadUrl() {
return markAsReadUrl;
}
}
private class MarkReadTask extends AsyncTask<String, Void, Integer> { private class MarkReadTask extends AsyncTask<String, Void, Integer> {
private static final int SUCCESS = 0; private static final int SUCCESS = 0;
private static final int NETWORK_ERROR = 1; private static final int NETWORK_ERROR = 1;

5
app/src/main/res/drawable/ic_mark_as_read.xml

@ -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="M14,10L2,10v2h12v-2zM14,6L2,6v2h12L14,6zM2,16h8v-2L2,14v2zM21.5,11.5L23,13l-6.99,7 -4.51,-4.5L13,14l3.01,3 5.49,-5.5z"/>
</vector>

60
app/src/main/res/layout/fragment_unread.xml

@ -1,28 +1,45 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:background="@color/background">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <RelativeLayout
android:id="@+id/swiperefresh" android:id="@+id/relativeLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<gr.thmmy.mthmmy.utils.CustomRecyclerView <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/list" android:id="@+id/swiperefresh"
android:name="gr.thmmy.mthmmy.sections.unread.UnreadFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:background="@color/background"
android:paddingBottom="4dp" <gr.thmmy.mthmmy.utils.CustomRecyclerView
android:paddingTop="4dp" android:id="@+id/list"
app:layoutManager="LinearLayoutManager" android:name="gr.thmmy.mthmmy.sections.unread.UnreadFragment"
tools:context=".activities.main.unread.UnreadFragment" android:layout_width="match_parent"
tools:listitem="@layout/fragment_unread_row"/> android:layout_height="match_parent"
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> android:background="@color/background"
android:paddingTop="4dp"
android:paddingBottom="4dp"
app:layoutManager="LinearLayoutManager"
tools:context=".activities.main.unread.UnreadFragment"
tools:listitem="@layout/fragment_unread_row" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</RelativeLayout>
<TextView
android:id="@+id/no_unread_topics"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:text="@string/no_unread_topics"
android:textColor="@color/primary_text"
app:layout_anchor="@+id/relativeLayout"
app:layout_anchorGravity="center" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar <me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
@ -35,4 +52,13 @@
app:mpb_indeterminateTint="@color/accent" app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal"/> app:mpb_progressStyle="horizontal"/>
</RelativeLayout> <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/unread_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margins"
android:layout_marginBottom="@dimen/fab_margins"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_mark_as_read" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

19
app/src/main/res/layout/fragment_unread_empty_row.xml

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="6dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="20dp">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAlignment="center"
android:textColor="@color/accent"
android:textSize="@dimen/big_text" />
</LinearLayout>

17
app/src/main/res/layout/fragment_unread_mark_read_row.xml

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/mark_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="10dp"
android:paddingStart="10dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textAlignment="center"
android:textColor="@color/accent" />
</LinearLayout>

1
app/src/main/res/values/strings.xml

@ -23,6 +23,7 @@
<string name="unread">Unread</string> <string name="unread">Unread</string>
<string name="shoutbox">Shoutbox</string> <string name="shoutbox">Shoutbox</string>
<string name="refresh">Refresh</string> <string name="refresh">Refresh</string>
<string name="no_unread_topics">No unread topics!</string>
<!--Login Activity--> <!--Login Activity-->
<string name="thmmy_img_description">thmmy.gr</string> <string name="thmmy_img_description">thmmy.gr</string>

Loading…
Cancel
Save