Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
83aec5a
feat: add new settingComposable ActionText
shamim-emon May 25, 2026
da70d4f
feat: include ActionTextItem in FakeSettingData
shamim-emon May 25, 2026
f3038a7
feat: add ActionTextItem preview
shamim-emon May 25, 2026
8277ba9
feat: include ActionTextItem in SettingItem composable
shamim-emon May 25, 2026
c005b18
feat: add string resource for FetchingMailSettings
shamim-emon May 25, 2026
2017f9b
feat: add FetchingMailSettingsId
shamim-emon May 25, 2026
72c5b07
feat: add feature:launcher dependency in feature:account:settings:impl
shamim-emon May 25, 2026
c0b4a88
feat: add AccountSettingsRoute for FetchingMailSettings and AdvancedF…
shamim-emon May 25, 2026
8109958
feat: add FeatureLauncherTarget for AccountFetchingMailSettings and A…
shamim-emon May 25, 2026
7797257
feat: add UpdateFetchingMailSettings, UpdateFetchingMailSettingsComma…
shamim-emon May 25, 2026
77c986a
feat: add FetchingMailSettingsContract
shamim-emon May 25, 2026
553b948
feat: add FetchingMailSettingsBuilder
shamim-emon May 25, 2026
3e9eae9
feat: add UpdateFetchingMailSettings implementation for UseCase.Updat…
shamim-emon May 25, 2026
fe55a70
feat: add FetchingMailSettingsViewModel
shamim-emon May 25, 2026
5336702
feat: add AdvancedFetchingMailSettingsContent
shamim-emon May 25, 2026
a738384
feat: add AdvancedFetchingMailSettingsScreen
shamim-emon May 25, 2026
d588544
feat: add FetchingMailSettingsContent
shamim-emon May 25, 2026
cc7d036
feat: add FetchingMailSettingsScreen
shamim-emon May 25, 2026
92e2497
feat: register navigation route for AccountSettingsRoute.FetchingMail…
shamim-emon May 25, 2026
06a6e08
feat: inject UseCase.UpdateFetchingMailSettings, FetchingMailSettings…
shamim-emon May 25, 2026
334d5cb
refactor: update AccountSettingsFragment to comply with relevant changes
shamim-emon May 25, 2026
b2414eb
test: add tests for FetchingMailSettingsBuilder
shamim-emon May 25, 2026
7e8d94b
test: add tests for FetchingMailSettingsViewModel
shamim-emon May 25, 2026
8f7f6bd
test: add test for UpdateFetchingMailSettings UseCase
shamim-emon May 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@ sealed interface SettingValue<T> : Setting {
override val requiresEditView: Boolean = true
}

/**
* A setting that displays a text value and triggers an action when clicked.
*
* Unlike [Text], this setting does not require an edit view. Instead,
* the entire setting item acts as a clickable action that can be used
* for navigation, opening dialogs, launching pickers, or performing
* custom actions.
*
* @param id The unique identifier for the setting.
* @param title A lambda that returns the title of the setting.
* @param description A lambda that returns the description of the setting. Default is null.
* @param icon A lambda that returns the icon of the setting as an [ImageVector]. Default is null.
* @param value The current text value displayed by the setting.
* @param onClick The action to invoke when the setting is clicked.
*/
data class ActionText(
override val id: String,
val title: () -> String,
val description: () -> String? = { null },
val icon: () -> ImageVector? = { null },
override val value: String,
val onClick: () -> Unit,
) : SettingValue<String> {
override val requiresEditView: Boolean = false
}

