Add AdaptiveActionsToolbar for better context bar controls.

This commit is contained in:
Alex Hart 2020-02-05 08:51:05 -04:00 committed by GitHub
parent ecf7a416eb
commit 7c729c2c4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 4 deletions

View File

@ -114,6 +114,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException; import java.io.IOException;
@ -1211,6 +1212,7 @@ public class ConversationFragment extends Fragment
} }
setCorrectMenuVisibility(menu); setCorrectMenuVisibility(menu);
AdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
listener.onMessageActionToolbarOpened(); listener.onMessageActionToolbarOpened();
return true; return true;
} }

View File

@ -29,6 +29,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -203,6 +205,14 @@ public class ViewUtil {
return Math.round(dp * Resources.getSystem().getDisplayMetrics().density); 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) { public static void updateLayoutParams(@NonNull View view, int width, int height) {
view.getLayoutParams().width = width; view.getLayoutParams().width = width;
view.getLayoutParams().height = height; view.getLayoutParams().height = height;

View File

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

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" <org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="@color/action_mode_status_bar" android:background="@color/action_mode_status_bar"
android:theme="@style/TextSecure.DarkActionBar.Conversation" android:theme="@style/TextSecure.DarkActionBar.Conversation"
app:navigationIcon="@drawable/ic_x_conversation" app:menu="@menu/conversation_reactions_long_press_menu"
app:menu="@menu/conversation_reactions_long_press_menu"> app:navigationIcon="@drawable/ic_x_conversation">
</androidx.appcompat.widget.Toolbar> </org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar>

View File

@ -454,4 +454,8 @@
<declare-styleable name="ReactionsConversationView"> <declare-styleable name="ReactionsConversationView">
<attr name="rcv_outgoing" format="boolean" /> <attr name="rcv_outgoing" format="boolean" />
</declare-styleable> </declare-styleable>
<declare-styleable name="AdaptiveActionsToolbar">
<attr name="aat_max_shown" format="integer" />
</declare-styleable>
</resources> </resources>