diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/SubscribedSubredditsRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/SubscribedSubredditsRecyclerViewAdapter.java index 9be1284c..1d1b7e22 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/SubscribedSubredditsRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Adapter/SubscribedSubredditsRecyclerViewAdapter.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; @@ -16,25 +17,45 @@ import com.bumptech.glide.request.RequestOptions; import java.util.List; +import butterknife.BindView; +import butterknife.ButterKnife; import jp.wasabeef.glide.transformations.RoundedCornersTransformation; import ml.docilealligator.infinityforreddit.Activity.ViewSubredditDetailActivity; +import ml.docilealligator.infinityforreddit.FavoriteThing; import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.SubscribedSubredditDatabase.SubscribedSubredditData; import pl.droidsonroids.gif.GifImageView; +import retrofit2.Retrofit; public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapter { + private static final int VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER = 0; + private static final int VIEW_TYPE_FAVORITE_SUBREDDIT = 1; + private static final int VIEW_TYPE_SUBREDDIT_DIVIDER = 2; + private static final int VIEW_TYPE_SUBREDDIT = 3; + private Context mContext; + private Retrofit mOauthRetrofit; + private RedditDataRoomDatabase mRedditDataRoomDatabase; private List mSubscribedSubredditData; + private List mFavoriteSubscribedSubredditData; private RequestManager glide; private ItemClickListener itemClickListener; + private String accessToken; private String username; private String userIconUrl; private boolean hasClearSelectionRow; - public SubscribedSubredditsRecyclerViewAdapter(Context context) { + public SubscribedSubredditsRecyclerViewAdapter(Context context, Retrofit oauthRetrofit, + RedditDataRoomDatabase redditDataRoomDatabase, + String accessToken) { mContext = context; glide = Glide.with(context.getApplicationContext()); + mOauthRetrofit = oauthRetrofit; + mRedditDataRoomDatabase = redditDataRoomDatabase; + this.accessToken = accessToken; + } public SubscribedSubredditsRecyclerViewAdapter(Context context, boolean hasClearSelectionRow, ItemClickListener itemClickListener) { @@ -44,66 +65,239 @@ public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapte this.itemClickListener = itemClickListener; } + @Override + public int getItemViewType(int position) { + if (itemClickListener != null) { + return VIEW_TYPE_SUBREDDIT; + } else { + if (mFavoriteSubscribedSubredditData != null && mFavoriteSubscribedSubredditData.size() > 0) { + if (position == 0) { + return VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER; + } else if (position == mFavoriteSubscribedSubredditData.size() + 1) { + return VIEW_TYPE_SUBREDDIT_DIVIDER; + } else if (position <= mFavoriteSubscribedSubredditData.size()) { + return VIEW_TYPE_FAVORITE_SUBREDDIT; + } else { + return VIEW_TYPE_SUBREDDIT; + } + } else { + return VIEW_TYPE_SUBREDDIT; + } + } + } + @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { - return new SubredditViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_subscribed_thing, viewGroup, false)); + switch (i) { + case VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER: + return new FavoriteSubredditsDividerViewHolder(LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_favorite_subreddits_divider, viewGroup, false)); + case VIEW_TYPE_FAVORITE_SUBREDDIT: + return new FavoriteSubredditViewHolder(LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_subscribed_thing, viewGroup, false)); + case VIEW_TYPE_SUBREDDIT_DIVIDER: + return new AllSubredditsDividerViewHolder(LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_favorite_subreddits_divider, viewGroup, false)); + default: + return new SubredditViewHolder(LayoutInflater.from(viewGroup.getContext()) + .inflate(R.layout.item_subscribed_thing, viewGroup, false)); + } } @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, final int i) { - String name; - String iconUrl; + if (viewHolder instanceof SubredditViewHolder) { + String name; + String iconUrl; - if (itemClickListener != null) { - if (hasClearSelectionRow) { - if (viewHolder.getAdapterPosition() == 0) { - ((SubredditViewHolder) viewHolder).subredditNameTextView.setText(R.string.all_subreddits); - viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(null, null, false)); - return; - } else if (viewHolder.getAdapterPosition() == 1) { - name = username; - iconUrl = userIconUrl; - viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, true)); + if (itemClickListener != null) { + if (hasClearSelectionRow) { + if (viewHolder.getAdapterPosition() == 0) { + ((SubredditViewHolder) viewHolder).subredditNameTextView.setText(R.string.all_subreddits); + viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(null, null, false)); + return; + } else if (viewHolder.getAdapterPosition() == 1) { + name = username; + iconUrl = userIconUrl; + viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, true)); + } else { + name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 2).getName(); + iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 2).getIconUrl(); + viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, false)); + } } else { - name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 2).getName(); - iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 2).getIconUrl(); - viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, false)); + if (viewHolder.getAdapterPosition() == 0) { + name = username; + iconUrl = userIconUrl; + viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, true)); + } else { + name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getName(); + iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getIconUrl(); + viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, false)); + } } } else { - if (viewHolder.getAdapterPosition() == 0) { - name = username; - iconUrl = userIconUrl; - viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, true)); - } else { - name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getName(); - iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getIconUrl(); - viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(name, iconUrl, false)); - } - } - } else { - name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getName(); - iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition()).getIconUrl(); + int offset = (mFavoriteSubscribedSubredditData != null && mFavoriteSubscribedSubredditData.size() > 0) ? + mFavoriteSubscribedSubredditData.size() + 2 : 0; + name = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).getName(); + iconUrl = mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).getIconUrl(); + if(mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).isFavorite()) { + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } else { + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + + ((SubredditViewHolder) viewHolder).favoriteImageView.setOnClickListener(view -> { + if(mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).isFavorite()) { + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).setFavorite(false); + FavoriteThing.unfavoriteThing(mOauthRetrofit, mRedditDataRoomDatabase, accessToken, + mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset), false, + new FavoriteThing.FavoriteThingListener() { + @Override + public void success() { + int position = viewHolder.getAdapterPosition() - offset; + if(position >= 0 && mSubscribedSubredditData.size() > position) { + mSubscribedSubredditData.get(position).setFavorite(false); + } + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + + @Override + public void failed() { + int position = viewHolder.getAdapterPosition() - offset; + if(position >= 0 && mSubscribedSubredditData.size() > position) { + mSubscribedSubredditData.get(position).setFavorite(true); + } + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } + }); + } else { + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset).setFavorite(true); + FavoriteThing.favoriteThing(mOauthRetrofit, mRedditDataRoomDatabase, accessToken, + mSubscribedSubredditData.get(viewHolder.getAdapterPosition() - offset), false, + new FavoriteThing.FavoriteThingListener() { + @Override + public void success() { + int position = viewHolder.getAdapterPosition() - offset; + if(position >= 0 && mSubscribedSubredditData.size() > position) { + mSubscribedSubredditData.get(position).setFavorite(true); + } + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } + + @Override + public void failed() { + int position = viewHolder.getAdapterPosition() - offset; + if(position >= 0 && mSubscribedSubredditData.size() > position) { + mSubscribedSubredditData.get(position).setFavorite(false); + } + ((SubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + }); + } + }); + viewHolder.itemView.setOnClickListener(view -> { + Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); + intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, name); + mContext.startActivity(intent); + }); + } + + if (iconUrl != null && !iconUrl.equals("")) { + glide.load(iconUrl) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .error(glide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))) + .into(((SubredditViewHolder) viewHolder).iconGifImageView); + } else { + glide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .into(((SubredditViewHolder) viewHolder).iconGifImageView); + } + ((SubredditViewHolder) viewHolder).subredditNameTextView.setText(name); + } else if (viewHolder instanceof FavoriteSubredditViewHolder) { + String name = mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getName(); + String iconUrl = mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).getIconUrl(); + if(mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).isFavorite()) { + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } else { + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setOnClickListener(view -> { + if(mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).isFavorite()) { + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).setFavorite(false); + FavoriteThing.unfavoriteThing(mOauthRetrofit, mRedditDataRoomDatabase, accessToken, + mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1), false, + new FavoriteThing.FavoriteThingListener() { + @Override + public void success() { + int position = viewHolder.getAdapterPosition() - 1; + if(position >= 0 && mFavoriteSubscribedSubredditData.size() > position) { + mFavoriteSubscribedSubredditData.get(position).setFavorite(false); + } + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + + @Override + public void failed() { + int position = viewHolder.getAdapterPosition() - 1; + if(position >= 0 && mFavoriteSubscribedSubredditData.size() > position) { + mFavoriteSubscribedSubredditData.get(position).setFavorite(true); + } + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } + }); + } else { + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1).setFavorite(true); + FavoriteThing.favoriteThing(mOauthRetrofit, mRedditDataRoomDatabase, accessToken, + mFavoriteSubscribedSubredditData.get(viewHolder.getAdapterPosition() - 1), false, + new FavoriteThing.FavoriteThingListener() { + @Override + public void success() { + int position = viewHolder.getAdapterPosition() - 1; + if(position >= 0 && mFavoriteSubscribedSubredditData.size() > position) { + mFavoriteSubscribedSubredditData.get(position).setFavorite(true); + } + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_24dp); + } + + @Override + public void failed() { + int position = viewHolder.getAdapterPosition() - 1; + if(position >= 0 && mFavoriteSubscribedSubredditData.size() > position) { + mFavoriteSubscribedSubredditData.get(position).setFavorite(false); + } + ((FavoriteSubredditViewHolder) viewHolder).favoriteImageView.setImageResource(R.drawable.ic_favorite_border_24dp); + } + }); + } + }); viewHolder.itemView.setOnClickListener(view -> { Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, name); mContext.startActivity(intent); }); - } - if (iconUrl != null && !iconUrl.equals("")) { - glide.load(iconUrl) - .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) - .error(glide.load(R.drawable.subreddit_default_icon) - .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))) - .into(((SubredditViewHolder) viewHolder).iconGifImageView); - } else { - glide.load(R.drawable.subreddit_default_icon) - .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) - .into(((SubredditViewHolder) viewHolder).iconGifImageView); + if (iconUrl != null && !iconUrl.equals("")) { + glide.load(iconUrl) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .error(glide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))) + .into(((FavoriteSubredditViewHolder) viewHolder).iconGifImageView); + } else { + glide.load(R.drawable.subreddit_default_icon) + .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))) + .into(((FavoriteSubredditViewHolder) viewHolder).iconGifImageView); + } + ((FavoriteSubredditViewHolder) viewHolder).subredditNameTextView.setText(name); } - ((SubredditViewHolder) viewHolder).subredditNameTextView.setText(name); } @Override @@ -117,6 +311,11 @@ public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapte } } + if(mFavoriteSubscribedSubredditData != null && mFavoriteSubscribedSubredditData.size() > 0) { + return mSubscribedSubredditData.size() > 0 ? + mFavoriteSubscribedSubredditData.size() + mSubscribedSubredditData.size() + 2 : 0; + } + return mSubscribedSubredditData.size(); } return 0; @@ -124,7 +323,11 @@ public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapte @Override public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { - glide.clear(((SubredditViewHolder) holder).iconGifImageView); + if(holder instanceof SubredditViewHolder) { + glide.clear(((SubredditViewHolder) holder).iconGifImageView); + } else if (holder instanceof FavoriteSubredditViewHolder) { + glide.clear(((FavoriteSubredditViewHolder) holder).iconGifImageView); + } } public void setSubscribedSubreddits(List subscribedSubreddits) { @@ -132,6 +335,11 @@ public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapte notifyDataSetChanged(); } + public void setFavoriteSubscribedSubreddits(List favoriteSubscribedSubredditData) { + mFavoriteSubscribedSubredditData = favoriteSubscribedSubredditData; + notifyDataSetChanged(); + } + public void addUser(String username, String userIconUrl) { this.username = username; this.userIconUrl = userIconUrl; @@ -141,14 +349,51 @@ public class SubscribedSubredditsRecyclerViewAdapter extends RecyclerView.Adapte void onClick(String name, String iconUrl, boolean subredditIsUser); } - private class SubredditViewHolder extends RecyclerView.ViewHolder { - private final GifImageView iconGifImageView; - private final TextView subredditNameTextView; + class SubredditViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.subreddit_icon_gif_image_view_item_subscribed_subreddit) + GifImageView iconGifImageView; + @BindView(R.id.subreddit_name_text_view_item_subscribed_subreddit) + TextView subredditNameTextView; + @BindView(R.id.favorite_image_view_item_subscribed_subreddit) + ImageView favoriteImageView; SubredditViewHolder(View itemView) { super(itemView); - iconGifImageView = itemView.findViewById(R.id.subreddit_icon_gif_image_view_item_subscribed_subreddit); - subredditNameTextView = itemView.findViewById(R.id.subreddit_name_text_view_item_subscribed_subreddit); + ButterKnife.bind(this, itemView); + } + } + + class FavoriteSubredditViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.subreddit_icon_gif_image_view_item_subscribed_subreddit) + GifImageView iconGifImageView; + @BindView(R.id.subreddit_name_text_view_item_subscribed_subreddit) + TextView subredditNameTextView; + @BindView(R.id.favorite_image_view_item_subscribed_subreddit) + ImageView favoriteImageView; + + FavoriteSubredditViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + + class FavoriteSubredditsDividerViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.divider_text_view_item_favorite_subreddits_divider) TextView dividerTextView; + + FavoriteSubredditsDividerViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + dividerTextView.setText(R.string.favorites); + } + } + + class AllSubredditsDividerViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.divider_text_view_item_favorite_subreddits_divider) TextView dividerTextView; + + AllSubredditsDividerViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + dividerTextView.setText(R.string.all); } } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/InsertSubscribedThingsAsyncTask.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/InsertSubscribedThingsAsyncTask.java index ab52b035..dcc36a0b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/InsertSubscribedThingsAsyncTask.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AsyncTask/InsertSubscribedThingsAsyncTask.java @@ -21,10 +21,11 @@ public class InsertSubscribedThingsAsyncTask extends AsyncTask private SubscribedSubredditDao mSubscribedSubredditDao; private SubscribedUserDao mUserDao; private SubredditDao mSubredditDao; + private SubscribedSubredditData mSingleSubscribedSubredditData; private List subscribedSubredditData; private List subscribedUserData; private List subredditData; - private InsertSubscribedThingListener insertSubscribedThingListener; + private InsertSubscribedThingListener mInsertSubscribedThingListener; public InsertSubscribedThingsAsyncTask(RedditDataRoomDatabase redditDataRoomDatabase, @Nullable String accountName, List subscribedSubredditData, List subscribedUserData, @@ -39,7 +40,17 @@ public class InsertSubscribedThingsAsyncTask extends AsyncTask this.subscribedSubredditData = subscribedSubredditData; this.subscribedUserData = subscribedUserData; this.subredditData = subredditData; - this.insertSubscribedThingListener = insertSubscribedThingListener; + mInsertSubscribedThingListener = insertSubscribedThingListener; + } + + public InsertSubscribedThingsAsyncTask(RedditDataRoomDatabase redditDataRoomDatabase, + SubscribedSubredditData subscribedSubredditData, + InsertSubscribedThingListener insertSubscribedThingListener) { + mRedditDataRoomDatabase = redditDataRoomDatabase; + mSubscribedSubredditDao = redditDataRoomDatabase.subscribedSubredditDao(); + mAccountName = subscribedSubredditData.getUsername(); + mSingleSubscribedSubredditData = subscribedSubredditData; + mInsertSubscribedThingListener = insertSubscribedThingListener; } @Override @@ -48,21 +59,25 @@ public class InsertSubscribedThingsAsyncTask extends AsyncTask return null; } - if (subscribedSubredditData != null) { - for (SubscribedSubredditData s : subscribedSubredditData) { - mSubscribedSubredditDao.insert(s); + if(mSingleSubscribedSubredditData != null) { + mSubscribedSubredditDao.insert(mSingleSubscribedSubredditData); + } else { + if (subscribedSubredditData != null) { + for (SubscribedSubredditData s : subscribedSubredditData) { + mSubscribedSubredditDao.insert(s); + } } - } - if (subscribedUserData != null) { - for (SubscribedUserData s : subscribedUserData) { - mUserDao.insert(s); + if (subscribedUserData != null) { + for (SubscribedUserData s : subscribedUserData) { + mUserDao.insert(s); + } } - } - if (subredditData != null) { - for (SubredditData s : subredditData) { - mSubredditDao.insert(s); + if (subredditData != null) { + for (SubredditData s : subredditData) { + mSubredditDao.insert(s); + } } } return null; @@ -70,7 +85,7 @@ public class InsertSubscribedThingsAsyncTask extends AsyncTask @Override protected void onPostExecute(Void aVoid) { - insertSubscribedThingListener.insertSuccess(); + mInsertSubscribedThingListener.insertSuccess(); } public interface InsertSubscribedThingListener { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FavoriteThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FavoriteThing.java new file mode 100644 index 00000000..6fdd28e2 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FavoriteThing.java @@ -0,0 +1,77 @@ +package ml.docilealligator.infinityforreddit; + +import androidx.annotation.NonNull; + +import java.util.HashMap; +import java.util.Map; + +import ml.docilealligator.infinityforreddit.AsyncTask.InsertSubscribedThingsAsyncTask; +import ml.docilealligator.infinityforreddit.SubscribedSubredditDatabase.SubscribedSubredditData; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class FavoriteThing { + public static void favoriteThing(Retrofit oauthRetrofit, RedditDataRoomDatabase redditDataRoomDatabase, + String accessToken, SubscribedSubredditData subscribedSubredditData, + boolean isUser, FavoriteThingListener favoriteThingListener) { + Map params = new HashMap<>(); + if (isUser) { + params.put(RedditUtils.SR_NAME_KEY, "u_" + subscribedSubredditData.getName()); + } else { + params.put(RedditUtils.SR_NAME_KEY, subscribedSubredditData.getName()); + } + params.put(RedditUtils.MAKE_FAVORITE_KEY, "true"); + oauthRetrofit.create(RedditAPI.class).favoriteThing(RedditUtils.getOAuthHeader(accessToken), params).enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful()) { + new InsertSubscribedThingsAsyncTask(redditDataRoomDatabase, subscribedSubredditData, + favoriteThingListener::success).execute(); + } else { + favoriteThingListener.failed(); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + favoriteThingListener.failed(); + } + }); + } + + public static void unfavoriteThing(Retrofit oauthRetrofit, RedditDataRoomDatabase redditDataRoomDatabase, + String accessToken, SubscribedSubredditData subscribedSubredditData, + boolean isUser, FavoriteThingListener favoriteThingListener) { + Map params = new HashMap<>(); + if (isUser) { + params.put(RedditUtils.SR_NAME_KEY, "u_" + subscribedSubredditData.getName()); + } else { + params.put(RedditUtils.SR_NAME_KEY, subscribedSubredditData.getName()); + } + params.put(RedditUtils.MAKE_FAVORITE_KEY, "false"); + oauthRetrofit.create(RedditAPI.class).favoriteThing(RedditUtils.getOAuthHeader(accessToken), params).enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful()) { + new InsertSubscribedThingsAsyncTask(redditDataRoomDatabase, subscribedSubredditData, + favoriteThingListener::success).execute(); + } else { + favoriteThingListener.failed(); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + favoriteThingListener.failed(); + } + }); + } + + public interface FavoriteThingListener { + void success(); + + void failed(); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SubscribedSubredditsListingFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SubscribedSubredditsListingFragment.java index 4f60b6a8..ceb4aeed 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SubscribedSubredditsListingFragment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Fragment/SubscribedSubredditsListingFragment.java @@ -22,6 +22,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.RequestManager; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; @@ -31,6 +32,7 @@ import ml.docilealligator.infinityforreddit.Infinity; import ml.docilealligator.infinityforreddit.R; import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; import ml.docilealligator.infinityforreddit.SubscribedSubredditDatabase.SubscribedSubredditViewModel; +import retrofit2.Retrofit; /** @@ -38,7 +40,8 @@ import ml.docilealligator.infinityforreddit.SubscribedSubredditDatabase.Subscrib */ public class SubscribedSubredditsListingFragment extends Fragment { - public static final String EXTRA_ACCOUNT_NAME = "EAT"; + public static final String EXTRA_ACCOUNT_NAME = "EAN"; + public static final String EXTRA_ACCESS_TOKEN = "EAT"; public static final String EXTRA_ACCOUNT_PROFILE_IMAGE_URL = "EAPIU"; public static final String EXTRA_IS_SUBREDDIT_SELECTION = "EISS"; public static final String EXTRA_EXTRA_CLEAR_SELECTION = "EECS"; @@ -50,6 +53,9 @@ public class SubscribedSubredditsListingFragment extends Fragment { @BindView(R.id.no_subscriptions_image_view_subreddits_listing_fragment) ImageView mImageView; @Inject + @Named("oauth") + Retrofit mOauthRetrofit; + @Inject RedditDataRoomDatabase mRedditDataRoomDatabase; private Activity mActivity; private RequestManager mGlide; @@ -82,6 +88,7 @@ public class SubscribedSubredditsListingFragment extends Fragment { } String accountName = getArguments().getString(EXTRA_ACCOUNT_NAME); + String accessToken = getArguments().getString(EXTRA_ACCESS_TOKEN); mGlide = Glide.with(this); @@ -92,7 +99,7 @@ public class SubscribedSubredditsListingFragment extends Fragment { adapter = new SubscribedSubredditsRecyclerViewAdapter(mActivity, getArguments().getBoolean(EXTRA_EXTRA_CLEAR_SELECTION), (name, iconUrl, subredditIsUser) -> ((SubredditSelectionActivity) mActivity).getSelectedSubreddit(name, iconUrl, subredditIsUser)); } else { - adapter = new SubscribedSubredditsRecyclerViewAdapter(mActivity); + adapter = new SubscribedSubredditsRecyclerViewAdapter(mActivity, mOauthRetrofit, mRedditDataRoomDatabase, accessToken); } mRecyclerView.setAdapter(adapter); @@ -115,6 +122,16 @@ public class SubscribedSubredditsListingFragment extends Fragment { adapter.setSubscribedSubreddits(subscribedSubredditData); }); + mSubscribedSubredditViewModel.getAllFavoriteSubscribedSubreddits().observe(this, favoriteSubscribedSubredditData -> { + if (favoriteSubscribedSubredditData != null && favoriteSubscribedSubredditData.size() > 0) { + mLinearLayout.setVisibility(View.GONE); + mRecyclerView.setVisibility(View.VISIBLE); + mGlide.clear(mImageView); + } + + adapter.setFavoriteSubscribedSubreddits(favoriteSubscribedSubredditData); + }); + return rootView; } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java index 1e73bcb2..62322490 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java @@ -85,4 +85,5 @@ public class JSONUtils { public static final String NEW_KEY = "new"; public static final String NUM_COMMENTS_KEY = "num_comments"; public static final String HIDDEN_KEY = "hidden"; + public static final String USER_HAS_FAVORITED_KEY = "user_has_favorited"; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java index 990542d8..116d2ba2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseSubscribedThing.java @@ -87,22 +87,17 @@ class ParseSubscribedThing { } } String id = data.getString(JSONUtils.NAME_KEY); - if (iconUrl.equals("") || iconUrl.equals("null")) { - iconUrl = data.getString(JSONUtils.COMMUNITY_ICON_KEY); - if (iconUrl.equals("null")) { - iconUrl = ""; - } - } + boolean isFavorite = data.getBoolean(JSONUtils.USER_HAS_FAVORITED_KEY); if (data.getString(JSONUtils.SUBREDDIT_TYPE_KEY) .equals(JSONUtils.SUBREDDIT_TYPE_VALUE_USER)) { //It's a user - newSubscribedUserData.add(new SubscribedUserData(name.substring(2), iconUrl, accountName)); + newSubscribedUserData.add(new SubscribedUserData(name.substring(2), iconUrl, accountName, isFavorite)); } else { String subredditFullName = data.getString(JSONUtils.DISPLAY_NAME); String description = data.getString(JSONUtils.PUBLIC_DESCRIPTION_KEY).trim(); int nSubscribers = data.getInt(JSONUtils.SUBSCRIBERS_KEY); - newSubscribedSubredditData.add(new SubscribedSubredditData(id, name, iconUrl, accountName)); + newSubscribedSubredditData.add(new SubscribedSubredditData(id, name, iconUrl, accountName, isFavorite)); newSubredditData.add(new SubredditData(id, subredditFullName, iconUrl, bannerImageUrl, description, nSubscribers)); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java index 05311cf1..2a326228 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java @@ -195,4 +195,8 @@ public interface RedditAPI { @FormUrlEncoded @POST("/api/unhide") Call unhide(@HeaderMap Map headers, @FieldMap Map params); + + @FormUrlEncoded + @POST("/api/favorite") + Call favoriteThing(@HeaderMap Map headers, @FieldMap Map params); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java index 8681fb35..bc73c266 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditDataRoomDatabase.java @@ -5,6 +5,8 @@ import android.content.Context; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; import ml.docilealligator.infinityforreddit.Account.Account; import ml.docilealligator.infinityforreddit.Account.AccountDao; @@ -17,7 +19,7 @@ import ml.docilealligator.infinityforreddit.SubscribedUserDatabase.SubscribedUse import ml.docilealligator.infinityforreddit.User.UserDao; import ml.docilealligator.infinityforreddit.User.UserData; -@Database(entities = {Account.class, SubredditData.class, SubscribedSubredditData.class, UserData.class, SubscribedUserData.class}, version = 1) +@Database(entities = {Account.class, SubredditData.class, SubscribedSubredditData.class, UserData.class, SubscribedUserData.class}, version = 2) public abstract class RedditDataRoomDatabase extends RoomDatabase { private static RedditDataRoomDatabase INSTANCE; @@ -27,6 +29,7 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), RedditDataRoomDatabase.class, "reddit_data") + .addMigrations(MIGRATION_1_2) .build(); } } @@ -43,4 +46,14 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase { public abstract UserDao userDao(); public abstract SubscribedUserDao subscribedUserDao(); + + private static final Migration MIGRATION_1_2 = new Migration(1, 2) { + @Override + public void migrate(SupportSQLiteDatabase database) { + database.execSQL("ALTER TABLE subscribed_subreddits" + + " ADD COLUMN is_favorite INTEGER DEFAULT 0 NOT NULL"); + database.execSQL("ALTER TABLE subscribed_users" + + " ADD COLUMN is_favorite INTEGER DEFAULT 0 NOT NULL"); + } + }; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java index 78d0d9b0..cc282ca3 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditUtils.java @@ -79,6 +79,8 @@ public class RedditUtils { public static final String LINK_KEY = "link"; public static final String FLAIR_TEMPLATE_ID_KEY = "flair_template_id"; + public static final String MAKE_FAVORITE_KEY = "make_favorite"; + public static Map getHttpBasicAuthHeader() { Map params = new HashMap<>(); String credentials = String.format("%s:%s", RedditUtils.CLIENT_ID, ""); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditSubscription.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditSubscription.java index 6508020a..15d9ee3b 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditSubscription.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubredditSubscription.java @@ -100,7 +100,7 @@ public class SubredditSubscription { String accountName, boolean isSubscribing) { this.redditDataRoomDatabase = redditDataRoomDatabase; this.subscribedSubredditData = new SubscribedSubredditData(subredditData.getId(), subredditData.getName(), - subredditData.getIconUrl(), accountName); + subredditData.getIconUrl(), accountName, false); this.accountName = accountName; this.isSubscribing = isSubscribing; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditDao.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditDao.java index 6caf7703..6bfa103e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditDao.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditDao.java @@ -19,6 +19,9 @@ public interface SubscribedSubredditDao { @Query("SELECT * from subscribed_subreddits WHERE username = :accountName ORDER BY name COLLATE NOCASE ASC") LiveData> getAllSubscribedSubreddits(String accountName); + @Query("SELECT * from subscribed_subreddits WHERE username = :accountName AND is_favorite = 1 ORDER BY name COLLATE NOCASE ASC") + LiveData> getAllFavoriteSubscribedSubreddits(String accountName); + @Query("SELECT * from subscribed_subreddits WHERE name = :subredditName AND username = :accountName COLLATE NOCASE LIMIT 1") SubscribedSubredditData getSubscribedSubreddit(String subredditName, String accountName); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditData.java index 50cc103e..8cc75e5a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditData.java @@ -22,12 +22,16 @@ public class SubscribedSubredditData { private String iconUrl; @ColumnInfo(name = "username") private String username; + @ColumnInfo(name = "is_favorite") + private boolean favorite; - public SubscribedSubredditData(@NonNull String id, String name, String iconUrl, String username) { + public SubscribedSubredditData(@NonNull String id, String name, String iconUrl, String username, + boolean favorite) { this.id = id; this.name = name; this.iconUrl = iconUrl; this.username = username; + this.favorite = favorite; } @NonNull @@ -50,4 +54,12 @@ public class SubscribedSubredditData { public void setUsername(String username) { this.username = username; } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditRepository.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditRepository.java index f10f93b8..3f2da07d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditRepository.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditRepository.java @@ -11,16 +11,22 @@ import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; public class SubscribedSubredditRepository { private SubscribedSubredditDao mSubscribedSubredditDao; private LiveData> mAllSubscribedSubreddits; + private LiveData> mAllFavoriteSubscribedSubreddits; SubscribedSubredditRepository(RedditDataRoomDatabase redditDataRoomDatabase, String accountName) { mSubscribedSubredditDao = redditDataRoomDatabase.subscribedSubredditDao(); mAllSubscribedSubreddits = mSubscribedSubredditDao.getAllSubscribedSubreddits(accountName); + mAllFavoriteSubscribedSubreddits = mSubscribedSubredditDao.getAllFavoriteSubscribedSubreddits(accountName); } LiveData> getAllSubscribedSubreddits() { return mAllSubscribedSubreddits; } + public LiveData> getAllFavoriteSubscribedSubreddits() { + return mAllFavoriteSubscribedSubreddits; + } + public void insert(SubscribedSubredditData subscribedSubredditData) { new insertAsyncTask(mSubscribedSubredditDao).execute(subscribedSubredditData); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditViewModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditViewModel.java index c1965641..56ff6c5e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditViewModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedSubredditDatabase/SubscribedSubredditViewModel.java @@ -15,17 +15,23 @@ import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase; public class SubscribedSubredditViewModel extends AndroidViewModel { private SubscribedSubredditRepository mSubscribedSubredditRepository; private LiveData> mAllSubscribedSubreddits; + private LiveData> mAllFavoriteSubscribedSubreddits; public SubscribedSubredditViewModel(Application application, RedditDataRoomDatabase redditDataRoomDatabase, String accountName) { super(application); mSubscribedSubredditRepository = new SubscribedSubredditRepository(redditDataRoomDatabase, accountName); mAllSubscribedSubreddits = mSubscribedSubredditRepository.getAllSubscribedSubreddits(); + mAllFavoriteSubscribedSubreddits = mSubscribedSubredditRepository.getAllFavoriteSubscribedSubreddits(); } public LiveData> getAllSubscribedSubreddits() { return mAllSubscribedSubreddits; } + public LiveData> getAllFavoriteSubscribedSubreddits() { + return mAllFavoriteSubscribedSubreddits; + } + public void insert(SubscribedSubredditData subscribedSubredditData) { mSubscribedSubredditRepository.insert(subscribedSubredditData); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserData.java index 50b05f3d..701e7e5d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/SubscribedUserDatabase/SubscribedUserData.java @@ -19,11 +19,14 @@ public class SubscribedUserData { private String iconUrl; @ColumnInfo(name = "username") private String username; + @ColumnInfo(name = "is_favorite") + private boolean favorite; - public SubscribedUserData(@NonNull String name, String iconUrl, String username) { + public SubscribedUserData(@NonNull String name, String iconUrl, String username, boolean favorite) { this.name = name; this.iconUrl = iconUrl; this.username = username; + this.favorite = favorite; } @NonNull @@ -42,4 +45,12 @@ public class SubscribedUserData { public void setUsername(String username) { this.username = username; } + + public boolean isFavorite() { + return favorite; + } + + public void setFavorite(boolean favorite) { + this.favorite = favorite; + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java index bbe8849a..b48bfde9 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/UserFollowing.java @@ -99,7 +99,7 @@ public class UserFollowing { String accountName, boolean isSubscribing) { this.subscribedUserDao = subscribedUserDao; this.subscribedUserData = new SubscribedUserData(userData.getName(), userData.getIconUrl(), - accountName); + accountName, false); this.accountName = accountName; this.isSubscribing = isSubscribing; } diff --git a/app/src/main/res/drawable/ic_favorite_24dp.xml b/app/src/main/res/drawable/ic_favorite_24dp.xml new file mode 100644 index 00000000..64afd4b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_favorite_border_24dp.xml b/app/src/main/res/drawable/ic_favorite_border_24dp.xml new file mode 100644 index 00000000..48a506b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_favorite_border_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/item_favorite_subreddits_divider.xml b/app/src/main/res/layout/item_favorite_subreddits_divider.xml new file mode 100644 index 00000000..7b3f34a8 --- /dev/null +++ b/app/src/main/res/layout/item_favorite_subreddits_divider.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_subscribed_thing.xml b/app/src/main/res/layout/item_subscribed_thing.xml index 92e381aa..bb76a5fb 100644 --- a/app/src/main/res/layout/item_subscribed_thing.xml +++ b/app/src/main/res/layout/item_subscribed_thing.xml @@ -17,10 +17,18 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 24407978..bcd99f75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -332,4 +332,7 @@ Unable to save comment Comment unsaved Unable to unsave comment + + Favorites + All