1
0
Fork 0

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
master
Jeff Boek 2020-04-30 13:53:10 -07:00 committed by GitHub
parent f7dcb9f7b3
commit a8a90bd4d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 172 additions and 26 deletions

View File

@ -43,4 +43,9 @@ object FeatureFlags {
* Enables tip feature * Enables tip feature
*/ */
val tips = Config.channel.isDebug val tips = Config.channel.isDebug
/**
* Enables new tab tray pref
*/
val tabTray = Config.channel.isDebug
} }

View File

@ -313,6 +313,12 @@ class DefaultBrowserToolbarController(
} }
private fun animateTabAndNavigateHome() { private fun animateTabAndNavigateHome() {
if (activity.settings().useNewTabTray) {
val directions = BrowserFragmentDirections.actionBrowserFragmentToTabsTrayFragment()
navController.navigate(directions)
return
}
scope.launch { scope.launch {
browserAnimator.beginAnimateOut() browserAnimator.beginAnimateOut()
// Delay for a short amount of time so the browser has time to start animating out // Delay for a short amount of time so the browser has time to start animating out

View File

@ -26,6 +26,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels 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.media.ext.pauseIfPlaying
import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.TopSite
import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.lib.state.ext.flowScoped import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.android.util.dpToPx import mozilla.components.support.ktx.android.util.dpToPx
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged 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.settings.deletebrowsingdata.deleteAndQuit
import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.FragmentPreDrawManager import org.mozilla.fenix.utils.FragmentPreDrawManager
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
import org.mozilla.fenix.whatsnew.WhatsNew import org.mozilla.fenix.whatsnew.WhatsNew
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -232,14 +235,20 @@ class HomeFragment : Fragment() {
updateLayout(view) updateLayout(view)
setOffset(view) setOffset(view)
sessionControlView = SessionControlView( sessionControlView = SessionControlView(
homeFragmentStore,
view.sessionControlRecyclerView, view.sessionControlRecyclerView,
sessionControlInteractor, sessionControlInteractor,
viewLifecycleOwner,
homeViewModel homeViewModel
) )
activity.themeManager.applyStatusBarTheme(activity) 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 return view
} }
@ -344,6 +353,12 @@ class HomeFragment : Fragment() {
navigateToSearch() navigateToSearch()
} }
view.tab_button.setOnClickListener {
invokePendingDeleteJobs()
hideOnboardingIfNeeded()
findNavController().navigate(HomeFragmentDirections.actionGlobalTabTrayFragment())
}
PrivateBrowsingButtonView( PrivateBrowsingButtonView(
privateBrowsingButton, privateBrowsingButton,
browsingModeManager browsingModeManager
@ -538,6 +553,11 @@ class HomeFragment : Fragment() {
scrollToSelectedTab() scrollToSelectedTab()
sharedViewModel.shouldScrollToSelectedTab = false sharedViewModel.shouldScrollToSelectedTab = false
} }
requireContext().settings().useNewTabTray.also {
view?.add_tab_button?.isVisible = !it
view?.tab_button?.isVisible = it
}
} }
override fun onPause() { override fun onPause() {

View File

@ -4,9 +4,9 @@
package org.mozilla.fenix.home.sessioncontrol package org.mozilla.fenix.home.sessioncontrol
import android.content.Context
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -14,15 +14,14 @@ import kotlinx.android.extensions.LayoutContainer
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.feature.tab.collections.TabCollection import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.TopSite
import mozilla.components.lib.state.ext.consumeFrom
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.home.HomeFragmentState import org.mozilla.fenix.home.HomeFragmentState
import org.mozilla.fenix.home.HomeFragmentStore
import org.mozilla.fenix.home.HomeScreenViewModel import org.mozilla.fenix.home.HomeScreenViewModel
import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.Mode
import org.mozilla.fenix.home.OnboardingState import org.mozilla.fenix.home.OnboardingState
import org.mozilla.fenix.home.Tab import org.mozilla.fenix.home.Tab
import org.mozilla.fenix.components.tips.Tip import org.mozilla.fenix.components.tips.Tip
import org.mozilla.fenix.ext.settings
val noTabMessage = AdapterItem.NoContentMessageWithAction( val noTabMessage = AdapterItem.NoContentMessageWithAction(
R.string.no_open_tabs_header_2, R.string.no_open_tabs_header_2,
@ -36,7 +35,11 @@ val noCollectionMessage = AdapterItem.NoContentMessage(
R.string.collections_description 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( private fun normalModeAdapterItems(
context: Context,
tabs: List<Tab>, tabs: List<Tab>,
topSites: List<TopSite>, topSites: List<TopSite>,
collections: List<TabCollection>, collections: List<TabCollection>,
@ -52,26 +55,30 @@ private fun normalModeAdapterItems(
items.add(AdapterItem.TopSiteList(topSites)) 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 { when {
tabs.isNotEmpty() && collections.isNotEmpty() -> { tabs.isNotEmpty() && collections.isNotEmpty() -> {
showTabs(items, tabs) if (!useNewTabTray) { showTabs(items, tabs) }
showCollections(collections, expandedCollections, tabs, items) showCollections(collections, expandedCollections, tabs, items)
} }
tabs.isNotEmpty() && collections.isEmpty() -> { tabs.isNotEmpty() && collections.isEmpty() -> {
showTabs(items, tabs) if (!useNewTabTray) { showTabs(items, tabs) }
items.add(AdapterItem.CollectionHeader) items.add(AdapterItem.CollectionHeader)
items.add(noCollectionMessage) items.add(noCollectionMessage)
} }
tabs.isEmpty() && collections.isNotEmpty() -> { tabs.isEmpty() && collections.isNotEmpty() -> {
items.add(noTabMessage) if (!useNewTabTray) { items.add(noTabMessage) }
showCollections(collections, expandedCollections, tabs, items) showCollections(collections, expandedCollections, tabs, items)
} }
tabs.isEmpty() && collections.isEmpty() -> { tabs.isEmpty() && collections.isEmpty() && !useNewTabTray -> {
items.add(noTabMessage) items.add(noTabMessage)
} }
} }
@ -105,14 +112,21 @@ private fun showCollections(
} }
} }
private fun privateModeAdapterItems(tabs: List<Tab>): List<AdapterItem> { private fun privateModeAdapterItems(context: Context, tabs: List<Tab>): List<AdapterItem> {
val items = mutableListOf<AdapterItem>() val items = mutableListOf<AdapterItem>()
items.add(AdapterItem.TabHeader(true, tabs.isNotEmpty()))
if (tabs.isNotEmpty()) { val useNewTabTray = context.settings().useNewTabTray
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
} else { if (useNewTabTray) {
items.add(AdapterItem.PrivateBrowsingDescription) 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 return items
@ -153,9 +167,9 @@ private fun onboardingAdapterItems(onboardingState: OnboardingState): List<Adapt
return items return items
} }
private fun HomeFragmentState.toAdapterList(): List<AdapterItem> = when (mode) { private fun HomeFragmentState.toAdapterList(context: Context): List<AdapterItem> = when (mode) {
is Mode.Normal -> normalModeAdapterItems(tabs, topSites, collections, expandedCollections, tip) is Mode.Normal -> normalModeAdapterItems(context, tabs, topSites, collections, expandedCollections, tip)
is Mode.Private -> privateModeAdapterItems(tabs) is Mode.Private -> privateModeAdapterItems(context, tabs)
is Mode.Onboarding -> onboardingAdapterItems(mode.state) is Mode.Onboarding -> onboardingAdapterItems(mode.state)
} }
@ -165,10 +179,8 @@ private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapI
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
class SessionControlView( class SessionControlView(
private val homeFragmentStore: HomeFragmentStore,
override val containerView: View?, override val containerView: View?,
interactor: SessionControlInteractor, interactor: SessionControlInteractor,
private val viewLifecycleOwner: LifecycleOwner,
private var homeScreenViewModel: HomeScreenViewModel private var homeScreenViewModel: HomeScreenViewModel
) : LayoutContainer { ) : LayoutContainer {
@ -187,10 +199,6 @@ class SessionControlView(
) )
) )
itemTouchHelper.attachToRecyclerView(this) itemTouchHelper.attachToRecyclerView(this)
view.consumeFrom(homeFragmentStore, viewLifecycleOwner) {
update(it)
}
} }
} }
@ -200,7 +208,7 @@ class SessionControlView(
sessionControlAdapter.submitList(null) sessionControlAdapter.submitList(null)
} }
val stateAdapterList = state.toAdapterList() val stateAdapterList = state.toAdapterList(view.context)
if (homeScreenViewModel.shouldScrollToTopSites) { if (homeScreenViewModel.shouldScrollToTopSites) {
sessionControlAdapter.submitList(stateAdapterList) { sessionControlAdapter.submitList(stateAdapterList) {

View File

@ -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<SwitchPreference>(getPreferenceKey(R.string.pref_key_enable_new_tab_tray))?.apply {
onPreferenceChangeListener = SharedPreferenceUpdater()
isChecked = context.settings().useNewTabTray
}
}
}

View File

@ -277,6 +277,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
startActivity(intent) startActivity(intent)
null null
} }
resources.getString(R.string.pref_key_debug_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToSecretSettingsFragment()
}
else -> null else -> null
} }
directions?.let { navigateFromSettings(directions) } directions?.let { navigateFromSettings(directions) }
@ -327,6 +330,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
} }
preferenceFxAOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater preferenceFxAOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater
preferenceSyncOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater preferenceSyncOverride?.onPreferenceChangeListener = syncFxAOverrideUpdater
findPreference<Preference>(
getPreferenceKey(R.string.pref_key_debug_settings)
)?.isVisible = requireContext().settings().showSecretDebugMenuThisSession
} }
private fun navigateFromSettings(directions: NavDirections) { private fun navigateFromSettings(directions: NavDirections) {

View File

@ -24,6 +24,7 @@ import mozilla.components.support.ktx.android.content.longPreference
import mozilla.components.support.ktx.android.content.stringPreference import mozilla.components.support.ktx.android.content.stringPreference
import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config import org.mozilla.fenix.Config
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.metrics.MozillaProductDetector import org.mozilla.fenix.components.metrics.MozillaProductDetector
@ -635,4 +636,15 @@ class Settings private constructor(
appContext.getPreferenceKey(R.string.pref_key_top_sites_size), appContext.getPreferenceKey(R.string.pref_key_top_sites_size),
default = 0 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()
}
} }

