Some improvements with counters and pagination

This commit is contained in:
Thomas 2022-10-03 17:48:12 +02:00
parent 900a91f13f
commit d8f8c2dc0d
14 changed files with 108 additions and 38 deletions

View File

@ -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<String, List<Emoji>> 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);

View File

@ -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> Conversation received
*/
private void updateConversationListWith(List<Conversation> conversationsReceived) {
private int updateConversationListWith(List<Conversation> 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);
}
}

View File

@ -63,6 +63,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
private boolean flagLoading;
private List<Notification> 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<Notification> Notifications received
*/
private void updateNotificationListWith(List<Notification> notificationsReceived) {
private int updateNotificationListWith(List<Notification> 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;
}
}
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -75,7 +75,7 @@ public class NotificationsVM extends AndroidViewModel {
private static void addFetchMoreNotifications(List<Notification> notificationList, List<Notification> 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) {

View File

@ -343,7 +343,7 @@ public class TimelinesVM extends AndroidViewModel {
private static void addFetchMore(List<Status> statusList, List<Status> 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<Conversation> conversationList, List<Conversation> 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) {

View File

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:tint="?attr/iconColor"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:fillColor="?attr/iconColor"
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z" />
</vector>

View File

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:tint="?attr/iconColor"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:fillColor="?attr/iconColor"
android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z" />
</vector>

View File

@ -5,5 +5,5 @@
<padding
android:left="2dp"
android:right="2dp" />
<corners android:radius="3dp" />
<corners android:radius="50dp" />
</shape>

View File

@ -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"

View File

@ -1,23 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/icon"
tools:src="@drawable/ic_baseline_home_24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<TextView
android:layout_alignStart="@+id/icon"
android:layout_marginStart="2dp"
android:gravity="top|end"
android:id="@+id/tab_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/icon"
android:layout_alignEnd="@+id/icon"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
app:layout_constraintStart_toEndOf="@+id/icon"
app:layout_constraintTop_toTopOf="parent"
android:background="@drawable/shape_counter"
android:paddingLeft="2dp"
android:paddingRight="2dp"
@ -26,4 +34,4 @@
android:visibility="gone"
tools:text="35"
tools:visibility="visible" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -7,6 +7,7 @@
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
tools:src="@drawable/nitter"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_gravity="center" />
@ -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"