From a8a90bd4d6e2a993dc492d8877ac31ff6447336f Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Thu, 30 Apr 2020 13:53:10 -0700 Subject: [PATCH] For #1063: Put tab tray behind a feature flag and hidden pref (#10313) * For #1063 - Adds feature flag and pref for new tab tray * For #1063 - Swaps add tab to tab tray button when newTabTray is enabled * For #1063 - Creates hidden preference to use new tab tray * For #1063 - Hides tabs on home screen when setting is enabled * For #1063 - Navigate to new tab tray from browser with setting enabled * For #1063 - Fixes regression where we dont show the new tab message with no tabs and no collections * For #1063 - Fixes crash when toggling to private mode on the home screen * For #1063 - combines both settings. Cleans up lint errors --- .../java/org/mozilla/fenix/FeatureFlags.kt | 5 ++ .../toolbar/BrowserToolbarController.kt | 6 +++ .../org/mozilla/fenix/home/HomeFragment.kt | 24 ++++++++- .../home/sessioncontrol/SessionControlView.kt | 54 +++++++++++-------- .../settings/SecretSettingsPreference.kt | 35 ++++++++++++ .../fenix/settings/SettingsFragment.kt | 6 +++ .../java/org/mozilla/fenix/utils/Settings.kt | 12 +++++ app/src/main/res/layout/fragment_home.xml | 20 ++++++- app/src/main/res/navigation/nav_graph.xml | 11 ++++ app/src/main/res/values/preference_keys.xml | 3 ++ app/src/main/res/values/static_strings.xml | 4 ++ app/src/main/res/xml/preferences.xml | 6 +++ .../res/xml/secret_settings_preferences.xml | 12 +++++ 13 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/settings/SecretSettingsPreference.kt create mode 100644 app/src/main/res/xml/secret_settings_preferences.xml diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index 12f8b8b53..1b5f36a7b 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -43,4 +43,9 @@ object FeatureFlags { * Enables tip feature */ val tips = Config.channel.isDebug + + /** + * Enables new tab tray pref + */ + val tabTray = Config.channel.isDebug } diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt index 0c322ab51..d370f5f84 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt @@ -313,6 +313,12 @@ class DefaultBrowserToolbarController( } private fun animateTabAndNavigateHome() { + if (activity.settings().useNewTabTray) { + val directions = BrowserFragmentDirections.actionBrowserFragmentToTabsTrayFragment() + navController.navigate(directions) + return + } + scope.launch { browserAnimator.beginAnimateOut() // Delay for a short amount of time so the browser has time to start animating out diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index 50aaa89ac..7bfd66872 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -26,6 +26,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -64,6 +65,7 @@ import mozilla.components.concept.sync.OAuthAccount import mozilla.components.feature.media.ext.pauseIfPlaying import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.top.sites.TopSite +import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.lib.state.ext.flowScoped import mozilla.components.support.ktx.android.util.dpToPx import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged @@ -98,6 +100,7 @@ import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.FragmentPreDrawManager +import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.whatsnew.WhatsNew import java.lang.ref.WeakReference @@ -232,14 +235,20 @@ class HomeFragment : Fragment() { updateLayout(view) setOffset(view) sessionControlView = SessionControlView( - homeFragmentStore, view.sessionControlRecyclerView, sessionControlInteractor, - viewLifecycleOwner, homeViewModel ) activity.themeManager.applyStatusBarTheme(activity) + view.consumeFrom(homeFragmentStore, viewLifecycleOwner) { + sessionControlView?.update(it) + + if (context?.settings()?.useNewTabTray == true) { + view.tab_button.setCountWithAnimation(it.tabs.size) + } + } + return view } @@ -344,6 +353,12 @@ class HomeFragment : Fragment() { navigateToSearch() } + view.tab_button.setOnClickListener { + invokePendingDeleteJobs() + hideOnboardingIfNeeded() + findNavController().navigate(HomeFragmentDirections.actionGlobalTabTrayFragment()) + } + PrivateBrowsingButtonView( privateBrowsingButton, browsingModeManager @@ -538,6 +553,11 @@ class HomeFragment : Fragment() { scrollToSelectedTab() sharedViewModel.shouldScrollToSelectedTab = false } + + requireContext().settings().useNewTabTray.also { + view?.add_tab_button?.isVisible = !it + view?.tab_button?.isVisible = it + } } override fun onPause() { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 3b2a4a20c..1d3373173 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -4,9 +4,9 @@ package org.mozilla.fenix.home.sessioncontrol +import android.content.Context import android.os.Build import android.view.View -import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -14,15 +14,14 @@ import kotlinx.android.extensions.LayoutContainer import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.top.sites.TopSite -import mozilla.components.lib.state.ext.consumeFrom import org.mozilla.fenix.R import org.mozilla.fenix.home.HomeFragmentState -import org.mozilla.fenix.home.HomeFragmentStore import org.mozilla.fenix.home.HomeScreenViewModel import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.OnboardingState import org.mozilla.fenix.home.Tab import org.mozilla.fenix.components.tips.Tip +import org.mozilla.fenix.ext.settings val noTabMessage = AdapterItem.NoContentMessageWithAction( R.string.no_open_tabs_header_2, @@ -36,7 +35,11 @@ val noCollectionMessage = AdapterItem.NoContentMessage( R.string.collections_description ) +// This method got a little complex with the addition of the tab tray feature flag +// When we remove the tabs from the home screen this will get much simpler again. +@SuppressWarnings("LongParameterList", "ComplexMethod") private fun normalModeAdapterItems( + context: Context, tabs: List, topSites: List, collections: List, @@ -52,26 +55,30 @@ private fun normalModeAdapterItems( items.add(AdapterItem.TopSiteList(topSites)) } - items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty())) + val useNewTabTray = context.settings().useNewTabTray + + if (!useNewTabTray) { + items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty())) + } when { tabs.isNotEmpty() && collections.isNotEmpty() -> { - showTabs(items, tabs) + if (!useNewTabTray) { showTabs(items, tabs) } showCollections(collections, expandedCollections, tabs, items) } tabs.isNotEmpty() && collections.isEmpty() -> { - showTabs(items, tabs) + if (!useNewTabTray) { showTabs(items, tabs) } items.add(AdapterItem.CollectionHeader) items.add(noCollectionMessage) } tabs.isEmpty() && collections.isNotEmpty() -> { - items.add(noTabMessage) + if (!useNewTabTray) { items.add(noTabMessage) } showCollections(collections, expandedCollections, tabs, items) } - tabs.isEmpty() && collections.isEmpty() -> { + tabs.isEmpty() && collections.isEmpty() && !useNewTabTray -> { items.add(noTabMessage) } } @@ -105,14 +112,21 @@ private fun showCollections( } } -private fun privateModeAdapterItems(tabs: List): List { +private fun privateModeAdapterItems(context: Context, tabs: List): List { val items = mutableListOf() - items.add(AdapterItem.TabHeader(true, tabs.isNotEmpty())) - if (tabs.isNotEmpty()) { - items.addAll(tabs.reversed().map(AdapterItem::TabItem)) - } else { + val useNewTabTray = context.settings().useNewTabTray + + if (useNewTabTray) { items.add(AdapterItem.PrivateBrowsingDescription) + } else { + items.add(AdapterItem.TabHeader(true, tabs.isNotEmpty())) + + if (tabs.isNotEmpty()) { + items.addAll(tabs.reversed().map(AdapterItem::TabItem)) + } else { + items.add(AdapterItem.PrivateBrowsingDescription) + } } return items @@ -153,9 +167,9 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List = when (mode) { - is Mode.Normal -> normalModeAdapterItems(tabs, topSites, collections, expandedCollections, tip) - is Mode.Private -> privateModeAdapterItems(tabs) +private fun HomeFragmentState.toAdapterList(context: Context): List = when (mode) { + is Mode.Normal -> normalModeAdapterItems(context, tabs, topSites, collections, expandedCollections, tip) + is Mode.Private -> privateModeAdapterItems(context, tabs) is Mode.Onboarding -> onboardingAdapterItems(mode.state) } @@ -165,10 +179,8 @@ private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapI @ExperimentalCoroutinesApi class SessionControlView( - private val homeFragmentStore: HomeFragmentStore, override val containerView: View?, interactor: SessionControlInteractor, - private val viewLifecycleOwner: LifecycleOwner, private var homeScreenViewModel: HomeScreenViewModel ) : LayoutContainer { @@ -187,10 +199,6 @@ class SessionControlView( ) ) itemTouchHelper.attachToRecyclerView(this) - - view.consumeFrom(homeFragmentStore, viewLifecycleOwner) { - update(it) - } } } @@ -200,7 +208,7 @@ class SessionControlView( sessionControlAdapter.submitList(null) } - val stateAdapterList = state.toAdapterList() + val stateAdapterList = state.toAdapterList(view.context) if (homeScreenViewModel.shouldScrollToTopSites) { sessionControlAdapter.submitList(stateAdapterList) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsPreference.kt b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsPreference.kt new file mode 100644 index 000000000..89818945e --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsPreference.kt @@ -0,0 +1,35 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.settings + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreference +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.getPreferenceKey +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.ext.showToolbar + +/** + * Lets the user customize Private browsing options. + */ +class SecretSettingsPreference : PreferenceFragmentCompat() { + override fun onResume() { + super.onResume() + showToolbar(getString(R.string.preferences_debug_settings)) + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.secret_settings_preferences, rootKey) + updatePreferences() + } + + private fun updatePreferences() { + findPreference(getPreferenceKey(R.string.pref_key_enable_new_tab_tray))?.apply { + onPreferenceChangeListener = SharedPreferenceUpdater() + isChecked = context.settings().useNewTabTray + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index c34b07cc2..f4c297839 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -277,6 +277,9 @@ class SettingsFragment : PreferenceFragmentCompat() { startActivity(intent) null } + resources.getString(R.string.pref_key_debug_settings) -> { + SettingsFragmentDirections.actionSettingsFragmentToSecretSettingsFragment() + } else -> null } directions?.let { navigateFromSettings(directions) } @@ -327,6 +330,9 @@ class SettingsFragment : PreferenceFragmentCompat() { } preferenceFxAOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater preferenceSyncOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater + findPreference( + getPreferenceKey(R.string.pref_key_debug_settings) + )?.isVisible = requireContext().settings().showSecretDebugMenuThisSession } private fun navigateFromSettings(directions: NavDirections) { 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 4563ba260..6e26340e5 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -24,6 +24,7 @@ import mozilla.components.support.ktx.android.content.longPreference import mozilla.components.support.ktx.android.content.stringPreference import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.components.metrics.MozillaProductDetector @@ -635,4 +636,15 @@ class Settings private constructor( appContext.getPreferenceKey(R.string.pref_key_top_sites_size), default = 0 ) + + var useNewTabTray: Boolean + get() = preferences.let { + val prefKey = appContext.getPreferenceKey(R.string.pref_key_enable_new_tab_tray) + val useNewTabTray = it.getBoolean(prefKey, false) + FeatureFlags.tabTray && useNewTabTray } + set(value) { + preferences.edit() + .putBoolean(appContext.getPreferenceKey(R.string.pref_key_enable_new_tab_tray), value) + .apply() + } } diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 824bb6905..9fdcc6454 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -105,7 +105,7 @@ android:contentDescription="@string/search_hint" android:focusable="true" app:layout_constraintBottom_toBottomOf="@id/bottom_bar" - app:layout_constraintEnd_toStartOf="@+id/add_tab_button" + app:layout_constraintEnd_toStartOf="@+id/accessory_button_barrier" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@id/bottom_bar"> @@ -135,6 +135,13 @@ android:textSize="15sp" /> + + + + + + + diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index d4e99abde..0388b54b9 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -165,4 +165,7 @@ pref_key_migrating_from_firefox_nightly_tip pref_key_migrating_from_fenix_tip + pref_key_new_tab_tray + + pref_key_debug_settings diff --git a/app/src/main/res/values/static_strings.xml b/app/src/main/res/values/static_strings.xml index 845b84524..4fe788087 100644 --- a/app/src/main/res/values/static_strings.xml +++ b/app/src/main/res/values/static_strings.xml @@ -43,4 +43,8 @@ Go home Toggle tab mode + + + Secret Settings + Use New Tab Tray diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 5e2a93a26..f7c2972ab 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -159,5 +159,11 @@ android:icon="@drawable/ic_info" android:key="@string/pref_key_about" android:title="@string/preferences_about" /> + + diff --git a/app/src/main/res/xml/secret_settings_preferences.xml b/app/src/main/res/xml/secret_settings_preferences.xml new file mode 100644 index 000000000..e50426381 --- /dev/null +++ b/app/src/main/res/xml/secret_settings_preferences.xml @@ -0,0 +1,12 @@ + + + + +