diff --git a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt index 912ba0757..283b7e02b 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/CustomizationFragment.kt @@ -57,6 +57,8 @@ class CustomizationFragment : PreferenceFragmentCompat() { bindAutoBatteryTheme() setupRadioGroups() setupToolbarCategory() + setupTabsTrayCategory() + setupFabCategory() setupHomeCategory() setupAddonsCustomizationCategory() } @@ -142,10 +144,40 @@ class CustomizationFragment : PreferenceFragmentCompat() { addToRadioGroup(topPreference, bottomPreference) } + private fun setupTabsTrayCategory() { + requirePreference(R.string.pref_key_tabs_tray_compact_tab).apply { + isChecked = context.settings().enableCompactTabs + onPreferenceChangeListener = SharedPreferenceUpdater() + } + + requirePreference(R.string.pref_key_tabs_tray_top_tray).apply { + isChecked = context.settings().useTopTabsTray + onPreferenceChangeListener = SharedPreferenceUpdater() + } + + requirePreference(R.string.pref_key_tabs_tray_reverse_tab_order).apply { + isChecked = context.settings().reverseTabOrderInTabsTray + onPreferenceChangeListener = SharedPreferenceUpdater() + } + } + + private fun setupFabCategory() { + requirePreference(R.string.pref_key_tabs_tray_use_fab).apply { + isChecked = context.settings().useNewTabFloatingActionButton + onPreferenceChangeListener = SharedPreferenceUpdater() + } + + requirePreference(R.string.pref_key_tabs_tray_fab_top_position).apply { + isChecked = context.settings().placeNewTabFloatingActionButtonAtTop + onPreferenceChangeListener = SharedPreferenceUpdater() + } + } + private fun setupHomeCategory() { requirePreference(R.string.pref_home_category).apply { isVisible = FeatureFlags.topFrecentSite } + requirePreference(R.string.pref_key_enable_top_frecent_sites).apply { isVisible = FeatureFlags.topFrecentSite isChecked = context.settings().showTopFrecentSites diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt index 815170d81..bdd97d2e5 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/FenixTabsAdapter.kt @@ -18,6 +18,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.metrics +import org.mozilla.fenix.ext.settings class FenixTabsAdapter( private val context: Context, @@ -26,7 +27,7 @@ class FenixTabsAdapter( viewHolderProvider = { parentView -> TabTrayViewHolder( LayoutInflater.from(context).inflate( - R.layout.tab_tray_item, + if (context.settings().enableCompactTabs) R.layout.tab_tray_item_compact else R.layout.tab_tray_item, parentView, false ), diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt index 0c6a02a57..85de54cdb 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/SyncedTabsController.kt @@ -21,6 +21,7 @@ import mozilla.components.browser.storage.sync.SyncedDeviceTabs import mozilla.components.feature.syncedtabs.view.SyncedTabsView import mozilla.components.lib.state.ext.flowScoped import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.sync.ListenerDelegate import org.mozilla.fenix.sync.SyncedTabsAdapter import org.mozilla.fenix.sync.ext.toAdapterList @@ -63,7 +64,11 @@ class SyncedTabsController( override fun displaySyncedTabs(syncedTabs: List) { scope.launch { val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList() - adapter.submitList(tabsList) + if (view.context.settings().reverseTabOrderInTabsTray) { + adapter.submitList(tabsList.reversed()) + } else { + adapter.submitList(tabsList) + } } } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt index c92964508..ca5dfa50c 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayDialogFragment.kt @@ -21,7 +21,8 @@ import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import kotlinx.android.synthetic.main.component_tabstray.view.* +import kotlinx.android.synthetic.main.component_tabstray_bottom.view.* +import kotlinx.android.synthetic.main.component_tabstray_fab_bottom.view.* import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.* import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.view.* import kotlinx.coroutines.Dispatchers @@ -66,7 +67,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler private lateinit var tabTrayDialogStore: TabTrayDialogFragmentStore private val snackbarAnchor: View? - get() = null + get() = if (tabTrayView.fabView.new_tab_button.isVisible) tabTrayView.fabView.new_tab_button + else null private val collectionStorageObserver = object : TabCollectionStorage.Observer { override fun onCollectionCreated(title: String, sessions: List) { 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 2a4fec19b..b034c4f20 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayView.kt @@ -21,10 +21,12 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.tabs.TabLayout import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.component_tabstray.view.* +import kotlinx.android.synthetic.main.component_tabstray_bottom.view.* +import kotlinx.android.synthetic.main.component_tabstray_fab_bottom.view.* import kotlinx.android.synthetic.main.tabs_tray_tab_counter.* import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.delay @@ -45,13 +47,14 @@ 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 import org.mozilla.fenix.components.toolbar.TabCounter.Companion.SO_MANY_TABS_OPEN -import org.mozilla.fenix.components.toolbar.ToolbarPosition import org.mozilla.fenix.components.topsheet.TopSheetBehavior import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.settings import org.mozilla.fenix.tabtray.SaveToCollectionsButtonAdapter.MultiselectModeChange import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode import java.text.NumberFormat +import kotlin.math.max +import kotlin.math.min import mozilla.components.browser.storage.sync.Tab as SyncTab /** @@ -70,16 +73,27 @@ class TabTrayView( ) : LayoutContainer, TabLayout.OnTabSelectedListener { val lifecycleScope = lifecycleOwner.lifecycleScope - val view = when (container.context.settings().toolbarPosition) { - ToolbarPosition.BOTTOM -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_bottom, container, true) - ToolbarPosition.TOP -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray, container, true) + private val useFab = container.context.settings().useNewTabFloatingActionButton + val fabView: View = when (container.context.settings().placeNewTabFloatingActionButtonAtTop) { + true -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_fab_top, container, true) + false -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_fab_bottom, container, true) + } + + private val enableCompactTabs = container.context.settings().enableCompactTabs + private val reverseTabOrderInTabsTray = container.context.settings().reverseTabOrderInTabsTray + private val hasAccessibilityEnabled = container.context.settings().accessibilityServicesEnabled + private val useTopTabsTray = container.context.settings().useTopTabsTray + + val view: View = when (useTopTabsTray) { + true -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_top, container, true) + false -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_bottom, container, true) } private val isPrivateModeSelected: Boolean get() = view.tab_layout.selectedTabPosition == PRIVATE_TAB_ID - private val behavior = when (container.context.settings().toolbarPosition) { - ToolbarPosition.BOTTOM -> TopSheetBehavior.from(view.tab_wrapper) - ToolbarPosition.TOP -> BottomSheetBehavior.from(view.tab_wrapper) + private val behavior = when (useTopTabsTray) { + true -> TopSheetBehavior.from(view.tab_wrapper) + false -> BottomSheetBehavior.from(view.tab_wrapper) } private val concatAdapter = ConcatAdapter(tabsAdapter) @@ -102,27 +116,43 @@ class TabTrayView( init { components.analytics.metrics.track(Event.TabsTrayOpened) - if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { - (behavior as BottomSheetBehavior).addBottomSheetCallback(object : - BottomSheetBehavior.BottomSheetCallback() { - override fun onSlide(bottomSheet: View, slideOffset: Float) { + toggleFabText(isPrivate) + + if (useTopTabsTray) { + (behavior as TopSheetBehavior).setTopSheetCallback(object : + TopSheetBehavior.TopSheetCallback() { + override fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) { + if (interactor.onModeRequested() is Mode.Normal && useFab) { + if (slideOffset >= SLIDE_OFFSET) { + fabView.new_tab_button.show() + } else { + fabView.new_tab_button.hide() + } + } } - override fun onStateChanged(bottomSheet: View, newState: Int) { - if (newState == BottomSheetBehavior.STATE_HIDDEN) { + override fun onStateChanged(topSheet: View, newState: Int) { + if (newState == TopSheetBehavior.STATE_HIDDEN) { components.analytics.metrics.track(Event.TabsTrayClosed) interactor.onTabTrayDismissed() } } }) } else { - (behavior as TopSheetBehavior).setTopSheetCallback(object : - TopSheetBehavior.TopSheetCallback() { - override fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) { + (behavior as BottomSheetBehavior).addBottomSheetCallback(object : + BottomSheetBehavior.BottomSheetCallback() { + override fun onSlide(bottomSheet: View, slideOffset: Float) { + if (interactor.onModeRequested() is Mode.Normal && useFab) { + if (slideOffset >= SLIDE_OFFSET) { + fabView.new_tab_button.show() + } else { + fabView.new_tab_button.hide() + } + } } - override fun onStateChanged(topSheet: View, newState: Int) { - if (newState == TopSheetBehavior.STATE_HIDDEN) { + override fun onStateChanged(bottomSheet: View, newState: Int) { + if (newState == BottomSheetBehavior.STATE_HIDDEN) { components.analytics.metrics.track(Event.TabsTrayClosed) interactor.onTabTrayDismissed() } @@ -186,19 +216,28 @@ class TabTrayView( tabsAdapter.tabTrayInteractor = interactor tabsAdapter.onTabsUpdated = { // Put the 'Add to collections' button after the tabs have loaded. - concatAdapter.addAdapter(collectionsButtonAdapter) - - // Put the Synced Tabs adapter at the end. - concatAdapter.addAdapter(syncedTabsController.adapter) - - if (view.context.settings().accessibilityServicesEnabled) { - tabsAdapter.notifyDataSetChanged() + // And, put the Synced Tabs adapter at the end. + if (reverseTabOrderInTabsTray) { + concatAdapter.addAdapter(0, collectionsButtonAdapter) + concatAdapter.addAdapter(0, syncedTabsController.adapter) + } else { + concatAdapter.addAdapter(collectionsButtonAdapter) + concatAdapter.addAdapter(syncedTabsController.adapter) } + // Disabling the following block of code because it causes a crash when + // accessibility services are enabled! `notifyDataSetChanged()` is incompatible + // with concatAdapter. See: https://github.com/mozilla-mobile/fenix/issues/14540 + // WARNING: Merging the upstream fix for this will cause lot of conflicts! + // + // if (hasAccessibilityEnabled) { + // tabsAdapter.notifyDataSetChanged() + // } + if (!hasLoaded) { hasLoaded = true scrollToTab(view.context.components.core.store.state.selectedTabId) - if (view.context.settings().accessibilityServicesEnabled) { + if (hasAccessibilityEnabled) { lifecycleScope.launch { delay(SELECTION_DELAY.toLong()) lifecycleScope.launch(Main) { @@ -260,7 +299,15 @@ class TabTrayView( private fun adjustNewTabButtonForNormalMode() { view.tab_tray_new_tab.apply { - visibility = View.VISIBLE + visibility = if (useFab) View.GONE else View.VISIBLE + setOnClickListener { + sendNewTabEvent(isPrivateModeSelected) + interactor.onNewTabTapped(isPrivateModeSelected) + } + } + + fabView.new_tab_button.apply { + isVisible = useFab setOnClickListener { sendNewTabEvent(isPrivateModeSelected) interactor.onNewTabTapped(isPrivateModeSelected) @@ -280,30 +327,65 @@ class TabTrayView( fun updateTabsTrayLayout() { view.tabsTray.apply { - val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context)) - if (container.context.settings().toolbarPosition == ToolbarPosition.BOTTOM) { - gridLayoutManager.reverseLayout = true - } - gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { - override fun getSpanSize(position: Int): Int { - val numTabs = tabsAdapter.itemCount - return if (position < numTabs) { - 1 + if (enableCompactTabs) { + val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context)) + if (useTopTabsTray) { + if (!reverseTabOrderInTabsTray) { + gridLayoutManager.reverseLayout = true + } + } else { + if (reverseTabOrderInTabsTray) { + gridLayoutManager.reverseLayout = true + } + } + gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + val numTabs = tabsAdapter.itemCount + val totalItems = numTabs + collectionsButtonAdapter.itemCount + + syncedTabsController.adapter.itemCount + + return if (reverseTabOrderInTabsTray) { + if (totalItems - 1 - position < numTabs) { + 1 + } else { + gridViewNumberOfCols(container.context) + } + } else { + if (position < numTabs) { + 1 + } else { + gridViewNumberOfCols(container.context) + } + } + } + } + + layoutManager = gridLayoutManager + } else { + val linearLayoutManager = LinearLayoutManager(container.context) + if (useTopTabsTray) { + if (!reverseTabOrderInTabsTray) { + linearLayoutManager.reverseLayout = true } else { - gridViewNumberOfCols(container.context) + linearLayoutManager.stackFromEnd = true + } + } else { + if (reverseTabOrderInTabsTray) { + linearLayoutManager.reverseLayout = true + linearLayoutManager.stackFromEnd = true } } - } - layoutManager = gridLayoutManager + layoutManager = linearLayoutManager + } } } fun expand() { - if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { - (behavior as BottomSheetBehavior).state = BottomSheetBehavior.STATE_EXPANDED - } else { + if (useTopTabsTray) { (behavior as TopSheetBehavior).state = TopSheetBehavior.STATE_EXPANDED + } else { + (behavior as BottomSheetBehavior).state = BottomSheetBehavior.STATE_EXPANDED } } @@ -319,6 +401,7 @@ class TabTrayView( } override fun onTabSelected(tab: TabLayout.Tab?) { + toggleFabText(isPrivateModeSelected) filterTabs.invoke(isPrivateModeSelected) toggleSaveToCollectionButton(isPrivateModeSelected) @@ -343,7 +426,7 @@ class TabTrayView( if (oldMode::class != state.mode::class) { updateTabsForMultiselectModeChanged(state.mode is Mode.MultiSelect) - if (view.context.settings().accessibilityServicesEnabled) { + if (hasAccessibilityEnabled) { view.announceForAccessibility( if (state.mode == Mode.Normal) view.context.getString( R.string.tab_tray_exit_multiselect_content_description @@ -369,6 +452,7 @@ class TabTrayView( toggleUIMultiselect(multiselect = true) + fabView.new_tab_button.isVisible = false view.tab_tray_new_tab.isVisible = false view.collect_multi_select.isVisible = state.mode.selectedItems.isNotEmpty() @@ -389,7 +473,7 @@ class TabTrayView( val unselectedItems = oldMode.selectedItems - state.mode.selectedItems state.mode.selectedItems.union(unselectedItems).forEach { item -> - if (view.context.settings().accessibilityServicesEnabled) { + if (hasAccessibilityEnabled) { view.announceForAccessibility( if (unselectedItems.contains(item)) view.context.getString( R.string.tab_tray_item_unselected_multiselect_content_description, @@ -463,12 +547,12 @@ class TabTrayView( if (multiselect) MULTISELECT_HANDLE_HEIGHT.dpToPx(displayMetrics) else NORMAL_HANDLE_HEIGHT.dpToPx( displayMetrics ) - if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { - topMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_TOP_MARGIN.dpToPx( + if (useTopTabsTray) { + bottomMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_BOTTOM_MARGIN.dpToPx( displayMetrics ) } else { - bottomMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_BOTTOM_MARGIN.dpToPx( + topMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_TOP_MARGIN.dpToPx( displayMetrics ) } @@ -544,7 +628,7 @@ class TabTrayView( view.context.resources.getDimension(R.dimen.tab_tray_top_offset).toInt() } - if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { + if (!useTopTabsTray) { (behavior as BottomSheetBehavior).setExpandedOffset(topOffset) } } @@ -553,6 +637,18 @@ class TabTrayView( menu?.dismiss() } + private fun toggleFabText(private: Boolean) { + if (private) { + fabView.new_tab_button.extend() + fabView.new_tab_button.contentDescription = + view.context.resources.getString(R.string.add_private_tab) + } else { + fabView.new_tab_button.shrink() + fabView.new_tab_button.contentDescription = + view.context.resources.getString(R.string.add_tab) + } + } + fun onBackPressed(): Boolean { return interactor.onBackPressed() } @@ -568,7 +664,25 @@ class TabTrayView( val selectedBrowserTabIndex = tabs .indexOfFirst { it.id == sessionId } - layoutManager?.scrollToPosition(selectedBrowserTabIndex) + val recyclerViewIndex = if (reverseTabOrderInTabsTray && !enableCompactTabs) { + // For reverse tab order and non-compact tabs, we add the items in collections button + // adapter and synced tabs adapter, and offset by 1 to show the tab above the + // current tab, unless current tab is first in reverse order. + min(selectedBrowserTabIndex + 1, tabsAdapter.itemCount - 1) + + collectionsButtonAdapter.itemCount + syncedTabsController.adapter.itemCount + } else if (reverseTabOrderInTabsTray && enableCompactTabs) { + // For reverse tab order and compact tabs, we add the items in collections button + // adapter and synced tabs adapter, and offset by -1 to show the tab above the + // current tab, unless current tab is first in reverse order. + max(0, selectedBrowserTabIndex - 1 + collectionsButtonAdapter.itemCount + + syncedTabsController.adapter.itemCount) + } else { + // We offset index by -1 to show the tab above the current tab, unless current tab + // is the first. + max(0, selectedBrowserTabIndex - 1) + } + + layoutManager?.scrollToPosition(recyclerViewIndex) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt index a6ed73cd4..ad1a1f1a1 100644 --- a/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/tabtray/TabTrayViewHolder.kt @@ -19,6 +19,7 @@ import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.tabstray.TabViewHolder import mozilla.components.browser.tabstray.TabsTrayStyling import mozilla.components.browser.tabstray.thumbnail.TabThumbnailView +import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.concept.tabstray.Tab import mozilla.components.concept.tabstray.TabsTray import mozilla.components.feature.media.ext.pauseIfPlaying @@ -29,12 +30,7 @@ import mozilla.components.support.images.loader.ImageLoader import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.MetricController -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.getMediaStateForSession -import org.mozilla.fenix.ext.increaseTapArea -import org.mozilla.fenix.ext.removeAndDisable -import org.mozilla.fenix.ext.removeTouchDelegate -import org.mozilla.fenix.ext.showAndEnable +import org.mozilla.fenix.ext.* import org.mozilla.fenix.utils.Do import kotlin.math.max @@ -57,6 +53,7 @@ class TabTrayViewHolder( itemView.findViewById(R.id.mozac_browser_tabstray_thumbnail) @VisibleForTesting + internal val urlView: TextView? = itemView.findViewById(R.id.mozac_browser_tabstray_url) private val playPauseButtonView: ImageButton = itemView.findViewById(R.id.play_pause_button) override var tab: Tab? = null @@ -74,6 +71,7 @@ class TabTrayViewHolder( // Basic text updateTitle(tab) + updateUrl(tab) updateIcon(tab) updateCloseButtonDescription(tab.title) @@ -148,6 +146,24 @@ class TabTrayViewHolder( titleView.text = title } + private fun updateUrl(tab: Tab) { + // Truncate to MAX_URI_LENGTH to prevent the UI from locking up for + // extremely large URLs such as data URIs or bookmarklets. The same + // is done in the toolbar and awesomebar: + // https://github.com/mozilla-mobile/fenix/issues/1824 + // https://github.com/mozilla-mobile/android-components/issues/6985 + urlView?.apply { + text = + if (context.settings().shouldStripUrl) { + tab.url + .toShortUrl(itemView.context.components.publicSuffixList) + .take(MAX_URI_LENGTH) + } else { + tab.url.take(MAX_URI_LENGTH) + } + } + } + private fun updateIcon(tab: Tab) { if (tab.icon != null) { iconCard.visibility = View.VISIBLE 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 ad5d8497c..4652b855d 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -875,6 +875,31 @@ class Settings(private val appContext: Context) : PreferencesHolder { BuildConfig.AMO_COLLECTION ) + val enableCompactTabs by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tabs_tray_compact_tab), + default = false + ) + + val useTopTabsTray by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tabs_tray_top_tray), + default = false + ) + + val reverseTabOrderInTabsTray by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tabs_tray_reverse_tab_order), + default = true + ) + + val useNewTabFloatingActionButton by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tabs_tray_use_fab), + default = true + ) + + val placeNewTabFloatingActionButtonAtTop by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_tabs_tray_fab_top_position), + default = false + ) + private var savedLoginsSortingStrategyString by stringPreference( appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy), default = SavedLoginsSortingStrategyMenu.Item.AlphabeticallySort.strategyString diff --git a/app/src/main/res/layout/component_tabstray_bottom.xml b/app/src/main/res/layout/component_tabstray_bottom.xml index ad7480343..59c777c05 100644 --- a/app/src/main/res/layout/component_tabstray_bottom.xml +++ b/app/src/main/res/layout/component_tabstray_bottom.xml @@ -6,44 +6,45 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/tab_wrapper" - style="@style/TopSheetModal" + style="@style/BottomSheetModal" android:layout_width="match_parent" android:layout_height="match_parent" android:backgroundTint="@color/foundation_normal_theme" - app:layout_behavior="org.mozilla.fenix.components.topsheet.TopSheetBehavior"> + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> + app:layout_constraintTop_toBottomOf="@id/topBar" /> + app:layout_constraintTop_toBottomOf="@+id/handle"> + app:layout_constraintTop_toBottomOf="@+id/topBar" /> + app:layout_constraintTop_toBottomOf="@+id/divider" /> diff --git a/app/src/main/res/layout/component_tabstray_fab_bottom.xml b/app/src/main/res/layout/component_tabstray_fab_bottom.xml new file mode 100644 index 000000000..00118bf66 --- /dev/null +++ b/app/src/main/res/layout/component_tabstray_fab_bottom.xml @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/component_tabstray_fab_top.xml b/app/src/main/res/layout/component_tabstray_fab_top.xml new file mode 100644 index 000000000..7b1153c0d --- /dev/null +++ b/app/src/main/res/layout/component_tabstray_fab_top.xml @@ -0,0 +1,22 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/component_tabstray.xml b/app/src/main/res/layout/component_tabstray_top.xml similarity index 93% rename from app/src/main/res/layout/component_tabstray.xml rename to app/src/main/res/layout/component_tabstray_top.xml index 59c777c05..ad7480343 100644 --- a/app/src/main/res/layout/component_tabstray.xml +++ b/app/src/main/res/layout/component_tabstray_top.xml @@ -6,45 +6,44 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/tab_wrapper" - style="@style/BottomSheetModal" + style="@style/TopSheetModal" android:layout_width="match_parent" android:layout_height="match_parent" android:backgroundTint="@color/foundation_normal_theme" - app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> + app:layout_behavior="org.mozilla.fenix.components.topsheet.TopSheetBehavior"> + app:layout_constraintBottom_toTopOf="@+id/divider" /> + app:layout_constraintBottom_toTopOf="@id/handle"> + app:layout_constraintBottom_toTopOf="@+id/topBar" /> + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@+id/divider" /> diff --git a/app/src/main/res/layout/tab_tray_item.xml b/app/src/main/res/layout/tab_tray_item.xml index bf1d3a9cc..e1f57d360 100644 --- a/app/src/main/res/layout/tab_tray_item.xml +++ b/app/src/main/res/layout/tab_tray_item.xml @@ -7,7 +7,7 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/tab_item" android:layout_width="match_parent" - android:layout_height="165dp" + android:layout_height="88dp" android:clickable="true" android:focusable="true" android:foreground="?android:selectableItemBackground"> @@ -16,21 +16,22 @@ android:id="@+id/play_pause_button" android:layout_width="24dp" android:layout_height="24dp" - android:layout_marginTop="23dp" + android:layout_marginStart="80dp" + android:layout_marginTop="4dp" android:background="?attr/selectableItemBackgroundBorderless" android:contentDescription="@string/mozac_feature_media_notification_action_pause" android:elevation="10dp" android:visibility="gone" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="@id/mozac_browser_tabstray_card" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/media_state_play" /> - + + diff --git a/app/src/main/res/layout/tab_tray_item_compact.xml b/app/src/main/res/layout/tab_tray_item_compact.xml new file mode 100644 index 000000000..5b65659dc --- /dev/null +++ b/app/src/main/res/layout/tab_tray_item_compact.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 43e2e9b00..7e3c33476 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -159,6 +159,9 @@ 40dp 125dp 130dp + + 92dp + 69dp 10dp diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 9a3f2f3c5..1c8c284b0 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -126,6 +126,17 @@ pref_home_category + + pref_tabs_tray_settings_category + pref_key_tabs_tray_compact_tab + pref_key_tabs_tray_top_tray + pref_key_tabs_tray_reverse_tab_order + + + pref_tabs_tray_fab_settings_category + pref_key_tabs_tray_use_fab + pref_key_tabs_tray_fab_top_position + pref_addons_settings_category pref_key_addons_custom_account diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 260049429..0e01a9811 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -282,6 +282,10 @@ Theme Home + + Tabs tray + + Floating action button (FAB) Customize @@ -1530,11 +1534,26 @@ Show most visited sites - + Set custom add-ons account - + Set custom add-ons collection + + Enable compact tabs + + Enable top tabs tray + + Reverse tab order in tray + + Enable to put new tabs at start of the tabs list, disable to put new tabs at end of the tabs list + + Enable FAB for new tab + + Place FAB at the top + + Enable to place button for new tab at the top, disable to place it at the bottom + Remove diff --git a/app/src/main/res/xml/customization_preferences.xml b/app/src/main/res/xml/customization_preferences.xml index 54a00d869..25bee4f1e 100644 --- a/app/src/main/res/xml/customization_preferences.xml +++ b/app/src/main/res/xml/customization_preferences.xml @@ -35,7 +35,7 @@ + + + + + + + + + + +