diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java index a6c23bc9f..ea4c7d765 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java @@ -95,8 +95,8 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab private TimelineDefinition[] timelines; private final Map timelinesByMenuItem = new HashMap<>(); private SubMenu hashtagsMenu, listsMenu; - private Menu optionsMenu; - private MenuInflater optionsMenuInflater; + private PopupMenu overflowPopup; + private View overflowActionView = null; private boolean announcementsBadged, settingsBadged; @Override @@ -153,6 +153,12 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab view.addView(pager, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + overflowActionView = UiUtils.makeOverflowActionView(getContext()); + overflowPopup = new PopupMenu(getContext(), overflowActionView); + overflowPopup.setOnMenuItemClickListener(this::onOptionsItemSelected); + overflowActionView.setOnClickListener(l -> overflowPopup.show()); + overflowActionView.setOnTouchListener(overflowPopup.getDragToOpenListener()); + return view; } @@ -231,9 +237,49 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab if(GithubSelfUpdater.needSelfUpdating()){ updateUpdateState(GithubSelfUpdater.getInstance().getState()); } + + new GetLists().setCallback(new Callback<>() { + @Override + public void onSuccess(List lists) { + updateList(lists, listItems); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(getContext()); + } + }).exec(accountID); + + new GetFollowedHashtags().setCallback(new Callback<>() { + @Override + public void onSuccess(HeaderPaginationList hashtags) { + updateList(hashtags, hashtagsItems); + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(getContext()); + } + }).exec(accountID); + + new GetAnnouncements(false).setCallback(new Callback<>() { + @Override + public void onSuccess(List result) { + if (result.stream().anyMatch(a -> !a.read)) { + announcementsBadged = true; + announcements.setVisible(false); + announcementsAction.setVisible(true); + } + } + + @Override + public void onError(ErrorResponse error) { + error.showToast(getActivity()); + } + }).exec(accountID); } - private void addListsToOptionsMenu() { + private void addListsToOverflowMenu() { Context ctx = getContext(); listsMenu.clear(); listsMenu.getItem().setVisible(listItems.size() > 0); @@ -245,7 +291,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab }); } - private void addHashtagsToOptionsMenu() { + private void addHashtagsToOverflowMenu() { Context ctx = getContext(); hashtagsMenu.clear(); hashtagsMenu.getItem().setVisible(hashtagsItems.size() > 0); @@ -291,79 +337,45 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab } } - private void createOptionsMenu() { - optionsMenu.clear(); - optionsMenuInflater.inflate(R.menu.home, optionsMenu); - announcements = optionsMenu.findItem(R.id.announcements); - announcementsAction = optionsMenu.findItem(R.id.announcements_action); - settings = optionsMenu.findItem(R.id.settings); - settingsAction = optionsMenu.findItem(R.id.settings_action); - hashtagsMenu = optionsMenu.findItem(R.id.hashtags).getSubMenu(); - listsMenu = optionsMenu.findItem(R.id.lists).getSubMenu(); + private void updateOverflowMenu() { + Menu m = overflowPopup.getMenu(); + m.clear(); + overflowPopup.inflate(R.menu.home_overflow); + announcements = m.findItem(R.id.announcements); + settings = m.findItem(R.id.settings); + hashtagsMenu = m.findItem(R.id.hashtags).getSubMenu(); + listsMenu = m.findItem(R.id.lists).getSubMenu(); announcements.setVisible(!announcementsBadged); announcementsAction.setVisible(announcementsBadged); settings.setVisible(!settingsBadged); settingsAction.setVisible(settingsBadged); - UiUtils.enableOptionsMenuIcons(getContext(), optionsMenu, - R.id.overflow, R.id.announcements_action, R.id.settings_action); + UiUtils.enablePopupMenuIcons(getContext(), overflowPopup); - addListsToOptionsMenu(); - addHashtagsToOptionsMenu(); + addListsToOverflowMenu(); + addHashtagsToOverflowMenu(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + m.setGroupDividerEnabled(true); + } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ - this.optionsMenu = menu; - this.optionsMenuInflater = inflater; - createOptionsMenu(); + inflater.inflate(R.menu.home, menu); - new GetLists().setCallback(new Callback<>() { - @Override - public void onSuccess(List lists) { - updateList(lists, listItems); - } + menu.findItem(R.id.overflow).setActionView(overflowActionView); + announcementsAction = menu.findItem(R.id.announcements_action); + settingsAction = menu.findItem(R.id.settings_action); - @Override - public void onError(ErrorResponse error) { - error.showToast(getContext()); - } - }).exec(accountID); - - new GetFollowedHashtags().setCallback(new Callback<>() { - @Override - public void onSuccess(HeaderPaginationList hashtags) { - updateList(hashtags, hashtagsItems); - } - - @Override - public void onError(ErrorResponse error) { - error.showToast(getContext()); - } - }).exec(accountID); - - new GetAnnouncements(false).setCallback(new Callback<>() { - @Override - public void onSuccess(List result) { - if (result.stream().anyMatch(a -> !a.read)) { - announcementsBadged = true; - announcements.setVisible(false); - announcementsAction.setVisible(true); - } - } - - @Override - public void onError(ErrorResponse error) { - error.showToast(getActivity()); - } - }).exec(accountID); + updateOverflowMenu(); } private void updateList(List addItems, Map items) { if (addItems.size() == 0) return; for (int i = 0; i < addItems.size(); i++) items.put(View.generateViewId(), addItems.get(i)); - createOptionsMenu(); + updateOverflowMenu(); } private void updateSwitcherMenu() { @@ -427,8 +439,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab Hashtag hashtag; if (item.getItemId() == R.id.menu_back) { - createOptionsMenu(); - optionsMenu.performIdentifierAction(R.id.overflow, 0); + getToolbar().post(() -> overflowPopup.show()); return true; } else if (id == R.id.settings || id == R.id.settings_action) { Nav.go(getActivity(), SettingsFragment.class, args); @@ -563,6 +574,14 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab @Override public void onDestroyView(){ super.onDestroyView(); + if (overflowPopup != null) { + overflowPopup.dismiss(); + overflowPopup = null; + } + if (switcherPopup != null) { + switcherPopup.dismiss(); + switcherPopup = null; + } if(GithubSelfUpdater.needSelfUpdating()){ E.unregister(this); } @@ -625,10 +644,10 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab if (shouldBeInList) { existingThings.put(existingThing.isPresent() ? existingThing.get().getKey() : View.generateViewId(), makeNewThing.get()); - createOptionsMenu(); + updateOverflowMenu(); } else if (existingThing.isPresent() && !shouldBeInList) { existingThings.remove(existingThing.get().getKey()); - createOptionsMenu(); + updateOverflowMenu(); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index c3ab1a6e7..68047ffc6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -40,6 +40,8 @@ import android.view.SubMenu; import android.view.View; import android.webkit.MimeTypeMap; import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.Toast; @@ -1111,4 +1113,42 @@ public class UiUtils{ Log.e("reduceSwipeSensitivity", Log.getStackTraceString(ex)); } } + + public static View makeOverflowActionView(Context ctx) { + // container needs tooltip, content description + LinearLayout container = new LinearLayout(ctx, null, 0, R.style.Widget_Mastodon_ActionButton_Overflow) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + // image needs, well, the image, and the paddings + ImageView image = new ImageView(ctx, null, 0, R.style.Widget_Mastodon_ActionButton_Overflow); + + image.setDuplicateParentStateEnabled(true); + image.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + image.setClickable(false); + image.setFocusable(false); + image.setEnabled(false); + + // problem: as per overflow action button defaults, the padding on left and right is unequal + // so (however the native overflow button manages this), the ripple background is off-center + + // workaround: set both paddings to the smaller one… + int end = image.getPaddingEnd(); + int start = image.getPaddingStart(); + int paddingDiff = end - start; // what's missing to the long padding + image.setPaddingRelative(start, image.getPaddingTop(), start, image.getPaddingBottom()); + + // …and make up for the additional padding using a negative margin in a container + container.setPaddingRelative(0, 0, paddingDiff, 0); + container.setBackground(null); + container.setClickable(true); + container.setFocusable(true); + + container.addView(image); + + // fucking finally + return container; + } } diff --git a/mastodon/src/main/res/layout/display_item_header.xml b/mastodon/src/main/res/layout/display_item_header.xml index c494cb460..4cfb34607 100644 --- a/mastodon/src/main/res/layout/display_item_header.xml +++ b/mastodon/src/main/res/layout/display_item_header.xml @@ -3,23 +3,16 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="16dp" - android:paddingRight="16dp" - android:paddingLeft="16dp"> + android:paddingTop="11dp" + android:paddingEnd="4dp" + android:paddingStart="16dp"> - + android:layout_marginEnd="12dp" + android:layout_marginTop="5dp" /> diff --git a/mastodon/src/main/res/menu/home.xml b/mastodon/src/main/res/menu/home.xml index d0c5d65c1..c31bde6a9 100644 --- a/mastodon/src/main/res/menu/home.xml +++ b/mastodon/src/main/res/menu/home.xml @@ -19,34 +19,5 @@ android:id="@+id/overflow" android:title="@string/more_options" android:icon="@drawable/ic_fluent_more_vertical_24_regular" - android:showAsAction="always"> - - - - - - - - - - - - + android:showAsAction="always" /> \ No newline at end of file diff --git a/mastodon/src/main/res/menu/home_overflow.xml b/mastodon/src/main/res/menu/home_overflow.xml new file mode 100644 index 000000000..a9d006070 --- /dev/null +++ b/mastodon/src/main/res/menu/home_overflow.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index 0020581b7..9dcc23aa7 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -225,12 +225,11 @@ @style/Widget.Mastodon.Toolbar ?colorGray800 ?colorGray800 - @style/Theme.Mastodon.ActionButton.Overflow + @style/Widget.Mastodon.ActionButton.Overflow -