diff --git a/app/src/main/java/org/mozilla/fenix/browser/InfoBanner.kt b/app/src/main/java/org/mozilla/fenix/browser/InfoBanner.kt index be74646d2..d7f4187cc 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/InfoBanner.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/InfoBanner.kt @@ -13,6 +13,7 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import kotlinx.android.synthetic.main.info_banner.view.* import org.mozilla.fenix.R +import org.mozilla.fenix.ext.settings /** * Displays an Info Banner in the specified container with a message and an optional action. @@ -25,12 +26,15 @@ import org.mozilla.fenix.R * @param actionText - The text on the action to perform button * @param actionToPerform - The action to be performed on action button press */ +@SuppressWarnings("LongParameterList") class InfoBanner( private val context: Context, private val container: ViewGroup, private val message: String, private val dismissText: String, private val actionText: String? = null, + private val dismissByHiding: Boolean = false, + private val dismissAction: (() -> Unit)? = null, private val actionToPerform: (() -> Unit)? = null ) { @SuppressLint("InflateParams") @@ -54,12 +58,15 @@ class InfoBanner( params.width = MATCH_PARENT bannerLayout.dismiss.setOnClickListener { - dismiss() + dismissAction?.invoke() + if (dismissByHiding) { bannerLayout.visibility = GONE } else { dismiss() } } bannerLayout.action.setOnClickListener { actionToPerform?.invoke() } + + context.settings().lastCfrShownTimeInMillis = System.currentTimeMillis() } internal fun dismiss() { diff --git a/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt b/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt index 43be8b169..63b8c2635 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt @@ -60,7 +60,6 @@ class OpenInAppOnboardingObserver( infoBanner?.showBanner() sessionDomainForDisplayedBanner = session.url.tryGetHostFromUrl() - settings.lastCfrShownTimeInMillis = System.currentTimeMillis() settings.shouldShowOpenInAppBanner = false } } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt index 431bfe898..41c6ddf40 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayController.kt @@ -43,6 +43,7 @@ interface TabTrayController { fun handleOpenTab(tab: Tab) fun handleEnterMultiselect() fun handleRecentlyClosedClicked() + fun handleSetUpAutoCloseTabsClicked() } /** @@ -184,4 +185,9 @@ class DefaultTabTrayController( val directions = TabTrayDialogFragmentDirections.actionGlobalRecentlyClosed() navController.navigate(directions) } + + override fun handleSetUpAutoCloseTabsClicked() { + val directions = TabTrayDialogFragmentDirections.actionGlobalCloseTabSettingsFragment() + navController.navigate(directions) + } } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt index 3cf89a386..556023572 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractor.kt @@ -54,6 +54,11 @@ interface TabTrayInteractor { */ fun onModeRequested(): TabTrayDialogFragmentState.Mode + /** + * Called when user clicks on the "set it up" prompt for automatically closing tabs + */ + fun onSetUpAutoCloseTabsClicked() + /** * Called when a tab should be opened in the browser. */ @@ -140,4 +145,8 @@ class TabTrayFragmentInteractor(private val controller: TabTrayController) : Tab override fun onEnterMultiselect() { controller.handleEnterMultiselect() } + + override fun onSetUpAutoCloseTabsClicked() { + controller.handleSetUpAutoCloseTabsClicked() + } } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt index 948fb9e88..2d24cc0ef 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -43,6 +43,7 @@ import mozilla.components.browser.tabstray.TabViewHolder import mozilla.components.feature.syncedtabs.SyncedTabsFeature import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import org.mozilla.fenix.R +import org.mozilla.fenix.browser.InfoBanner import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.toolbar.TabCounter.Companion.INFINITE_CHAR_PADDING_BOTTOM import org.mozilla.fenix.components.toolbar.TabCounter.Companion.MAX_VISIBLE_TABS @@ -239,6 +240,28 @@ class TabTrayView( } adjustNewTabButtonsForNormalMode() + + if ( + view.context.settings().shouldShowAutoCloseTabsBanner && + view.context.settings().canShowCfr && + tabs.size >= TAB_COUNT_SHOW_CFR + ) { + InfoBanner( + context = view.context, + message = view.context.getString(R.string.tab_tray_close_tabs_banner_message), + dismissText = view.context.getString(R.string.tab_tray_close_tabs_banner_negative_button_text), + actionText = view.context.getString(R.string.tab_tray_close_tabs_banner_positive_button_text), + container = view.infoBanner, + dismissByHiding = true, + dismissAction = { view.context.settings().shouldShowAutoCloseTabsBanner = false } + ) { + interactor.onSetUpAutoCloseTabsClicked() + view.context.settings().shouldShowAutoCloseTabsBanner = false + }.apply { + view.infoBanner.visibility = View.VISIBLE + showBanner() + } + } } private fun handleTabClicked(tab: SyncTab) { @@ -578,6 +601,7 @@ class TabTrayView( } companion object { + private const val TAB_COUNT_SHOW_CFR = 6 private const val DEFAULT_TAB_ID = 0 private const val PRIVATE_TAB_ID = 1 private const val EXPAND_AT_SIZE = 3 diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index ff4bed759..a0bd0ad76 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -689,6 +689,11 @@ class Settings(private val appContext: Context) : PreferencesHolder { val shouldShowOpenInAppCfr: Boolean get() = canShowCfr && shouldShowOpenInAppBanner + var shouldShowAutoCloseTabsBanner by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_should_show_auto_close_tabs_banner), + default = true + ) + @VisibleForTesting(otherwise = PRIVATE) internal val trackingProtectionOnboardingCount = counterPreference( appContext.getPreferenceKey(R.string.pref_key_tracking_protection_onboarding), diff --git a/app/src/main/res/layout/component_tabstray.xml b/app/src/main/res/layout/component_tabstray.xml index e785b4dfd..0005ecb5a 100644 --- a/app/src/main/res/layout/component_tabstray.xml +++ b/app/src/main/res/layout/component_tabstray.xml @@ -24,6 +24,15 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_percent="0.1" /> + + + + app:layout_constraintTop_toBottomOf="@id/infoBanner" /> + app:layout_constraintTop_toBottomOf="@+id/infoBanner" /> pref_key_should_show_open_in_app_banner + + pref_key_should_show_auto_close_tabs_banner + pref_key_migrating_from_fenix_nightly_tip pref_key_migrating_from_firefox_nightly_tip pref_key_migrating_from_fenix_tip diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt index 0e478c3ba..c484c82a2 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/DefaultTabTrayControllerTest.kt @@ -248,4 +248,14 @@ class DefaultTabTrayControllerTest { showChooseCollectionDialog(listOf(session)) } } + + @Test + fun handleSetUpAutoCloseTabsClicked() { + controller.handleSetUpAutoCloseTabsClicked() + val directions = TabTrayDialogFragmentDirections.actionGlobalCloseTabSettingsFragment() + + verify { + navController.navigate(directions) + } + } } diff --git a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt index 7fbb8306c..1e1f027e1 100644 --- a/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/tabtray/TabTrayFragmentInteractorTest.kt @@ -106,4 +106,10 @@ class TabTrayFragmentInteractorTest { interactor.onEnterMultiselect() verify { controller.handleEnterMultiselect() } } + + @Test + fun onSetUpAutoCloseTabsClicked() { + interactor.onSetUpAutoCloseTabsClicked() + verify { controller.handleSetUpAutoCloseTabsClicked() } + } } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index ff7344e09..6daeba32e 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -15,7 +15,7 @@ object Versions { const val androidx_appcompat = "1.2.0-rc01" const val androidx_biometric = "1.1.0-alpha01" const val androidx_coordinator_layout = "1.1.0-rc01" - const val androidx_constraint_layout = "2.0.0-beta6" + const val androidx_constraint_layout = "2.0.0" const val androidx_preference = "1.1.0" const val androidx_legacy = "1.0.0" const val androidx_annotation = "1.1.0"