From 47dc7a042b007653de7cc6785d20ae5eae36f98b Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 12 Mar 2024 14:59:45 +1000 Subject: [PATCH 01/11] Add WPViewPager2Transformer This is meant to be used as a drop-in replacement of the original WPVIewPagerTransformer. Once all ViewPager's have been migrated to ViewPager2, the original can be deleted. --- .../widgets/WPViewPager2Transformer.kt | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt b/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt new file mode 100644 index 000000000000..097ed2b5ccd3 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt @@ -0,0 +1,104 @@ +package org.wordpress.android.widgets + +import android.view.View +import androidx.viewpager2.widget.ViewPager2 +import org.wordpress.android.widgets.WPViewPager2Transformer.TransformType.Flow +import org.wordpress.android.widgets.WPViewPager2Transformer.TransformType.Depth +import org.wordpress.android.widgets.WPViewPager2Transformer.TransformType.Zoom +import org.wordpress.android.widgets.WPViewPager2Transformer.TransformType.SlideOver +import kotlin.math.abs +import kotlin.math.max + +/** + * #### Transformer for ViewPager2 + * This is a clone of [WPViewPagerTransformer], with ViewPager2 compatibility. The purpose of this class is to ease the + * migration from ViewPager to ViewPager2 by providing a drop-in replacement for wherever the ViewPager-based + * transformer is used. + */ +class WPViewPager2Transformer(private val mTransformType: TransformType) : ViewPager2.PageTransformer { + sealed class TransformType { + data object Flow: TransformType() { const val ROTATION_FACTOR = -30f } + data object Depth: TransformType() + data object Zoom: TransformType() + data object SlideOver: TransformType() + } + + override fun transformPage(page: View, position: Float) { + val alpha: Float + val scale: Float + val translationX: Float + when (mTransformType) { + Flow -> { + page.rotationY = position * Flow.ROTATION_FACTOR + return + } + + SlideOver -> if (position < 0 && position > -1) { + // this is the page to the left + scale = (abs((abs(position.toDouble()) - 1)) * (1.0f - SCALE_FACTOR_SLIDE) + SCALE_FACTOR_SLIDE) + .toFloat() + alpha = max( + MIN_ALPHA_SLIDE.toDouble(), + (1 - abs(position.toDouble())) + ) + .toFloat() + val pageWidth = page.width + val translateValue = position * -pageWidth + translationX = if (translateValue > -pageWidth) { + translateValue + } else { + 0f + } + } else { + alpha = 1f + scale = 1f + translationX = 0f + } + + Depth -> if (position > 0 && position < 1) { + // moving to the right + alpha = 1 - position + scale = (MIN_SCALE_DEPTH + (1 - MIN_SCALE_DEPTH) * (1 - abs( position.toDouble()))).toFloat() + translationX = page.width * -position + } else { + // use default for all other cases + alpha = 1f + scale = 1f + translationX = 0f + } + + Zoom -> if (position >= -1 && position <= 1) { + scale = max( + MIN_SCALE_ZOOM.toDouble(), + (1 - abs(position.toDouble())) + ) + .toFloat() + alpha = (MIN_ALPHA_ZOOM + + (scale - MIN_SCALE_ZOOM) / (1 - MIN_SCALE_ZOOM) * (1 - MIN_ALPHA_ZOOM)) + val vMargin = (page.height * (1 - scale) / 2) + val hMargin = (page.width * (1 - scale) / 2) + translationX = if (position < 0) { + hMargin - vMargin / 2 + } else { + -hMargin + vMargin / 2 + } + } else { + alpha = 1f + scale = 1f + translationX = 0f + } + } + page.setAlpha(alpha) + page.translationX = translationX + page.scaleX = scale + page.scaleY = scale + } + + companion object { + private const val MIN_SCALE_DEPTH = 0.75f + private const val MIN_SCALE_ZOOM = 0.85f + private const val MIN_ALPHA_ZOOM = 0.5f + private const val SCALE_FACTOR_SLIDE = 0.85f + private const val MIN_ALPHA_SLIDE = 0.35f + } +} From 5bcd34aa176b685405de92fce3be89842aadcd7f Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 12 Mar 2024 15:05:40 +1000 Subject: [PATCH 02/11] Implement ViewPager2 versions of WPSwipeSnackbar methods --- .../android/widgets/WPSwipeSnackbar.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java b/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java index a3804cef9e26..54fb8ab102c7 100644 --- a/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java +++ b/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java @@ -7,8 +7,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.widget.ViewPager2; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; @@ -27,6 +29,23 @@ private WPSwipeSnackbar() { throw new AssertionError(); } + /** {@link ViewPager2}-based clone of the original helper method: {@link #show(ViewPager)} */ + @NonNull + public static Snackbar show(@NonNull ViewPager2 viewPager) { + SwipeArrows arrows; + Adapter adapter = viewPager.getAdapter(); + if (adapter == null || adapter.getItemCount() <= 1) { + arrows = SwipeArrows.NONE; + } else if (viewPager.getCurrentItem() == 0) { + arrows = SwipeArrows.RIGHT; + } else if (viewPager.getCurrentItem() == (adapter.getItemCount() - 1)) { + arrows = SwipeArrows.LEFT; + } else { + arrows = SwipeArrows.BOTH; + } + return show(viewPager, arrows); + } + public static Snackbar show(@NonNull ViewPager viewPager) { SwipeArrows arrows; PagerAdapter adapter = viewPager.getAdapter(); @@ -73,6 +92,38 @@ private static Snackbar show(@NonNull ViewPager viewPager, @NonNull SwipeArrows return snackbar; } + /** {@link ViewPager2}-based clone of the original helper method: {@link #show(ViewPager, SwipeArrows)} */ + @NonNull + private static Snackbar show(@NonNull ViewPager2 viewPager, @NonNull SwipeArrows arrows) { + Context context = viewPager.getContext(); + String swipeText = context.getResources().getString(R.string.swipe_for_more); + String arrowLeft = context.getResources().getString(R.string.previous_button); + String arrowRight = context.getResources().getString(R.string.next_button); + + String text; + switch (arrows) { + case LEFT: + text = arrowLeft + " " + swipeText; + break; + case RIGHT: + text = swipeText + " " + arrowRight; + break; + case BOTH: + text = arrowLeft + " " + swipeText + " " + arrowRight; + break; + case NONE: + default: + text = swipeText; + break; + } + + Snackbar snackbar = Snackbar.make(viewPager, text, BaseTransientBottomBar.LENGTH_LONG); // CHECKSTYLE IGNORE + centerSnackbarText(snackbar); + snackbar.show(); + + return snackbar; + } + /* * horizontally center the snackbar's text */ From e35723bf9a1971c410829d5e02d96d205a49f10f Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 12 Mar 2024 15:06:13 +1000 Subject: [PATCH 03/11] Use ViewPager2 in NotificationDetailActivity --- .../NotificationsDetailActivity.java | 103 +++++++++--------- .../layout/notifications_detail_activity.xml | 2 +- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java index 47a8d87f0e67..4e0c0787e672 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java @@ -2,7 +2,6 @@ import android.content.Intent; import android.os.Bundle; -import android.os.Parcelable; import android.text.TextUtils; import android.view.MenuItem; import android.view.View; @@ -14,9 +13,10 @@ import androidx.appcompat.app.ActionBar; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.lifecycle.Lifecycle; import androidx.lifecycle.ViewModelProvider; -import androidx.viewpager.widget.ViewPager; +import androidx.viewpager2.adapter.FragmentStateAdapter; +import androidx.viewpager2.widget.ViewPager2; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -66,7 +66,8 @@ import org.wordpress.android.util.extensions.AppBarLayoutExtensionsKt; import org.wordpress.android.util.extensions.CompatExtensionsKt; import org.wordpress.android.widgets.WPSwipeSnackbar; -import org.wordpress.android.widgets.WPViewPagerTransformer; +import org.wordpress.android.widgets.WPViewPager2Transformer; +import org.wordpress.android.widgets.WPViewPager2Transformer.TransformType.SlideOver; import java.util.ArrayList; import java.util.Collections; @@ -103,7 +104,7 @@ public class NotificationsDetailActivity extends LocaleAwareActivity implements @Nullable private String mNoteId; private boolean mIsTappedOnNotification; - @Nullable private ViewPager.OnPageChangeListener mOnPageChangeListener; + @Nullable private ViewPager2.OnPageChangeCallback mOnPageChangeListener; @Nullable private NotificationDetailFragmentAdapter mAdapter; @Nullable private NotificationsDetailActivityBinding mBinding = null; @@ -155,8 +156,7 @@ public void handleOnBackPressed() { // set up the viewpager and adapter for lateral navigation if (mBinding != null) { - mBinding.viewpager.setPageTransformer(false, - new WPViewPagerTransformer(WPViewPagerTransformer.TransformType.SLIDE_OVER)); + mBinding.viewpager.setPageTransformer(new WPViewPager2Transformer(SlideOver.INSTANCE)); } Note note = NotificationsTable.getNoteById(mNoteId); @@ -233,10 +233,10 @@ private void updateUIAndNote(boolean doRefresh) { private void resetOnPageChangeListener() { if (mOnPageChangeListener != null) { if (mBinding != null) { - mBinding.viewpager.removeOnPageChangeListener(mOnPageChangeListener); + mBinding.viewpager.unregisterOnPageChangeCallback(mOnPageChangeListener); } } else { - mOnPageChangeListener = new ViewPager.OnPageChangeListener() { + mOnPageChangeListener = new ViewPager2.OnPageChangeCallback() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @@ -244,7 +244,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse @Override public void onPageSelected(int position) { if (mBinding != null && mAdapter != null) { - Fragment fragment = mAdapter.getItem(mBinding.viewpager.getCurrentItem()); + Fragment fragment = mAdapter.createFragment(mBinding.viewpager.getCurrentItem()); boolean hideToolbar = (fragment instanceof ReaderPostDetailFragment); showHideToolbar(hideToolbar); @@ -268,7 +268,7 @@ public void onPageScrollStateChanged(int state) { }; } if (mBinding != null) { - mBinding.viewpager.addOnPageChangeListener(mOnPageChangeListener); + mBinding.viewpager.registerOnPageChangeCallback(mOnPageChangeListener); } } @@ -320,7 +320,7 @@ protected void onStart() { EventBus.getDefault().register(this); // If the user hasn't used swipe yet and if the adapter is initialised and have at least 2 notifications, // show a hint to promote swipe usage on the ViewPager - if (!AppPrefs.isNotificationsSwipeToNavigateShown() && mAdapter != null && mAdapter.getCount() > 1) { + if (!AppPrefs.isNotificationsSwipeToNavigateShown() && mAdapter != null && 1 < mAdapter.getItemCount()) { if (mBinding != null) { WPSwipeSnackbar.show(mBinding.viewpager); AppPrefs.setNotificationsSwipeToNavigateShown(true); @@ -380,7 +380,7 @@ private NotificationDetailFragmentAdapter buildNoteListAdapterAndSetPosition(Not // apply filter to the list so we show the same items that the list show vertically, but horizontally ArrayList filteredNotes = NotesAdapter.buildFilteredNotesList(notes, filter); - adapter = new NotificationDetailFragmentAdapter(getSupportFragmentManager(), filteredNotes); + adapter = new NotificationDetailFragmentAdapter(getSupportFragmentManager(), getLifecycle(), filteredNotes); if (mBinding != null) { mBinding.viewpager.setAdapter(adapter); @@ -395,8 +395,7 @@ private NotificationDetailFragmentAdapter buildNoteListAdapterAndSetPosition(Not * Defaults to NotificationDetailListFragment */ @NonNull - @SuppressWarnings("deprecation") - private Fragment getDetailFragmentForNote(@NonNull Note note) { + private Fragment createDetailFragmentForNote(@NonNull Note note) { Fragment fragment; if (note.isCommentType()) { // show comment detail for comment notifications @@ -589,7 +588,7 @@ public void onEventMainThread(NotificationEvents.NotificationsRefreshError error @Override public void onPositiveClicked(@NonNull String instanceTag) { if (mBinding != null && mAdapter != null) { - Fragment fragment = mAdapter.getItem(mBinding.viewpager.getCurrentItem()); + Fragment fragment = mAdapter.createFragment(mBinding.viewpager.getCurrentItem()); if (fragment instanceof BasicFragmentDialog.BasicDialogPositiveClickInterface) { ((BasicDialogPositiveClickInterface) fragment).onPositiveClicked(instanceTag); } @@ -603,56 +602,60 @@ public void onScrollableViewInitialized(int containerId) { } } - @SuppressWarnings("deprecation") - private class NotificationDetailFragmentAdapter extends FragmentStatePagerAdapter { + private class NotificationDetailFragmentAdapter extends FragmentStateAdapter { + @NonNull private final ArrayList mNoteList; @SuppressWarnings("unchecked") - NotificationDetailFragmentAdapter(FragmentManager fm, ArrayList notes) { - super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + NotificationDetailFragmentAdapter(@NonNull FragmentManager fm, @NonNull Lifecycle lifecycle, + @NonNull ArrayList notes) { + super(fm, lifecycle); mNoteList = (ArrayList) notes.clone(); } @NonNull @Override - public Fragment getItem(int position) { - return getDetailFragmentForNote(mNoteList.get(position)); + public Fragment createFragment(int position) { + return createDetailFragmentForNote(mNoteList.get(position)); } @Override - public int getCount() { + public int getItemCount() { return mNoteList.size(); } - @Override - public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) { - // work around "Fragment no longer exists for key" Android bug - // by catching the IllegalStateException - // https://code.google.com/p/android/issues/detail?id=42601 - try { - AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter restoreState"); - super.restoreState(state, loader); - } catch (IllegalStateException e) { - AppLog.e(AppLog.T.NOTIFS, e); - } - } - - @Nullable - @Override - public Parcelable saveState() { - AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter saveState"); - Bundle bundle = (Bundle) super.saveState(); - if (bundle == null) { - bundle = new Bundle(); - } - // This is a possible solution to https://github.com/wordpress-mobile/WordPress-Android/issues/5456 - // See https://issuetracker.google.com/issues/37103380#comment77 for more details - bundle.putParcelableArray("states", null); - return bundle; - } + // TODO: The following work-arounds have been commented out because the overridden methods are either final + // or non-existent. It should be determined whether these are still necessary, and if there are similar + // work-arounds that can be applied for ViewPager2. +// @Override +// public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) { +// // work around "Fragment no longer exists for key" Android bug +// // by catching the IllegalStateException +// // https://code.google.com/p/android/issues/detail?id=42601 +// try { +// AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter restoreState"); +// super.restoreState(state, loader); +// } catch (IllegalStateException e) { +// AppLog.e(AppLog.T.NOTIFS, e); +// } +// } +// +// @Nullable +// @Override +// public Parcelable saveState() { +// AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter saveState"); +// Bundle bundle = (Bundle) super.saveState(); +// if (bundle == null) { +// bundle = new Bundle(); +// } +// // This is a possible solution to https://github.com/wordpress-mobile/WordPress-Android/issues/5456 +// // See https://issuetracker.google.com/issues/37103380#comment77 for more details +// bundle.putParcelableArray("states", null); +// return bundle; +// } boolean isValidPosition(int position) { - return (position >= 0 && position < getCount()); + return (position >= 0 && position < getItemCount()); } private Note getNoteAtPosition(int position) { diff --git a/WordPress/src/main/res/layout/notifications_detail_activity.xml b/WordPress/src/main/res/layout/notifications_detail_activity.xml index 9fc00ff4ed72..6a2ffd460509 100644 --- a/WordPress/src/main/res/layout/notifications_detail_activity.xml +++ b/WordPress/src/main/res/layout/notifications_detail_activity.xml @@ -39,7 +39,7 @@ - Date: Thu, 14 Mar 2024 17:44:26 +1000 Subject: [PATCH 04/11] Remove work-arounds for buggy framework implementations It seems that these issues are most likely related with issues in the implementation of FragmentStatePagerAdapter, which is no longer used in this Activity after migrating to ViewPager2. At least one improvement can be found in FragmentStateAdapter, which is the use of LongSparseArray, which possibly alleviates the pressure on the state-saving mechanism. Still, it would be good to keep an eye on the release that these changes ship in to ensure it doens't introduce regressions for edge cases. --- .../NotificationsDetailActivity.java | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java index 4e0c0787e672..aba6b4d515dd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java @@ -624,36 +624,6 @@ public int getItemCount() { return mNoteList.size(); } - // TODO: The following work-arounds have been commented out because the overridden methods are either final - // or non-existent. It should be determined whether these are still necessary, and if there are similar - // work-arounds that can be applied for ViewPager2. -// @Override -// public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) { -// // work around "Fragment no longer exists for key" Android bug -// // by catching the IllegalStateException -// // https://code.google.com/p/android/issues/detail?id=42601 -// try { -// AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter restoreState"); -// super.restoreState(state, loader); -// } catch (IllegalStateException e) { -// AppLog.e(AppLog.T.NOTIFS, e); -// } -// } -// -// @Nullable -// @Override -// public Parcelable saveState() { -// AppLog.d(AppLog.T.NOTIFS, "notifications pager > adapter saveState"); -// Bundle bundle = (Bundle) super.saveState(); -// if (bundle == null) { -// bundle = new Bundle(); -// } -// // This is a possible solution to https://github.com/wordpress-mobile/WordPress-Android/issues/5456 -// // See https://issuetracker.google.com/issues/37103380#comment77 for more details -// bundle.putParcelableArray("states", null); -// return bundle; -// } - boolean isValidPosition(int position) { return (position >= 0 && position < getItemCount()); } From 01e886547deed990d691190c78dae8cc8c90fdd4 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 3 Apr 2024 17:52:41 +0300 Subject: [PATCH 05/11] Fixes detekt issue --- .../android/widgets/WPViewPager2Transformer.kt | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt b/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt index 097ed2b5ccd3..6183e8f26c94 100644 --- a/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt +++ b/WordPress/src/main/java/org/wordpress/android/widgets/WPViewPager2Transformer.kt @@ -37,11 +37,7 @@ class WPViewPager2Transformer(private val mTransformType: TransformType) : ViewP // this is the page to the left scale = (abs((abs(position.toDouble()) - 1)) * (1.0f - SCALE_FACTOR_SLIDE) + SCALE_FACTOR_SLIDE) .toFloat() - alpha = max( - MIN_ALPHA_SLIDE.toDouble(), - (1 - abs(position.toDouble())) - ) - .toFloat() + alpha = max(MIN_ALPHA_SLIDE.toDouble(), (1 - abs(position.toDouble()))).toFloat() val pageWidth = page.width val translateValue = position * -pageWidth translationX = if (translateValue > -pageWidth) { @@ -68,13 +64,8 @@ class WPViewPager2Transformer(private val mTransformType: TransformType) : ViewP } Zoom -> if (position >= -1 && position <= 1) { - scale = max( - MIN_SCALE_ZOOM.toDouble(), - (1 - abs(position.toDouble())) - ) - .toFloat() - alpha = (MIN_ALPHA_ZOOM - + (scale - MIN_SCALE_ZOOM) / (1 - MIN_SCALE_ZOOM) * (1 - MIN_ALPHA_ZOOM)) + scale = max(MIN_SCALE_ZOOM.toDouble(), (1 - abs(position.toDouble()))).toFloat() + alpha = (MIN_ALPHA_ZOOM + (scale - MIN_SCALE_ZOOM) / (1 - MIN_SCALE_ZOOM) * (1 - MIN_ALPHA_ZOOM)) val vMargin = (page.height * (1 - scale) / 2) val hMargin = (page.width * (1 - scale) / 2) translationX = if (position < 0) { From 8ed9e829988c5c31405deca1c150dcde3f2fffb7 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 3 Apr 2024 19:11:47 +0300 Subject: [PATCH 06/11] Removes duplicate code --- .../android/widgets/WPSwipeSnackbar.java | 70 ++++++------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java b/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java index 54fb8ab102c7..a807c3fee765 100644 --- a/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java +++ b/WordPress/src/main/java/org/wordpress/android/widgets/WPSwipeSnackbar.java @@ -1,6 +1,5 @@ package org.wordpress.android.widgets; -import android.annotation.SuppressLint; import android.content.Context; import android.view.Gravity; import android.view.View; @@ -34,68 +33,48 @@ private WPSwipeSnackbar() { public static Snackbar show(@NonNull ViewPager2 viewPager) { SwipeArrows arrows; Adapter adapter = viewPager.getAdapter(); - if (adapter == null || adapter.getItemCount() <= 1) { + if (adapter == null) { arrows = SwipeArrows.NONE; - } else if (viewPager.getCurrentItem() == 0) { - arrows = SwipeArrows.RIGHT; - } else if (viewPager.getCurrentItem() == (adapter.getItemCount() - 1)) { - arrows = SwipeArrows.LEFT; } else { - arrows = SwipeArrows.BOTH; + arrows = getSwipeArrows(adapter.getItemCount(), viewPager.getCurrentItem()); } return show(viewPager, arrows); } - public static Snackbar show(@NonNull ViewPager viewPager) { + @NonNull public static Snackbar show(@NonNull ViewPager viewPager) { SwipeArrows arrows; PagerAdapter adapter = viewPager.getAdapter(); - if (adapter == null || adapter.getCount() <= 1) { + if (adapter == null) { arrows = SwipeArrows.NONE; - } else if (viewPager.getCurrentItem() == 0) { - arrows = SwipeArrows.RIGHT; - } else if (viewPager.getCurrentItem() == (adapter.getCount() - 1)) { - arrows = SwipeArrows.LEFT; } else { - arrows = SwipeArrows.BOTH; + arrows = getSwipeArrows(adapter.getCount(), viewPager.getCurrentItem()); } return show(viewPager, arrows); } - // BaseTransientBottomBar.LENGTH_LONG is pointing to Snackabr.LENGTH_LONG which confuses checkstyle - @SuppressLint("WrongConstant") - private static Snackbar show(@NonNull ViewPager viewPager, @NonNull SwipeArrows arrows) { - Context context = viewPager.getContext(); - String swipeText = context.getResources().getString(R.string.swipe_for_more); - String arrowLeft = context.getResources().getString(R.string.previous_button); - String arrowRight = context.getResources().getString(R.string.next_button); - - String text; - switch (arrows) { - case LEFT: - text = arrowLeft + " " + swipeText; - break; - case RIGHT: - text = swipeText + " " + arrowRight; - break; - case BOTH: - text = arrowLeft + " " + swipeText + " " + arrowRight; - break; - default: - text = swipeText; - break; + @NonNull private static SwipeArrows getSwipeArrows(int itemCount, int currentItem) { + SwipeArrows arrows; + if (itemCount <= 1) { + arrows = SwipeArrows.NONE; + } else if (currentItem == 0) { + arrows = SwipeArrows.RIGHT; + } else if (currentItem == (itemCount - 1)) { + arrows = SwipeArrows.LEFT; + } else { + arrows = SwipeArrows.BOTH; } + return arrows; + } - Snackbar snackbar = Snackbar.make(viewPager, text, BaseTransientBottomBar.LENGTH_LONG); // CHECKSTYLE IGNORE + @NonNull private static Snackbar show(@NonNull View view, @NonNull SwipeArrows arrows) { + String text = getSwipeText(view.getContext(), arrows); + Snackbar snackbar = WPSnackbar.make(view, text, BaseTransientBottomBar.LENGTH_LONG); centerSnackbarText(snackbar); snackbar.show(); - return snackbar; } - /** {@link ViewPager2}-based clone of the original helper method: {@link #show(ViewPager, SwipeArrows)} */ - @NonNull - private static Snackbar show(@NonNull ViewPager2 viewPager, @NonNull SwipeArrows arrows) { - Context context = viewPager.getContext(); + @NonNull private static String getSwipeText(@NonNull Context context, @NonNull SwipeArrows arrows) { String swipeText = context.getResources().getString(R.string.swipe_for_more); String arrowLeft = context.getResources().getString(R.string.previous_button); String arrowRight = context.getResources().getString(R.string.next_button); @@ -116,12 +95,7 @@ private static Snackbar show(@NonNull ViewPager2 viewPager, @NonNull SwipeArrows text = swipeText; break; } - - Snackbar snackbar = Snackbar.make(viewPager, text, BaseTransientBottomBar.LENGTH_LONG); // CHECKSTYLE IGNORE - centerSnackbarText(snackbar); - snackbar.show(); - - return snackbar; + return text; } /* From b19ce37db8bbf630ab407be29b8527c5049a6c0a Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Wed, 3 Apr 2024 19:59:08 +0300 Subject: [PATCH 07/11] Update layout size --- .../src/main/res/layout/notifications_detail_activity.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/res/layout/notifications_detail_activity.xml b/WordPress/src/main/res/layout/notifications_detail_activity.xml index b017bed2105d..af60bb0384d3 100644 --- a/WordPress/src/main/res/layout/notifications_detail_activity.xml +++ b/WordPress/src/main/res/layout/notifications_detail_activity.xml @@ -31,10 +31,9 @@ From d6da7a08aa9bc68bac739bf8b24da2d2ea393f22 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Thu, 4 Apr 2024 11:16:56 +0300 Subject: [PATCH 08/11] Make sure we are hiding the correct actionbar --- .../ui/notifications/NotificationsDetailActivity.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java index aba6b4d515dd..8ba42d654a6d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java @@ -281,14 +281,14 @@ private void trackCommentNote(@NonNull Note note) { } public void showHideToolbar(boolean hide) { + if (mBinding != null) { + setSupportActionBar(mBinding.toolbarMain); + } if (getSupportActionBar() != null) { if (hide) { getSupportActionBar().hide(); } else { - if (mBinding != null) { - setSupportActionBar(mBinding.toolbarMain); - getSupportActionBar().show(); - } + getSupportActionBar().show(); } getSupportActionBar().setDisplayShowTitleEnabled(!hide); } From 65c518e4d4c5c6f863fd9f561ab4c93333635eb8 Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Thu, 4 Apr 2024 18:08:18 +0800 Subject: [PATCH 09/11] Fix an issue related to the conflicted toolbar/supportActionBar --- .../ui/reader/ReaderPostDetailFragment.kt | 34 +++---------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt index 5d0e2422014b..5d8db866a488 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt @@ -19,7 +19,6 @@ import android.view.ContextThemeWrapper import android.view.Gravity import android.view.LayoutInflater import android.view.Menu -import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup @@ -30,14 +29,12 @@ import android.widget.ImageView.ScaleType.CENTER_CROP import android.widget.ProgressBar import android.widget.TextView import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.ListPopupWindow import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat -import androidx.core.view.MenuProvider import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.isInvisible @@ -45,7 +42,6 @@ import androidx.core.view.isVisible import androidx.fragment.app.FragmentManager import androidx.fragment.app.commit import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider.Factory import androidx.recyclerview.widget.DefaultItemAnimator @@ -172,7 +168,6 @@ import com.google.android.material.R as MaterialR @Suppress("LargeClass") class ReaderPostDetailFragment : ViewPagerFragment(), WPMainActivity.OnActivityBackPressedListener, - MenuProvider, ScrollDirectionListener, ReaderCustomViewListener, ReaderWebViewPageFinishedListener, @@ -416,7 +411,6 @@ class ReaderPostDetailFragment : ViewPagerFragment(), appBar = view.findViewById(R.id.appbar_with_collapsing_toolbar_layout) toolBar = appBar.findViewById(R.id.toolbar_main) - toolBar.setVisible(true) appBar.addOnOffsetChangedListener(appBarLayoutOffsetChangedListener) // Fixes collapsing toolbar layout being obscured by the status bar when drawn behind it @@ -430,6 +424,7 @@ class ReaderPostDetailFragment : ViewPagerFragment(), // Fixes viewpager not displaying menu items for first fragment toolBar.inflateMenu(R.menu.reader_detail) + toolBar.setOnMenuItemClickListener { handleMenuItemSelected(it)} // for related posts, show an X in the toolbar which closes the activity if (isRelatedPost) { @@ -534,24 +529,8 @@ class ReaderPostDetailFragment : ViewPagerFragment(), activity?.window?.setWindowNavigationBarColor(themeValues.intBackgroundColor) } - override fun onResume() { - super.onResume() - replaceActivityToolbarWithCollapsingToolbar() - } - - private fun replaceActivityToolbarWithCollapsingToolbar() { - val activity = activity as? AppCompatActivity - activity?.supportActionBar?.hide() - - toolBar.setVisible(true) - activity?.setSupportActionBar(toolBar) - - activity?.supportActionBar?.setDisplayShowTitleEnabled(isRelatedPost) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) initLikeFacesRecycler(savedInstanceState) initCommentSnippetRecycler(savedInstanceState) @@ -865,7 +844,7 @@ class ReaderPostDetailFragment : ViewPagerFragment(), @Suppress("ForbiddenComment") private fun onPostExecuteShowPost() { // make sure options menu reflects whether we now have a post - activity?.invalidateOptionsMenu() + prepareMenu(toolBar.menu) viewModel.post?.let { if (handleDirectOperation()) return @@ -1079,12 +1058,7 @@ class ReaderPostDetailFragment : ViewPagerFragment(), moreMenuPopup?.dismiss() } - override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - menu.clear() - menuInflater.inflate(R.menu.reader_detail, menu) - } - - override fun onPrepareMenu(menu: Menu) { + private fun prepareMenu(menu: Menu) { val postHasUrl = viewModel.post?.hasUrl() == true val menuBrowse = menu.findItem(R.id.menu_browse) // browse require the post to have a URL (some feed-based posts don't have one) or an intercepted URI @@ -1097,7 +1071,7 @@ class ReaderPostDetailFragment : ViewPagerFragment(), menuReadingPreferences?.isVisible = readingPreferencesFeatureConfig.isEnabled() } - override fun onMenuItemSelected(menuItem: MenuItem) = when (menuItem.itemId) { + private fun handleMenuItemSelected(menuItem: MenuItem) = when (menuItem.itemId) { R.id.menu_browse -> { val interceptedUri = viewModel.interceptedUri if (viewModel.hasPost) { From 88c6031857942d8872e28df5428758783bab08f7 Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Thu, 4 Apr 2024 18:15:46 +0800 Subject: [PATCH 10/11] Fix the duplicate toolbar when clicked on a mentioned notification --- .../wordpress/android/ui/reader/ReaderPostDetailFragment.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt index 5d8db866a488..571698865778 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.kt @@ -29,6 +29,7 @@ import android.widget.ImageView.ScaleType.CENTER_CROP import android.widget.ProgressBar import android.widget.TextView import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.ListPopupWindow import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout @@ -423,6 +424,8 @@ class ReaderPostDetailFragment : ViewPagerFragment(), } // Fixes viewpager not displaying menu items for first fragment + val activity = activity as? AppCompatActivity + activity?.supportActionBar?.hide() toolBar.inflateMenu(R.menu.reader_detail) toolBar.setOnMenuItemClickListener { handleMenuItemSelected(it)} From 10c9cefc90cb7dfbd064fa400569aa3c7680ebdb Mon Sep 17 00:00:00 2001 From: Jarvis Lin Date: Thu, 4 Apr 2024 20:17:58 +0800 Subject: [PATCH 11/11] Remove the animation of viewpager --- .../android/ui/notifications/NotificationsDetailActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java index 8ba42d654a6d..79ba8a858972 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsDetailActivity.java @@ -384,7 +384,8 @@ private NotificationDetailFragmentAdapter buildNoteListAdapterAndSetPosition(Not if (mBinding != null) { mBinding.viewpager.setAdapter(adapter); - mBinding.viewpager.setCurrentItem(NotificationsUtils.findNoteInNoteArray(filteredNotes, note.getId())); + mBinding.viewpager.setCurrentItem( + NotificationsUtils.findNoteInNoteArray(filteredNotes, note.getId()), false); } return adapter;