Massive tabs tray customization options

pull/65/head
Abhijit Valluri 4 years ago
parent 23ff09fba6
commit 275c5c1a7b

@ -57,6 +57,8 @@ class CustomizationFragment : PreferenceFragmentCompat() {
bindAutoBatteryTheme() bindAutoBatteryTheme()
setupRadioGroups() setupRadioGroups()
setupToolbarCategory() setupToolbarCategory()
setupTabsTrayCategory()
setupFabCategory()
setupHomeCategory() setupHomeCategory()
setupAddonsCustomizationCategory() setupAddonsCustomizationCategory()
} }
@ -142,10 +144,40 @@ class CustomizationFragment : PreferenceFragmentCompat() {
addToRadioGroup(topPreference, bottomPreference) addToRadioGroup(topPreference, bottomPreference)
} }
private fun setupTabsTrayCategory() {
requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_compact_tab).apply {
isChecked = context.settings().enableCompactTabs
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_top_tray).apply {
isChecked = context.settings().useTopTabsTray
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_reverse_tab_order).apply {
isChecked = context.settings().reverseTabOrderInTabsTray
onPreferenceChangeListener = SharedPreferenceUpdater()
}
}
private fun setupFabCategory() {
requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_use_fab).apply {
isChecked = context.settings().useNewTabFloatingActionButton
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_tabs_tray_fab_top_position).apply {
isChecked = context.settings().placeNewTabFloatingActionButtonAtTop
onPreferenceChangeListener = SharedPreferenceUpdater()
}
}
private fun setupHomeCategory() { private fun setupHomeCategory() {
requirePreference<PreferenceCategory>(R.string.pref_home_category).apply { requirePreference<PreferenceCategory>(R.string.pref_home_category).apply {
isVisible = FeatureFlags.topFrecentSite isVisible = FeatureFlags.topFrecentSite
} }
requirePreference<SwitchPreference>(R.string.pref_key_enable_top_frecent_sites).apply { requirePreference<SwitchPreference>(R.string.pref_key_enable_top_frecent_sites).apply {
isVisible = FeatureFlags.topFrecentSite isVisible = FeatureFlags.topFrecentSite
isChecked = context.settings().showTopFrecentSites isChecked = context.settings().showTopFrecentSites

@ -18,6 +18,7 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.settings
class FenixTabsAdapter( class FenixTabsAdapter(
private val context: Context, private val context: Context,
@ -26,7 +27,7 @@ class FenixTabsAdapter(
viewHolderProvider = { parentView -> viewHolderProvider = { parentView ->
TabTrayViewHolder( TabTrayViewHolder(
LayoutInflater.from(context).inflate( 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, parentView,
false false
), ),

@ -21,6 +21,7 @@ import mozilla.components.browser.storage.sync.SyncedDeviceTabs
import mozilla.components.feature.syncedtabs.view.SyncedTabsView import mozilla.components.feature.syncedtabs.view.SyncedTabsView
import mozilla.components.lib.state.ext.flowScoped import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged 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.ListenerDelegate
import org.mozilla.fenix.sync.SyncedTabsAdapter import org.mozilla.fenix.sync.SyncedTabsAdapter
import org.mozilla.fenix.sync.ext.toAdapterList import org.mozilla.fenix.sync.ext.toAdapterList
@ -63,7 +64,11 @@ class SyncedTabsController(
override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) { override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
scope.launch { scope.launch {
val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList() val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList()
adapter.submitList(tabsList) if (view.context.settings().reverseTabOrderInTabsTray) {
adapter.submitList(tabsList.reversed())
} else {
adapter.submitList(tabsList)
}
} }
} }

@ -21,7 +21,8 @@ import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView 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.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.view.* import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -66,7 +67,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment(), UserInteractionHandler
private lateinit var tabTrayDialogStore: TabTrayDialogFragmentStore private lateinit var tabTrayDialogStore: TabTrayDialogFragmentStore
private val snackbarAnchor: View? 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 { private val collectionStorageObserver = object : TabCollectionStorage.Observer {
override fun onCollectionCreated(title: String, sessions: List<Session>) { override fun onCollectionCreated(title: String, sessions: List<Session>) {

@ -21,10 +21,12 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.extensions.LayoutContainer 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.android.synthetic.main.tabs_tray_tab_counter.*
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay 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.INFINITE_CHAR_PADDING_BOTTOM
import org.mozilla.fenix.components.toolbar.TabCounter.Companion.MAX_VISIBLE_TABS 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.TabCounter.Companion.SO_MANY_TABS_OPEN
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.components.topsheet.TopSheetBehavior import org.mozilla.fenix.components.topsheet.TopSheetBehavior
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.tabtray.SaveToCollectionsButtonAdapter.MultiselectModeChange import org.mozilla.fenix.tabtray.SaveToCollectionsButtonAdapter.MultiselectModeChange
import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode import org.mozilla.fenix.tabtray.TabTrayDialogFragmentState.Mode
import java.text.NumberFormat import java.text.NumberFormat
import kotlin.math.max
import kotlin.math.min
import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.browser.storage.sync.Tab as SyncTab
/** /**
@ -70,16 +73,27 @@ class TabTrayView(
) : LayoutContainer, TabLayout.OnTabSelectedListener { ) : LayoutContainer, TabLayout.OnTabSelectedListener {
val lifecycleScope = lifecycleOwner.lifecycleScope val lifecycleScope = lifecycleOwner.lifecycleScope
val view = when (container.context.settings().toolbarPosition) { private val useFab = container.context.settings().useNewTabFloatingActionButton
ToolbarPosition.BOTTOM -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray_bottom, container, true) val fabView: View = when (container.context.settings().placeNewTabFloatingActionButtonAtTop) {
ToolbarPosition.TOP -> LayoutInflater.from(container.context).inflate(R.layout.component_tabstray, container, true) 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 isPrivateModeSelected: Boolean get() = view.tab_layout.selectedTabPosition == PRIVATE_TAB_ID
private val behavior = when (container.context.settings().toolbarPosition) { private val behavior = when (useTopTabsTray) {
ToolbarPosition.BOTTOM -> TopSheetBehavior.from(view.tab_wrapper) true -> TopSheetBehavior.from(view.tab_wrapper)
ToolbarPosition.TOP -> BottomSheetBehavior.from(view.tab_wrapper) false -> BottomSheetBehavior.from(view.tab_wrapper)
} }
private val concatAdapter = ConcatAdapter(tabsAdapter) private val concatAdapter = ConcatAdapter(tabsAdapter)
@ -102,27 +116,43 @@ class TabTrayView(
init { init {
components.analytics.metrics.track(Event.TabsTrayOpened) components.analytics.metrics.track(Event.TabsTrayOpened)
if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { toggleFabText(isPrivate)
(behavior as BottomSheetBehavior).addBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() { if (useTopTabsTray) {
override fun onSlide(bottomSheet: View, slideOffset: Float) { (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) { override fun onStateChanged(topSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) { if (newState == TopSheetBehavior.STATE_HIDDEN) {
components.analytics.metrics.track(Event.TabsTrayClosed) components.analytics.metrics.track(Event.TabsTrayClosed)
interactor.onTabTrayDismissed() interactor.onTabTrayDismissed()
} }
} }
}) })
} else { } else {
(behavior as TopSheetBehavior).setTopSheetCallback(object : (behavior as BottomSheetBehavior).addBottomSheetCallback(object :
TopSheetBehavior.TopSheetCallback() { BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) { 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) { override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == TopSheetBehavior.STATE_HIDDEN) { if (newState == BottomSheetBehavior.STATE_HIDDEN) {
components.analytics.metrics.track(Event.TabsTrayClosed) components.analytics.metrics.track(Event.TabsTrayClosed)
interactor.onTabTrayDismissed() interactor.onTabTrayDismissed()
} }
@ -186,19 +216,28 @@ class TabTrayView(
tabsAdapter.tabTrayInteractor = interactor tabsAdapter.tabTrayInteractor = interactor
tabsAdapter.onTabsUpdated = { tabsAdapter.onTabsUpdated = {
// Put the 'Add to collections' button after the tabs have loaded. // Put the 'Add to collections' button after the tabs have loaded.
concatAdapter.addAdapter(collectionsButtonAdapter) // And, put the Synced Tabs adapter at the end.
if (reverseTabOrderInTabsTray) {
// Put the Synced Tabs adapter at the end. concatAdapter.addAdapter(0, collectionsButtonAdapter)
concatAdapter.addAdapter(syncedTabsController.adapter) concatAdapter.addAdapter(0, syncedTabsController.adapter)
} else {
if (view.context.settings().accessibilityServicesEnabled) { concatAdapter.addAdapter(collectionsButtonAdapter)
tabsAdapter.notifyDataSetChanged() 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) { if (!hasLoaded) {
hasLoaded = true hasLoaded = true
scrollToTab(view.context.components.core.store.state.selectedTabId) scrollToTab(view.context.components.core.store.state.selectedTabId)
if (view.context.settings().accessibilityServicesEnabled) { if (hasAccessibilityEnabled) {
lifecycleScope.launch { lifecycleScope.launch {
delay(SELECTION_DELAY.toLong()) delay(SELECTION_DELAY.toLong())
lifecycleScope.launch(Main) { lifecycleScope.launch(Main) {
@ -260,7 +299,15 @@ class TabTrayView(
private fun adjustNewTabButtonForNormalMode() { private fun adjustNewTabButtonForNormalMode() {
view.tab_tray_new_tab.apply { 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 { setOnClickListener {
sendNewTabEvent(isPrivateModeSelected) sendNewTabEvent(isPrivateModeSelected)
interactor.onNewTabTapped(isPrivateModeSelected) interactor.onNewTabTapped(isPrivateModeSelected)
@ -280,30 +327,65 @@ class TabTrayView(
fun updateTabsTrayLayout() { fun updateTabsTrayLayout() {
view.tabsTray.apply { view.tabsTray.apply {
val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context)) if (enableCompactTabs) {
if (container.context.settings().toolbarPosition == ToolbarPosition.BOTTOM) { val gridLayoutManager = GridLayoutManager(container.context, gridViewNumberOfCols(container.context))
gridLayoutManager.reverseLayout = true if (useTopTabsTray) {
} if (!reverseTabOrderInTabsTray) {
gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { gridLayoutManager.reverseLayout = true
override fun getSpanSize(position: Int): Int { }
val numTabs = tabsAdapter.itemCount } else {
return if (position < numTabs) { if (reverseTabOrderInTabsTray) {
1 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 { } else {
gridViewNumberOfCols(container.context) linearLayoutManager.stackFromEnd = true
}
} else {
if (reverseTabOrderInTabsTray) {
linearLayoutManager.reverseLayout = true
linearLayoutManager.stackFromEnd = true
} }
} }
}
layoutManager = gridLayoutManager layoutManager = linearLayoutManager
}
} }
} }
fun expand() { fun expand() {
if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { if (useTopTabsTray) {
(behavior as BottomSheetBehavior).state = BottomSheetBehavior.STATE_EXPANDED
} else {
(behavior as TopSheetBehavior).state = TopSheetBehavior.STATE_EXPANDED (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?) { override fun onTabSelected(tab: TabLayout.Tab?) {
toggleFabText(isPrivateModeSelected)
filterTabs.invoke(isPrivateModeSelected) filterTabs.invoke(isPrivateModeSelected)
toggleSaveToCollectionButton(isPrivateModeSelected) toggleSaveToCollectionButton(isPrivateModeSelected)
@ -343,7 +426,7 @@ class TabTrayView(
if (oldMode::class != state.mode::class) { if (oldMode::class != state.mode::class) {
updateTabsForMultiselectModeChanged(state.mode is Mode.MultiSelect) updateTabsForMultiselectModeChanged(state.mode is Mode.MultiSelect)
if (view.context.settings().accessibilityServicesEnabled) { if (hasAccessibilityEnabled) {
view.announceForAccessibility( view.announceForAccessibility(
if (state.mode == Mode.Normal) view.context.getString( if (state.mode == Mode.Normal) view.context.getString(
R.string.tab_tray_exit_multiselect_content_description R.string.tab_tray_exit_multiselect_content_description
@ -369,6 +452,7 @@ class TabTrayView(
toggleUIMultiselect(multiselect = true) toggleUIMultiselect(multiselect = true)
fabView.new_tab_button.isVisible = false
view.tab_tray_new_tab.isVisible = false view.tab_tray_new_tab.isVisible = false
view.collect_multi_select.isVisible = state.mode.selectedItems.isNotEmpty() view.collect_multi_select.isVisible = state.mode.selectedItems.isNotEmpty()
@ -389,7 +473,7 @@ class TabTrayView(
val unselectedItems = oldMode.selectedItems - state.mode.selectedItems val unselectedItems = oldMode.selectedItems - state.mode.selectedItems
state.mode.selectedItems.union(unselectedItems).forEach { item -> state.mode.selectedItems.union(unselectedItems).forEach { item ->
if (view.context.settings().accessibilityServicesEnabled) { if (hasAccessibilityEnabled) {
view.announceForAccessibility( view.announceForAccessibility(
if (unselectedItems.contains(item)) view.context.getString( if (unselectedItems.contains(item)) view.context.getString(
R.string.tab_tray_item_unselected_multiselect_content_description, 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( if (multiselect) MULTISELECT_HANDLE_HEIGHT.dpToPx(displayMetrics) else NORMAL_HANDLE_HEIGHT.dpToPx(
displayMetrics displayMetrics
) )
if (container.context.settings().toolbarPosition == ToolbarPosition.TOP) { if (useTopTabsTray) {
topMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_TOP_MARGIN.dpToPx( bottomMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_BOTTOM_MARGIN.dpToPx(
displayMetrics displayMetrics
) )
} else { } else {
bottomMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_BOTTOM_MARGIN.dpToPx( topMargin = if (multiselect) 0.dpToPx(displayMetrics) else NORMAL_TOP_MARGIN.dpToPx(
displayMetrics displayMetrics
) )
} }
@ -544,7 +628,7 @@ class TabTrayView(
view.context.resources.getDimension(R.dimen.tab_tray_top_offset).toInt() 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) (behavior as BottomSheetBehavior).setExpandedOffset(topOffset)
} }
} }
@ -553,6 +637,18 @@ class TabTrayView(
menu?.dismiss() 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 { fun onBackPressed(): Boolean {
return interactor.onBackPressed() return interactor.onBackPressed()
} }
@ -568,7 +664,25 @@ class TabTrayView(
val selectedBrowserTabIndex = tabs val selectedBrowserTabIndex = tabs
.indexOfFirst { it.id == sessionId } .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)
} }
} }

@ -19,6 +19,7 @@ import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.tabstray.TabViewHolder import mozilla.components.browser.tabstray.TabViewHolder
import mozilla.components.browser.tabstray.TabsTrayStyling import mozilla.components.browser.tabstray.TabsTrayStyling
import mozilla.components.browser.tabstray.thumbnail.TabThumbnailView 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.Tab
import mozilla.components.concept.tabstray.TabsTray import mozilla.components.concept.tabstray.TabsTray
import mozilla.components.feature.media.ext.pauseIfPlaying 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.R
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.*
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.utils.Do import org.mozilla.fenix.utils.Do
import kotlin.math.max import kotlin.math.max
@ -57,6 +53,7 @@ class TabTrayViewHolder(
itemView.findViewById(R.id.mozac_browser_tabstray_thumbnail) itemView.findViewById(R.id.mozac_browser_tabstray_thumbnail)
@VisibleForTesting @VisibleForTesting
internal val urlView: TextView? = itemView.findViewById(R.id.mozac_browser_tabstray_url)
private val playPauseButtonView: ImageButton = itemView.findViewById(R.id.play_pause_button) private val playPauseButtonView: ImageButton = itemView.findViewById(R.id.play_pause_button)
override var tab: Tab? = null override var tab: Tab? = null
@ -74,6 +71,7 @@ class TabTrayViewHolder(
// Basic text // Basic text
updateTitle(tab) updateTitle(tab)
updateUrl(tab)
updateIcon(tab) updateIcon(tab)
updateCloseButtonDescription(tab.title) updateCloseButtonDescription(tab.title)
@ -148,6 +146,24 @@ class TabTrayViewHolder(
titleView.text = title 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) { private fun updateIcon(tab: Tab) {
if (tab.icon != null) { if (tab.icon != null) {
iconCard.visibility = View.VISIBLE iconCard.visibility = View.VISIBLE

@ -875,6 +875,31 @@ class Settings(private val appContext: Context) : PreferencesHolder {
BuildConfig.AMO_COLLECTION 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( private var savedLoginsSortingStrategyString by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy), appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
default = SavedLoginsSortingStrategyMenu.Item.AlphabeticallySort.strategyString default = SavedLoginsSortingStrategyMenu.Item.AlphabeticallySort.strategyString

@ -6,44 +6,45 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_wrapper" android:id="@+id/tab_wrapper"
style="@style/TopSheetModal" style="@style/BottomSheetModal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:backgroundTint="@color/foundation_normal_theme" android:backgroundTint="@color/foundation_normal_theme"
app:layout_behavior="org.mozilla.fenix.components.topsheet.TopSheetBehavior"> app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<View <View
android:id="@+id/handle" android:id="@+id/handle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="3dp" android:layout_height="3dp"
android:layout_marginBottom="8dp" android:layout_marginTop="8dp"
android:background="@color/secondary_text_normal_theme" android:background="@color/secondary_text_normal_theme"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.1" /> app:layout_constraintWidth_percent="0.1" />
<TextView <TextView
android:id="@+id/tab_tray_empty_view" android:id="@+id/tab_tray_empty_view"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="0dp"
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true" android:focusableInTouchMode="true"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingBottom="80dp" android:paddingTop="80dp"
android:text="@string/no_open_tabs_description" android:text="@string/no_open_tabs_description"
android:textColor="?secondaryText" android:textColor="?secondaryText"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/divider" /> app:layout_constraintTop_toBottomOf="@id/topBar" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topBar" android:id="@+id/topBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="80dp" android:layout_height="80dp"
android:background="@color/foundation_normal_theme" android:background="@color/foundation_normal_theme"
app:layout_constraintBottom_toTopOf="@id/handle"> app:layout_constraintTop_toBottomOf="@+id/handle">
<ImageButton <ImageButton
android:id="@+id/exit_multi_select" android:id="@+id/exit_multi_select"
@ -161,17 +162,18 @@
android:background="@color/tab_tray_item_divider_normal_theme" android:background="@color/tab_tray_item_divider_normal_theme"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/topBar" /> app:layout_constraintTop_toBottomOf="@+id/topBar" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/tabsTray" android:id="@+id/tabsTray"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingBottom="140dp"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toBottomOf="@+id/divider" />
app:layout_constraintBottom_toTopOf="@+id/divider" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,22 @@
<?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/. -->
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/new_tab_button"
style="@style/TabTrayFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:scrollbars="none"
android:layout_margin="16dp"
android:backgroundTint="@color/accent_normal_theme"
android:contentDescription="@string/add_tab"
android:elevation="99dp"
android:text="@string/tab_drawer_fab_content"
android:textColor="@color/photonWhite"
app:elevation="99dp"
app:borderWidth="0dp"
app:icon="@drawable/ic_new"
app:iconTint="@color/photonWhite" />

@ -0,0 +1,22 @@
<?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/. -->
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/new_tab_button"
style="@style/TabTrayFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:scrollbars="none"
android:layout_margin="16dp"
android:backgroundTint="@color/accent_normal_theme"
android:contentDescription="@string/add_tab"
android:elevation="99dp"
android:text="@string/tab_drawer_fab_content"
android:textColor="@color/photonWhite"
app:elevation="99dp"
app:borderWidth="0dp"
app:icon="@drawable/ic_new"
app:iconTint="@color/photonWhite" />

@ -6,45 +6,44 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_wrapper" android:id="@+id/tab_wrapper"
style="@style/BottomSheetModal" style="@style/TopSheetModal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:backgroundTint="@color/foundation_normal_theme" android:backgroundTint="@color/foundation_normal_theme"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> app:layout_behavior="org.mozilla.fenix.components.topsheet.TopSheetBehavior">
<View <View
android:id="@+id/handle" android:id="@+id/handle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="3dp" android:layout_height="3dp"
android:layout_marginTop="8dp" android:layout_marginBottom="8dp"
android:background="@color/secondary_text_normal_theme" android:background="@color/secondary_text_normal_theme"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintWidth_percent="0.1" /> app:layout_constraintWidth_percent="0.1" />
<TextView <TextView
android:id="@+id/tab_tray_empty_view" android:id="@+id/tab_tray_empty_view"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="wrap_content"
android:focusable="true" android:focusable="true"
android:focusableInTouchMode="true" android:focusableInTouchMode="true"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingTop="80dp" android:paddingBottom="80dp"
android:text="@string/no_open_tabs_description" android:text="@string/no_open_tabs_description"
android:textColor="?secondaryText" android:textColor="?secondaryText"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/topBar" /> app:layout_constraintBottom_toTopOf="@+id/divider" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topBar" android:id="@+id/topBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="80dp" android:layout_height="80dp"
android:background="@color/foundation_normal_theme" android:background="@color/foundation_normal_theme"
app:layout_constraintTop_toBottomOf="@+id/handle"> app:layout_constraintBottom_toTopOf="@id/handle">
<ImageButton <ImageButton
android:id="@+id/exit_multi_select" android:id="@+id/exit_multi_select"
@ -162,18 +161,17 @@
android:background="@color/tab_tray_item_divider_normal_theme" android:background="@color/tab_tray_item_divider_normal_theme"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topBar" /> app:layout_constraintBottom_toTopOf="@+id/topBar" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/tabsTray" android:id="@+id/tabsTray"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingBottom="140dp"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider" /> app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/divider" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -7,7 +7,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_item" android:id="@+id/tab_item"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="165dp" android:layout_height="88dp"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:foreground="?android:selectableItemBackground"> android:foreground="?android:selectableItemBackground">
@ -16,21 +16,22 @@
android:id="@+id/play_pause_button" android:id="@+id/play_pause_button"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginTop="23dp" android:layout_marginStart="80dp"
android:layout_marginTop="4dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/mozac_feature_media_notification_action_pause" android:contentDescription="@string/mozac_feature_media_notification_action_pause"
android:elevation="10dp" android:elevation="10dp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/media_state_play" /> app:srcCompat="@drawable/media_state_play" />
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/mozac_browser_tabstray_card" android:id="@+id/mozac_browser_tabstray_card"
android:layout_width="match_parent" android:layout_width="@dimen/tab_tray_thumbnail_width_original"
android:layout_height="@dimen/tab_tray_thumbnail_height" android:layout_height="@dimen/tab_tray_thumbnail_height_original"
android:layout_marginHorizontal="7dp" android:layout_marginStart="16dp"
android:layout_marginTop="30dp" android:layout_marginTop="8dp"
android:backgroundTint="?tabTrayThumbnailItemBackground" android:backgroundTint="?tabTrayThumbnailItemBackground"
app:cardBackgroundColor="@color/photonWhite" app:cardBackgroundColor="@color/photonWhite"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -77,9 +78,9 @@
android:id="@+id/mozac_browser_tabstray_icon_card" android:id="@+id/mozac_browser_tabstray_icon_card"
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
app:layout_constraintStart_toStartOf="@id/mozac_browser_tabstray_card" android:layout_marginStart="8dp"
app:layout_constraintBottom_toTopOf="@id/mozac_browser_tabstray_card" app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="@id/mozac_browser_tabstray_title"
app:cardCornerRadius="5dp" > app:cardCornerRadius="5dp" >
<ImageView <ImageView
@ -90,7 +91,6 @@
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<TextView <TextView
android:id="@+id/mozac_browser_tabstray_title" android:id="@+id/mozac_browser_tabstray_title"
android:layout_width="0dp" android:layout_width="0dp"
@ -100,24 +100,42 @@
android:fadingEdgeLength="25dp" android:fadingEdgeLength="25dp"
android:ellipsize="none" android:ellipsize="none"
android:singleLine="true" android:singleLine="true"
android:paddingHorizontal="7dp" android:paddingStart="8dp"
android:paddingVertical="5dp" android:paddingTop="22dp"
android:textColor="@color/tab_tray_item_text_normal_theme" android:textColor="@color/tab_tray_item_text_normal_theme"
android:textSize="14sp" android:textSize="16sp"
android:visibility="visible" tools:text="This is the title of the tab and it is long"
tools:text="Webpage tile that is long"
app:layout_constraintEnd_toStartOf="@id/mozac_browser_tabstray_close" app:layout_constraintEnd_toStartOf="@id/mozac_browser_tabstray_close"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_icon_card" app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_icon_card"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/mozac_browser_tabstray_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:requiresFadingEdge="horizontal"
android:fadingEdgeLength="25dp"
android:ellipsize="none"
android:singleLine="true"
android:paddingStart="8dp"
android:textColor="@color/tab_tray_item_url_normal_theme"
android:textSize="14sp"
tools:text="https://www.google.com"
app:layout_constraintEnd_toStartOf="@id/mozac_browser_tabstray_close"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toBottomOf="@id/mozac_browser_tabstray_title" />
<androidx.appcompat.widget.AppCompatImageButton <androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/mozac_browser_tabstray_close" android:id="@+id/mozac_browser_tabstray_close"
android:layout_width="wrap_content" android:layout_width="48dp"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackgroundBorderless" android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/close_tab" android:contentDescription="@string/close_tab"
app:layout_constraintEnd_toEndOf="@id/mozac_browser_tabstray_card" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/mozac_browser_tabstray_card" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/mozac_ic_close" app:srcCompat="@drawable/mozac_ic_close"
app:tint="@color/tab_tray_item_text_normal_theme" /> app:tint="@color/tab_tray_item_text_normal_theme" />

@ -0,0 +1,141 @@
<?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/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tab_item"
android:layout_width="match_parent"
android:layout_height="165dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:selectableItemBackground">
<ImageButton
android:id="@+id/play_pause_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="23dp"
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_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/media_state_play" />
<androidx.cardview.widget.CardView
android:id="@+id/mozac_browser_tabstray_card"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_tray_thumbnail_height"
android:layout_marginHorizontal="7dp"
android:layout_marginTop="30dp"
android:backgroundTint="?tabTrayThumbnailItemBackground"
app:cardBackgroundColor="@color/photonWhite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/default_tab_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no"
android:padding="22dp"
app:srcCompat="@drawable/mozac_ic_globe"
app:tint="?tabTrayThumbnailIcon" />
<mozilla.components.browser.tabstray.thumbnail.TabThumbnailView
android:id="@+id/mozac_browser_tabstray_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/mozac_browser_tabstray_open_tab" />
<View
android:id="@+id/selected_mask"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/tab_tray_selected_mask_normal_theme"
android:visibility="gone" />
<ImageView
android:id="@+id/checkmark"
android:contentDescription="@string/tab_tray_multiselect_selected_content_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:background="@drawable/favicon_background"
android:backgroundTint="@color/accent_normal_theme"
android:elevation="1dp"
android:padding="10dp"
android:visibility="gone"
app:srcCompat="@drawable/mozac_ic_check" />
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:id="@+id/mozac_browser_tabstray_icon_card"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintStart_toStartOf="@id/mozac_browser_tabstray_card"
app:layout_constraintBottom_toTopOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toTopOf="parent"
app:cardCornerRadius="5dp" >
<ImageView
android:id="@+id/mozac_browser_tabstray_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:importantForAccessibility="no" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/mozac_browser_tabstray_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:requiresFadingEdge="horizontal"
android:fadingEdgeLength="25dp"
android:ellipsize="none"
android:singleLine="true"
android:paddingHorizontal="7dp"
android:paddingVertical="5dp"
android:textColor="@color/tab_tray_item_text_normal_theme"
android:textSize="14sp"
android:visibility="visible"
tools:text="Webpage tile that is long and will overflow textview widget"
app:layout_constraintEnd_toStartOf="@id/mozac_browser_tabstray_close"
app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_icon_card"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/mozac_browser_tabstray_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:lines="1"
android:paddingStart="8dp"
android:textColor="@color/tab_tray_item_url_normal_theme"
android:textSize="14sp"
tools:text="https://www.google.com"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@id/mozac_browser_tabstray_close"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toBottomOf="@id/mozac_browser_tabstray_title" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/mozac_browser_tabstray_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/close_tab"
app:layout_constraintEnd_toEndOf="@id/mozac_browser_tabstray_card"
app:layout_constraintBottom_toTopOf="@id/mozac_browser_tabstray_card"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/mozac_ic_close"
app:tint="@color/tab_tray_item_text_normal_theme" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -159,6 +159,9 @@
<dimen name="tab_tray_top_offset">40dp</dimen> <dimen name="tab_tray_top_offset">40dp</dimen>
<dimen name="tab_tray_thumbnail_width">125dp</dimen> <dimen name="tab_tray_thumbnail_width">125dp</dimen>
<dimen name="tab_tray_thumbnail_height">130dp</dimen> <dimen name="tab_tray_thumbnail_height">130dp</dimen>
<!-- Tabs Tray -->
<dimen name="tab_tray_thumbnail_width_original">92dp</dimen>
<dimen name="tab_tray_thumbnail_height_original">69dp</dimen>
<!-- Saved Logins Fragment --> <!-- Saved Logins Fragment -->
<dimen name="saved_logins_sort_menu_dropdown_chevron_icon_margin_start">10dp</dimen> <dimen name="saved_logins_sort_menu_dropdown_chevron_icon_margin_start">10dp</dimen>

@ -126,6 +126,17 @@
<!-- Customization Settings --> <!-- Customization Settings -->
<string name="pref_home_category" translatable="false">pref_home_category</string> <string name="pref_home_category" translatable="false">pref_home_category</string>
<!-- Tabs Tray Customization Settings -->
<string name="pref_tabs_tray_settings_category" translatable="false">pref_tabs_tray_settings_category</string>
<string name="pref_key_tabs_tray_compact_tab" translatable="false">pref_key_tabs_tray_compact_tab</string>
<string name="pref_key_tabs_tray_top_tray" translatable="false">pref_key_tabs_tray_top_tray</string>
<string name="pref_key_tabs_tray_reverse_tab_order" translatable="false">pref_key_tabs_tray_reverse_tab_order</string>
<!-- Tabs Tray FAB Customization Settings -->
<string name="pref_tabs_tray_fab_settings_category" translatable="false">pref_tabs_tray_fab_settings_category</string>
<string name="pref_key_tabs_tray_use_fab" translatable="false">pref_key_tabs_tray_use_fab</string>
<string name="pref_key_tabs_tray_fab_top_position" translatable="false">pref_key_tabs_tray_fab_top_position</string>
<!-- Add-ons Source Customization Settings --> <!-- Add-ons Source Customization Settings -->
<string name="pref_addons_settings_category" translatable="false">pref_addons_settings_category</string> <string name="pref_addons_settings_category" translatable="false">pref_addons_settings_category</string>
<string name="pref_key_addons_custom_account" translatable="false">pref_key_addons_custom_account</string> <string name="pref_key_addons_custom_account" translatable="false">pref_key_addons_custom_account</string>

@ -282,6 +282,10 @@
<string name="preferences_theme">Theme</string> <string name="preferences_theme">Theme</string>
<!-- Preference for customizing the home screen --> <!-- Preference for customizing the home screen -->
<string name="preferences_home">Home</string> <string name="preferences_home">Home</string>
<!-- Preference for customizing the tabs tray -->
<string name="preferences_tabs_tray">Tabs tray</string>
<!-- Preference for customizing the tabs tray FAB -->
<string name="preferences_tabs_tray_fab">Floating action button (FAB)</string>
<!-- Preference for settings related to visual options --> <!-- Preference for settings related to visual options -->
<string name="preferences_customize">Customize</string> <string name="preferences_customize">Customize</string>
<!-- Preference description for banner about signing in --> <!-- Preference description for banner about signing in -->
@ -1530,11 +1534,26 @@
<!-- Label for the show most visited sites preference --> <!-- Label for the show most visited sites preference -->
<string name="top_sites_toggle_top_frecent_sites">Show most visited sites</string> <string name="top_sites_toggle_top_frecent_sites">Show most visited sites</string>
<!-- Label for add-ons custom source account --> <!-- Label for add-ons custom source account preference -->
<string name="addons_custom_source_account">Set custom add-ons account</string> <string name="addons_custom_source_account">Set custom add-ons account</string>
<!-- Label for add-ons custom source collection --> <!-- Label for add-ons custom source collection preference -->
<string name="addons_custom_source_collection">Set custom add-ons collection</string> <string name="addons_custom_source_collection">Set custom add-ons collection</string>
<!-- Label for enable compact tabs in tabs tray preference -->
<string name="enable_compact_tabs">Enable compact tabs</string>
<!-- Label for enable top tabs tray preference -->
<string name="enable_top_tabs_tray">Enable top tabs tray</string>
<!-- Label for reverse tab order in tabs tray preference -->
<string name="reverse_tab_order_tabs_tray">Reverse tab order in tray</string>
<!-- Summary for reverse tab order preference -->
<string name="reverse_tab_order_description">Enable to put new tabs at start of the tabs list, disable to put new tabs at end of the tabs list</string>
<!-- Label for enable FAB in tabs tray preference -->
<string name="enable_fab_tabs_tray">Enable FAB for new tab</string>
<!-- Label for top FAB position in tabs tray preference -->
<string name="fab_tabs_tray_top">Place FAB at the top</string>
<!-- Label for top FAB position in tabs tray preference -->
<string name="fab_tabs_tray_top_description">Enable to place button for new tab at the top, disable to place it at the bottom</string>
<!-- Content description for close button in collection placeholder. --> <!-- Content description for close button in collection placeholder. -->
<string name="remove_home_collection_placeholder_content_description">Remove</string> <string name="remove_home_collection_placeholder_content_description">Remove</string>

@ -35,7 +35,7 @@
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
android:layout="@layout/preference_cat_style" android:layout="@layout/preference_cat_style"
android:title="@string/preferences_toolbar" android:title="@string/preferences_toolbar"
app:allowDividerAbove="false" app:allowDividerAbove="true"
app:iconSpaceReserved="false"> app:iconSpaceReserved="false">
<org.mozilla.fenix.settings.RadioButtonPreference <org.mozilla.fenix.settings.RadioButtonPreference
android:key="@string/pref_key_toolbar_top" android:key="@string/pref_key_toolbar_top"
@ -50,11 +50,49 @@
android:title="@string/preferences_strip_url_title" /> android:title="@string/preferences_strip_url_title" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:key="@string/pref_tabs_tray_settings_category"
android:layout="@layout/preference_cat_style"
android:title="@string/preferences_tabs_tray"
app:allowDividerAbove="true"
app:iconSpaceReserved="false">
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_tabs_tray_compact_tab"
android:title="@string/enable_compact_tabs" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_tabs_tray_top_tray"
android:title="@string/enable_top_tabs_tray" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/pref_key_tabs_tray_reverse_tab_order"
android:title="@string/reverse_tab_order_tabs_tray"
android:summary="@string/reverse_tab_order_description" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:key="@string/pref_tabs_tray_fab_settings_category"
android:layout="@layout/preference_cat_style"
android:title="@string/preferences_tabs_tray_fab"
app:allowDividerAbove="false"
app:iconSpaceReserved="false">
<SwitchPreference
android:defaultValue="true"
android:key="@string/pref_key_tabs_tray_use_fab"
android:title="@string/enable_fab_tabs_tray" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/pref_key_tabs_tray_fab_top_position"
android:title="@string/fab_tabs_tray_top"
android:summary="@string/fab_tabs_tray_top_description" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
android:key="@string/pref_home_category" android:key="@string/pref_home_category"
android:layout="@layout/preference_cat_style" android:layout="@layout/preference_cat_style"
android:title="@string/preferences_home" android:title="@string/preferences_home"
app:allowDividerAbove="false" app:allowDividerAbove="true"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:isPreferenceVisible="false"> app:isPreferenceVisible="false">
<androidx.preference.SwitchPreference <androidx.preference.SwitchPreference
@ -66,7 +104,7 @@
android:key="@string/pref_addons_settings_category" android:key="@string/pref_addons_settings_category"
android:layout="@layout/preference_cat_style" android:layout="@layout/preference_cat_style"
android:title="@string/preferences_addons_customization" android:title="@string/preferences_addons_customization"
app:allowDividerAbove="false" app:allowDividerAbove="true"
app:iconSpaceReserved="false"> app:iconSpaceReserved="false">
<androidx.preference.EditTextPreference <androidx.preference.EditTextPreference
android:key="@string/pref_key_addons_custom_account" android:key="@string/pref_key_addons_custom_account"

Loading…
Cancel
Save