From e1d56f1868d1be0f77797c0dad943be21e4fc843 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Thu, 2 Jul 2026 16:58:05 -0500 Subject: [PATCH] feat(settings): reorder top-level settings sections and add appearance subtext Reorders SettingsScreen's top-level (non-Advanced) sections per #158: Accounts, Message downloading, Contacts, Appearance, Settings Backup, Notifications, Storage on this device, then a header-less trailing Report a Problem row (mirrors AccountSettingsScreen's headerless "Remove account" row now that Diagnostics is down to one item). - Move "Message downloading" up to directly follow Accounts. - Add a two-line descriptive subtext under the Appearance header ("Match device theme" / "Material You theming (Android 12+)"); no new toggle, since LibreMailTheme already always follows the system light/dark setting via isSystemInDarkTheme(). - Rename settings_backup "Backup" -> "Settings Backup" and settings_new_mail "New-mail notifications" -> "New mail notifications" (drop hyphen). - Drop the now-single-item settings_diagnostics header string; keep Contacts positioned directly before Appearance (its prior relative spot), per the ticket's suggested safest default for the unresolved placement question. Advanced's internal order is untouched (out of scope; tracked by #162). Closes #158 Co-Authored-By: Claude Opus 4.8 --- .../libremail/ui/settings/SettingsScreen.kt | 87 ++++++++++--------- app/src/main/res/values/strings.xml | 6 +- 2 files changed, 50 insertions(+), 43 deletions(-) diff --git a/app/src/main/kotlin/org/libremail/ui/settings/SettingsScreen.kt b/app/src/main/kotlin/org/libremail/ui/settings/SettingsScreen.kt index da70170..9a7cdd8 100644 --- a/app/src/main/kotlin/org/libremail/ui/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/org/libremail/ui/settings/SettingsScreen.kt @@ -132,41 +132,6 @@ fun SettingsScreen( ClickRow(title = stringResource(R.string.settings_add_account), onClick = onAddAccount) HorizontalDivider() - SectionHeader(stringResource(R.string.settings_notifications)) - SwitchRow( - title = stringResource(R.string.settings_new_mail), - checked = settings.newMailNotifications, - onCheckedChange = viewModel::setNewMailNotifications, - subtitle = stringResource(R.string.settings_new_mail_summary), - ) - HorizontalDivider() - - SectionHeader(stringResource(R.string.settings_contacts)) - ContactAutocompleteRow( - state = contactsState, - onClick = { - when (contactsState) { - // Already on: send to system settings, the only place to turn it back off. - ContactPermissionState.GRANTED -> - runCatching { context.startActivity(viewModel.contactsSettingsIntent()) } - // Re-requestable in-app: explain first (#128), then launch the system dialog. - ContactPermissionState.DENIED -> showContactsRationale = true - // Permanently denied: an in-app request is a no-op, so deep-link to settings. - ContactPermissionState.BLOCKED -> showContactsBlocked = true - } - }, - ) - HorizontalDivider() - - SectionHeader(stringResource(R.string.settings_appearance)) - SwitchRow( - title = stringResource(R.string.settings_dynamic_color), - checked = settings.dynamicColor, - onCheckedChange = viewModel::setDynamicColor, - subtitle = stringResource(R.string.settings_dynamic_color_summary), - ) - HorizontalDivider() - SectionHeader(stringResource(R.string.settings_downloading)) RadioRow( title = stringResource(R.string.fetch_always), @@ -188,11 +153,35 @@ fun SettingsScreen( ) HorizontalDivider() - SectionHeader(stringResource(R.string.settings_diagnostics)) - ClickRow( - title = stringResource(R.string.settings_report_problem), - subtitle = stringResource(R.string.settings_report_problem_summary), - onClick = onReportProblem, + SectionHeader(stringResource(R.string.settings_contacts)) + ContactAutocompleteRow( + state = contactsState, + onClick = { + when (contactsState) { + // Already on: send to system settings, the only place to turn it back off. + ContactPermissionState.GRANTED -> + runCatching { context.startActivity(viewModel.contactsSettingsIntent()) } + // Re-requestable in-app: explain first (#128), then launch the system dialog. + ContactPermissionState.DENIED -> showContactsRationale = true + // Permanently denied: an in-app request is a no-op, so deep-link to settings. + ContactPermissionState.BLOCKED -> showContactsBlocked = true + } + }, + ) + HorizontalDivider() + + SectionHeader(stringResource(R.string.settings_appearance)) + Text( + text = stringResource(R.string.settings_appearance_summary), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = 16.dp), + ) + SwitchRow( + title = stringResource(R.string.settings_dynamic_color), + checked = settings.dynamicColor, + onCheckedChange = viewModel::setDynamicColor, + subtitle = stringResource(R.string.settings_dynamic_color_summary), ) HorizontalDivider() @@ -205,6 +194,15 @@ fun SettingsScreen( ) HorizontalDivider() + SectionHeader(stringResource(R.string.settings_notifications)) + SwitchRow( + title = stringResource(R.string.settings_new_mail), + checked = settings.newMailNotifications, + onCheckedChange = viewModel::setNewMailNotifications, + subtitle = stringResource(R.string.settings_new_mail_summary), + ) + HorizontalDivider() + // Global device-only retention default (issue #13); accounts may override it. RetentionSection( count = settings.retentionCount, @@ -215,6 +213,15 @@ fun SettingsScreen( ) HorizontalDivider() + // Standalone trailing action, no section header — matches AccountSettingsScreen's + // "Remove account" row; self-explanatory as the last item in the list (#158). + ClickRow( + title = stringResource(R.string.settings_report_problem), + subtitle = stringResource(R.string.settings_report_problem_summary), + onClick = onReportProblem, + ) + HorizontalDivider() + AdvancedHeader(expanded = advancedExpanded, onToggle = viewModel::toggleAdvanced) AnimatedVisibility(visible = advancedExpanded) { Column { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df95327..9001283 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -224,13 +224,13 @@ Always on-demand Sync only message headers; download a message\'s content when you open it. Notifications - New-mail notifications + New mail notifications Show a notification when new mail arrives No accounts yet Remove account - Backup + Settings Backup Include settings in Android Backup Let Android back up your LibreMail preferences (Google Auto Backup) so they restore when you set up a new device. Your mail, accounts, passwords, and encryption keys are never backed up — only app settings. Off by default; uses Google infrastructure. @@ -278,6 +278,7 @@ Sound & vibration Manage sound, vibration, and importance in Android settings Appearance + Match device theme\nMaterial You theming (Android 12+) Use wallpaper colors Material You dynamic theming (Android 12+) Add account @@ -319,7 +320,6 @@ Open settings - Diagnostics Report a problem Capture diagnostics you can review and optionally send Problem reports