View File

@ -105,7 +105,7 @@
android:contentDescription="@string/search_hint" android:contentDescription="@string/search_hint"
android:focusable="true" android:focusable="true"
app:layout_constraintBottom_toBottomOf="@id/bottom_bar" 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_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/bottom_bar"> app:layout_constraintTop_toTopOf="@id/bottom_bar">
@ -135,6 +135,13 @@
android:textSize="15sp" /> android:textSize="15sp" />
</FrameLayout> </FrameLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/accessory_button_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="start"
app:constraint_referenced_ids="tab_button,add_tab_button" />
<ImageButton <ImageButton
android:id="@+id/add_tab_button" android:id="@+id/add_tab_button"
android:layout_width="48dp" android:layout_width="48dp"
@ -147,6 +154,17 @@
app:layout_constraintEnd_toStartOf="@+id/menuButton" app:layout_constraintEnd_toStartOf="@+id/menuButton"
app:layout_constraintStart_toEndOf="@id/toolbar_wrapper"/> app:layout_constraintStart_toEndOf="@id/toolbar_wrapper"/>
<org.mozilla.fenix.components.toolbar.TabCounter
android:id="@+id/tab_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:visibility="gone"
app:layout_constraintTop_toTopOf="@id/bottom_bar"
app:layout_constraintBottom_toBottomOf="@id/bottom_bar"
app:layout_constraintEnd_toStartOf="@+id/menuButton"
app:layout_constraintStart_toEndOf="@id/toolbar_wrapper"/>
<mozilla.components.browser.menu.view.MenuButton <mozilla.components.browser.menu.view.MenuButton
android:id="@+id/menuButton" android:id="@+id/menuButton"
android:layout_width="36dp" android:layout_width="36dp"

