diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/effect/MessageListEffect.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/effect/MessageListEffect.kt new file mode 100644 index 00000000000..b4ce249c14c --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/effect/MessageListEffect.kt @@ -0,0 +1,76 @@ +package net.thunderbird.feature.mail.message.list.ui.effect + +import net.thunderbird.feature.account.AccountId + +/** + * Represents one-time side effects that can be triggered from the message list screen. + * These effects are intended to be consumed by the UI to perform actions like navigation + * or showing transient messages. + */ +sealed interface MessageListEffect { + /** + * Effect to navigate back from the current screen. + */ + data object NavigateBack : MessageListEffect + + /** + * Effect to navigate to the "Move To" screen, allowing the user to select a destination + * folder for the given messages. + * + * @param messagesIds The unique identifiers of the messages to be moved. + * @param accountId The identifier of the account to which the messages belong. + */ + data class NavigateToMoveToScreen(val messagesIds: List, val accountId: AccountId) : MessageListEffect + + /** + * Represents the effect of messages being successfully archived. + * This is typically used to show a notification or a snackbar to the user. + * + * @param messagesIdByAccountId A map where keys are account IDs and values are lists of message IDs + * that have been archived for that account. + */ + data class ArchivedMessages(val messagesIdByAccountId: Map>) : MessageListEffect + + /** + * Represents an effect for when pending (outbox) messages have been successfully sent. + * + * This effect is triggered after messages residing in the outbox are processed and sent, + * typically resulting in them being moved to the Sent folder, if any configured. + * + * @param messagesIdByAccountId A map where each key is an [AccountId] and the value is a list of + * message IDs that have been sent for that account. + */ + data class PendingMessagesSent(val messagesIdByAccountId: Map>) : MessageListEffect + + /** + * Represents an effect for when messages have been permanently removed (expunged) from a folder. + * + * This typically happens after messages marked for deletion are purged from the server, + * particularly with IMAP accounts. The UI should reflect this by removing these messages + * or updating its state accordingly. + * + * @param messagesIdByAccountId A map where keys are account IDs and values are lists of message IDs + * that have been expunged. This structure supports handling expunged messages from multiple accounts + * in a single operation. + */ + data class ExpungedMessages(val messagesIdByAccountId: Map>) : MessageListEffect + + /** + * Represents the side effect that messages have been marked for deletion. + * + * This effect is typically triggered after a user performs a delete action. The UI can use this + * to show a confirmation, such as a snackbar, indicating the successful deletion. + * + * @param messagesIdByAccountId A map where each key is an [AccountId] and the corresponding value + * is a list of message IDs that have been deleted for that account. + */ + data class DeletedMessages(val messagesIdByAccountId: Map>) : MessageListEffect + + /** + * Represents the effect of one or more draft messages being discarded (deleted). + * + * @param messagesIdByAccountId A map where each key is an [AccountId] and the value is a list of message IDs + * that have been discarded for that account. + */ + data class DraftsDiscarded(val messagesIdByAccountId: Map>) : MessageListEffect +} diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/FolderEvent.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/FolderEvent.kt new file mode 100644 index 00000000000..fbebda24e11 --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/FolderEvent.kt @@ -0,0 +1,69 @@ +package net.thunderbird.feature.mail.message.list.ui.event + +import net.thunderbird.feature.mail.message.list.ui.state.Folder + +/** + * Represents UI events related to folder actions, extending [MessageListEvent]. + * These events are typically triggered by user interactions within a specific folder view. + * + * @see MessageListEvent + */ +sealed interface FolderEvent : MessageListEvent { + /** + * Event to expunge (permanently delete) messages marked for deletion in a specific folder. + * + * @param folder The folder from which to expunge messages. + */ + data class Expunge(val folder: Folder) : FolderEvent + + /** + * Event to create a new folder to be used as the archive folder. + * + * @param name The name of the folder to be created. + */ + data class CreateArchiveFolder(val name: String) : FolderEvent + + /** + * Event to assign an existing folder as the archive folder. + * + * @param folder The folder to be designated as the archive folder. + */ + data class AssignArchiveFolder(val folder: Folder) : FolderEvent + + /** + * Event to mark all messages within a specific folder as read. + * + * @param folder The folder in which all messages should be marked as read. + */ + data class MarkAllMessagesAsRead(val folder: Folder) : FolderEvent +} + +/** + * Represents events that are specific to the Trash folder. + */ +sealed interface TrashFolderEvent : FolderEvent { + /** + * Event to permanently delete all messages in the Trash folder. + */ + data object EmptyTrash : FolderEvent +} + +/** + * Represents events that are specific to the Outbox folder. + */ +sealed interface OutboxFolderEvent : FolderEvent { + /** + * Event to trigger sending all pending messages in the Outbox. + */ + data object SendPendingMessages : FolderEvent +} + +/** + * Represents events that are specific to the Spam folder. + */ +sealed interface SpamFolderEvent : FolderEvent { + /** + * Event to permanently delete all messages in the spam folder. + */ + data object EmptySpamFolder : FolderEvent +} diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageItemEvent.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageItemEvent.kt new file mode 100644 index 00000000000..f50614b30bd --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageItemEvent.kt @@ -0,0 +1,63 @@ +package net.thunderbird.feature.mail.message.list.ui.event + +import net.thunderbird.core.common.action.SwipeAction +import net.thunderbird.core.common.mail.Flag +import net.thunderbird.feature.mail.message.list.ui.state.MessageItemUi + +/** + * Represents events that can be triggered on a single message item in the message list, extending [MessageListEvent]. + * + * @see MessageListEvent + */ +sealed interface MessageItemEvent : MessageListEvent.UserEvent { + /** + * Represents an event triggered when a user clicks on a single message item in the list. + * + * @param message The [MessageItemUi] that was clicked. + */ + data class OnMessageClick(val message: MessageItemUi) : MessageItemEvent + + /** + * Event to toggle the selection state of one or more messages. + * + * @param messages The list of messages whose selection state should be toggled. + */ + data class ToggleSelectMessages(val messages: List) : MessageItemEvent { + constructor(message: MessageItemUi) : this(messages = listOf(message)) + } + + /** + * Event to toggle the 'favourite' (starred) state of one or more messages. + * + * @param messages The list of [MessageItemUi]s to be toggled. + */ + data class ToggleFavourite(val messages: List) : MessageItemEvent { + constructor(message: MessageItemUi) : this(messages = listOf(message)) + } + + /** + * An event to toggle the read/unread status of one or more messages. + * + * @param messages The list of messages whose read/unread status should be toggled. + */ + data class ToggleReadUnread(val messages: List) : MessageItemEvent { + constructor(message: MessageItemUi) : this(messages = listOf(message)) + } + + /** + * Flags a list of messages with the given [Flag]. + * + * @param messages The list of messages to flag. + * @param flag The flag to apply to the messages. + */ + data class FlagMessages(val messages: List, val flag: Flag) : MessageItemEvent { + constructor(message: MessageItemUi, flag: Flag) : this(messages = listOf(message), flag = flag) + } + + /** + * Represents a swipe action on a message item. + * + * @property message The message item that was swiped. + */ + data class OnSwipeMessage(val message: MessageItemUi, val swipeAction: SwipeAction) : MessageItemEvent +} diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListEvent.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListEvent.kt new file mode 100644 index 00000000000..bcaf48541b5 --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListEvent.kt @@ -0,0 +1,95 @@ +package net.thunderbird.feature.mail.message.list.ui.event + +import net.thunderbird.core.common.action.SwipeActions +import net.thunderbird.feature.account.AccountId +import net.thunderbird.feature.mail.message.list.preferences.MessageListPreferences +import net.thunderbird.feature.mail.message.list.ui.state.MessageItemUi +import net.thunderbird.feature.mail.message.list.ui.state.SortType + +/** + * Represents the events that can be triggered from the message list screen. + * These events are handled by the [MessageListViewModel] to update the UI state. + */ +sealed interface MessageListEvent { + sealed interface SystemEvent : MessageListEvent + sealed interface UserEvent : MessageListEvent + + /** + * A system event to trigger the loading of initial configurations for the message list. + * This includes loading swipe actions, user preferences, and available sort types. + */ + data object LoadConfigurations : SystemEvent + + /** + * A system event indicating that the swipe actions for one or more accounts have been loaded. + * + * @param swipeActions A map where the key is the [AccountId] and the value is the corresponding [SwipeActions] + * configuration for that account. + */ + data class SwipeActionsLoaded(val swipeActions: Map) : SystemEvent + + /** + * A system event to update the message list preferences. + * This is typically triggered when preferences change from an external source, like the settings screen. + * + * @param preferences The new [MessageListPreferences] to apply. + */ + data class UpdatePreferences(val preferences: MessageListPreferences) : SystemEvent + + /** + * A system event indicating that the sort types for various accounts have been loaded. + * + * @param sortTypes A map where the key is the [AccountId] and the value is the corresponding [SortType]. + * A `null` key represents the global or default sort type. + */ + data class SortTypesLoaded(val sortTypes: Map) : SystemEvent + + /** + * Signals that all initial configurations, such as preferences, swipe actions, and sort types, + * have been successfully loaded and applied. This event indicates that the system is ready + * to proceed with loading the actual message list content. + */ + data object AllConfigsReady : SystemEvent + + /** + * A system event to update the progress of the loading indicator. + * + * @param progress A float value between 0.0 and 1.0 representing the loading completion percentage. + */ + data class UpdateLoadingProgress(val progress: Float) : SystemEvent + + /** + * A system event indicating that a list of messages has been successfully loaded. + * + * @param messages The list of [MessageItemUi] objects to be displayed. + */ + data class MessagesLoaded(val messages: List) : SystemEvent + + /** + * Event triggered when the user initiates selection mode, usually through a long press on a message item. + */ + data object EnterSelectionMode : UserEvent + + /** + * Event triggered when the user exits the message selection mode. + * This typically happens when the user deselects all messages or cancels the selection action. + */ + data object ExitSelectionMode : UserEvent + + /** + * Represents the event of a user requesting to load more messages in the list. + */ + data object LoadMore : UserEvent + + /** + * Triggers a refresh of the message list, fetching the latest messages from the server. + */ + data object Refresh : UserEvent + + /** + * An event that is triggered when the user changes the sort order of the message list. + * + * @param sortType The new [SortType] to apply to the message list. + */ + data class ChangeSortType(val sortType: SortType) : UserEvent +} diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListSearchEvent.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListSearchEvent.kt new file mode 100644 index 00000000000..7ac9dadf923 --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/MessageListSearchEvent.kt @@ -0,0 +1,38 @@ +package net.thunderbird.feature.mail.message.list.ui.event + +/** + * Defines the events related to searching, extending [MessageListEvent]. + * These events are typically triggered by user interactions or specific conditions. + * + * @see MessageListEvent + */ +sealed interface MessageListSearchEvent : MessageListEvent.UserEvent { + /** + * Event triggered when a user performs a search with a specific query. + * + * @param query The text string to search for within the message list. + */ + data class UpdateSearchQuery(val query: String) : MessageListSearchEvent + + /** + * Represents an event to trigger a "search everywhere" action. + * This typically expands the search scope to include all folders or accounts, + * not just the currently viewed one. + */ + data object SearchEverywhere : MessageListSearchEvent + + /** + * Event to trigger a remote search on the server for the current query. + */ + data object SearchRemotely : MessageListSearchEvent + + /** + * Event triggered to enter in the search mode. + */ + data object EnterSearchMode : MessageListSearchEvent + + /** + * Event triggered to clear the current search query and exit the search mode. + */ + data object ExitSearchMode : MessageListSearchEvent +} diff --git a/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/RefileEvent.kt b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/RefileEvent.kt new file mode 100644 index 00000000000..1c4c128a90f --- /dev/null +++ b/feature/mail/message/list/api/src/main/kotlin/net/thunderbird/feature/mail/message/list/ui/event/RefileEvent.kt @@ -0,0 +1,64 @@ +package net.thunderbird.feature.mail.message.list.ui.event + +import net.thunderbird.feature.mail.message.list.preferences.ActionRequiringUserConfirmation +import net.thunderbird.feature.mail.message.list.preferences.MessageListPreferences +import net.thunderbird.feature.mail.message.list.ui.state.Folder +import net.thunderbird.feature.mail.message.list.ui.state.MessageItemUi + +/** + * Represents events related to refiling messages, such as archiving, deleting, moving, or copying. + * These events are triggered by user actions in the message list UI. + * + * @see MessageListEvent + */ +sealed interface RefileEvent : MessageListEvent.UserEvent { + /** + * Event to archive one or more messages. + * + * @param messages The list of messages to be archived. + */ + data class ArchiveMessages(val messages: List) : RefileEvent { + constructor(message: MessageItemUi) : this(messages = listOf(message)) + } + + /** + * Event to delete a list of messages. + * + * @param messages The list of [MessageItemUi] to be deleted. + */ + data class DeleteMessages(val messages: List) : RefileEvent { + constructor(message: MessageItemUi) : this(messages = listOf(message)) + } + + /** + * Event to move one or more messages to a different folder. + * + * @param messages The list of [MessageItemUi]s to be moved. + * @param folder The destination [Folder] where the messages will be moved. + */ + data class MoveMessages(val messages: List, val folder: Folder) : RefileEvent { + constructor(message: MessageItemUi, folder: Folder) : this(messages = listOf(message), folder = folder) + } + + /** + * Event to copy a list of messages to a specific folder. + * + * @param messages The list of [MessageItemUi] to be copied. + * @param folder The destination [Folder] to copy the messages to. + */ + data class CopyMessages(val messages: List, val folder: Folder) : RefileEvent { + constructor(message: MessageItemUi, folder: Folder) : this(messages = listOf(message), folder = folder) + } + + /** + * Event to request user confirmation for a refile action (e.g., delete, archive). + * + * This is typically triggered when the user has configured the app to ask for confirmation + * before performing certain destructive or irreversible actions. + * + * @param action The specific action that requires confirmation from the user. + * @see ActionRequiringUserConfirmation + * @see MessageListPreferences + */ + data class ConfirmAction(val action: ActionRequiringUserConfirmation) : RefileEvent +}