From 7c729c2c4e8cac4d4ffaa02ff5e1f8334343bc52 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 5 Feb 2020 08:51:05 -0400 Subject: [PATCH] Add AdaptiveActionsToolbar for better context bar controls. --- .../conversation/ConversationFragment.java | 2 + .../thoughtcrime/securesms/util/ViewUtil.java | 10 +++ .../util/views/AdaptiveActionsToolbar.java | 86 +++++++++++++++++++ ...nversation_reaction_long_press_toolbar.xml | 8 +- app/src/main/res/values/attrs.xml | 4 + 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/views/AdaptiveActionsToolbar.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 9279f808b6..eac0b03a39 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -114,6 +114,7 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; +import org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar; import org.whispersystems.libsignal.util.guava.Optional; import java.io.IOException; @@ -1211,6 +1212,7 @@ public class ConversationFragment extends Fragment } setCorrectMenuVisibility(menu); + AdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth()); listener.onMessageActionToolbarOpened(); return true; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java index ba99406018..3782dc3f0e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java @@ -29,6 +29,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import androidx.interpolator.view.animation.FastOutSlowInInterpolator; + +import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -203,6 +205,14 @@ public class ViewUtil { return Math.round(dp * Resources.getSystem().getDisplayMetrics().density); } + public static int dpToSp(int dp) { + return (int) (dpToPx(dp) / Resources.getSystem().getDisplayMetrics().scaledDensity); + } + + public static int spToPx(float sp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, Resources.getSystem().getDisplayMetrics()); + } + public static void updateLayoutParams(@NonNull View view, int width, int height) { view.getLayoutParams().width = width; view.getLayoutParams().height = height; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/views/AdaptiveActionsToolbar.java b/app/src/main/java/org/thoughtcrime/securesms/util/views/AdaptiveActionsToolbar.java new file mode 100644 index 0000000000..bf6e28239b --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/util/views/AdaptiveActionsToolbar.java @@ -0,0 +1,86 @@ +package org.thoughtcrime.securesms.util.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.Menu; +import android.view.MenuItem; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ViewUtil; + +/** + * AdaptiveActionsToolbar behaves like a normal {@link Toolbar} except in that it ignores the + * showAsAlways attributes of menu items added via menu inflation, opting for an adaptive algorithm + * instead. This algorithm will display as many icons as it can up to a specific percentage of the + * screen. + * + * Each ActionView icon is expected to occupy 48dp of space, including padding. Items are stacked one + * after the next with no margins. + * + * This view can be customized via attributes: + * + * aat_max_shown -- controls the max number of items to display. + * aat_percent_for_actions -- controls the max percent of screen width the buttons can occupy. + */ +public class AdaptiveActionsToolbar extends Toolbar { + + private static final int NAVIGATION_SP = 48; + private static final int ACTION_VIEW_WIDTH_SP = 42; + private static final int OVERFLOW_VIEW_WIDTH_SP = 35; + + private int maxShown; + + public AdaptiveActionsToolbar(@NonNull Context context) { + this(context, null); + } + + public AdaptiveActionsToolbar(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, R.attr.toolbarStyle); + } + + public AdaptiveActionsToolbar(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AdaptiveActionsToolbar); + + maxShown = array.getInteger(R.styleable.AdaptiveActionsToolbar_aat_max_shown, 100); + + array.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + adjustMenuActions(getMenu(), maxShown, getMeasuredWidth()); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public static void adjustMenuActions(@NonNull Menu menu, int maxToShow, int toolbarWidthPx) { + int menuSize = menu.size(); + + int widthAllowed = toolbarWidthPx - ViewUtil.spToPx(NAVIGATION_SP); + int nItemsToShow = Math.min(maxToShow, Math.round(widthAllowed / ViewUtil.spToPx(ACTION_VIEW_WIDTH_SP))); + + if (nItemsToShow < menuSize) { + widthAllowed -= ViewUtil.spToPx(OVERFLOW_VIEW_WIDTH_SP); + } + + nItemsToShow = Math.min(maxToShow, Math.round(widthAllowed / ViewUtil.spToPx(ACTION_VIEW_WIDTH_SP))); + + for (int i = 0; i < menu.size(); i++) { + MenuItem item = menu.getItem(i); + if (nItemsToShow > 0) { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } else { + item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + } + nItemsToShow--; + } + } + +} diff --git a/app/src/main/res/layout/conversation_reaction_long_press_toolbar.xml b/app/src/main/res/layout/conversation_reaction_long_press_toolbar.xml index fdcfa492cc..e47279075a 100644 --- a/app/src/main/res/layout/conversation_reaction_long_press_toolbar.xml +++ b/app/src/main/res/layout/conversation_reaction_long_press_toolbar.xml @@ -1,11 +1,11 @@ - + app:menu="@menu/conversation_reactions_long_press_menu" + app:navigationIcon="@drawable/ic_x_conversation"> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index a0469f0040..f193692025 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -454,4 +454,8 @@ + + + +