From acb1048526567f762d8adbf763f7589029488799 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Sun, 27 Mar 2022 21:30:15 +0900 Subject: [PATCH 1/7] upgrade material version to 1.5.0 --- buildSrc/src/main/java/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index c90def4321..d1eb85166a 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -8,7 +8,7 @@ object Versions { const val gms_oss_licenses_plugin = "0.10.4" const val support = "1.0.0" const val appcompat = "1.3.1" - const val material = "1.4.0" + const val material = "1.5.0" const val cardview = "1.0.0" const val recyclerview = "1.2.1" const val constraint = "2.1.1" From d58fc02fb91ba684db950bc5adce3d4fa5574dc7 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Tue, 29 Mar 2022 22:59:42 +0900 Subject: [PATCH 2/7] add buttom sheet background resource --- app/src/main/res/drawable/background_bottom_sheet.xml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/src/main/res/drawable/background_bottom_sheet.xml diff --git a/app/src/main/res/drawable/background_bottom_sheet.xml b/app/src/main/res/drawable/background_bottom_sheet.xml new file mode 100644 index 0000000000..9a49305530 --- /dev/null +++ b/app/src/main/res/drawable/background_bottom_sheet.xml @@ -0,0 +1,9 @@ + + + + + + From 326b253295b2331440de5280101b1365074b2472 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Tue, 29 Mar 2022 01:06:50 +0900 Subject: [PATCH 3/7] ScrollableBottomSheetHelper do not set corner immediately extract the function of setting corner, then we can decide to apply rounded corner or not --- .../main/java/org/mozilla/focus/fragment/ListPanelDialog.kt | 2 ++ .../org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/mozilla/focus/fragment/ListPanelDialog.kt b/app/src/main/java/org/mozilla/focus/fragment/ListPanelDialog.kt index 1f810900c8..b1c8116a86 100644 --- a/app/src/main/java/org/mozilla/focus/fragment/ListPanelDialog.kt +++ b/app/src/main/java/org/mozilla/focus/fragment/ListPanelDialog.kt @@ -56,6 +56,8 @@ class ListPanelDialog : DialogFragment() { this.dismissAllowingStateLoss() } + ScrollableBottomSheetHelper.setRoundedCorner(it.container) + setTopButtonsClickListener(it) enableLoadMore(it.mainContent) }.root diff --git a/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt b/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt index 3fcc557298..fc34b69fbe 100644 --- a/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt +++ b/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt @@ -22,7 +22,6 @@ object ScrollableBottomSheetHelper { menuBottomMargin: Float = context.resources.getDimension(R.dimen.menu_bottom_margin), dismissListener: () -> Unit ) { - setRoundedCorner(binding.container, cornerRadius) binding.container.setOnClickListener { dismissListener.invoke() } @@ -35,7 +34,10 @@ object ScrollableBottomSheetHelper { ) } - private fun setRoundedCorner(container: CoordinatorLayout, cornerRadius: Float) { + fun setRoundedCorner( + container: ViewGroup, + cornerRadius: Float = container.resources.getDimension(R.dimen.menu_corner_radius) + ) { container.outlineProvider = RoundedCornerOutlineProvider(cornerRadius) container.clipToOutline = true } From 37f2ab092a94f03ba426fb7d73ffc33f0dbc01d1 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Tue, 29 Mar 2022 22:52:09 +0900 Subject: [PATCH 4/7] ScrollableBottomSheetHelper only move specific view do not move the whole root view, instead, move only the specified view --- .../mozilla/focus/utils/ScrollableBottomSheetHelper.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt b/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt index fc34b69fbe..17d97feead 100644 --- a/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt +++ b/app/src/main/java/org/mozilla/focus/utils/ScrollableBottomSheetHelper.kt @@ -57,7 +57,7 @@ object ScrollableBottomSheetHelper { val callback = BottomSheetCallback( bottomSheetBehavior, - rootView, + bottomSheet, menuBottomMargin, cornerRadius, dismissListener @@ -76,7 +76,7 @@ object ScrollableBottomSheetHelper { private class BottomSheetCallback( val bottomSheetBehavior: BottomSheetBehavior, - val rootView: ViewGroup, + val movableView: ViewGroup, menuBottomMargin: Float, cornerRadius: Float, val dismissListener: () -> Unit @@ -108,12 +108,12 @@ object ScrollableBottomSheetHelper { if (translationYChanged) { this.translationY = currentTranslationY if (abs(currentTranslationY) <= maxTranslationY) { - rootView.translationY = currentTranslationY + movableView.translationY = currentTranslationY } else if (currentTranslationY > maxTranslationY && - rootView.translationY < maxTranslationY + movableView.translationY < maxTranslationY ) { // In case of fast changing - rootView.translationY = maxTranslationY + movableView.translationY = maxTranslationY } } } From 11d8deaa67d1d3ebc78df428c995d674c408e388 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Wed, 8 Dec 2021 01:52:15 +0900 Subject: [PATCH 5/7] rewrite bottom sheet home menu xml file * use ConstraintLayout to replace nested LinearLayout * Apply CoordinateLayout to make it to be swipe-to-dismiss known issue: If the list was too long, and user's phone screen was short, maybe we cannot see the whole list. I tried adding NestedScrollView but sometimes the Y-position of root view is not correct while first time opening the BottomSheet. Mabye it is because HomeMenuDialog is a BototmSheetDialog. We should try to use Fragment instead. There are 2 CoordinateLayout since HomeMenuDialog is extending BottomSheetDialog. This is not right. Reproduce step: set layout_height=500dp to menu_night_mode --- .../org/mozilla/rocket/menu/HomeMenuDialog.kt | 36 +- .../res/layout/bottom_sheet_home_menu.xml | 587 +++++++----------- 2 files changed, 250 insertions(+), 373 deletions(-) diff --git a/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt b/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt index 2d328477f1..2a1bb49883 100644 --- a/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt +++ b/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt @@ -1,24 +1,23 @@ package org.mozilla.rocket.menu import android.content.Context -import android.graphics.Outline import android.os.Bundle import android.os.Handler import android.os.Looper import android.view.View -import android.view.ViewOutlineProvider -import android.widget.ScrollView import android.widget.Toast import androidx.annotation.StyleRes import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.lifecycle.Observer +import com.google.android.material.bottomsheet.BottomSheetBehavior import dagger.Lazy import org.mozilla.fileutils.FileUtils import org.mozilla.focus.R import org.mozilla.focus.databinding.BottomSheetHomeMenuBinding import org.mozilla.focus.telemetry.TelemetryWrapper import org.mozilla.focus.utils.FormatUtils +import org.mozilla.focus.utils.ScrollableBottomSheetHelper import org.mozilla.rocket.chrome.ChromeViewModel import org.mozilla.rocket.chrome.MenuViewModel import org.mozilla.rocket.content.appComponent @@ -72,25 +71,32 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { super.onDetachedFromWindow() } + override fun show() { + super.show() + BottomSheetBehavior + .from(binding.bottomSheet) + // by default, BottomSheet is showing half part, it is Collapsed + .also { it.state = BottomSheetBehavior.STATE_COLLAPSED } + } + private fun resetStates() { - binding.scrollView.fullScroll(ScrollView.FOCUS_UP) hideNewItemHint() } private fun initLayout() { binding = BottomSheetHomeMenuBinding.inflate(layoutInflater, null, false) - binding.scrollView.apply { - outlineProvider = object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - val dimen = resources.getDimension(R.dimen.menu_corner_radius) - outline.setRoundRect(0, 0, view.width, view.height, dimen) - } - } - clipToOutline = true - } initMenuTabs() initMenuItems() setContentView(binding.root) + val helperBinding = ScrollableBottomSheetHelper.Binding( + binding.root, + binding.container, + binding.bottomSheet + ) + + ScrollableBottomSheetHelper.makeViewScrollable(context, helperBinding) { + dismiss() + } } private fun initMenuTabs() { @@ -139,7 +145,9 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { binding.menuSmartShoppingSearch.isVisible = it } chromeViewModel.isPrivateBrowsingActive.observe(this@HomeMenuDialog) { - binding.imgPrivateMode.isActivated = it + // TODO: how to re-enable this? + // we removed this image, and use `drawableStart` instead + //binding.imgPrivateMode.isActivated = it } menuViewModel.shouldShowNewMenuItemHint.observe(this@HomeMenuDialog) { if (it) { diff --git a/app/src/main/res/layout/bottom_sheet_home_menu.xml b/app/src/main/res/layout/bottom_sheet_home_menu.xml index 4e242713d5..425ea56f48 100644 --- a/app/src/main/res/layout/bottom_sheet_home_menu.xml +++ b/app/src/main/res/layout/bottom_sheet_home_menu.xml @@ -1,447 +1,316 @@ + + - - + + + android:layout_height="match_parent"> - + app:behavior_hideable="true" + app:behavior_peekHeight="@dimen/menu_height" + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> - + android:background="@drawable/background_menu" + android:paddingBottom="8dp"> + app:layout_constraintEnd_toStartOf="@id/menu_bookmark" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:src="@drawable/menu_my_shots_states" /> + android:gravity="top|center_horizontal" + android:text="@string/label_menu_my_shots" /> - - - - - - - - - + + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - + android:layout_marginEnd="16dp" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:drawablePadding="10dp" + android:gravity="top|center_horizontal" + android:paddingTop="10dp" + android:text="@string/label_menu_download" + app:drawableTopCompat="@drawable/menu_download" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/menu_history" + app:layout_constraintTop_toTopOf="parent" /> + + - + android:layout_height="1dp" + android:layout_marginTop="4dp" + android:layout_marginBottom="7dp" + android:background="@color/paletteLightGreyA100" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/first_barrier" /> + + + - - + android:layout_marginEnd="22dp" + android:src="@drawable/ic_arrow_right" + app:layout_constraintBottom_toBottomOf="@id/menu_exit" + app:layout_constraintEnd_toEndOf="@id/menu_exit" + app:layout_constraintTop_toTopOf="@id/menu_exit" /> - - + - - - - - - + style="@style/BottomSheetRowMenuItemTextStyle" + android:drawableStart="@drawable/icon_night_mode" + android:text="@string/label_menu_night_mode" + app:layout_constraintEnd_toStartOf="@id/menu_night_mode_gutter" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/btn_private_browsing" /> + android:background="@color/paletteLightGreyA100" + app:layout_constraintBottom_toBottomOf="@id/menu_night_mode" + app:layout_constraintStart_toEndOf="@id/menu_night_mode" + app:layout_constraintTop_toTopOf="@id/menu_night_mode" /> - + android:layout_marginStart="12dp" + android:layout_marginEnd="24dp" + app:layout_constraintBottom_toBottomOf="@id/menu_night_mode" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/menu_night_mode_gutter" + app:layout_constraintTop_toTopOf="@id/menu_night_mode" /> + + + + - - - + - - - - + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="@id/menu_themes" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/menu_themes" + tools:visibility="visible" /> + + + - - - - + android:layout_marginEnd="22dp" + android:src="@drawable/ic_arrow_right" + app:layout_constraintBottom_toBottomOf="@id/menu_add_top_sites" + app:layout_constraintEnd_toEndOf="@id/menu_add_top_sites" + app:layout_constraintTop_toTopOf="@id/menu_add_top_sites" /> - - - - + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="@id/menu_add_top_sites" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/menu_add_top_sites" + tools:visibility="visible" /> + + + - - - - - - - - - - + android:layout_marginEnd="22dp" + android:src="@drawable/ic_arrow_right" + app:layout_constraintBottom_toBottomOf="@id/menu_preferences" + app:layout_constraintEnd_toEndOf="@id/menu_preferences" + app:layout_constraintTop_toTopOf="@id/menu_preferences" /> + + + - - - - - - - - - - - - + android:layout_marginEnd="22dp" + android:src="@drawable/ic_arrow_right" + app:layout_constraintBottom_toBottomOf="@id/menu_delete" + app:layout_constraintEnd_toEndOf="@id/menu_delete" + app:layout_constraintTop_toTopOf="@id/menu_delete" /> + + + - - - - - - - - - - \ No newline at end of file + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_marginEnd="22dp" + android:src="@drawable/ic_arrow_right" + app:layout_constraintBottom_toBottomOf="@id/menu_exit" + app:layout_constraintEnd_toEndOf="@id/menu_exit" + app:layout_constraintTop_toTopOf="@id/menu_exit" /> + + + + + + + + + + + From eeaa3275ba5b20ce03336d73bfef1e3be527b665 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Mon, 28 Mar 2022 22:42:25 +0900 Subject: [PATCH 6/7] add BottomSheetBrowserMenuFragment to replace HomeMenuDialog avoid using BottomSheetDialog, create a DialogFragment for showing Home Menu --- .../mozilla/focus/activity/MainActivity.kt | 53 ++++--- .../org/mozilla/rocket/di/AppComponent.kt | 4 +- ...alog.kt => BottomSheetHomeMenuFragment.kt} | 135 +++++++++--------- .../res/layout/bottom_sheet_home_menu.xml | 6 +- app/src/main/res/values/dimens.xml | 1 + 5 files changed, 107 insertions(+), 92 deletions(-) rename app/src/main/java/org/mozilla/rocket/menu/{HomeMenuDialog.kt => BottomSheetHomeMenuFragment.kt} (71%) diff --git a/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt b/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt index 4adbe716f7..c731f827f9 100644 --- a/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt +++ b/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt @@ -30,6 +30,8 @@ import androidx.appcompat.app.AlertDialog import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.fragment.app.DialogFragment +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.localbroadcastmanager.content.LocalBroadcastManager @@ -83,8 +85,8 @@ import org.mozilla.rocket.landing.NavigationModel import org.mozilla.rocket.landing.OrientationState import org.mozilla.rocket.landing.PortraitComponent import org.mozilla.rocket.landing.PortraitStateModel +import org.mozilla.rocket.menu.BottomSheetHomeMenuFragment import org.mozilla.rocket.menu.BrowserMenuDialog -import org.mozilla.rocket.menu.HomeMenuDialog import org.mozilla.rocket.periodic.FirstLaunchWorker import org.mozilla.rocket.periodic.PeriodicReceiver import org.mozilla.rocket.privately.PrivateMode @@ -131,7 +133,6 @@ class MainActivity : private lateinit var downloadIndicatorViewModel: DownloadIndicatorViewModel private var promotionModel: PromotionModel? = null - private lateinit var homeMenu: HomeMenuDialog private lateinit var browserMenu: BrowserMenuDialog private var myshotOnBoardingDialog: Dialog? = null @@ -231,22 +232,10 @@ class MainActivity : } private fun setUpMenu() { - if (::homeMenu.isInitialized) { - homeMenu.release() - } - homeMenu = HomeMenuDialog(this, R.style.BottomSheetTheme).apply { - setCanceledOnTouchOutside(true) - setOnShowListener { portraitStateModel.request(PortraitComponent.BottomMenu) } - setOnDismissListener { portraitStateModel.cancelRequest(PortraitComponent.BottomMenu) } - } - if (::browserMenu.isInitialized) { - browserMenu.release() - } - browserMenu = BrowserMenuDialog(this, R.style.BottomSheetTheme).apply { - setCanceledOnTouchOutside(true) - setOnShowListener { portraitStateModel.request(PortraitComponent.BottomMenu) } - setOnDismissListener { portraitStateModel.cancelRequest(PortraitComponent.BottomMenu) } - } + supportFragmentManager.registerFragmentLifecycleCallbacks( + FragmentStateListener(portraitStateModel), + false + ) } private fun initBroadcastReceivers() { @@ -355,7 +344,9 @@ class MainActivity : TabTray.show(supportFragmentManager) } ) - showHomeMenu.observe(this@MainActivity, Observer { homeMenu.show() }) + showHomeMenu.observe(this@MainActivity) { + BottomSheetHomeMenuFragment.show(supportFragmentManager) + } showBrowserMenu.observe(this@MainActivity, Observer { browserMenu.show() }) showNewTab.observe( this@MainActivity, @@ -698,7 +689,7 @@ class MainActivity : } private fun dismissAllMenus() { - homeMenu.dismiss() + BottomSheetHomeMenuFragment.dismiss(supportFragmentManager) browserMenu.dismiss() visibleBrowserFragment?.run { dismissAllMenus() } getListPanelFragment()?.dismissAllowingStateLoss() @@ -1011,6 +1002,28 @@ class MainActivity : } } + private class FragmentStateListener( + private val portraitStateModel: PortraitStateModel + ) : FragmentManager.FragmentLifecycleCallbacks() { + override fun onFragmentAttached( + fm: FragmentManager, + f: Fragment, + context: Context + ) { + when (f.tag) { + BottomSheetHomeMenuFragment.TAG -> + portraitStateModel.request(PortraitComponent.BottomMenu) + } + } + + override fun onFragmentDetached(fm: FragmentManager, f: Fragment) { + when (f.tag) { + BottomSheetHomeMenuFragment.TAG -> + portraitStateModel.cancelRequest(PortraitComponent.BottomMenu) + } + } + } + companion object { const val REQUEST_CODE_IN_APP_UPDATE = 1024 const val ACTION_INSTALL_IN_APP_UPDATE = "action_install_in_app_update" diff --git a/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt b/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt index 16ecb9d07a..5a541fe381 100644 --- a/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt +++ b/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt @@ -43,8 +43,8 @@ import org.mozilla.rocket.home.HomeFragment import org.mozilla.rocket.home.di.HomeModule import org.mozilla.rocket.home.topsites.domain.GetTopSitesUseCase import org.mozilla.rocket.home.topsites.ui.AddNewTopSitesFragment +import org.mozilla.rocket.menu.BottomSheetHomeMenuFragment import org.mozilla.rocket.menu.BrowserMenuDialog -import org.mozilla.rocket.menu.HomeMenuDialog import org.mozilla.rocket.menu.PrivateBrowserMenuDialog import org.mozilla.rocket.privately.PrivateModeActivity import org.mozilla.rocket.privately.home.PrivateHomeFragment @@ -91,7 +91,7 @@ interface AppComponent { fun inject(tabTrayFragment: TabTrayFragment) fun inject(privateHomeFragment: PrivateHomeFragment) fun inject(urlInputFragment: UrlInputFragment) - fun inject(homeMenuDialog: HomeMenuDialog) + fun inject(homeMenuFragment: BottomSheetHomeMenuFragment) fun inject(browserMenuDialog: BrowserMenuDialog) fun inject(privateBrowserMenuDialog: PrivateBrowserMenuDialog) fun inject(browsingHistoryFragment: BrowsingHistoryFragment) diff --git a/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt b/app/src/main/java/org/mozilla/rocket/menu/BottomSheetHomeMenuFragment.kt similarity index 71% rename from app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt rename to app/src/main/java/org/mozilla/rocket/menu/BottomSheetHomeMenuFragment.kt index 2a1bb49883..3b797ef0c8 100644 --- a/app/src/main/java/org/mozilla/rocket/menu/HomeMenuDialog.kt +++ b/app/src/main/java/org/mozilla/rocket/menu/BottomSheetHomeMenuFragment.kt @@ -1,16 +1,17 @@ package org.mozilla.rocket.menu -import android.content.Context import android.os.Bundle import android.os.Handler import android.os.Looper +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.Toast -import androidx.annotation.StyleRes import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer -import com.google.android.material.bottomsheet.BottomSheetBehavior import dagger.Lazy import org.mozilla.fileutils.FileUtils import org.mozilla.focus.R @@ -22,13 +23,11 @@ import org.mozilla.rocket.chrome.ChromeViewModel import org.mozilla.rocket.chrome.MenuViewModel import org.mozilla.rocket.content.appComponent import org.mozilla.rocket.content.getActivityViewModel -import org.mozilla.rocket.extension.toFragmentActivity import org.mozilla.rocket.nightmode.AdjustBrightnessDialog import org.mozilla.rocket.shopping.search.ui.ShoppingSearchActivity -import org.mozilla.rocket.widget.LifecycleBottomSheetDialog import javax.inject.Inject -class HomeMenuDialog : LifecycleBottomSheetDialog { +class BottomSheetHomeMenuFragment : DialogFragment() { @Inject lateinit var chromeViewModelCreator: Lazy @@ -39,95 +38,80 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { private lateinit var chromeViewModel: ChromeViewModel private lateinit var menuViewModel: MenuViewModel - private lateinit var binding: BottomSheetHomeMenuBinding + private var binding: BottomSheetHomeMenuBinding? = null private val uiHandler = Handler(Looper.getMainLooper()) - constructor(context: Context) : super(context) - constructor(context: Context, @StyleRes theme: Int) : super(context, theme) - override fun onCreate(savedInstanceState: Bundle?) { appComponent().inject(this) super.onCreate(savedInstanceState) - context.toFragmentActivity().lifecycle.addObserver(this) + // overwrite android.R.style.Theme_Panel, so it looks like normal Fragment + setStyle(STYLE_NO_TITLE, R.style.BottomSheetTheme) + chromeViewModel = getActivityViewModel(chromeViewModelCreator) menuViewModel = getActivityViewModel(menuViewModelCreator) - - initLayout() - observeChromeAction() - setCancelable(false) - setCanceledOnTouchOutside(true) } - override fun dismiss() { - if (::binding.isInitialized) { - resetStates() - } - super.dismiss() - } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = BottomSheetHomeMenuBinding.inflate(inflater, container, false).also { + binding = it + initLayout(it) + observeChromeAction() + }.root - override fun onDetachedFromWindow() { + override fun onDestroyView() { + super.onDestroyView() uiHandler.removeCallbacksAndMessages(null) - super.onDetachedFromWindow() - } - - override fun show() { - super.show() - BottomSheetBehavior - .from(binding.bottomSheet) - // by default, BottomSheet is showing half part, it is Collapsed - .also { it.state = BottomSheetBehavior.STATE_COLLAPSED } - } - - private fun resetStates() { - hideNewItemHint() + binding = null } - private fun initLayout() { - binding = BottomSheetHomeMenuBinding.inflate(layoutInflater, null, false) - initMenuTabs() - initMenuItems() - setContentView(binding.root) + private fun initLayout(binding: BottomSheetHomeMenuBinding) { val helperBinding = ScrollableBottomSheetHelper.Binding( binding.root, binding.container, binding.bottomSheet ) - ScrollableBottomSheetHelper.makeViewScrollable(context, helperBinding) { - dismiss() + ScrollableBottomSheetHelper.makeViewScrollable(this.requireContext(), helperBinding) { + this.dismissAllowingStateLoss() } + + initMenuTabs(binding) + initMenuItems(binding) } - private fun initMenuTabs() { + private fun initMenuTabs(binding: BottomSheetHomeMenuBinding) { binding.contentLayout.apply { - chromeViewModel.hasUnreadScreenshot.observe(this@HomeMenuDialog) { + chromeViewModel.hasUnreadScreenshot.observe(this@BottomSheetHomeMenuFragment) { binding.imgScreenshots.isActivated = it } binding.menuScreenshots.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showScreenshots() } } binding.menuBookmark.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showBookmarks.call() TelemetryWrapper.clickMenuBookmark() } } binding.menuHistory.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showHistory.call() TelemetryWrapper.clickMenuHistory() } } binding.menuDownload.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showDownloadPanel.call() TelemetryWrapper.clickMenuDownload() } @@ -135,21 +119,21 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } } - private fun initMenuItems() { + private fun initMenuItems(binding: BottomSheetHomeMenuBinding) { binding.contentLayout.apply { - chromeViewModel.isNightMode.observe(this@HomeMenuDialog) { nightModeSettings -> + chromeViewModel.isNightMode.observe(this@BottomSheetHomeMenuFragment) { nightModeSettings -> binding.nightModeSwitch.isChecked = nightModeSettings.isEnabled } - menuViewModel.isHomeScreenShoppingSearchEnabled.observe(this@HomeMenuDialog) { + menuViewModel.isHomeScreenShoppingSearchEnabled.observe(this@BottomSheetHomeMenuFragment) { binding.btnPrivateBrowsing.isVisible = !it binding.menuSmartShoppingSearch.isVisible = it } - chromeViewModel.isPrivateBrowsingActive.observe(this@HomeMenuDialog) { + chromeViewModel.isPrivateBrowsingActive.observe(this@BottomSheetHomeMenuFragment) { // TODO: how to re-enable this? // we removed this image, and use `drawableStart` instead - //binding.imgPrivateMode.isActivated = it + // binding.imgPrivateMode.isActivated = it } - menuViewModel.shouldShowNewMenuItemHint.observe(this@HomeMenuDialog) { + menuViewModel.shouldShowNewMenuItemHint.observe(this@BottomSheetHomeMenuFragment) { if (it) { showNewItemHint() menuViewModel.onNewMenuItemDisplayed() @@ -158,14 +142,14 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { binding.btnPrivateBrowsing.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.togglePrivateMode.call() TelemetryWrapper.togglePrivateMode(true) } } binding.menuSmartShoppingSearch.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() showShoppingSearch() } } @@ -181,21 +165,21 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } binding.menuAddTopSites.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.onAddNewTopSiteMenuClicked() TelemetryWrapper.clickMenuAddTopsite() } } binding.menuThemes.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.onThemeSettingMenuClicked() TelemetryWrapper.clickMenuTheme() } } binding.menuPreferences.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.checkToDriveDefaultBrowser() chromeViewModel.openPreference.call() TelemetryWrapper.clickMenuSettings() @@ -203,14 +187,14 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } binding.menuDelete.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() onDeleteClicked() TelemetryWrapper.clickMenuClearCache() } } binding.menuExit.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.exitApp.call() TelemetryWrapper.clickMenuExit() } @@ -219,16 +203,13 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } private fun showNewItemHint() { + val binding = binding ?: return binding.addTopSitesRedDot.visibility = View.VISIBLE binding.themesRedDot.visibility = View.VISIBLE } - private fun hideNewItemHint() { - binding.addTopSitesRedDot.visibility = View.INVISIBLE - binding.themesRedDot.visibility = View.INVISIBLE - } - private fun onDeleteClicked() { + val context = context ?: return val diff = FileUtils.clearCache(context) val stringId = if (diff < 0) R.string.message_clear_cache_fail else R.string.message_cleared_cached @@ -241,6 +222,7 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } private fun showAdjustBrightness() { + val context = context ?: return ContextCompat.startActivity( context, AdjustBrightnessDialog.Intents.getStartIntentFromMenu(context), @@ -249,6 +231,7 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { } private fun showShoppingSearch() { + val context = context ?: return context.startActivity(ShoppingSearchActivity.getStartIntent(context)) } @@ -263,4 +246,22 @@ class HomeMenuDialog : LifecycleBottomSheetDialog { 150 ) } + + companion object { + const val TAG = "BottomSheetHomeMenuFragment" + + fun createInstance(): BottomSheetHomeMenuFragment { + return BottomSheetHomeMenuFragment() + } + + fun show(supportFragmentManager: FragmentManager) { + createInstance().show(supportFragmentManager, TAG) + } + + fun dismiss(supportFragmentManager: FragmentManager) { + val taggedFragment = supportFragmentManager.findFragmentByTag(TAG) ?: return + val dialogFragment = taggedFragment as? BottomSheetHomeMenuFragment ?: return + dialogFragment.dismissAllowingStateLoss() + } + } } diff --git a/app/src/main/res/layout/bottom_sheet_home_menu.xml b/app/src/main/res/layout/bottom_sheet_home_menu.xml index 425ea56f48..1404933e84 100644 --- a/app/src/main/res/layout/bottom_sheet_home_menu.xml +++ b/app/src/main/res/layout/bottom_sheet_home_menu.xml @@ -18,16 +18,16 @@ 12dp 48dp 363dp + 320dp 4dp 16dp From a53910605bc5b29ed868971ac0b2a8685f82ae20 Mon Sep 17 00:00:00 2001 From: Julian_Chu Date: Mon, 28 Mar 2022 00:40:04 +0900 Subject: [PATCH 7/7] add BottomSheeBrowserMenuFragment to replace BrowserMenuDialog avoid using BottomSheetDialog, create a DialogFragment for showing Home Menu --- .../mozilla/focus/activity/MainActivity.kt | 14 +- .../org/mozilla/rocket/di/AppComponent.kt | 4 +- ...g.kt => BottomSheetBrowserMenuFragment.kt} | 194 ++++--- .../res/layout/bottom_sheet_browser_menu.xml | 518 +++++++++--------- app/src/main/res/values/dimens.xml | 1 + 5 files changed, 386 insertions(+), 345 deletions(-) rename app/src/main/java/org/mozilla/rocket/menu/{BrowserMenuDialog.kt => BottomSheetBrowserMenuFragment.kt} (70%) diff --git a/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt b/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt index c731f827f9..bf9b2a0bb9 100644 --- a/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt +++ b/app/src/main/java/org/mozilla/focus/activity/MainActivity.kt @@ -85,8 +85,8 @@ import org.mozilla.rocket.landing.NavigationModel import org.mozilla.rocket.landing.OrientationState import org.mozilla.rocket.landing.PortraitComponent import org.mozilla.rocket.landing.PortraitStateModel +import org.mozilla.rocket.menu.BottomSheetBrowserMenuFragment import org.mozilla.rocket.menu.BottomSheetHomeMenuFragment -import org.mozilla.rocket.menu.BrowserMenuDialog import org.mozilla.rocket.periodic.FirstLaunchWorker import org.mozilla.rocket.periodic.PeriodicReceiver import org.mozilla.rocket.privately.PrivateMode @@ -133,7 +133,6 @@ class MainActivity : private lateinit var downloadIndicatorViewModel: DownloadIndicatorViewModel private var promotionModel: PromotionModel? = null - private lateinit var browserMenu: BrowserMenuDialog private var myshotOnBoardingDialog: Dialog? = null private lateinit var screenNavigator: ScreenNavigator @@ -347,7 +346,9 @@ class MainActivity : showHomeMenu.observe(this@MainActivity) { BottomSheetHomeMenuFragment.show(supportFragmentManager) } - showBrowserMenu.observe(this@MainActivity, Observer { browserMenu.show() }) + showBrowserMenu.observe(this@MainActivity) { + BottomSheetBrowserMenuFragment.show(supportFragmentManager) + } showNewTab.observe( this@MainActivity, Observer { @@ -690,7 +691,7 @@ class MainActivity : private fun dismissAllMenus() { BottomSheetHomeMenuFragment.dismiss(supportFragmentManager) - browserMenu.dismiss() + BottomSheetBrowserMenuFragment.dismiss(supportFragmentManager) visibleBrowserFragment?.run { dismissAllMenus() } getListPanelFragment()?.dismissAllowingStateLoss() myshotOnBoardingDialog?.run { @@ -853,7 +854,7 @@ class MainActivity : @VisibleForTesting @UiThread fun showMyShotOnBoarding() { - val view = browserMenu.findViewById(R.id.menu_screenshots) + val view = BottomSheetBrowserMenuFragment.getScreenshotMenuButton(supportFragmentManager) view?.post { myshotOnBoardingDialog = DialogUtils.showMyShotOnBoarding( this@MainActivity, @@ -869,7 +870,6 @@ class MainActivity : ) chromeViewModel.onMyShotOnBoardingDisplayed() } - browserMenu.show() } private fun checkInAppUpdate() { @@ -1011,6 +1011,7 @@ class MainActivity : context: Context ) { when (f.tag) { + BottomSheetBrowserMenuFragment.TAG, BottomSheetHomeMenuFragment.TAG -> portraitStateModel.request(PortraitComponent.BottomMenu) } @@ -1018,6 +1019,7 @@ class MainActivity : override fun onFragmentDetached(fm: FragmentManager, f: Fragment) { when (f.tag) { + BottomSheetBrowserMenuFragment.TAG, BottomSheetHomeMenuFragment.TAG -> portraitStateModel.cancelRequest(PortraitComponent.BottomMenu) } diff --git a/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt b/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt index 5a541fe381..6b8a5d2203 100644 --- a/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt +++ b/app/src/main/java/org/mozilla/rocket/di/AppComponent.kt @@ -43,8 +43,8 @@ import org.mozilla.rocket.home.HomeFragment import org.mozilla.rocket.home.di.HomeModule import org.mozilla.rocket.home.topsites.domain.GetTopSitesUseCase import org.mozilla.rocket.home.topsites.ui.AddNewTopSitesFragment +import org.mozilla.rocket.menu.BottomSheetBrowserMenuFragment import org.mozilla.rocket.menu.BottomSheetHomeMenuFragment -import org.mozilla.rocket.menu.BrowserMenuDialog import org.mozilla.rocket.menu.PrivateBrowserMenuDialog import org.mozilla.rocket.privately.PrivateModeActivity import org.mozilla.rocket.privately.home.PrivateHomeFragment @@ -92,7 +92,7 @@ interface AppComponent { fun inject(privateHomeFragment: PrivateHomeFragment) fun inject(urlInputFragment: UrlInputFragment) fun inject(homeMenuFragment: BottomSheetHomeMenuFragment) - fun inject(browserMenuDialog: BrowserMenuDialog) + fun inject(browserMenuFragment: BottomSheetBrowserMenuFragment) fun inject(privateBrowserMenuDialog: PrivateBrowserMenuDialog) fun inject(browsingHistoryFragment: BrowsingHistoryFragment) fun inject(privateModeActivity: PrivateModeActivity) diff --git a/app/src/main/java/org/mozilla/rocket/menu/BrowserMenuDialog.kt b/app/src/main/java/org/mozilla/rocket/menu/BottomSheetBrowserMenuFragment.kt similarity index 70% rename from app/src/main/java/org/mozilla/rocket/menu/BrowserMenuDialog.kt rename to app/src/main/java/org/mozilla/rocket/menu/BottomSheetBrowserMenuFragment.kt index 3a63054dc4..7bb2c47712 100644 --- a/app/src/main/java/org/mozilla/rocket/menu/BrowserMenuDialog.kt +++ b/app/src/main/java/org/mozilla/rocket/menu/BottomSheetBrowserMenuFragment.kt @@ -1,17 +1,16 @@ package org.mozilla.rocket.menu -import android.content.Context -import android.graphics.Outline import android.os.Bundle import android.os.Handler import android.os.Looper +import android.view.LayoutInflater import android.view.View -import android.view.ViewOutlineProvider -import android.widget.ScrollView +import android.view.ViewGroup import android.widget.Toast -import androidx.annotation.StyleRes import androidx.core.content.ContextCompat import androidx.core.content.pm.ShortcutManagerCompat +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentManager import androidx.lifecycle.Observer import dagger.Lazy import org.mozilla.fileutils.FileUtils @@ -19,19 +18,19 @@ import org.mozilla.focus.R import org.mozilla.focus.databinding.BottomSheetBrowserMenuBinding import org.mozilla.focus.telemetry.TelemetryWrapper import org.mozilla.focus.utils.FormatUtils +import org.mozilla.focus.utils.ScrollableBottomSheetHelper import org.mozilla.rocket.chrome.BottomBarItemAdapter import org.mozilla.rocket.chrome.ChromeViewModel import org.mozilla.rocket.chrome.MenuViewModel -import org.mozilla.rocket.chrome.bottombar.BottomBarItem.ItemType +import org.mozilla.rocket.chrome.bottombar.BottomBarItem import org.mozilla.rocket.content.appComponent import org.mozilla.rocket.content.getActivityViewModel import org.mozilla.rocket.extension.nonNullObserve import org.mozilla.rocket.extension.switchFrom import org.mozilla.rocket.nightmode.AdjustBrightnessDialog -import org.mozilla.rocket.widget.LifecycleBottomSheetDialog import javax.inject.Inject -class BrowserMenuDialog : LifecycleBottomSheetDialog { +class BottomSheetBrowserMenuFragment : DialogFragment() { @Inject lateinit var chromeViewModelCreator: Lazy @@ -39,91 +38,85 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { @Inject lateinit var menuViewModelCreator: Lazy - private lateinit var menuViewModel: MenuViewModel + private val uiHandler = Handler(Looper.getMainLooper()) + private lateinit var chromeViewModel: ChromeViewModel + private lateinit var menuViewModel: MenuViewModel private lateinit var bottomBarItemAdapter: BottomBarItemAdapter - private lateinit var binding: BottomSheetBrowserMenuBinding - private val uiHandler = Handler(Looper.getMainLooper()) - - constructor(context: Context) : super(context) - constructor(context: Context, @StyleRes theme: Int) : super(context, theme) + private var binding: BottomSheetBrowserMenuBinding? = null override fun onCreate(savedInstanceState: Bundle?) { appComponent().inject(this) super.onCreate(savedInstanceState) + // overwrite android.R.style.Theme_Panel, so it looks like normal Fragment + setStyle(STYLE_NO_TITLE, R.style.BottomSheetTheme) + chromeViewModel = getActivityViewModel(chromeViewModelCreator) menuViewModel = getActivityViewModel(menuViewModelCreator) - - initLayout() - observeChromeAction() - setCancelable(false) - setCanceledOnTouchOutside(true) } - override fun dismiss() { - if (::binding.isInitialized) { - binding.scrollView.fullScroll(ScrollView.FOCUS_UP) - } - super.dismiss() - } + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = BottomSheetBrowserMenuBinding.inflate(inflater, container, false).also { + binding = it + initLayout(it) + observeChromeAction() + }.root - override fun onDetachedFromWindow() { + override fun onDestroyView() { + super.onDestroyView() uiHandler.removeCallbacksAndMessages(null) - super.onDetachedFromWindow() + binding = null } - private fun initLayout() { - binding = BottomSheetBrowserMenuBinding.inflate(layoutInflater, null, false) - binding.contentLayout.apply { - outlineProvider = object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - 0, - 0, - view.width, - view.height, - resources.getDimension(R.dimen.menu_corner_radius) - ) - } - } - clipToOutline = true + private fun initLayout(binding: BottomSheetBrowserMenuBinding) { + val helperBinding = ScrollableBottomSheetHelper.Binding( + binding.root, + binding.container, + binding.bottomSheet + ) + + ScrollableBottomSheetHelper.makeViewScrollable(this.requireContext(), helperBinding) { + this.dismissAllowingStateLoss() } - initMenuTabs() - initMenuItems() - initBottomBar() - setContentView(binding.root) + + initMenuTabs(binding) + initMenuItems(binding) + initBottomBar(binding) } - private fun initMenuTabs() { + private fun initMenuTabs(binding: BottomSheetBrowserMenuBinding) { binding.contentLayout.apply { - chromeViewModel.hasUnreadScreenshot.observe(this@BrowserMenuDialog) { + chromeViewModel.hasUnreadScreenshot.observe(this@BottomSheetBrowserMenuFragment) { binding.imgScreenshots.isActivated = it } binding.menuScreenshots.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showScreenshots() } } binding.menuBookmark.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showBookmarks.call() TelemetryWrapper.clickMenuBookmark() } } binding.menuHistory.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showHistory.call() TelemetryWrapper.clickMenuHistory() } } binding.menuDownload.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showDownloadPanel.call() TelemetryWrapper.clickMenuDownload() } @@ -131,36 +124,36 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } } - private fun initMenuItems() { + private fun initMenuItems(binding: BottomSheetBrowserMenuBinding) { binding.contentLayout.apply { - chromeViewModel.isTurboModeEnabled.observe(this@BrowserMenuDialog) { + chromeViewModel.isTurboModeEnabled.observe(this@BottomSheetBrowserMenuFragment) { binding.turboModeSwitch.isChecked = it } - chromeViewModel.isBlockImageEnabled.observe(this@BrowserMenuDialog) { + chromeViewModel.isBlockImageEnabled.observe(this@BottomSheetBrowserMenuFragment) { binding.blockImagesSwitch.isChecked = it } - chromeViewModel.isNightMode.observe(this@BrowserMenuDialog) { nightModeSettings -> + chromeViewModel.isNightMode.observe(this@BottomSheetBrowserMenuFragment) { nightModeSettings -> binding.nightModeSwitch.isChecked = nightModeSettings.isEnabled } binding.menuFindInPage.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.showFindInPage.call() } } binding.menuPinShortcut.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.pinShortcut.call() TelemetryWrapper.clickMenuPinShortcut() } } binding.menuPinSite.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.pinSite.call() } } @@ -190,7 +183,7 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } binding.menuPreferences.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.checkToDriveDefaultBrowser() chromeViewModel.openPreference.call() TelemetryWrapper.clickMenuSettings() @@ -198,14 +191,14 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } binding.menuDelete.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() onDeleteClicked() TelemetryWrapper.clickMenuClearCache() } } binding.menuExit.setOnClickListener { postDelayClickEvent { - cancel() + dismissAllowingStateLoss() chromeViewModel.exitApp.call() TelemetryWrapper.clickMenuExit() } @@ -214,6 +207,7 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } private fun onDeleteClicked() { + val context = context ?: return val diff = FileUtils.clearCache(context) val stringId = if (diff < 0) R.string.message_clear_cache_fail else R.string.message_cleared_cached @@ -226,6 +220,7 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } private fun showAdjustBrightness() { + val context = context ?: return ContextCompat.startActivity( context, AdjustBrightnessDialog.Intents.getStartIntentFromMenu(context), @@ -233,51 +228,51 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { ) } - private fun initBottomBar() { + private fun initBottomBar(binding: BottomSheetBrowserMenuBinding) { val bottomBar = binding.menuBottomBar bottomBar.setOnItemClickListener { type, position -> - cancel() + dismissAllowingStateLoss() when (type) { - ItemType.TAB_COUNTER -> { + BottomBarItem.ItemType.TAB_COUNTER -> { chromeViewModel.showTabTray.call() TelemetryWrapper.showTabTrayToolbar( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.MENU -> { + BottomBarItem.ItemType.MENU -> { chromeViewModel.showBrowserMenu.call() TelemetryWrapper.showMenuToolbar( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.HOME -> { + BottomBarItem.ItemType.HOME -> { chromeViewModel.showNewTab.call() TelemetryWrapper.clickAddTabToolbar( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.SEARCH -> { + BottomBarItem.ItemType.SEARCH -> { chromeViewModel.showUrlInput.call() TelemetryWrapper.clickToolbarSearch( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.CAPTURE -> chromeViewModel.onDoScreenshot( + BottomBarItem.ItemType.CAPTURE -> chromeViewModel.onDoScreenshot( ChromeViewModel.ScreenCaptureTelemetryData( TelemetryWrapper.Extra_Value.MENU, position ) ) - ItemType.PIN_SHORTCUT -> { + BottomBarItem.ItemType.PIN_SHORTCUT -> { chromeViewModel.pinShortcut.call() TelemetryWrapper.clickAddToHome(TelemetryWrapper.Extra_Value.MENU, position) } - ItemType.BOOKMARK -> { - val nullableItem = bottomBarItemAdapter.getItem(ItemType.BOOKMARK) + BottomBarItem.ItemType.BOOKMARK -> { + val nullableItem = bottomBarItemAdapter.getItem(BottomBarItem.ItemType.BOOKMARK) val isActivated = nullableItem?.view?.isActivated == true TelemetryWrapper.clickToolbarBookmark( !isActivated, @@ -286,35 +281,35 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { ) chromeViewModel.toggleBookmark() } - ItemType.REFRESH -> { + BottomBarItem.ItemType.REFRESH -> { chromeViewModel.refreshOrStop.call() TelemetryWrapper.clickToolbarReload( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.SHARE -> { + BottomBarItem.ItemType.SHARE -> { chromeViewModel.share.call() TelemetryWrapper.clickToolbarShare( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.NEXT -> { + BottomBarItem.ItemType.NEXT -> { chromeViewModel.goNext.call() TelemetryWrapper.clickToolbarForward( TelemetryWrapper.Extra_Value.MENU, position ) } - ItemType.BACK -> { + BottomBarItem.ItemType.BACK -> { chromeViewModel.goBack.call() TelemetryWrapper.clickToolbarBack(position) } - ItemType.PRIVATE_HOME, - ItemType.DELETE, - ItemType.TRACKER, - ItemType.SHOPPING_SEARCH -> + BottomBarItem.ItemType.PRIVATE_HOME, + BottomBarItem.ItemType.DELETE, + BottomBarItem.ItemType.TRACKER, + BottomBarItem.ItemType.SHOPPING_SEARCH -> throw IllegalArgumentException("Unhandled bottom bar item, type: $type") } // move Telemetry to ScreenCaptureTask doInBackground() cause we need to init category first. } @@ -337,11 +332,12 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { } private fun hidePinShortcutButtonIfNotSupported() { + val context = context ?: return val requestPinShortcutSupported = ShortcutManagerCompat.isRequestPinShortcutSupported(context) if (!requestPinShortcutSupported) { val pinShortcutItem = - bottomBarItemAdapter.getItem(ItemType.PIN_SHORTCUT) + bottomBarItemAdapter.getItem(BottomBarItem.ItemType.PIN_SHORTCUT) pinShortcutItem?.view?.apply { visibility = View.GONE } @@ -352,6 +348,40 @@ class BrowserMenuDialog : LifecycleBottomSheetDialog { * Post delay click event to wait the clicking feedback shows */ private fun postDelayClickEvent(action: () -> Unit) { - uiHandler.postDelayed({ action() }, 150) + uiHandler.postDelayed( + { + action() + }, + 150 + ) + } + + companion object { + const val TAG = "BottomSheetBrowserMenuFragment" + + fun createInstance(): BottomSheetBrowserMenuFragment { + return BottomSheetBrowserMenuFragment() + } + + fun show(supportFragmentManager: FragmentManager) { + createInstance().show(supportFragmentManager, TAG) + } + + fun dismiss(supportFragmentManager: FragmentManager) { + val fragment = getDisplayedFragment(supportFragmentManager) + fragment?.dismissAllowingStateLoss() + } + + fun getScreenshotMenuButton(supportFragmentManager: FragmentManager): View? { + val fragment = getDisplayedFragment(supportFragmentManager) + return fragment?.binding?.menuScreenshots + } + + private fun getDisplayedFragment( + supportFragmentManager: FragmentManager + ): BottomSheetBrowserMenuFragment? { + val taggedFragment = supportFragmentManager.findFragmentByTag(TAG) ?: return null + return taggedFragment as? BottomSheetBrowserMenuFragment ?: return null + } } } diff --git a/app/src/main/res/layout/bottom_sheet_browser_menu.xml b/app/src/main/res/layout/bottom_sheet_browser_menu.xml index e6281e6163..b3a1ee9670 100644 --- a/app/src/main/res/layout/bottom_sheet_browser_menu.xml +++ b/app/src/main/res/layout/bottom_sheet_browser_menu.xml @@ -7,284 +7,292 @@ + android:orientation="vertical"> - - - - + + - - + android:paddingBottom="8dp"> - + + + + + + + + + + + android:paddingTop="10dp" + android:text="@string/label_menu_history" + app:drawableTopCompat="@drawable/menu_history" + app:layout_constraintEnd_toStartOf="@id/menu_download" + app:layout_constraintStart_toEndOf="@id/menu_bookmark" + app:layout_constraintTop_toTopOf="parent" /> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + style="@style/MenuButtonText" + android:layout_width="74dp" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:drawablePadding="10dp" + android:gravity="top|center_horizontal" + android:paddingTop="10dp" + android:text="@string/label_menu_download" + app:drawableTopCompat="@drawable/menu_download" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/menu_history" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + app:dividerColor="@color/paletteLightGreyA100" + tools:background="#F0F" /> - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 7bbcbef8bd..b8c883e5b5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -25,6 +25,7 @@ 48dp 363dp 320dp + 280dp 4dp 16dp