You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragmentStore.kt

181 lines
7.1 KiB
Kotlin

/* 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.library.history
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import mozilla.components.concept.storage.HistoryMetadata
import mozilla.components.concept.storage.HistoryMetadataKey
import mozilla.components.lib.state.Action
import mozilla.components.lib.state.State
import mozilla.components.lib.state.Store
import mozilla.components.support.ktx.kotlin.tryGetHostFromUrl
/**
* Class representing a history entry.
*/
sealed class History : Parcelable {
abstract val position: Int
abstract val title: String
abstract val visitedAt: Long
abstract val historyTimeGroup: HistoryItemTimeGroup
abstract val selected: Boolean
/**
* A regular history item.
*
* @property position Position of this item in a result list of other [History] items.
* @property title Title of the history item.
* @property url URL of the history item.
* @property visitedAt Timestamp of when this history item was visited.
* @property historyTimeGroup [HistoryItemTimeGroup] of the history item.
* @property selected Whether or not the history item is selected.
*/
@Parcelize data class Regular(
override val position: Int,
override val title: String,
val url: String,
override val visitedAt: Long,
override val historyTimeGroup: HistoryItemTimeGroup,
override val selected: Boolean = false
) : History()
/**
* A history metadata item.
*
* @property position Position of this item in a result list of other [History] items.
* @property title Title of the history metadata item.
* @property url URL of the history metadata item.
* @property visitedAt Timestamp of when this history metadata item was visited.
* @property historyTimeGroup [HistoryItemTimeGroup] of the history item.
* @property totalViewTime Total time the user viewed the page associated with this record.
* @property historyMetadataKey The [HistoryMetadataKey] of the new tab in case this tab
* was opened from history.
* @property selected Whether or not the history metadata item is selected.
*/
@Parcelize data class Metadata(
override val position: Int,
override val title: String,
val url: String,
override val visitedAt: Long,
override val historyTimeGroup: HistoryItemTimeGroup,
val totalViewTime: Int,
val historyMetadataKey: HistoryMetadataKey,
override val selected: Boolean = false
) : History()
/**
* A history metadata group.
*
* @property position Position of this item in a result list of other [History] items.
* @property title Title of the history metadata group.
* @property visitedAt Timestamp of when this history metadata group was visited.
* @property historyTimeGroup [HistoryItemTimeGroup] of the history item.
* @property items List of history metadata items associated with the group.
* @property selected Whether or not the history group is selected.
*/
@Parcelize data class Group(
override val position: Int,
override val title: String,
override val visitedAt: Long,
override val historyTimeGroup: HistoryItemTimeGroup,
val items: List<Metadata>,
override val selected: Boolean = false
) : History()
}
/**
* Extension function for converting a [HistoryMetadata] into a [History.Metadata].
*/
fun HistoryMetadata.toHistoryMetadata(position: Int): History.Metadata {
return History.Metadata(
position = position,
title = title?.takeIf(String::isNotEmpty)
?: key.url.tryGetHostFromUrl(),
url = key.url,
visitedAt = createdAt,
historyTimeGroup = HistoryItemTimeGroup.timeGroupForTimestamp(createdAt),
totalViewTime = totalViewTime,
historyMetadataKey = key
)
}
/**
* The [Store] for holding the [HistoryFragmentState] and applying [HistoryFragmentAction]s.
*/
class HistoryFragmentStore(initialState: HistoryFragmentState) :
Store<HistoryFragmentState, HistoryFragmentAction>(initialState, ::historyStateReducer)
/**
* Actions to dispatch through the `HistoryStore` to modify `HistoryState` through the reducer.
*/
sealed class HistoryFragmentAction : Action {
object ExitEditMode : HistoryFragmentAction()
data class AddItemForRemoval(val item: History) : HistoryFragmentAction()
data class RemoveItemForRemoval(val item: History) : HistoryFragmentAction()
data class AddPendingDeletionSet(val itemIds: Set<Long>) : HistoryFragmentAction()
data class UndoPendingDeletionSet(val itemIds: Set<Long>) : HistoryFragmentAction()
object EnterDeletionMode : HistoryFragmentAction()
object ExitDeletionMode : HistoryFragmentAction()
object StartSync : HistoryFragmentAction()
object FinishSync : HistoryFragmentAction()
}
/**
* The state for the History Screen
* @property items List of History to display
* @property mode Current Mode of History
*/
data class HistoryFragmentState(
val items: List<History>,
val mode: Mode,
val pendingDeletionIds: Set<Long>,
val isDeletingItems: Boolean
) : State {
sealed class Mode {
open val selectedItems = emptySet<History>()
object Normal : Mode()
object Syncing : Mode()
data class Editing(override val selectedItems: Set<History>) : Mode()
}
}
/**
* The HistoryState Reducer.
*/
private fun historyStateReducer(
state: HistoryFragmentState,
action: HistoryFragmentAction
): HistoryFragmentState {
return when (action) {
is HistoryFragmentAction.AddItemForRemoval ->
state.copy(mode = HistoryFragmentState.Mode.Editing(state.mode.selectedItems + action.item))
is HistoryFragmentAction.RemoveItemForRemoval -> {
val selected = state.mode.selectedItems - action.item
state.copy(
mode = if (selected.isEmpty()) {
HistoryFragmentState.Mode.Normal
} else {
HistoryFragmentState.Mode.Editing(selected)
}
)
}
is HistoryFragmentAction.ExitEditMode -> state.copy(mode = HistoryFragmentState.Mode.Normal)
is HistoryFragmentAction.EnterDeletionMode -> state.copy(isDeletingItems = true)
is HistoryFragmentAction.ExitDeletionMode -> state.copy(isDeletingItems = false)
is HistoryFragmentAction.StartSync -> state.copy(mode = HistoryFragmentState.Mode.Syncing)
is HistoryFragmentAction.FinishSync -> state.copy(mode = HistoryFragmentState.Mode.Normal)
is HistoryFragmentAction.AddPendingDeletionSet ->
state.copy(
pendingDeletionIds = state.pendingDeletionIds + action.itemIds
)
is HistoryFragmentAction.UndoPendingDeletionSet ->
state.copy(
pendingDeletionIds = state.pendingDeletionIds - action.itemIds
)
}
}