Some improvements with counters and pagination

pull/434/head
Thomas 2 years ago
parent 900a91f13f
commit d8f8c2dc0d

@ -37,7 +37,6 @@ import android.os.Looper;
import android.text.Editable; import android.text.Editable;
import android.text.Html; import android.text.Html;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.util.Patterns; import android.util.Patterns;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.Gravity; import android.view.Gravity;
@ -150,7 +149,7 @@ import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; 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 String currentInstance, currentToken, currentUserID, client_id, client_secret, software;
public static HashMap<String, List<Emoji>> emojis = new HashMap<>(); 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 @Override
public void onUpdate(int count, Timeline.TimeLineEnum type, String slug) { public void onUpdate(int count, Timeline.TimeLineEnum type, String slug) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this); SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this);
@ -1139,16 +1168,12 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
} }
int selectedTab = binding.tabLayout.getSelectedTabPosition(); int selectedTab = binding.tabLayout.getSelectedTabPosition();
TabLayout.Tab tab = binding.tabLayout.getTabAt(selectedTab); TabLayout.Tab tab = binding.tabLayout.getTabAt(selectedTab);
Log.v(Helper.TAG, "selectedTab: " + selectedTab);
Log.v(Helper.TAG, "tab: " + tab);
View view = null; View view = null;
if (tab != null) { if (tab != null) {
view = tab.getCustomView(); view = tab.getCustomView();
} }
if (view != null) { if (view != null) {
Log.v(Helper.TAG, "view: " + view);
TextView counter = view.findViewById(R.id.tab_counter); TextView counter = view.findViewById(R.id.tab_counter);
Log.v(Helper.TAG, "counter: " + counter);
if (counter != null) { if (counter != null) {
if (count > 0) { if (count > 0) {
counter.setVisibility(View.VISIBLE); counter.setVisibility(View.VISIBLE);

@ -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 String max_id, min_id, min_id_fetch_more, max_id_fetch_more;
private ConversationAdapter conversationAdapter; private ConversationAdapter conversationAdapter;
private LinearLayoutManager mLayoutManager; private LinearLayoutManager mLayoutManager;
public UpdateCounters update;
public View onCreateView(@NonNull LayoutInflater inflater, public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) { ViewGroup container, Bundle savedInstanceState) {
@ -318,7 +319,11 @@ public class FragmentMastodonConversation extends Fragment implements Conversati
flagLoading = fetched_conversations.pagination.max_id == null; flagLoading = fetched_conversations.pagination.max_id == null;
binding.noAction.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE);
//Update the timeline with new statuses //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) { if (direction == FragmentMastodonTimeline.DIRECTION.TOP && fetchingMissing) {
binding.recyclerView.scrollToPosition(getPosition(fetched_conversations.conversations.get(fetched_conversations.conversations.size() - 1)) + 1); 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 * @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) { if (conversationsReceived != null && conversationsReceived.size() > 0) {
for (Conversation conversationReceived : conversationsReceived) { for (Conversation conversationReceived : conversationsReceived) {
int position = 0; int position = 0;
@ -379,6 +385,9 @@ public class FragmentMastodonConversation extends Fragment implements Conversati
if (!conversationList.contains(conversationReceived)) { if (!conversationList.contains(conversationReceived)) {
conversationList.add(position, conversationReceived); conversationList.add(position, conversationReceived);
conversationAdapter.notifyItemInserted(position); conversationAdapter.notifyItemInserted(position);
if (!conversationReceived.cached) {
insertedConversations++;
}
} }
break; 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); route(FragmentMastodonTimeline.DIRECTION.BOTTOM, true, conversationToUpdate);
} }
public interface UpdateCounters {
void onUpdateConversation(int count);
}
} }

@ -63,6 +63,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
private boolean flagLoading; private boolean flagLoading;
private List<Notification> notificationList; private List<Notification> notificationList;
private NotificationAdapter notificationAdapter; private NotificationAdapter notificationAdapter;
private final BroadcastReceiver receive_action = new BroadcastReceiver() { private final BroadcastReceiver receive_action = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { 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; flagLoading = fetched_notifications.pagination.max_id == null;
binding.noAction.setVisibility(View.GONE); binding.noAction.setVisibility(View.GONE);
//Update the timeline with new statuses //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) { if (direction == FragmentMastodonTimeline.DIRECTION.TOP && fetchingMissing) {
binding.recyclerView.scrollToPosition(getPosition(fetched_notifications.notifications.get(fetched_notifications.notifications.size() - 1)) + 1); 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 * @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) { if (notificationsReceived != null && notificationsReceived.size() > 0) {
for (Notification notificationReceived : notificationsReceived) { for (Notification notificationReceived : notificationsReceived) {
int position = 0; int position = 0;
@ -506,6 +511,9 @@ public class FragmentMastodonNotification extends Fragment implements Notificati
if (!notificationList.contains(notificationReceived)) { if (!notificationList.contains(notificationReceived)) {
notificationList.add(position, notificationReceived); notificationList.add(position, notificationReceived);
notificationAdapter.notifyItemInserted(position); notificationAdapter.notifyItemInserted(position);
if (!notificationReceived.cached) {
insertedNotifications++;
}
} }
break; 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; return value;
} }
} }
} }

@ -323,9 +323,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
} }
//Update the timeline with new statuses //Update the timeline with new statuses
int insertedStatus = updateStatusListWith(fetched_statuses.statuses); int insertedStatus = updateStatusListWith(fetched_statuses.statuses);
//For these directions, the app will display counters for new messages //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); update.onUpdate(insertedStatus, timelineType, slug);
} }
if (direction == DIRECTION.TOP && fetchingMissing) { if (direction == DIRECTION.TOP && fetchingMissing) {
@ -528,7 +527,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
//Initialize with default params //Initialize with default params
timelineParams = new TimelinesVM.TimelineParams(timelineType, direction, ident); timelineParams = new TimelinesVM.TimelineParams(timelineType, direction, ident);
timelineParams.limit = MastodonHelper.statusesPerCall(requireActivity()); 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.maxId = null;
timelineParams.minId = null; timelineParams.minId = null;
} else if (direction == DIRECTION.BOTTOM) { } else if (direction == DIRECTION.BOTTOM) {

@ -54,6 +54,7 @@ import es.dmoral.toasty.Toasty;
public class FragmentNotificationContainer extends Fragment { public class FragmentNotificationContainer extends Fragment {
private FragmentNotificationContainerBinding binding; private FragmentNotificationContainerBinding binding;
public static UpdateCounters update;
public View onCreateView(@NonNull LayoutInflater inflater, public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) { ViewGroup container, Bundle savedInstanceState) {
@ -268,4 +269,7 @@ public class FragmentNotificationContainer extends Fragment {
} }
public interface UpdateCounters {
void onUpdateNotification(int count, String slug);
}
} }

@ -118,9 +118,14 @@ public class FedilabPageAdapter extends FragmentStatePagerAdapter {
PinnedTimeline pinnedTimeline = pinned.pinnedTimelines.get(pinnedPosition); PinnedTimeline pinnedTimeline = pinned.pinnedTimelines.get(pinnedPosition);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, pinnedTimeline.type); bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, pinnedTimeline.type);
if (pinnedTimeline.type == Timeline.TimeLineEnum.NOTIFICATION) { 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) { } 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) { } else if (pinnedTimeline.type == Timeline.TimeLineEnum.LIST) {
bundle.putString(Helper.ARG_LIST_ID, pinnedTimeline.mastodonList.id); bundle.putString(Helper.ARG_LIST_ID, pinnedTimeline.mastodonList.id);
} else if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) { } else if (pinnedTimeline.type == Timeline.TimeLineEnum.TAG) {

@ -75,7 +75,7 @@ public class NotificationsVM extends AndroidViewModel {
private static void addFetchMoreNotifications(List<Notification> notificationList, List<Notification> timelineNotifications, TimelinesVM.TimelineParams timelineParams) throws DBException { 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 (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 //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) { if (notificationList.get(notificationList.size() - 1).id.compareToIgnoreCase(timelineNotifications.get(0).id) > 0) {
notificationList.get(notificationList.size() - 1).isFetchMore = true; notificationList.get(notificationList.size() - 1).isFetchMore = true;
@ -167,10 +167,12 @@ public class NotificationsVM extends AndroidViewModel {
notifications.notifications = notPresentNotifications; notifications.notifications = notPresentNotifications;
} }
TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications, true); TimelineHelper.filterNotification(getApplication().getApplicationContext(), notifications.notifications, true);
addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams); if (notifications.notifications.size() > 0) {
notifications.pagination = new Pagination(); addFetchMoreNotifications(notifications.notifications, notificationList, timelineParams);
notifications.pagination.min_id = notifications.notifications.get(0).id; notifications.pagination = new Pagination();
notifications.pagination.max_id = notifications.notifications.get(notifications.notifications.size() - 1).id; notifications.pagination.min_id = notifications.notifications.get(0).id;
notifications.pagination.max_id = notifications.notifications.get(notifications.notifications.size() - 1).id;
}
} }
} }
} catch (DBException e) { } catch (DBException e) {

@ -343,7 +343,7 @@ public class TimelinesVM extends AndroidViewModel {
private static void addFetchMore(List<Status> statusList, List<Status> timelineStatuses, TimelineParams timelineParams) throws DBException { 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 (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 //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) { if (statusList.get(statusList.size() - 1).id.compareToIgnoreCase(timelineStatuses.get(0).id) > 0) {
statusList.get(statusList.size() - 1).isFetchMore = true; 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 { 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 (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 //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) { if (conversationList.get(conversationList.size() - 1).id.compareToIgnoreCase(timelineConversations.get(0).id) > 0) {
conversationList.get(conversationList.size() - 1).isFetchMore = true; conversationList.get(conversationList.size() - 1).isFetchMore = true;
@ -586,10 +586,12 @@ public class TimelinesVM extends AndroidViewModel {
//Only not already present statuses are added //Only not already present statuses are added
conversations.conversations = notPresentConversations; conversations.conversations = notPresentConversations;
} }
addFetchMoreConversation(conversations.conversations, timelineConversations, timelineParams); if (conversations.conversations.size() > 0) {
conversations.pagination = new Pagination(); addFetchMoreConversation(conversations.conversations, timelineConversations, timelineParams);
conversations.pagination.min_id = conversations.conversations.get(0).id; conversations.pagination = new Pagination();
conversations.pagination.max_id = conversations.conversations.get(conversations.conversations.size() - 1).id; conversations.pagination.min_id = conversations.conversations.get(0).id;
conversations.pagination.max_id = conversations.conversations.get(conversations.conversations.size() - 1).id;
}
} }
} }
} catch (DBException e) { } catch (DBException e) {

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:tint="?attr/colorControlNormal" android:tint="?attr/iconColor"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <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" /> 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> </vector>

@ -1,10 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:tint="?attr/colorControlNormal" android:tint="?attr/iconColor"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <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" /> 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> </vector>

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

@ -586,6 +586,7 @@
android:id="@+id/action_button_bookmark" android:id="@+id/action_button_bookmark"
android:layout_width="28dp" android:layout_width="28dp"
android:layout_height="28dp" android:layout_height="28dp"
android:layout_gravity="center"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"

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

@ -7,6 +7,7 @@
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon" android:id="@+id/icon"
tools:src="@drawable/nitter"
android:layout_width="15dp" android:layout_width="15dp"
android:layout_height="15dp" android:layout_height="15dp"
android:layout_gravity="center" /> android:layout_gravity="center" />
@ -17,6 +18,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
tools:text="fedilab_app"
android:ellipsize="end" android:ellipsize="end"
android:maxWidth="150dp" android:maxWidth="150dp"
android:singleLine="true" android:singleLine="true"

Loading…
Cancel
Save