/* 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 mozilla.components.concept.tabstray.Tab import mozilla.components.lib.state.Action import mozilla.components.lib.state.Middleware import mozilla.components.lib.state.State import mozilla.components.lib.state.Store /** * Value type that represents the state of the tabs tray. * * @property selectedPage The current page in the tray can be on. * @property mode Whether the browser tab list is in multi-select mode or not with the set of * currently selected tabs. * @property syncing Whether the Synced Tabs feature should fetch the latest tabs from paired * devices. */ data class TabsTrayState( val selectedPage: Page = Page.NormalTabs, val mode: Mode = Mode.Normal, val syncing: Boolean = false ) : State { /** * The current mode that the tabs list is in. */ sealed class Mode { /** * A set of selected tabs which we would want to perform an action on. */ open val selectedTabs = emptySet() /** * The default mode the tabs list is in. */ object Normal : Mode() /** * The multi-select mode that the tabs list is in containing the set of currently * selected tabs. */ data class Select(override val selectedTabs: Set) : Mode() } } /** * The different pagers in the tray that we can switch between in the [TrayPagerAdapter]. */ enum class Page { /** * The pager position that displays normal tabs. */ NormalTabs, /** * The pager position that displays private tabs. */ PrivateTabs, /** * The pager position that displays Synced Tabs. */ SyncedTabs; companion object { fun positionToPage(position: Int): Page { return when (position) { 0 -> NormalTabs 1 -> PrivateTabs else -> SyncedTabs } } } } /** * [Action] implementation related to [TabsTrayStore]. */ sealed class TabsTrayAction : Action { /** * Entered multi-select mode. */ object EnterSelectMode : TabsTrayAction() /** * Exited multi-select mode. */ object ExitSelectMode : TabsTrayAction() /** * Added a new [Tab] to the selection set. */ data class AddSelectTab(val tab: Tab) : TabsTrayAction() /** * Removed a [Tab] from the selection set. */ data class RemoveSelectTab(val tab: Tab) : TabsTrayAction() /** * The active page in the tray that is now in focus. */ data class PageSelected(val page: Page) : TabsTrayAction() /** * A request to perform a "sync" action. */ object SyncNow : TabsTrayAction() /** * When a "sync" action has completed; this can be triggered immediately after [SyncNow] if * no sync action was able to be performed. */ object SyncCompleted : TabsTrayAction() } /** * Reducer for [TabsTrayStore]. */ internal object TabsTrayReducer { fun reduce(state: TabsTrayState, action: TabsTrayAction): TabsTrayState { return when (action) { is TabsTrayAction.EnterSelectMode -> state.copy(mode = TabsTrayState.Mode.Select(emptySet())) is TabsTrayAction.ExitSelectMode -> state.copy(mode = TabsTrayState.Mode.Normal) is TabsTrayAction.AddSelectTab -> state.copy(mode = TabsTrayState.Mode.Select(state.mode.selectedTabs + action.tab)) is TabsTrayAction.RemoveSelectTab -> { val selected = state.mode.selectedTabs - action.tab state.copy( mode = if (selected.isEmpty()) { TabsTrayState.Mode.Normal } else { TabsTrayState.Mode.Select(selected) } ) } is TabsTrayAction.PageSelected -> state.copy(selectedPage = action.page) is TabsTrayAction.SyncNow -> state.copy(syncing = true) is TabsTrayAction.SyncCompleted -> state.copy(syncing = false) } } } /** * A [Store] that holds the [TabsTrayState] for the tabs tray and reduces [TabsTrayAction]s * dispatched to the store. */ class TabsTrayStore( initialState: TabsTrayState = TabsTrayState(), middlewares: List> = emptyList() ) : Store( initialState, TabsTrayReducer::reduce, middlewares )