View File

@ -365,6 +365,13 @@
app:popEnterAnim="@anim/slide_in_left" app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" app:popExitAnim="@anim/slide_out_right"
app:destination="@id/aboutFragment" /> app:destination="@id/aboutFragment" />
<action
android:id="@+id/action_settingsFragment_to_secretSettingsFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:destination="@id/secretSettingsPreference" />
<action <action
android:id="@+id/action_settingsFragment_to_customizationFragment" android:id="@+id/action_settingsFragment_to_customizationFragment"
app:enterAnim="@anim/slide_in_right" app:enterAnim="@anim/slide_in_right"
@ -500,6 +507,10 @@
<fragment <fragment
android:id="@+id/aboutFragment" android:id="@+id/aboutFragment"
android:name="org.mozilla.fenix.settings.about.AboutFragment"/> android:name="org.mozilla.fenix.settings.about.AboutFragment"/>
<fragment
android:id="@+id/secretSettingsPreference"
android:name="org.mozilla.fenix.settings.SecretSettingsPreference"
android:label="@string/preferences_debug_settings" />
<fragment <fragment
android:id="@+id/crashReporterFragment" android:id="@+id/crashReporterFragment"
android:name="org.mozilla.fenix.crashes.CrashReporterFragment"> android:name="org.mozilla.fenix.crashes.CrashReporterFragment">

