diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFab.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFab.kt new file mode 100644 index 0000000000..a0275fe649 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFab.kt @@ -0,0 +1,110 @@ +/* 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.tabstray + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import mozilla.components.lib.state.ext.observeAsComposableState +import org.mozilla.fenix.R +import org.mozilla.fenix.compose.annotation.LightDarkPreview +import org.mozilla.fenix.compose.button.FloatingActionButton +import org.mozilla.fenix.theme.FirefoxTheme + +/** + * Floating action button for tabs tray. + * + * @param tabsTrayStore [TabsTrayStore] used to listen for changes to [TabsTrayState]. + */ +@Composable +fun TabsTrayFab( + tabsTrayStore: TabsTrayStore, +) { + val currentPage: Page = tabsTrayStore.observeAsComposableState { state -> + state.selectedPage + }.value ?: Page.NormalTabs + val isSyncing: Boolean = tabsTrayStore.observeAsComposableState { state -> + state.syncing + }.value ?: false + val isInNormalMode: Boolean = tabsTrayStore.observeAsComposableState { state -> + state.mode == TabsTrayState.Mode.Normal + }.value ?: false + + val icon: Painter + val contentDescription: String + val label: String? + + when (currentPage) { + Page.NormalTabs -> { + icon = painterResource(id = R.drawable.ic_new) + contentDescription = stringResource(id = R.string.add_tab) + label = null + } + + Page.SyncedTabs -> { + icon = painterResource(id = R.drawable.ic_fab_sync) + contentDescription = stringResource(id = R.string.tab_drawer_fab_sync) + label = if (isSyncing) { + stringResource(id = R.string.sync_syncing_in_progress) + } else { + stringResource(id = R.string.resync_button_content_description) + }.uppercase() + } + + Page.PrivateTabs -> { + icon = painterResource(id = R.drawable.ic_new) + contentDescription = stringResource(id = R.string.add_private_tab) + label = stringResource(id = R.string.tab_drawer_fab_content).uppercase() + } + } + + Box(Modifier.fillMaxSize()) { + if (isInNormalMode) { + FloatingActionButton( + icon = icon, + modifier = Modifier + .align(Alignment.BottomEnd) + .padding(16.dp), + contentDescription = contentDescription, + label = label, + ) {} + } + } +} + +@LightDarkPreview +@Composable +private fun TabsTraySyncFabPreview() { + val store = TabsTrayStore( + initialState = TabsTrayState( + selectedPage = Page.SyncedTabs, + syncing = true, + ), + ) + + FirefoxTheme { + TabsTrayFab(store) + } +} + +@LightDarkPreview +@Composable +private fun TabsTrayPrivateFabPreview() { + val store = TabsTrayStore( + initialState = TabsTrayState( + selectedPage = Page.PrivateTabs, + ), + ) + FirefoxTheme { + TabsTrayFab(store) + } +} diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index 3a0085b8d4..508143d336 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -40,6 +40,7 @@ import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.databinding.ComponentTabstray2Binding import org.mozilla.fenix.databinding.ComponentTabstray3Binding +import org.mozilla.fenix.databinding.ComponentTabstray3FabBinding import org.mozilla.fenix.databinding.ComponentTabstrayFabBinding import org.mozilla.fenix.databinding.FragmentTabTrayDialogBinding import org.mozilla.fenix.databinding.TabsTrayTabCounter2Binding @@ -115,6 +116,10 @@ class TabsTrayFragment : AppCompatDialogFragment() { internal var _tabsTrayComposeBinding: ComponentTabstray3Binding? = null private val tabsTrayComposeBinding get() = _tabsTrayComposeBinding!! + @Suppress("VariableNaming") + internal var _fabButtonComposeBinding: ComponentTabstray3FabBinding? = null + private val fabButtonComposeBinding get() = _fabButtonComposeBinding!! + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, R.style.TabTrayDialogStyle) @@ -205,6 +210,12 @@ class TabsTrayFragment : AppCompatDialogFragment() { true, ) + _fabButtonComposeBinding = ComponentTabstray3FabBinding.inflate( + inflater, + tabsTrayDialogBinding.root, + true, + ) + tabsTrayComposeBinding.root.setContent { FirefoxTheme(theme = Theme.getTheme(allowPrivateTheme = false)) { TabsTray( @@ -224,6 +235,12 @@ class TabsTrayFragment : AppCompatDialogFragment() { ) } } + + fabButtonComposeBinding.root.setContent { + FirefoxTheme(theme = Theme.getTheme(allowPrivateTheme = false)) { + TabsTrayFab(tabsTrayStore = tabsTrayStore) + } + } } else { _tabsTrayBinding = ComponentTabstray2Binding.inflate( inflater, diff --git a/app/src/main/res/layout/component_tabstray3_fab.xml b/app/src/main/res/layout/component_tabstray3_fab.xml new file mode 100644 index 0000000000..1dd4a117f5 --- /dev/null +++ b/app/src/main/res/layout/component_tabstray3_fab.xml @@ -0,0 +1,8 @@ + + +