From 5daa0de82ddaac31e7e43402d82cd6d2fe1adb4c Mon Sep 17 00:00:00 2001
From: Alex Ning <chineseperson5@gmail.com>
Date: Tue, 23 Jun 2020 16:32:40 +0800
Subject: [PATCH] Prepare to support PM.

---
 .../infinityforreddit/FetchMessages.java      |  24 +++-
 .../Fragment/ViewMessagesFragment.java        | 128 ++++++++++++++++++
 .../infinityforreddit/MessageDataSource.java  |  12 +-
 .../PullNotificationWorker.java               |   3 +-
 .../res/layout/fragment_view_messages.xml     |  46 +++++++
 5 files changed, 203 insertions(+), 10 deletions(-)
 create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewMessagesFragment.java
 create mode 100644 app/src/main/res/layout/fragment_view_messages.xml

diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMessages.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMessages.java
index e49e21ec..942d7f7a 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMessages.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchMessages.java
@@ -29,15 +29,19 @@ public class FetchMessages {
     public static final String WHERE_UNREAD = "unread";
     public static final String WHERE_SENT = "sent";
     public static final String WHERE_COMMENTS = "comments";
+    public static final String WHERE_MESSAGES = "messages";
+    public static final int MESSAGE_TYPE_NOTIFICATION = 0;
+    public static final int MESSAGE_TYPE_PRIVATE_MESSAGE = 1;
 
-    static void fetchMessagesAsync(Retrofit oauthRetrofit, Locale locale, String accessToken, String where,
-                                   String after, FetchMessagesListener fetchMessagesListener) {
+    static void fetchInbox(Retrofit oauthRetrofit, Locale locale, String accessToken, String where,
+                           String after, int messageType, FetchMessagesListener fetchMessagesListener) {
         oauthRetrofit.create(RedditAPI.class).getMessages(APIUtils.getOAuthHeader(accessToken), where, after)
                 .enqueue(new Callback<String>() {
                     @Override
                     public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                         if (response.isSuccessful()) {
-                            new ParseMessageAsnycTask(response.body(), locale, fetchMessagesListener::fetchSuccess).execute();
+                            new ParseMessageAsnycTask(response.body(), locale, messageType,
+                                    fetchMessagesListener::fetchSuccess).execute();
                         } else {
                             fetchMessagesListener.fetchFailed();
                         }
@@ -50,8 +54,7 @@ public class FetchMessages {
                 });
     }
 
-    @Nullable
-    static ArrayList<Message> parseMessage(String response, Locale locale) {
+    static ArrayList<Message> parseMessage(String response, Locale locale, int messageType) {
         JSONArray messageArray;
         try {
             messageArray = new JSONObject(response).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
@@ -65,6 +68,10 @@ public class FetchMessages {
             try {
                 JSONObject messageJSON = messageArray.getJSONObject(i);
                 String kind = messageJSON.getString(JSONUtils.KIND_KEY);
+                if ((messageType == MESSAGE_TYPE_NOTIFICATION && kind.equals("t4")) ||
+                        (messageType == MESSAGE_TYPE_PRIVATE_MESSAGE && !kind.equals("t4"))) {
+                    continue;
+                }
 
                 JSONObject rawMessageJSON = messageJSON.getJSONObject(JSONUtils.DATA_KEY);
                 String subredditName = rawMessageJSON.getString(JSONUtils.SUBREDDIT_KEY);
@@ -111,17 +118,20 @@ public class FetchMessages {
         private Locale locale;
         private ArrayList<Message> messages;
         private String after;
+        private int messageType;
         private ParseMessageAsyncTaskListener parseMessageAsyncTaskListener;
-        ParseMessageAsnycTask(String response, Locale locale, ParseMessageAsyncTaskListener parseMessageAsnycTaskListener) {
+        ParseMessageAsnycTask(String response, Locale locale, int messageType,
+                              ParseMessageAsyncTaskListener parseMessageAsnycTaskListener) {
             this.response = response;
             this.locale = locale;
+            this.messageType = messageType;
             messages = new ArrayList<>();
             this.parseMessageAsyncTaskListener = parseMessageAsnycTaskListener;
         }
 
         @Override
         protected Void doInBackground(Void... voids) {
-            messages = parseMessage(response, locale);
+            messages = parseMessage(response, locale, messageType);
             try {
                 after = new JSONObject(response).getJSONObject(JSONUtils.DATA_KEY).getString(JSONUtils.AFTER_KEY);
             } catch (JSONException e) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewMessagesFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewMessagesFragment.java
new file mode 100644
index 00000000..6d2d7061
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/ViewMessagesFragment.java
@@ -0,0 +1,128 @@
+package ml.docilealligator.infinityforreddit.Fragment;
+
+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.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import com.bumptech.glide.RequestManager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import butterknife.BindView;
+import ml.docilealligator.infinityforreddit.Adapter.MessageRecyclerViewAdapter;
+import ml.docilealligator.infinityforreddit.CustomTheme.CustomThemeWrapper;
+import ml.docilealligator.infinityforreddit.FetchMessages;
+import ml.docilealligator.infinityforreddit.FragmentCommunicator;
+import ml.docilealligator.infinityforreddit.MessageViewModel;
+import ml.docilealligator.infinityforreddit.NetworkState;
+import ml.docilealligator.infinityforreddit.R;
+import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
+import retrofit2.Retrofit;
+
+public class ViewMessagesFragment extends Fragment implements FragmentCommunicator {
+
+    @BindView(R.id.swipe_refresh_layout_view_messages_fragment)
+    SwipeRefreshLayout mSwipeRefreshLayout;
+    @BindView(R.id.recycler_view_view_messages_fragment)
+    RecyclerView mRecyclerView;
+    @BindView(R.id.fetch_messages_info_linear_layout_view_messages_fragment)
+    LinearLayout mFetchMessageInfoLinearLayout;
+    @BindView(R.id.fetch_messages_info_image_view_view_messages_fragment)
+    ImageView mFetchMessageInfoImageView;
+    @BindView(R.id.fetch_messages_info_text_view_view_messages_fragment)
+    TextView mFetchMessageInfoTextView;
+    MessageViewModel mMessageViewModel;
+    @Inject
+    @Named("oauth")
+    Retrofit mOauthRetrofit;
+    @Inject
+    RedditDataRoomDatabase mRedditDataRoomDatabase;
+    @Inject
+    @Named("default")
+    SharedPreferences mSharedPreferences;
+    @Inject
+    CustomThemeWrapper mCustomThemeWrapper;
+    private String mAccessToken;
+    private MessageRecyclerViewAdapter mAdapter;
+    private RequestManager mGlide;
+    private LinearLayoutManager mLinearLayoutManager;
+
+    public ViewMessagesFragment() {
+        // Required empty public constructor
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View rootView = inflater.inflate(R.layout.fragment_view_messages, container, false);
+
+        MessageViewModel.Factory factory = new MessageViewModel.Factory(mOauthRetrofit,
+                getResources().getConfiguration().locale, mAccessToken, FetchMessages.WHERE_INBOX);
+        mMessageViewModel = new ViewModelProvider(this, factory).get(MessageViewModel.class);
+        mMessageViewModel.getMessages().observe(getViewLifecycleOwner(), messages -> mAdapter.submitList(messages));
+
+        mMessageViewModel.hasMessage().observe(getViewLifecycleOwner(), hasMessage -> {
+            mSwipeRefreshLayout.setRefreshing(false);
+            if (hasMessage) {
+                mFetchMessageInfoLinearLayout.setVisibility(View.GONE);
+            } else {
+                mFetchMessageInfoLinearLayout.setOnClickListener(view -> {
+                    //Do nothing
+                });
+                showErrorView(R.string.no_messages);
+            }
+        });
+
+        mMessageViewModel.getInitialLoadingState().observe(getViewLifecycleOwner(), networkState -> {
+            if (networkState.getStatus().equals(NetworkState.Status.SUCCESS)) {
+                mSwipeRefreshLayout.setRefreshing(false);
+            } else if (networkState.getStatus().equals(NetworkState.Status.FAILED)) {
+                mSwipeRefreshLayout.setRefreshing(false);
+                mFetchMessageInfoLinearLayout.setOnClickListener(view -> {
+                    mFetchMessageInfoLinearLayout.setVisibility(View.GONE);
+                    mMessageViewModel.refresh();
+                    mAdapter.setNetworkState(null);
+                });
+                showErrorView(R.string.load_messages_failed);
+            } else {
+                mSwipeRefreshLayout.setRefreshing(true);
+            }
+        });
+
+        mMessageViewModel.getPaginationNetworkState().observe(getViewLifecycleOwner(), networkState -> {
+            mAdapter.setNetworkState(networkState);
+        });
+
+        mSwipeRefreshLayout.setOnRefreshListener(this::onRefresh);
+
+        return rootView;
+    }
+
+    private void showErrorView(int stringResId) {
+        mSwipeRefreshLayout.setRefreshing(false);
+        mFetchMessageInfoLinearLayout.setVisibility(View.VISIBLE);
+        mFetchMessageInfoTextView.setText(stringResId);
+        mGlide.load(R.drawable.error_image).into(mFetchMessageInfoImageView);
+    }
+
+    @Override
+    public void applyTheme() {
+
+    }
+
+    private void onRefresh() {
+        mMessageViewModel.refresh();
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/MessageDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/MessageDataSource.java
index 7d74afce..66fd7647 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/MessageDataSource.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/MessageDataSource.java
@@ -15,6 +15,7 @@ class MessageDataSource extends PageKeyedDataSource<String, Message> {
     private Locale locale;
     private String accessToken;
     private String where;
+    private int messageType;
 
     private MutableLiveData<NetworkState> paginationNetworkStateLiveData;
     private MutableLiveData<NetworkState> initialLoadStateLiveData;
@@ -28,6 +29,11 @@ class MessageDataSource extends PageKeyedDataSource<String, Message> {
         this.locale = locale;
         this.accessToken = accessToken;
         this.where = where;
+        if (where.equals(FetchMessages.WHERE_MESSAGES)) {
+            messageType = FetchMessages.MESSAGE_TYPE_PRIVATE_MESSAGE;
+        } else {
+            messageType = FetchMessages.MESSAGE_TYPE_NOTIFICATION;
+        }
         paginationNetworkStateLiveData = new MutableLiveData<>();
         initialLoadStateLiveData = new MutableLiveData<>();
         hasPostLiveData = new MutableLiveData<>();
@@ -53,7 +59,8 @@ class MessageDataSource extends PageKeyedDataSource<String, Message> {
     public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull LoadInitialCallback<String, Message> callback) {
         initialLoadStateLiveData.postValue(NetworkState.LOADING);
 
-        FetchMessages.fetchMessagesAsync(oauthRetrofit, locale, accessToken, where, null, new FetchMessages.FetchMessagesListener() {
+        FetchMessages.fetchInbox(oauthRetrofit, locale, accessToken, where, null, messageType,
+                new FetchMessages.FetchMessagesListener() {
             @Override
             public void fetchSuccess(ArrayList<Message> messages, @Nullable String after) {
                 if (messages.size() == 0) {
@@ -89,7 +96,8 @@ class MessageDataSource extends PageKeyedDataSource<String, Message> {
 
         paginationNetworkStateLiveData.postValue(NetworkState.LOADING);
 
-        FetchMessages.fetchMessagesAsync(oauthRetrofit, locale, accessToken, where, params.key, new FetchMessages.FetchMessagesListener() {
+        FetchMessages.fetchInbox(oauthRetrofit, locale, accessToken, where, params.key, messageType,
+                new FetchMessages.FetchMessagesListener() {
             @Override
             public void fetchSuccess(ArrayList<Message> messages, @Nullable String after) {
                 if (after == null || after.equals("") || after.equals("null")) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PullNotificationWorker.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PullNotificationWorker.java
index 214a9736..2473d074 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/PullNotificationWorker.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PullNotificationWorker.java
@@ -74,7 +74,8 @@ public class PullNotificationWorker extends Worker {
 
                 if (response != null && response.isSuccessful()) {
                     String responseBody = response.body();
-                    ArrayList<Message> messages = FetchMessages.parseMessage(responseBody, context.getResources().getConfiguration().locale);
+                    ArrayList<Message> messages = FetchMessages.parseMessage(responseBody,
+                            context.getResources().getConfiguration().locale, FetchMessages.MESSAGE_TYPE_NOTIFICATION);
 
                     if (messages != null && !messages.isEmpty()) {
                         NotificationManagerCompat notificationManager = NotificationUtils.getNotificationManager(context);
diff --git a/app/src/main/res/layout/fragment_view_messages.xml b/app/src/main/res/layout/fragment_view_messages.xml
new file mode 100644
index 00000000..a8f8439d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_view_messages.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".Fragment.ViewMessagesFragment">
+
+    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_refresh_layout_view_messages_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recycler_view_view_messages_fragment"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:clipToPadding="false" />
+
+    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+
+    <LinearLayout
+        android:id="@+id/fetch_messages_info_linear_layout_view_messages_fragment"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:visibility="gone">
+
+        <ImageView
+            android:id="@+id/fetch_messages_info_image_view_view_messages_fragment"
+            android:layout_width="150dp"
+            android:layout_height="wrap_content" />
+
+        <TextView
+            android:id="@+id/fetch_messages_info_text_view_view_messages_fragment"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:fontFamily="?attr/font_family"
+            android:gravity="center"
+            android:textSize="?attr/font_default" />
+
+    </LinearLayout>
+
+</RelativeLayout>
\ No newline at end of file