From d8f8c2dc0d800a00b74831bc4cd7ac37699c85e0 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 3 Oct 2022 17:48:12 +0200 Subject: [PATCH] Some improvements with counters and pagination --- .../app/fedilab/android/BaseMainActivity.java | 37 ++++++++++++++++--- .../FragmentMastodonConversation.java | 18 +++++++-- .../FragmentMastodonNotification.java | 14 ++++++- .../timeline/FragmentMastodonTimeline.java | 5 +-- .../FragmentNotificationContainer.java | 4 ++ .../ui/pageadapter/FedilabPageAdapter.java | 9 ++++- .../viewmodel/mastodon/NotificationsVM.java | 12 +++--- .../viewmodel/mastodon/TimelinesVM.java | 14 ++++--- .../res/drawable/ic_baseline_bookmark_24.xml | 4 +- .../ic_baseline_bookmark_border_24.xml | 4 +- app/src/main/res/drawable/shape_counter.xml | 2 +- app/src/main/res/layout/drawer_status.xml | 1 + .../res/layout/tab_custom_default_view.xml | 20 +++++++--- app/src/main/res/layout/tab_custom_view.xml | 2 + 14 files changed, 108 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java index 37fdadfb..192afd10 100644 --- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java +++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java @@ -37,7 +37,6 @@ import android.os.Looper; import android.text.Editable; import android.text.Html; import android.text.TextWatcher; -import android.util.Log; import android.util.Patterns; import android.view.ContextThemeWrapper; import android.view.Gravity; @@ -150,7 +149,7 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -public abstract class BaseMainActivity extends BaseActivity implements NetworkStateReceiver.NetworkStateReceiverListener, FragmentMastodonTimeline.UpdateCounters { +public abstract class BaseMainActivity extends BaseActivity implements NetworkStateReceiver.NetworkStateReceiverListener, FragmentMastodonTimeline.UpdateCounters, FragmentNotificationContainer.UpdateCounters, FragmentMastodonConversation.UpdateCounters { public static String currentInstance, currentToken, currentUserID, client_id, client_secret, software; public static HashMap> emojis = new HashMap<>(); @@ -1084,6 +1083,36 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } } + @Override + public void onUpdateConversation(int count) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this); + boolean singleBar = sharedpreferences.getBoolean(getString(R.string.SET_USE_SINGLE_TOPBAR), false); + if (!singleBar) { + if (count > 0) { + binding.bottomNavView.getOrCreateBadge(R.id.nav_privates).setNumber(count); + binding.bottomNavView.getBadge(R.id.nav_privates).setBackgroundColor(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_accent_reference)); + binding.bottomNavView.getBadge(R.id.nav_privates).setBadgeTextColor(ThemeHelper.getAttColor(BaseMainActivity.this, R.attr.mTextColor)); + } else { + binding.bottomNavView.removeBadge(R.id.nav_privates); + } + } + } + + @Override + public void onUpdateNotification(int count, String slug) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this); + boolean singleBar = sharedpreferences.getBoolean(getString(R.string.SET_USE_SINGLE_TOPBAR), false); + if (!singleBar) { + if (count > 0) { + binding.bottomNavView.getOrCreateBadge(R.id.nav_notifications).setNumber(count); + binding.bottomNavView.getBadge(R.id.nav_notifications).setBackgroundColor(ContextCompat.getColor(BaseMainActivity.this, R.color.cyanea_accent_reference)); + binding.bottomNavView.getBadge(R.id.nav_notifications).setBadgeTextColor(ThemeHelper.getAttColor(BaseMainActivity.this, R.attr.mTextColor)); + } else { + binding.bottomNavView.removeBadge(R.id.nav_notifications); + } + } + } + @Override public void onUpdate(int count, Timeline.TimeLineEnum type, String slug) { SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this); @@ -1139,16 +1168,12 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt } int selectedTab = binding.tabLayout.getSelectedTabPosition(); TabLayout.Tab tab = binding.tabLayout.getTabAt(selectedTab); - Log.v(Helper.TAG, "selectedTab: " + selectedTab); - Log.v(Helper.TAG, "tab: " + tab); View view = null; if (tab != null) { view = tab.getCustomView(); } if (view != null) { - Log.v(Helper.TAG, "view: " + view); TextView counter = view.findViewById(R.id.tab_counter); - Log.v(Helper.TAG, "counter: " + counter); if (counter != null) { if (count > 0) { counter.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java index db612463..f7fb285b 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java @@ -56,6 +56,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati private String max_id, min_id, min_id_fetch_more, max_id_fetch_more; private ConversationAdapter conversationAdapter; private LinearLayoutManager mLayoutManager; + public UpdateCounters update; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -318,7 +319,11 @@ public class FragmentMastodonConversation extends Fragment implements Conversati flagLoading = fetched_conversations.pagination.max_id == null; binding.noAction.setVisibility(View.GONE); //Update the timeline with new statuses - updateConversationListWith(fetched_conversations.conversations); + int insertedConversations = updateConversationListWith(fetched_conversations.conversations); + //For these directions, the app will display counters for new messages + if (insertedConversations >= 0 && update != null && (direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW || direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || direction == FragmentMastodonTimeline.DIRECTION.REFRESH)) { + update.onUpdateConversation(insertedConversations); + } if (direction == FragmentMastodonTimeline.DIRECTION.TOP && fetchingMissing) { binding.recyclerView.scrollToPosition(getPosition(fetched_conversations.conversations.get(fetched_conversations.conversations.size() - 1)) + 1); } @@ -365,7 +370,8 @@ public class FragmentMastodonConversation extends Fragment implements Conversati * * @param conversationsReceived - List Conversation received */ - private void updateConversationListWith(List conversationsReceived) { + private int updateConversationListWith(List conversationsReceived) { + int insertedConversations = 0; if (conversationsReceived != null && conversationsReceived.size() > 0) { for (Conversation conversationReceived : conversationsReceived) { int position = 0; @@ -379,6 +385,9 @@ public class FragmentMastodonConversation extends Fragment implements Conversati if (!conversationList.contains(conversationReceived)) { conversationList.add(position, conversationReceived); conversationAdapter.notifyItemInserted(position); + if (!conversationReceived.cached) { + insertedConversations++; + } } break; } @@ -392,6 +401,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati } } } + return insertedConversations; } @@ -411,5 +421,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati route(FragmentMastodonTimeline.DIRECTION.BOTTOM, true, conversationToUpdate); } - + public interface UpdateCounters { + void onUpdateConversation(int count); + } } \ No newline at end of file diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java index 07ade85f..3e58857a 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java @@ -63,6 +63,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati private boolean flagLoading; private List notificationList; private NotificationAdapter notificationAdapter; + private final BroadcastReceiver receive_action = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -465,7 +466,10 @@ public class FragmentMastodonNotification extends Fragment implements Notificati flagLoading = fetched_notifications.pagination.max_id == null; binding.noAction.setVisibility(View.GONE); //Update the timeline with new statuses - updateNotificationListWith(fetched_notifications.notifications); + int insertedStatus = updateNotificationListWith(fetched_notifications.notifications); + if (insertedStatus >= 0 && FragmentNotificationContainer.update != null && notificationType == NotificationTypeEnum.ALL && (direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW || direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || direction == FragmentMastodonTimeline.DIRECTION.REFRESH)) { + FragmentNotificationContainer.update.onUpdateNotification(insertedStatus, notificationType.getValue()); + } if (direction == FragmentMastodonTimeline.DIRECTION.TOP && fetchingMissing) { binding.recyclerView.scrollToPosition(getPosition(fetched_notifications.notifications.get(fetched_notifications.notifications.size() - 1)) + 1); } @@ -492,7 +496,8 @@ public class FragmentMastodonNotification extends Fragment implements Notificati * * @param notificationsReceived - List Notifications received */ - private void updateNotificationListWith(List notificationsReceived) { + private int updateNotificationListWith(List notificationsReceived) { + int insertedNotifications = 0; if (notificationsReceived != null && notificationsReceived.size() > 0) { for (Notification notificationReceived : notificationsReceived) { int position = 0; @@ -506,6 +511,9 @@ public class FragmentMastodonNotification extends Fragment implements Notificati if (!notificationList.contains(notificationReceived)) { notificationList.add(position, notificationReceived); notificationAdapter.notifyItemInserted(position); + if (!notificationReceived.cached) { + insertedNotifications++; + } } break; } @@ -519,6 +527,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } } } + return insertedNotifications; } @@ -575,4 +584,5 @@ public class FragmentMastodonNotification extends Fragment implements Notificati return value; } } + } \ No newline at end of file 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 413e406a..02485cc6 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 @@ -323,9 +323,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } //Update the timeline with new statuses int insertedStatus = updateStatusListWith(fetched_statuses.statuses); - //For these directions, the app will display counters for new messages - if (insertedStatus >= 0 && update != null && (direction == DIRECTION.FETCH_NEW || direction == DIRECTION.SCROLL_TOP)) { + if (insertedStatus >= 0 && update != null && (direction == DIRECTION.FETCH_NEW || direction == DIRECTION.SCROLL_TOP || direction == DIRECTION.REFRESH)) { update.onUpdate(insertedStatus, timelineType, slug); } if (direction == DIRECTION.TOP && fetchingMissing) { @@ -528,7 +527,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. //Initialize with default params timelineParams = new TimelinesVM.TimelineParams(timelineType, direction, ident); timelineParams.limit = MastodonHelper.statusesPerCall(requireActivity()); - if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) { + if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP || direction == DIRECTION.FETCH_NEW) { timelineParams.maxId = null; timelineParams.minId = null; } else if (direction == DIRECTION.BOTTOM) { diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java index 2e138d61..7427bb3a 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentNotificationContainer.java @@ -54,6 +54,7 @@ import es.dmoral.toasty.Toasty; public class FragmentNotificationContainer extends Fragment { private FragmentNotificationContainerBinding binding; + public static UpdateCounters update; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -268,4 +269,7 @@ public class FragmentNotificationContainer extends Fragment { } + public interface UpdateCounters { + void onUpdateNotification(int count, String slug); + } } diff --git a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java index 7203263b..e8f740f1 100644 --- a/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/pageadapter/FedilabPageAdapter.java @@ -118,9 +118,14 @@ public class FedilabPageAdapter extends FragmentStatePagerAdapter { PinnedTimeline pinnedTimeline = pinned.pinnedTimelines.get(pinnedPosition); bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, pinnedTimeline.type); if (pinnedTimeline.type == Timeline.TimeLineEnum.NOTIFICATION) { - return new FragmentNotificationContainer(); + FragmentNotificationContainer fragmentNotificationContainer = new FragmentNotificationContainer(); + FragmentNotificationContainer.update = activity; + return fragmentNotificationContainer; } else if (pinnedTimeline.type == Timeline.TimeLineEnum.DIRECT) { - return new FragmentMastodonConversation(); + FragmentMastodonConversation fragmentMastodonConversation = new FragmentMastodonConversation(); + fragmentMastodonConversation.update = activity; + return fragmentMastodonConversation; + } else if (pinnedTimeline.type == Timeline.TimeLineEnum.LIST) { bundle.putString(Helper.ARG_LIST_ID, pinnedTimeline.mastodonList.id); } else if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java index 71991091..b10ecf53 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java @@ -75,7 +75,7 @@ public class NotificationsVM extends AndroidViewModel { private static void addFetchMoreNotifications(List notificationList, List timelineNotifications, TimelinesVM.TimelineParams timelineParams) throws DBException { if (notificationList != null && notificationList.size() > 0 && timelineNotifications != null && timelineNotifications.size() > 0) { - if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP) { + if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (notificationList.get(notificationList.size() - 1).id.compareToIgnoreCase(timelineNotifications.get(0).id) > 0) { notificationList.get(notificationList.size() - 1).isFetchMore = true; @@ -167,10 +167,12 @@ public class NotificationsVM extends AndroidViewModel { notifications.notifications = notPresentNotifications; } TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications, true); - addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); - notifications.pagination = new Pagination(); - notifications.pagination.min_id = notifications.notifications.get(0).id; - notifications.pagination.max_id = notifications.notifications.get(notifications.notifications.size() - 1).id; + if (notifications.notifications.size() > 0) { + addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); + notifications.pagination = new Pagination(); + notifications.pagination.min_id = notifications.notifications.get(0).id; + notifications.pagination.max_id = notifications.notifications.get(notifications.notifications.size() - 1).id; + } } } } catch (DBException e) { 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 eab6b9a2..b34655e3 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 @@ -343,7 +343,7 @@ public class TimelinesVM extends AndroidViewModel { private static void addFetchMore(List statusList, List timelineStatuses, TimelineParams timelineParams) throws DBException { if (statusList != null && statusList.size() > 0 && timelineStatuses != null && timelineStatuses.size() > 0) { - if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP) { + if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (statusList.get(statusList.size() - 1).id.compareToIgnoreCase(timelineStatuses.get(0).id) > 0) { statusList.get(statusList.size() - 1).isFetchMore = true; @@ -365,7 +365,7 @@ public class TimelinesVM extends AndroidViewModel { private static void addFetchMoreConversation(List conversationList, List timelineConversations, TimelineParams timelineParams) throws DBException { if (conversationList != null && conversationList.size() > 0 && timelineConversations != null && timelineConversations.size() > 0) { - if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP) { + if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (conversationList.get(conversationList.size() - 1).id.compareToIgnoreCase(timelineConversations.get(0).id) > 0) { conversationList.get(conversationList.size() - 1).isFetchMore = true; @@ -586,10 +586,12 @@ public class TimelinesVM extends AndroidViewModel { //Only not already present statuses are added conversations.conversations = notPresentConversations; } - addFetchMoreConversation(conversations.conversations, timelineConversations, timelineParams); - conversations.pagination = new Pagination(); - conversations.pagination.min_id = conversations.conversations.get(0).id; - conversations.pagination.max_id = conversations.conversations.get(conversations.conversations.size() - 1).id; + if (conversations.conversations.size() > 0) { + addFetchMoreConversation(conversations.conversations, timelineConversations, timelineParams); + conversations.pagination = new Pagination(); + conversations.pagination.min_id = conversations.conversations.get(0).id; + conversations.pagination.max_id = conversations.conversations.get(conversations.conversations.size() - 1).id; + } } } } catch (DBException e) { diff --git a/app/src/main/res/drawable/ic_baseline_bookmark_24.xml b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml index 78ef4991..2c2418e9 100644 --- a/app/src/main/res/drawable/ic_baseline_bookmark_24.xml +++ b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml @@ -1,10 +1,10 @@ diff --git a/app/src/main/res/drawable/ic_baseline_bookmark_border_24.xml b/app/src/main/res/drawable/ic_baseline_bookmark_border_24.xml index 45fef5ac..b1d59a29 100644 --- a/app/src/main/res/drawable/ic_baseline_bookmark_border_24.xml +++ b/app/src/main/res/drawable/ic_baseline_bookmark_border_24.xml @@ -1,10 +1,10 @@ diff --git a/app/src/main/res/drawable/shape_counter.xml b/app/src/main/res/drawable/shape_counter.xml index 437e1b69..2356395e 100644 --- a/app/src/main/res/drawable/shape_counter.xml +++ b/app/src/main/res/drawable/shape_counter.xml @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index e97591b1..eb8c8731 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -586,6 +586,7 @@ android:id="@+id/action_button_bookmark" android:layout_width="28dp" android:layout_height="28dp" + android:layout_gravity="center" android:layout_marginStart="12dp" android:layout_marginTop="2dp" android:adjustViewBounds="true" diff --git a/app/src/main/res/layout/tab_custom_default_view.xml b/app/src/main/res/layout/tab_custom_default_view.xml index 3220650a..fb282e40 100644 --- a/app/src/main/res/layout/tab_custom_default_view.xml +++ b/app/src/main/res/layout/tab_custom_default_view.xml @@ -1,23 +1,31 @@ - + - + diff --git a/app/src/main/res/layout/tab_custom_view.xml b/app/src/main/res/layout/tab_custom_view.xml index 0a8ed3a8..5ae18c73 100644 --- a/app/src/main/res/layout/tab_custom_view.xml +++ b/app/src/main/res/layout/tab_custom_view.xml @@ -7,6 +7,7 @@ @@ -17,6 +18,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginStart="4dp" + tools:text="fedilab_app" android:ellipsize="end" android:maxWidth="150dp" android:singleLine="true"