View File

@ -165,4 +165,7 @@
<string name="pref_key_migrating_from_firefox_nightly_tip" translatable="false">pref_key_migrating_from_firefox_nightly_tip</string> <string name="pref_key_migrating_from_firefox_nightly_tip" translatable="false">pref_key_migrating_from_firefox_nightly_tip</string>
<string name="pref_key_migrating_from_fenix_tip" translatable="false">pref_key_migrating_from_fenix_tip</string> <string name="pref_key_migrating_from_fenix_tip" translatable="false">pref_key_migrating_from_fenix_tip</string>
<string name="pref_key_enable_new_tab_tray" translatable="false">pref_key_new_tab_tray</string>
<string name="pref_key_debug_settings" translatable="false">pref_key_debug_settings</string>
</resources> </resources>

View File

@ -43,4 +43,8 @@
<string name="tab_tray_menu_home" translatable="false">Go home</string> <string name="tab_tray_menu_home" translatable="false">Go home</string>
<!-- Shortcut action to toggle private mode --> <!-- Shortcut action to toggle private mode -->
<string name="tab_tray_menu_toggle" translatable="false">Toggle tab mode</string> <string name="tab_tray_menu_toggle" translatable="false">Toggle tab mode</string>
<!-- Label for the secret settings preference -->
<string name="preferences_debug_settings">Secret Settings</string>
<string name="preferences_debug_settings_enable_tab_tray">Use New Tab Tray</string>
</resources> </resources>

View File

@ -159,5 +159,11 @@
android:icon="@drawable/ic_info" android:icon="@drawable/ic_info"
android:key="@string/pref_key_about" android:key="@string/pref_key_about"
android:title="@string/preferences_about" /> android:title="@string/preferences_about" />
<androidx.preference.Preference
android:icon="@drawable/ic_info"
android:key="@string/pref_key_debug_settings"
android:title="@string/preferences_debug_settings"
app:isPreferenceVisible="false" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_enable_new_tab_tray"
android:title="@string/preferences_debug_settings_enable_tab_tray"
app:iconSpaceReserved="false" />
</PreferenceScreen>