From 70c581ba2108aea383f6dea063c369159ff1023c Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 26 Sep 2022 10:17:25 +0200 Subject: [PATCH] cache --- .../android/client/entities/api/Status.java | 2 + .../client/entities/app/StatusCache.java | 4 +- .../android/client/entities/app/Timeline.java | 2 + .../android/helper/TimelineHelper.java | 44 ++++++++----------- .../android/ui/drawer/StatusAdapter.java | 9 +++- .../timeline/FragmentMastodonTimeline.java | 14 +++++- .../viewmodel/mastodon/StatusesVM.java | 5 ++- .../viewmodel/mastodon/TimelinesVM.java | 27 +++++++++--- app/src/main/res/layout/drawer_status.xml | 8 ++++ 9 files changed, 78 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index 451610b7..3fc77d05 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -92,6 +92,8 @@ public class Status implements Serializable, Cloneable { public Poll poll; @SerializedName("pleroma") public Pleroma pleroma; + @SerializedName("cached") + public boolean cached = false; @Override public boolean equals(@Nullable Object obj) { diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java b/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java index 134717a0..42b432c9 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/StatusCache.java @@ -194,8 +194,9 @@ public class StatusCache { ContentValues values = new ContentValues(); values.put(Sqlite.COL_USER_ID, statusCache.user_id); values.put(Sqlite.COL_INSTANCE, statusCache.instance); - values.put(Sqlite.COL_SLUG, statusCache.slug); + values.put(Sqlite.COL_SLUG, slug); values.put(Sqlite.COL_STATUS_ID, statusCache.status_id); + values.put(Sqlite.COL_TYPE, statusCache.type.getValue()); values.put(Sqlite.COL_STATUS, mastodonStatusToStringStorage(statusCache.status)); values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(new Date())); //Inserts token @@ -415,7 +416,6 @@ public class StatusCache { /** * Get statuses from db * - * @param statusCache StatusCache - status in cache to compare * @return Statuses * @throws DBException - throws a db exception */ diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java index d26badc9..cc9c61a7 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java @@ -362,6 +362,8 @@ public class Timeline { LOCAL("LOCAL"), @SerializedName("PUBLIC") PUBLIC("PUBLIC"), + @SerializedName("CONTEXT") + CONTEXT("CONTEXT"), @SerializedName("TAG") TAG("TAG"), @SerializedName("ART") diff --git a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java index 766f8f18..471c90fc 100644 --- a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java @@ -22,8 +22,6 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; -import com.google.gson.annotations.SerializedName; - import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -36,6 +34,7 @@ import app.fedilab.android.client.endpoints.MastodonAccountsService; import app.fedilab.android.client.entities.api.Filter; import app.fedilab.android.client.entities.api.Notification; import app.fedilab.android.client.entities.api.Status; +import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.viewmodel.mastodon.AccountsVM; import okhttp3.OkHttpClient; import retrofit2.Call; @@ -64,10 +63,22 @@ public class TimelineHelper { * * @param context - Context * @param statuses - List of {@link Status} - * @param filterTimeLineType - {@link FilterTimeLineType} + * @param filterTimeLineType - {@link Timeline.TimeLineEnum} * @return filtered List */ - public static List filterStatus(Context context, List statuses, FilterTimeLineType filterTimeLineType) { + public static List filterStatus(Context context, List statuses, Timeline.TimeLineEnum filterTimeLineType) { + return filterStatus(context, statuses, filterTimeLineType, false); + } + + /** + * Allows to filter statuses, should be called in API calls (background) + * + * @param context - Context + * @param statuses - List of {@link Status} + * @param filterTimeLineType - {@link Timeline.TimeLineEnum} + * @return filtered List + */ + public static List filterStatus(Context context, List statuses, Timeline.TimeLineEnum filterTimeLineType, boolean cached) { //A security to make sure filters have been fetched before displaying messages List statusesToRemove = new ArrayList<>(); if (!BaseMainActivity.filterFetched) { @@ -95,11 +106,12 @@ public class TimelineHelper { continue; } for (String filterContext : filter.context) { - if (filterTimeLineType.value.equalsIgnoreCase(filterContext)) { + if (filterTimeLineType.getValue().equalsIgnoreCase(filterContext)) { if (filter.whole_word) { Pattern p = Pattern.compile("(^" + Pattern.quote(filter.phrase) + "\\b|\\b" + Pattern.quote(filter.phrase) + "$)"); for (Status status : statuses) { String content; + status.cached = cached; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(status.content, Html.FROM_HTML_MODE_LEGACY).toString(); else @@ -124,6 +136,7 @@ public class TimelineHelper { } else { for (Status status : statuses) { String content; + status.cached = cached; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) content = Html.fromHtml(status.content, Html.FROM_HTML_MODE_LEGACY).toString(); else @@ -183,7 +196,7 @@ public class TimelineHelper { continue; } for (String filterContext : filter.context) { - if (FilterTimeLineType.NOTIFICATION.value.equalsIgnoreCase(filterContext)) { + if (Timeline.TimeLineEnum.NOTIFICATION.getValue().equalsIgnoreCase(filterContext)) { if (filter.whole_word) { Pattern p = Pattern.compile("(^" + Pattern.quote(filter.phrase) + "\\b|\\b" + Pattern.quote(filter.phrase) + "$)"); for (Notification notification : notifications) { @@ -219,23 +232,4 @@ public class TimelineHelper { return notifications; } - public enum FilterTimeLineType { - @SerializedName("HOME") - HOME("HOME"), - @SerializedName("PUBLIC") - PUBLIC("PUBLIC"), - @SerializedName("CONTEXT") - CONTEXT("CONTEXT"), - @SerializedName("NOTIFICATION") - NOTIFICATION("NOTIFICATION"); - private final String value; - - FilterTimeLineType(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - } } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 782f4f01..9f94e9b6 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -495,7 +495,8 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.actionButtonFavorite.setInActiveImageTintColor(theme_icons_color); holder.binding.actionButtonBookmark.setInActiveImageTintColor(theme_icons_color); holder.binding.actionButtonBoost.setInActiveImageTintColor(theme_icons_color); - holder.binding.replyCount.setTextColor(theme_text_color); + Helper.changeDrawableColor(context, R.drawable.ic_baseline_cached_24, theme_icons_color); + holder.binding.replyCount.setTextColor(theme_icons_color); } else { holder.binding.actionButtonFavorite.setInActiveImageTintColor(ThemeHelper.getAttColor(context, R.attr.colorControlNormal)); holder.binding.actionButtonBookmark.setInActiveImageTintColor(ThemeHelper.getAttColor(context, R.attr.colorControlNormal)); @@ -515,6 +516,12 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.actionButtonBoost.setActiveImageTint(R.color.boost_icon); holder.binding.actionButtonBookmark.setActiveImageTint(R.color.marked_icon); + if (status.cached) { + holder.binding.cacheIndicator.setVisibility(View.VISIBLE); + } else { + holder.binding.cacheIndicator.setVisibility(View.GONE); + } + if (status.pinned) { holder.binding.statusPinned.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 05385ad8..ea703d69 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -574,9 +574,19 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. //Initialize with default params TimelinesVM.TimelineParams timelineParams = new TimelinesVM.TimelineParams(timelineType, direction, ident); timelineParams.limit = MastodonHelper.statusesPerCall(requireActivity()); - timelineParams.maxId = fetchingMissing ? max_id_fetch_more : max_id; - timelineParams.minId = fetchingMissing ? min_id_fetch_more : min_id; + + if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) { + timelineParams.maxId = null; + timelineParams.minId = null; + } else if (direction == DIRECTION.BOTTOM) { + timelineParams.maxId = fetchingMissing ? max_id_fetch_more : max_id; + timelineParams.minId = null; + } else { + timelineParams.minId = fetchingMissing ? min_id_fetch_more : min_id; + timelineParams.maxId = null; + } timelineParams.fetchingMissing = fetchingMissing; + switch (timelineType) { case LOCAL: timelineParams.local = true; diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java index dd4d6140..f094580d 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/StatusesVM.java @@ -43,6 +43,7 @@ import app.fedilab.android.client.entities.api.ScheduledStatuses; import app.fedilab.android.client.entities.api.Status; import app.fedilab.android.client.entities.app.BaseAccount; import app.fedilab.android.client.entities.app.StatusCache; +import app.fedilab.android.client.entities.app.Timeline; import app.fedilab.android.exception.DBException; import app.fedilab.android.helper.Helper; import app.fedilab.android.helper.MastodonHelper; @@ -352,8 +353,8 @@ public class StatusesVM extends AndroidViewModel { if (contextResponse.isSuccessful()) { context = contextResponse.body(); if (context != null) { - TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.descendants, TimelineHelper.FilterTimeLineType.CONTEXT); - TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.ancestors, TimelineHelper.FilterTimeLineType.CONTEXT); + TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.descendants, Timeline.TimeLineEnum.CONTEXT); + TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.ancestors, Timeline.TimeLineEnum.CONTEXT); } } diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index 65cd91fc..23b9aab3 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -127,7 +127,6 @@ public class TimelinesVM extends AndroidViewModel { Response> publicTlResponse = publicTlCall.execute(); if (publicTlResponse.isSuccessful()) { statusList = publicTlResponse.body(); - statusList = statusList; } } catch (Exception e) { e.printStackTrace(); @@ -248,7 +247,7 @@ public class TimelinesVM extends AndroidViewModel { statusList.add(status); } } - statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC); + statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, Timeline.TimeLineEnum.PUBLIC); statuses.pagination = new Pagination(); if (statusList.size() > 0) { statuses.pagination.min_id = statusList.get(0).id; @@ -294,7 +293,7 @@ public class TimelinesVM extends AndroidViewModel { statusList.add(status); } } - statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC); + statuses.statuses = TimelineHelper.filterStatus(getApplication(), statusList, Timeline.TimeLineEnum.PUBLIC); statuses.pagination = new Pagination(); if (statusList.size() > 0) { //These values are not used. @@ -371,8 +370,9 @@ public class TimelinesVM extends AndroidViewModel { Response> timelineResponse = timelineCall.execute(); if (timelineResponse.isSuccessful()) { List statusList = timelineResponse.body(); - statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), statusList, TimelineHelper.FilterTimeLineType.PUBLIC); + statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), statusList, timelineParams.type); statuses.pagination = MastodonHelper.getPagination(timelineResponse.headers()); + if (statusList != null && statusList.size() > 0) { if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP) { Status newestStatus = new StatusCache(getApplication().getApplicationContext()).getNewestStatus(timelineParams.slug, timelineParams.instance, timelineParams.userId); @@ -426,7 +426,7 @@ public class TimelinesVM extends AndroidViewModel { try { statuses = statusCacheDAO.geStatuses(timelineParams.slug, timelineParams.instance, timelineParams.userId, timelineParams.maxId, timelineParams.minId, timelineParams.sinceId); if (statuses != null) { - TimelineHelper.filterStatus(getApplication().getApplicationContext(), statuses.statuses, TimelineHelper.FilterTimeLineType.HOME); + TimelineHelper.filterStatus(getApplication().getApplicationContext(), statuses.statuses, timelineParams.type, true); if (statuses.statuses != null && statuses.statuses.size() > 0) { statuses.pagination = new Pagination(); statuses.pagination.min_id = statuses.statuses.get(0).id; @@ -480,6 +480,23 @@ public class TimelinesVM extends AndroidViewModel { } slug = key; } + + @NonNull + @Override + public String toString() { + return "direction: " + direction + "\n" + + "instance: " + instance + "\n" + + "token: " + token + "\n" + + "type: " + type + "\n" + + "slug: " + slug + "\n" + + "userId: " + userId + "\n" + + "remote: " + remote + "\n" + + "onlyMedia: " + onlyMedia + "\n" + + "local: " + local + "\n" + + "maxId: " + maxId + "\n" + + "sinceId: " + sinceId + "\n" + + "minId: " + minId + "\n"; + } } diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index f77efbe1..2600ed6e 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -594,6 +594,14 @@ app:sparkbutton_primaryColor="@color/marked_icon" app:sparkbutton_secondaryColor="@color/marked_icon" /> + +