/**
* A setting that holds a color value.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.thunderbird.core.ui.setting.dialog.ui.components.list.value

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
import net.thunderbird.core.ui.setting.dialog.ui.fake.FakeSettingData

@Composable
@Preview(showBackground = true)
internal fun ActionTextItemPreview() {
PreviewWithThemes {
ActionTextItem(
setting = FakeSettingData.actionText,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ internal object FakeSettingData {
value = "Value",
)

val actionText = SettingValue.ActionText(
id = "text",
icon = { Icons.Outlined.Delete },
title = { "Title" },
description = { "Description" },
value = "Value",
onClick = {},
)

val color = SettingValue.Color(
id = "color",
icon = { Icons.Outlined.Delete },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internal fun SettingDialog(
is SettingValue.IconList,
is SettingValue.SegmentedButton<*>,
is SettingValue.Switch,
is SettingValue.ActionText,
-> Unit
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import net.thunderbird.core.ui.setting.SettingValue
import net.thunderbird.core.ui.setting.dialog.ui.components.list.decoration.CustomItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.decoration.SectionDividerItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.decoration.SectionHeaderItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.value.ActionTextItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.value.ColorItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.value.IconListItem
import net.thunderbird.core.ui.setting.dialog.ui.components.list.value.SegmentedButtonItem
Expand Down Expand Up @@ -56,6 +57,13 @@ private fun RenderSettingValue(
)
}

is SettingValue.ActionText -> {
ActionTextItem(
setting = setting,
modifier = modifier,
)
}

is SettingValue.Color -> {
ColorItem(
setting = setting,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package net.thunderbird.core.ui.setting.dialog.ui.components.list.value

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyMedium
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium
import net.thunderbird.core.ui.setting.SettingValue
import net.thunderbird.core.ui.setting.component.list.item.SettingItemLayout

@Composable
internal fun ActionTextItem(
setting: SettingValue.ActionText,
modifier: Modifier = Modifier,
) {
SettingItemLayout(
onClick = setting.onClick,
icon = setting.icon(),
modifier = modifier,
) {
TextTitleMedium(text = setting.title())
TextBodyMedium(text = setting.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ sealed interface AccountSettingsRoute : Route {
}
}

@Serializable
data class FetchingMailSettings(val accountId: String) : AccountSettingsRoute {
override val basePath: String = BASE_PATH

override fun route(): String = "$basePath/$accountId"

companion object {
const val BASE_PATH = "$ACCOUNT_SETTINGS_BASE_PATH/fetching_mail"
}
}

@Serializable
data class AdvancedFetchingMailSettings(val accountId: String) : AccountSettingsRoute {
override val basePath: String = BASE_PATH

override fun route(): String = "$basePath/$accountId"

companion object {
const val BASE_PATH = "$ACCOUNT_SETTINGS_BASE_PATH/fetching_mail/advanced"
}
}

@Serializable
data class SearchSettings(val accountId: String) : AccountSettingsRoute {
override val basePath: String = BASE_PATH
Expand Down
2 changes: 2 additions & 0 deletions feature/account/settings/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ dependencies {

implementation(libs.uri)

implementation(projects.feature.launcher)

debugImplementation(projects.core.ui.setting.implDialog)

testImplementation(projects.core.logging.testing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ import net.thunderbird.feature.account.settings.impl.domain.usecase.GetAccountNa
import net.thunderbird.feature.account.settings.impl.domain.usecase.GetAccountProfile
import net.thunderbird.feature.account.settings.impl.domain.usecase.GetLegacyAccount
import net.thunderbird.feature.account.settings.impl.domain.usecase.UpdateAvatarImage
import net.thunderbird.feature.account.settings.impl.domain.usecase.UpdateFetchingMailSettings
import net.thunderbird.feature.account.settings.impl.domain.usecase.UpdateGeneralSettings
import net.thunderbird.feature.account.settings.impl.domain.usecase.UpdateReadEmailSettings
import net.thunderbird.feature.account.settings.impl.domain.usecase.UpdateSearchSettings
import net.thunderbird.feature.account.settings.impl.domain.usecase.ValidateAccountName
import net.thunderbird.feature.account.settings.impl.domain.usecase.ValidateAvatarMonogram
import net.thunderbird.feature.account.settings.impl.ui.fetchingMail.FetchingMailSettingsBuilder
import net.thunderbird.feature.account.settings.impl.ui.fetchingMail.FetchingMailSettingsContract
import net.thunderbird.feature.account.settings.impl.ui.fetchingMail.FetchingMailSettingsViewModel
import net.thunderbird.feature.account.settings.impl.ui.general.GeneralSettingsBuilder
import net.thunderbird.feature.account.settings.impl.ui.general.GeneralSettingsContract
import net.thunderbird.feature.account.settings.impl.ui.general.GeneralSettingsValidator
Expand Down Expand Up @@ -43,6 +47,12 @@ val featureAccountSettingsModule = module {
)
}

factory<UseCase.UpdateFetchingMailSettings> {
UpdateFetchingMailSettings(
repository = get(),
)
}

factory<UseCase.UpdateSearchSettings> {
UpdateSearchSettings(
repository = get(),
Expand Down Expand Up @@ -109,6 +119,12 @@ val featureAccountSettingsModule = module {
)
}

factory<FetchingMailSettingsContract.SettingsBuilder> {
FetchingMailSettingsBuilder(
resources = get<StringsResourceManager>(),
)
}

factory<SearchSettingsContract.SettingsBuilder> {
SearchSettingBuilder(
resources = get<StringsResourceManager>(),
Expand All @@ -126,6 +142,17 @@ val featureAccountSettingsModule = module {
)
}

viewModel { params ->
FetchingMailSettingsViewModel(
accountId = params.get(),
resources = get(),
logger = get(),
getAccountName = get(),
getLegacyAccount = get(),
updateFetchingMailSettings = get(),
)
}

viewModel { params ->
SearchSettingsViewModel(
accountId = params.get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import net.thunderbird.core.ui.navigation.deepLinkComposable
import net.thunderbird.feature.account.AccountIdFactory
import net.thunderbird.feature.account.settings.api.AccountSettingsNavigation
import net.thunderbird.feature.account.settings.api.AccountSettingsRoute
import net.thunderbird.feature.account.settings.impl.ui.fetchingMail.FetchingMailSettingsScreen
import net.thunderbird.feature.account.settings.impl.ui.fetchingMail.advanced.AdvancedFetchingMailSettingsScreen
import net.thunderbird.feature.account.settings.impl.ui.general.GeneralSettingsScreen
import net.thunderbird.feature.account.settings.impl.ui.readingMail.ReadingMailSettingsScreen
import net.thunderbird.feature.account.settings.impl.ui.search.SearchSettingsScreen

internal class DefaultAccountSettingsNavigation : AccountSettingsNavigation {

@Suppress("LongMethod")
override fun registerRoutes(
navGraphBuilder: NavGraphBuilder,
onBack: () -> Unit,
Expand Down Expand Up @@ -45,6 +48,35 @@ internal class DefaultAccountSettingsNavigation : AccountSettingsNavigation {
}
}

with(navGraphBuilder) {
deepLinkComposable<AccountSettingsRoute.FetchingMailSettings>(
basePath = AccountSettingsRoute.FetchingMailSettings.BASE_PATH,
) { backStackEntry ->
val fetchingMailSettingsRoute = backStackEntry.toRoute<AccountSettingsRoute.FetchingMailSettings>()
val accountId = AccountIdFactory.of(fetchingMailSettingsRoute.accountId)

FetchingMailSettingsScreen(
accountId = accountId,
onBack = onBack,
)
}
}

with(navGraphBuilder) {
deepLinkComposable<AccountSettingsRoute.AdvancedFetchingMailSettings>(
basePath = AccountSettingsRoute.AdvancedFetchingMailSettings.BASE_PATH,
) { backStackEntry ->
val advancedFetchingMailSettingsRoute =
backStackEntry.toRoute<AccountSettingsRoute.AdvancedFetchingMailSettings>()
val accountId = AccountIdFactory.of(advancedFetchingMailSettingsRoute.accountId)

AdvancedFetchingMailSettingsScreen(
accountId = accountId,
onBack = onBack,
)
}
}

with(navGraphBuilder) {
deepLinkComposable<AccountSettingsRoute.SearchSettings>(
basePath = AccountSettingsRoute.SearchSettings.Companion.BASE_PATH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ internal interface AccountSettingsDomainContract {
): Outcome<Unit, AccountSettingError>
}

fun interface UpdateFetchingMailSettings {
suspend operator fun invoke(
accountId: AccountId,
command: UpdateFetchingMailSettingsCommand,
): Outcome<Unit, AccountSettingError>
}

fun interface UpdateAvatarImage {
suspend operator fun invoke(
accountId: AccountId,
Expand Down Expand Up @@ -76,6 +83,19 @@ internal interface AccountSettingsDomainContract {
data class UpdateServerSearchLimit(val value: Int) : UpdateSearchSettingsCommand
}

sealed interface UpdateFetchingMailSettingsCommand {
data class UpdateLocalFolderSize(val value: Int) : UpdateFetchingMailSettingsCommand
data class UpdateSyncMessageFrom(val value: Int) : UpdateFetchingMailSettingsCommand
data class UpdateFetchMessageUpTo(val value: Int) : UpdateFetchingMailSettingsCommand
data class UpdateFolderPollFrequency(val value: Int) : UpdateFetchingMailSettingsCommand
data class UpdateSyncServerDeletions(val value: Boolean) : UpdateFetchingMailSettingsCommand
data class UpdateMarkAsReadWhenDeleted(val value: Boolean) : UpdateFetchingMailSettingsCommand
data class UpdateWhenIDeleteAMessage(val value: String) : UpdateFetchingMailSettingsCommand
data class UpdateEraseDeletedMessageOnServer(val value: String) : UpdateFetchingMailSettingsCommand
data class UpdateOnMaxFolderToCheckWithPushChange(val value: Int) : UpdateFetchingMailSettingsCommand
data class UpdateRefreshIdleConnectionFrequencyChange(val value: Int) : UpdateFetchingMailSettingsCommand
}

sealed interface AccountSettingError {
data class NotFound(
val message: String,
Expand Down
Loading
Loading