diff --git a/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/history/ChangelogE2ETest.kt b/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/history/ChangelogE2ETest.kt
index 321ac34..3599919 100644
--- a/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/history/ChangelogE2ETest.kt
+++ b/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/history/ChangelogE2ETest.kt
@@ -12,7 +12,7 @@ import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
-import androidx.compose.ui.test.performScrollToIndex
+import androidx.compose.ui.test.performScrollToKey
import com.google.common.truth.Truth
import com.serranoie.app.minus.R
import com.serranoie.app.minus.domain.model.PeriodMappingMode
@@ -95,6 +95,8 @@ class ChangelogE2ETest {
onNotificationTimeChange = { _, _ -> },
onRecurrentNotificationTimeChange = { _, _ -> },
onOpenExactAlarmSettings = {},
+ notificationPermissionGranted = true,
+ onOpenNotificationSettings = {},
periodMappingMode = PeriodMappingMode.ACTIVE_BUDGET,
onPeriodMappingModeChange = {},
onExportCsv = {},
@@ -137,20 +139,6 @@ class ChangelogE2ETest {
private fun closeContentDesc(): String =
composeTestRule.activity.getString(R.string.changelog_close)
- @Test
- fun when_settings_is_displayed_then_what_is_new_item_is_visible() {
- setSettingsContent()
- composeTestRule.waitForIdle()
- composeTestRule.mainClock.advanceTimeBy(500)
- composeTestRule.waitForIdle()
-
- composeTestRule.onNodeWithTag("SettingsScreen").performScrollToIndex(Int.MAX_VALUE)
- composeTestRule.waitForIdle()
-
- composeTestRule.onAllNodesWithText(whatsNewTitle()).onFirst().assertIsDisplayed()
- composeTestRule.onAllNodesWithText(whatsNewSubtitle()).onFirst().assertIsDisplayed()
- }
-
@Test
fun when_tapping_what_is_new_then_onNavigateToChangelog_callback_fires() {
var navigatedCount = 0
@@ -159,7 +147,8 @@ class ChangelogE2ETest {
composeTestRule.mainClock.advanceTimeBy(500)
composeTestRule.waitForIdle()
- composeTestRule.onNodeWithTag("SettingsScreen").performScrollToIndex(Int.MAX_VALUE)
+ composeTestRule.onNodeWithTag("SettingsScreen")
+ .performScrollToKey("settings_app_info_section")
composeTestRule.waitForIdle()
composeTestRule.onAllNodesWithText(whatsNewTitle()).onFirst().performClick()
@@ -306,7 +295,8 @@ class ChangelogE2ETest {
composeTestRule.mainClock.advanceTimeBy(500)
composeTestRule.waitForIdle()
- composeTestRule.onNodeWithTag("SettingsScreen").performScrollToIndex(Int.MAX_VALUE)
+ composeTestRule.onNodeWithTag("SettingsScreen")
+ .performScrollToKey("settings_app_info_section")
composeTestRule.waitForIdle()
composeTestRule.onAllNodesWithText(whatsNewTitle()).assertCountEquals(1)
diff --git a/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/home/MainScreenE2ETest.kt b/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/home/MainScreenE2ETest.kt
index 49d2e45..898129c 100644
--- a/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/home/MainScreenE2ETest.kt
+++ b/app/src/androidTest/java/com/serranoie/app/minus/presentation/ui/e2e/home/MainScreenE2ETest.kt
@@ -235,7 +235,9 @@ class MainScreenE2ETest {
onDelete = { capturedIntents += "Delete" },
onApply = { capturedIntents += "Apply" },
onOperatorInput = { capturedIntents += "Operator:$it" },
- modifier = Modifier.fillMaxSize().height(400.dp),
+ modifier = Modifier
+ .fillMaxSize()
+ .height(400.dp),
)
}
}
@@ -333,7 +335,8 @@ class MainScreenE2ETest {
animState = AnimState.EDITING,
)
- composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("123"))).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("123"))).onLast()
+ .assertIsDisplayed()
}
@Test
@@ -401,7 +404,8 @@ class MainScreenE2ETest {
budgetSettings = sampleBudgetSettings(totalBudget = BigDecimal("500.00")),
)
- composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("500.00"))).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("500.00"))).onLast()
+ .assertIsDisplayed()
}
@Test
@@ -417,7 +421,8 @@ class MainScreenE2ETest {
budgetSettings = sampleBudgetSettings(totalBudget = BigDecimal("500.00")),
)
- composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("450.00"))).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("450.00"))).onLast()
+ .assertIsDisplayed()
}
@Test
@@ -437,7 +442,8 @@ class MainScreenE2ETest {
viewPeriod = BudgetPeriod.WEEKLY,
)
- composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("700.00"))).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("700.00"))).onLast()
+ .assertIsDisplayed()
}
@Test
@@ -556,7 +562,8 @@ class MainScreenE2ETest {
animState = AnimState.EDITING,
)
- composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("123"))).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(formatExpected(BigDecimal("123"))).onLast()
+ .assertIsDisplayed()
composeTestRule.onAllNodesWithText("1", substring = true).onLast().assertIsDisplayed()
composeTestRule.onAllNodesWithText("2", substring = true).onLast().assertIsDisplayed()
composeTestRule.onAllNodesWithText("3", substring = true).onLast().assertIsDisplayed()
@@ -700,6 +707,7 @@ class MainScreenE2ETest {
composeTestRule.mainClock.advanceTimeBy(300)
val totalBudgetLabel = composeTestRule.activity.getString(R.string.total_budget)
- composeTestRule.onAllNodesWithText(totalBudgetLabel, substring = true).onLast().assertIsDisplayed()
+ composeTestRule.onAllNodesWithText(totalBudgetLabel, substring = true).onLast()
+ .assertIsDisplayed()
}
}
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/Settings.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/Settings.kt
index 3598183..eda59ac 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/Settings.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/Settings.kt
@@ -2,13 +2,13 @@
package com.serranoie.app.minus.presentation.ui.settings
-import android.app.TimePickerDialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -26,6 +26,7 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.automirrored.filled.ViewList
import androidx.compose.material.icons.filled.AccessTime
import androidx.compose.material.icons.filled.Alarm
+import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.filled.Backup
import androidx.compose.material.icons.filled.Brightness4
import androidx.compose.material.icons.filled.BugReport
@@ -40,7 +41,6 @@ import androidx.compose.material.icons.filled.Publish
import androidx.compose.material.icons.filled.QuestionMark
import androidx.compose.material.icons.filled.Repeat
import androidx.compose.material.icons.filled.TextFields
-import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.outlined.RemoveRedEye
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -59,10 +59,12 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.material3.TimePicker
import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.rememberTimePickerState
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -87,6 +89,7 @@ import com.serranoie.app.minus.R
import com.serranoie.app.minus.domain.model.PeriodMappingMode
import com.serranoie.app.minus.presentation.ui.history.RecurrentPaymentsViewMode
import com.serranoie.app.minus.presentation.ui.settings.bugreport.buildAppEnvironmentMetadata
+import com.serranoie.app.minus.presentation.ui.settings.components.NotificationPermissionItem
import com.serranoie.app.minus.presentation.ui.theme.MinusTheme
import com.serranoie.app.minus.presentation.ui.theme.bodySmallCondensed
import com.serranoie.app.minus.presentation.ui.theme.component.CustomPaddedExpandableItem
@@ -105,1030 +108,1114 @@ import java.util.Locale
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun Settings(
- modifier: Modifier = Modifier,
- isCensored: Boolean = false,
- currentTheme: String,
- currentTypography: String,
- isMaterialYouEnabled: Boolean,
- isCreditQuickToggleFeatureEnabled: Boolean,
- recurrentPaymentsViewMode: RecurrentPaymentsViewMode,
- notificationHour: Int,
- notificationMinute: Int,
- recurrentNotificationHour: Int,
- recurrentNotificationMinute: Int,
- exactAlarmEnabled: Boolean,
- onThemeChange: (String) -> Unit,
- onTypographyChange: (String) -> Unit,
- onMaterialYouToggle: () -> Unit,
- onCreditQuickToggleFeatureToggle: () -> Unit,
- onRecurrentPaymentsViewModeChange: (RecurrentPaymentsViewMode) -> Unit,
- onNotificationTimeChange: (Int, Int) -> Unit,
- onRecurrentNotificationTimeChange: (Int, Int) -> Unit,
- onOpenExactAlarmSettings: () -> Unit,
- periodMappingMode: PeriodMappingMode,
- onPeriodMappingModeChange: (PeriodMappingMode) -> Unit,
- onExportCsv: () -> Unit = {},
- onImportCsv: () -> Unit = {},
- onResetTutorial: () -> Unit = {},
- onBugReportClick: () -> Unit = {},
- onNavigateToChangelog: () -> Unit = {},
- onBack: () -> Unit = {},
+ modifier: Modifier = Modifier,
+ isCensored: Boolean = false,
+ currentTheme: String,
+ currentTypography: String,
+ isMaterialYouEnabled: Boolean,
+ isCreditQuickToggleFeatureEnabled: Boolean,
+ recurrentPaymentsViewMode: RecurrentPaymentsViewMode,
+ notificationHour: Int,
+ notificationMinute: Int,
+ recurrentNotificationHour: Int,
+ recurrentNotificationMinute: Int,
+ exactAlarmEnabled: Boolean,
+ notificationPermissionGranted: Boolean,
+ onThemeChange: (String) -> Unit,
+ onTypographyChange: (String) -> Unit,
+ onMaterialYouToggle: () -> Unit,
+ onCreditQuickToggleFeatureToggle: () -> Unit,
+ onRecurrentPaymentsViewModeChange: (RecurrentPaymentsViewMode) -> Unit,
+ onNotificationTimeChange: (Int, Int) -> Unit,
+ onRecurrentNotificationTimeChange: (Int, Int) -> Unit,
+ onOpenExactAlarmSettings: () -> Unit,
+ onOpenNotificationSettings: () -> Unit,
+ periodMappingMode: PeriodMappingMode,
+ onPeriodMappingModeChange: (PeriodMappingMode) -> Unit,
+ onExportCsv: () -> Unit = {},
+ onImportCsv: () -> Unit = {},
+ onResetTutorial: () -> Unit = {},
+ onBugReportClick: () -> Unit = {},
+ onNavigateToChangelog: () -> Unit = {},
+ onBack: () -> Unit = {},
) {
- var showThemeDialog by remember { mutableStateOf(false) }
- var showTypographyDialog by remember { mutableStateOf(false) }
- var showRecurrentPaymentsViewModeDialog by remember { mutableStateOf(false) }
- var showNotificationTimePicker by remember { mutableStateOf(false) }
- var showRecurrentNotificationTimePicker by remember { mutableStateOf(false) }
- var isCreditFeatureExpanded by remember { mutableStateOf(false) }
- val dismissThemeDialog = { showThemeDialog = false }
- val dismissTypographyDialog = { showTypographyDialog = false }
- val dismissRecurrentPaymentsViewModeDialog = { showRecurrentPaymentsViewModeDialog = false }
- val dismissNotificationTimePicker = { showNotificationTimePicker = false }
- val dismissRecurrentNotificationTimePicker = { showRecurrentNotificationTimePicker = false }
- val scrollBehavior =
- TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
- val context = LocalContext.current
- val view = LocalView.current
- val snackbarHostState = remember { SnackbarHostState() }
- val coroutineScope = rememberCoroutineScope()
- val appVersionName = "v${BuildConfig.VERSION_NAME}"
- val metadataCopiedMessage = stringResource(R.string.settings_version_metadata_copied)
+ var showThemeDialog by remember { mutableStateOf(false) }
+ var showTypographyDialog by remember { mutableStateOf(false) }
+ var showRecurrentPaymentsViewModeDialog by remember { mutableStateOf(false) }
+ var showNotificationTimePicker by remember { mutableStateOf(false) }
+ var showRecurrentNotificationTimePicker by remember { mutableStateOf(false) }
+ var isCreditFeatureExpanded by remember { mutableStateOf(false) }
+ val dismissThemeDialog = { showThemeDialog = false }
+ val dismissTypographyDialog = { showTypographyDialog = false }
+ val dismissRecurrentPaymentsViewModeDialog = { showRecurrentPaymentsViewModeDialog = false }
+ val dismissNotificationTimePicker = { showNotificationTimePicker = false }
+ val dismissRecurrentNotificationTimePicker = { showRecurrentNotificationTimePicker = false }
+ val scrollBehavior =
+ TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
+ val context = LocalContext.current
+ val view = LocalView.current
+ val snackbarHostState = remember { SnackbarHostState() }
+ val coroutineScope = rememberCoroutineScope()
+ val appVersionName = "v${BuildConfig.VERSION_NAME}"
+ val metadataCopiedMessage = stringResource(R.string.settings_version_metadata_copied)
- Scaffold(
- modifier = modifier
- .nestedScroll(scrollBehavior.nestedScrollConnection),
- snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
- topBar = {
- MediumTopAppBar(
- title = {
- Text(
- text = stringResource(R.string.settings_title),
- style = MaterialTheme.typography.titleLargeEmphasized,
- )
- }, navigationIcon = {
- IconButton(
- onClick = onBack, modifier = Modifier.testTag("SettingsBackButton")
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowBack,
- contentDescription = null
- )
- }
- }, colors = TopAppBarDefaults.topAppBarColors(
- containerColor = MaterialTheme.colorScheme.surface,
- titleContentColor = MaterialTheme.colorScheme.onSurface
- ), scrollBehavior = scrollBehavior
- )
- }) { paddingValues ->
- LazyColumn(
- modifier = Modifier
- .fillMaxSize()
- .padding(paddingValues)
- .testTag("SettingsScreen"),
- ) {
- if (isCensored) {
- item {
- OutlinedCard(
- modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 16.dp, vertical = 8.dp),
- shape = MaterialTheme.shapes.large,
- border = BorderStroke(
- 1.dp,
- MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
- ),
- colors = CardDefaults.outlinedCardColors(
- containerColor = Color.Transparent
- ),
- ) {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .padding(horizontal = 12.dp, vertical = 14.dp),
- ) {
- Row(verticalAlignment = Alignment.CenterVertically) {
- Icon(
- imageVector = Icons.Outlined.RemoveRedEye,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.outline,
- modifier = Modifier.size(20.dp)
- )
- Spacer(modifier = Modifier.width(8.dp))
- Text(
- text = stringResource(R.string.censor_mode_card_label),
- style = MaterialTheme.typography.bodySmallCondensed,
- color = MaterialTheme.colorScheme.outline,
- )
- }
- Text(
- text = stringResource(R.string.censor_mode_card_body),
- modifier = Modifier.padding(top = 4.dp),
- style = MaterialTheme.typography.bodySmallCondensed,
- color = MaterialTheme.colorScheme.onSurface,
- )
- }
- }
- }
- }
- item {
- PaddedListGroup(
- title = stringResource(R.string.settings_section_appearance)
- ) {
- CustomPaddedListItem(
- onClick = {
- showThemeDialog = true
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.First,
- modifier = Modifier.testTag("SettingsThemeItem")
- ) {
- Icon(
- imageVector = Icons.Default.Brightness4,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Spacer(modifier = Modifier.width(16.dp))
+ Scaffold(
+ modifier = modifier
+ .nestedScroll(scrollBehavior.nestedScrollConnection),
+ snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
+ topBar = {
+ MediumTopAppBar(
+ title = {
+ Text(
+ text = stringResource(R.string.settings_title),
+ style = MaterialTheme.typography.titleLargeEmphasized,
+ )
+ },
+ navigationIcon = {
+ IconButton(
+ onClick = onBack,
+ modifier = Modifier.testTag("SettingsBackButton")
+ ) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = null
+ )
+ }
+ },
+ colors = TopAppBarDefaults.topAppBarColors(
+ containerColor = MaterialTheme.colorScheme.surface,
+ titleContentColor = MaterialTheme.colorScheme.onSurface
+ ),
+ scrollBehavior = scrollBehavior
+ )
+ }
+ ) { paddingValues ->
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ .testTag("SettingsScreen"),
+ ) {
+ if (isCensored) {
+ item {
+ OutlinedCard(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 8.dp),
+ shape = MaterialTheme.shapes.large,
+ border = BorderStroke(
+ 1.dp,
+ MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
+ ),
+ colors = CardDefaults.outlinedCardColors(
+ containerColor = Color.Transparent
+ ),
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 12.dp, vertical = 14.dp),
+ ) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Icon(
+ imageVector = Icons.Outlined.RemoveRedEye,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.outline,
+ modifier = Modifier.size(20.dp)
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(
+ text = stringResource(R.string.censor_mode_card_label),
+ style = MaterialTheme.typography.bodySmallCondensed,
+ color = MaterialTheme.colorScheme.outline,
+ )
+ }
+ Text(
+ text = stringResource(R.string.censor_mode_card_body),
+ modifier = Modifier.padding(top = 4.dp),
+ style = MaterialTheme.typography.bodySmallCondensed,
+ color = MaterialTheme.colorScheme.onSurface,
+ )
+ }
+ }
+ }
+ }
+ item {
+ PaddedListGroup(
+ title = stringResource(R.string.settings_section_appearance)
+ ) {
+ CustomPaddedListItem(
+ onClick = {
+ showThemeDialog = true
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.First,
+ modifier = Modifier.testTag("SettingsThemeItem")
+ ) {
+ Icon(
+ imageVector = Icons.Default.Brightness4,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Spacer(modifier = Modifier.width(16.dp))
- Text(
- text = stringResource(R.string.settings_theme_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_theme_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Text(
- text = currentTheme,
- style = MaterialTheme.typography.labelLargeCondensed,
- color = MaterialTheme.colorScheme.primary
- )
- }
+ Text(
+ text = stringResource(R.string.settings_theme_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_theme_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Text(
+ text = currentTheme,
+ style = MaterialTheme.typography.labelLargeCondensed,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
- CustomPaddedListItem(
- onClick = {
- showTypographyDialog = true
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.Middle,
- modifier = Modifier.testTag("SettingsTypoItem")
- ) {
- Icon(
- imageVector = Icons.Default.TextFields,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
+ CustomPaddedListItem(
+ onClick = {
+ showTypographyDialog = true
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Middle,
+ modifier = Modifier.testTag("SettingsTypoItem")
+ ) {
+ Icon(
+ imageVector = Icons.Default.TextFields,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Spacer(modifier = Modifier.width(16.dp))
- Text(
- text = stringResource(R.string.settings_typography_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_typography_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Text(
- text = currentTypography,
- style = MaterialTheme.typography.labelLargeCondensed,
- color = MaterialTheme.colorScheme.primary
- )
- }
+ Text(
+ text = stringResource(R.string.settings_typography_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_typography_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Text(
+ text = currentTypography,
+ style = MaterialTheme.typography.labelLargeCondensed,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
- CustomPaddedListItem(
- onClick = onMaterialYouToggle,
- position = PaddedListItemPosition.Last,
- modifier = Modifier.testTag("SettingsMaterialYouItem")
- ) {
- Icon(
- imageVector = Icons.Default.Palette,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_material_you_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_material_you_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.padding(end = 4.dp)
- )
- }
- Switch(
- checked = isMaterialYouEnabled, onCheckedChange = {
- onMaterialYouToggle()
-// view.toggleFeedback()
- }, modifier = Modifier.testTag("SettingsMaterialYouSwitch")
- )
- }
- }
- }
+ CustomPaddedListItem(
+ onClick = onMaterialYouToggle,
+ position = PaddedListItemPosition.Last,
+ modifier = Modifier.testTag("SettingsMaterialYouItem")
+ ) {
+ Icon(
+ imageVector = Icons.Default.Palette,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_material_you_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_material_you_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.padding(end = 4.dp)
+ )
+ }
+ Switch(
+ checked = isMaterialYouEnabled,
+ onCheckedChange = {
+ onMaterialYouToggle()
+// view.toggleFeedback()
+ },
+ modifier = Modifier.testTag("SettingsMaterialYouSwitch")
+ )
+ }
+ }
+ }
- item {
- PaddedListGroup(
- title = stringResource(R.string.settings_section_features)
- ) {
- CustomPaddedExpandableItem(
- isExpanded = isCreditFeatureExpanded,
- onToggleExpanded = { isCreditFeatureExpanded = !isCreditFeatureExpanded },
- position = PaddedListItemPosition.First,
- modifier = Modifier.testTag("SettingsCreditQuickToggleFeatureItem"),
- defaultContent = {
- Icon(
- imageVector = Icons.Default.CreditCard,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_feature_credit_toggle_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_feature_credit_toggle_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Icon(
- imageVector = if (isCreditFeatureExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant
- )
- },
- expandedContent = {
- Text(
- text = stringResource(R.string.settings_feature_credit_toggle_details),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp)
- )
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = 8.dp, start = 6.dp, end = 6.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.settings_feature_credit_toggle_switch_label),
- style = MaterialTheme.typography.bodyMedium,
- color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.weight(1f)
- )
- Switch(
- checked = isCreditQuickToggleFeatureEnabled,
- onCheckedChange = { onCreditQuickToggleFeatureToggle() },
- modifier = Modifier.testTag("SettingsCreditQuickToggleFeatureSwitch")
- )
- }
- }
- )
+ item {
+ PaddedListGroup(
+ title = stringResource(R.string.settings_section_features)
+ ) {
+ CustomPaddedExpandableItem(
+ isExpanded = isCreditFeatureExpanded,
+ onToggleExpanded = { isCreditFeatureExpanded = !isCreditFeatureExpanded },
+ position = PaddedListItemPosition.First,
+ modifier = Modifier.testTag("SettingsCreditQuickToggleFeatureItem"),
+ defaultContent = {
+ Icon(
+ imageVector = Icons.Default.CreditCard,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_feature_credit_toggle_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_feature_credit_toggle_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Icon(
+ imageVector = if (isCreditFeatureExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ },
+ expandedContent = {
+ Text(
+ text = stringResource(R.string.settings_feature_credit_toggle_details),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp)
+ )
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp, start = 6.dp, end = 6.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(R.string.settings_feature_credit_toggle_switch_label),
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurface,
+ modifier = Modifier.weight(1f)
+ )
+ Switch(
+ checked = isCreditQuickToggleFeatureEnabled,
+ onCheckedChange = { onCreditQuickToggleFeatureToggle() },
+ modifier = Modifier.testTag("SettingsCreditQuickToggleFeatureSwitch")
+ )
+ }
+ }
+ )
- CustomPaddedListItem(
- onClick = {
- showRecurrentPaymentsViewModeDialog = true
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.Last,
- modifier = Modifier.testTag("SettingsRecurrentPaymentsViewModeItem")
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ViewList,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_recurrent_payments_view_mode_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_recurrent_payments_view_mode_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Text(
- text = recurrentPaymentsViewMode.label(),
- style = MaterialTheme.typography.labelLargeCondensed,
- color = MaterialTheme.colorScheme.primary
- )
- }
- }
- }
+ CustomPaddedListItem(
+ onClick = {
+ showRecurrentPaymentsViewModeDialog = true
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Last,
+ modifier = Modifier.testTag("SettingsRecurrentPaymentsViewModeItem")
+ ) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ViewList,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_recurrent_payments_view_mode_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_recurrent_payments_view_mode_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Text(
+ text = recurrentPaymentsViewMode.label(),
+ style = MaterialTheme.typography.labelLargeCondensed,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
+ }
+ }
- item {
- PaddedListGroup(
- title = stringResource(R.string.settings_section_notifications)
- ) {
- CustomPaddedListItem(
- onClick = {
- showNotificationTimePicker = true
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.First,
- ) {
- Icon(
- imageVector = Icons.Default.AccessTime,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_period_end_time_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_period_end_time_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Text(
- text = formatNotificationTime(
- context, notificationHour, notificationMinute
- ),
- style = MaterialTheme.typography.labelLargeCondensed,
- color = MaterialTheme.colorScheme.primary
- )
- }
+ item {
+ PaddedListGroup(
+ title = stringResource(R.string.settings_section_notifications)
+ ) {
+ NotificationPermissionItem(
+ granted = notificationPermissionGranted,
+ onClick = onOpenNotificationSettings,
+ position = PaddedListItemPosition.First,
+ )
- CustomPaddedListItem(
- onClick = {
- showRecurrentNotificationTimePicker = true
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.Middle,
- ) {
- Icon(
- imageVector = Icons.Default.Repeat,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_recurrent_notification_time_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_recurrent_notification_time_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Text(
- text = formatNotificationTime(
- context, recurrentNotificationHour, recurrentNotificationMinute
- ),
- style = MaterialTheme.typography.labelLargeCondensed,
- color = MaterialTheme.colorScheme.primary
- )
- }
+ CustomPaddedListItem(
+ onClick = {
+ showNotificationTimePicker = true
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Middle,
+ ) {
+ Icon(
+ imageVector = Icons.Default.AccessTime,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_period_end_time_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_period_end_time_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Text(
+ text = formatNotificationTime(
+ context,
+ notificationHour,
+ notificationMinute
+ ),
+ style = MaterialTheme.typography.labelLargeCondensed,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
- CustomPaddedListItem(
- onClick = {
- onOpenExactAlarmSettings()
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.Last,
- ) {
- Icon(
- imageVector = Icons.Default.Alarm,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_exact_alarm_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = if (exactAlarmEnabled) {
- stringResource(R.string.settings_exact_alarm_enabled_subtitle)
- } else {
- stringResource(R.string.settings_exact_alarm_disabled_subtitle)
- },
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
- }
- }
+ CustomPaddedListItem(
+ onClick = {
+ showRecurrentNotificationTimePicker = true
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Middle,
+ ) {
+ Icon(
+ imageVector = Icons.Default.Repeat,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_recurrent_notification_time_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_recurrent_notification_time_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Text(
+ text = formatNotificationTime(
+ context,
+ recurrentNotificationHour,
+ recurrentNotificationMinute
+ ),
+ style = MaterialTheme.typography.labelLargeCondensed,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
- item {
- PaddedListGroup(
- title = stringResource(R.string.settings_section_data_backup)
- ) {
- CustomPaddedListItem(
- onClick = {
- onExportCsv()
- view.toggleFeedback()
- }, position = PaddedListItemPosition.First
- ) {
- Icon(
- imageVector = Icons.Default.Backup,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_backup_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_backup_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
+ CustomPaddedListItem(
+ onClick = {
+ onOpenExactAlarmSettings()
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Last,
+ borderStroke = if (!exactAlarmEnabled) {
+ BorderStroke(1.dp, MaterialTheme.colorScheme.error)
+ } else {
+ null
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.Alarm,
+ contentDescription = null,
+ tint = if (exactAlarmEnabled) {
+ MaterialTheme.colorScheme.primary
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_exact_alarm_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = if (exactAlarmEnabled) {
+ MaterialTheme.colorScheme.onSurface
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ Text(
+ text = if (exactAlarmEnabled) {
+ stringResource(R.string.settings_exact_alarm_enabled_subtitle)
+ } else {
+ stringResource(R.string.settings_exact_alarm_disabled_subtitle)
+ },
+ style = MaterialTheme.typography.bodySmall,
+ color = if (exactAlarmEnabled) {
+ MaterialTheme.colorScheme.onSurfaceVariant
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ }
+ }
+ }
+ }
- CustomPaddedListItem(
- onClick = {
- onImportCsv()
- view.toggleFeedback()
- }, position = PaddedListItemPosition.Last
- ) {
- Icon(
- imageVector = Icons.Default.Publish,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_import_csv_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_import_csv_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
- }
- }
+ item {
+ PaddedListGroup(
+ title = stringResource(R.string.settings_section_data_backup)
+ ) {
+ CustomPaddedListItem(
+ onClick = {
+ onExportCsv()
+ view.toggleFeedback()
+ },
+ position = PaddedListItemPosition.First
+ ) {
+ Icon(
+ imageVector = Icons.Default.Backup,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_backup_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_backup_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
- item {
- PaddedListGroup(
- title = stringResource(R.string.settings_section_app_info)
- ) {
- CustomPaddedListItem(
- onClick = {
- onNavigateToChangelog()
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.First,
- ) {
- Icon(
- imageVector = Icons.Default.AutoAwesome,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.changelog_settings_item_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(
- R.string.changelog_settings_item_subtitle,
- BuildConfig.VERSION_NAME,
- ),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- Icon(
- imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurfaceVariant,
- )
- }
+ CustomPaddedListItem(
+ onClick = {
+ onImportCsv()
+ view.toggleFeedback()
+ },
+ position = PaddedListItemPosition.Last
+ ) {
+ Icon(
+ imageVector = Icons.Default.Publish,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_import_csv_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_import_csv_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+ }
+ }
- CustomPaddedListItem(
- onClick = {
- Utils.openWebLink(context, "https://www.github.com/isaacsa51/Minus")
- view.weakHapticFeedback()
- }, position = PaddedListItemPosition.Middle
- ) {
- Icon(
- imageVector = Icons.Default.QuestionMark,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_about_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_about_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
+ item(key = "settings_app_info_section") {
+ PaddedListGroup(
+ title = stringResource(R.string.settings_section_app_info)
+ ) {
+ CustomPaddedListItem(
+ onClick = {
+ onNavigateToChangelog()
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.First,
+ ) {
+ Icon(
+ imageVector = Icons.Default.AutoAwesome,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.changelog_settings_item_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(
+ R.string.changelog_settings_item_subtitle,
+ BuildConfig.VERSION_NAME,
+ ),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
- CustomPaddedListItem(
- onClick = {
- onBugReportClick()
- view.weakHapticFeedback()
- }, position = PaddedListItemPosition.Middle
- ) {
- Icon(
- imageVector = Icons.Default.BugReport,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_bug_report_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = stringResource(R.string.settings_bug_report_subtitle),
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
+ CustomPaddedListItem(
+ onClick = {
+ Utils.openWebLink(context, "https://www.github.com/isaacsa51/Minus")
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Middle
+ ) {
+ Icon(
+ imageVector = Icons.Default.QuestionMark,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_about_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_about_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+ CustomPaddedListItem(
+ onClick = {
+ onBugReportClick()
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Middle
+ ) {
+ Icon(
+ imageVector = Icons.Default.BugReport,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_bug_report_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = stringResource(R.string.settings_bug_report_subtitle),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
- CustomPaddedListItem(
- onClick = {
- view.weakHapticFeedback()
- },
- position = PaddedListItemPosition.Last,
- onLongClick = {
- context.copyAppEnvironmentMetadataToClipboard()
- view.toggleFeedback()
- coroutineScope.launch {
- snackbarHostState.showSnackbar(
- message = metadataCopiedMessage,
- duration = SnackbarDuration.Short,
- )
- }
- },
- ) {
- Icon(
- imageVector = Icons.Default.Info,
- contentDescription = null,
- tint = MaterialTheme.colorScheme.primary
- )
- Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = stringResource(R.string.settings_version_title),
- style = MaterialTheme.typography.bodyMediumEmphasized,
- color = MaterialTheme.colorScheme.onSurface
- )
- Text(
- text = appVersionName,
- style = MaterialTheme.typography.bodySmall,
- color = MaterialTheme.colorScheme.onSurfaceVariant
- )
- }
- }
- }
- }
+ CustomPaddedListItem(
+ onClick = {
+ view.weakHapticFeedback()
+ },
+ position = PaddedListItemPosition.Last,
+ onLongClick = {
+ context.copyAppEnvironmentMetadataToClipboard()
+ view.toggleFeedback()
+ coroutineScope.launch {
+ snackbarHostState.showSnackbar(
+ message = metadataCopiedMessage,
+ duration = SnackbarDuration.Short,
+ )
+ }
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.Info,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_version_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ Text(
+ text = appVersionName,
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+ }
+ }
//
-// item {
-// PaddedListGroup(
-// title = stringResource(R.string.settings_section_tutorial)
-// ) {
-// CustomPaddedListItem(
-// onClick = {
-// onResetTutorial()
-// view.toggleFeedback()
-// },
-// position = PaddedListItemPosition.Single,
-// modifier = Modifier.testTag("SettingsResetTutorialItem")
-// ) {
-// Icon(
-// imageVector = Icons.Default.Refresh,
-// contentDescription = null,
-// tint = MaterialTheme.colorScheme.primary
-// )
-// Spacer(modifier = Modifier.width(16.dp))
-// Column(modifier = Modifier.weight(1f)) {
-// Text(
-// text = stringResource(R.string.settings_reset_tutorial_title),
-// style = MaterialTheme.typography.bodyMediumEmphasized,
-// color = MaterialTheme.colorScheme.onSurface
-// )
-// Text(
-// text = stringResource(R.string.settings_reset_tutorial_subtitle),
-// style = MaterialTheme.typography.bodySmall,
-// color = MaterialTheme.colorScheme.onSurfaceVariant
-// )
-// }
-// }
-// }
-// }
- }
+// item {
+// PaddedListGroup(
+// title = stringResource(R.string.settings_section_tutorial)
+// ) {
+// CustomPaddedListItem(
+// onClick = {
+// onResetTutorial()
+// view.toggleFeedback()
+// },
+// position = PaddedListItemPosition.Single,
+// modifier = Modifier.testTag("SettingsResetTutorialItem")
+// ) {
+// Icon(
+// imageVector = Icons.Default.Refresh,
+// contentDescription = null,
+// tint = MaterialTheme.colorScheme.primary
+// )
+// Spacer(modifier = Modifier.width(16.dp))
+// Column(modifier = Modifier.weight(1f)) {
+// Text(
+// text = stringResource(R.string.settings_reset_tutorial_title),
+// style = MaterialTheme.typography.bodyMediumEmphasized,
+// color = MaterialTheme.colorScheme.onSurface
+// )
+// Text(
+// text = stringResource(R.string.settings_reset_tutorial_subtitle),
+// style = MaterialTheme.typography.bodySmall,
+// color = MaterialTheme.colorScheme.onSurfaceVariant
+// )
+// }
+// }
+// }
+// }
+ }
- if (showThemeDialog) {
- ThemePickerDialog(
- currentTheme = currentTheme,
- onThemeSelected = onThemeChange,
- onDismiss = dismissThemeDialog
- )
- }
+ if (showThemeDialog) {
+ ThemePickerDialog(
+ currentTheme = currentTheme,
+ onThemeSelected = onThemeChange,
+ onDismiss = dismissThemeDialog
+ )
+ }
- if (showTypographyDialog) {
- TypographyPickerDialog(
- currentTypography = currentTypography,
- onTypographySelected = onTypographyChange,
- onDismiss = dismissTypographyDialog,
- )
- }
+ if (showTypographyDialog) {
+ TypographyPickerDialog(
+ currentTypography = currentTypography,
+ onTypographySelected = onTypographyChange,
+ onDismiss = dismissTypographyDialog,
+ )
+ }
- if (showRecurrentPaymentsViewModeDialog) {
- RecurrentPaymentsViewModePickerDialog(
- currentMode = recurrentPaymentsViewMode,
- onModeSelected = onRecurrentPaymentsViewModeChange,
- onDismiss = dismissRecurrentPaymentsViewModeDialog,
- )
- }
+ if (showRecurrentPaymentsViewModeDialog) {
+ RecurrentPaymentsViewModePickerDialog(
+ currentMode = recurrentPaymentsViewMode,
+ onModeSelected = onRecurrentPaymentsViewModeChange,
+ onDismiss = dismissRecurrentPaymentsViewModeDialog,
+ )
+ }
- if (showNotificationTimePicker) {
- NotificationTimePickerDialog(
- initialHour = notificationHour,
- initialMinute = notificationMinute,
- onDismiss = dismissNotificationTimePicker,
- onTimeSelected = { hour, minute ->
- onNotificationTimeChange(hour, minute)
- dismissNotificationTimePicker()
- })
- }
+ if (showNotificationTimePicker) {
+ NotificationTimePickerDialog(
+ initialHour = notificationHour,
+ initialMinute = notificationMinute,
+ onDismiss = dismissNotificationTimePicker,
+ onTimeSelected = { hour, minute ->
+ onNotificationTimeChange(hour, minute)
+ dismissNotificationTimePicker()
+ }
+ )
+ }
- if (showRecurrentNotificationTimePicker) {
- NotificationTimePickerDialog(
- initialHour = recurrentNotificationHour,
- initialMinute = recurrentNotificationMinute,
- onDismiss = dismissRecurrentNotificationTimePicker,
- onTimeSelected = { hour, minute ->
- onRecurrentNotificationTimeChange(hour, minute)
- dismissRecurrentNotificationTimePicker()
- })
- }
- }
+ if (showRecurrentNotificationTimePicker) {
+ NotificationTimePickerDialog(
+ initialHour = recurrentNotificationHour,
+ initialMinute = recurrentNotificationMinute,
+ onDismiss = dismissRecurrentNotificationTimePicker,
+ onTimeSelected = { hour, minute ->
+ onRecurrentNotificationTimeChange(hour, minute)
+ dismissRecurrentNotificationTimePicker()
+ }
+ )
+ }
+ }
}
@Composable
fun ThemePickerDialog(
- currentTheme: String, onThemeSelected: (String) -> Unit, onDismiss: () -> Unit
+ currentTheme: String,
+ onThemeSelected: (String) -> Unit,
+ onDismiss: () -> Unit
) {
- Dialog(onDismissRequest = onDismiss) {
- Surface(
- shape = RoundedCornerShape(28.dp),
- color = MaterialTheme.colorScheme.surfaceContainerHigh,
- tonalElevation = 6.dp,
- modifier = Modifier.testTag("ThemePickerDialog")
- ) {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .padding(24.dp)
- ) {
- Text(
- text = stringResource(R.string.settings_theme_dialog_title),
- style = MaterialTheme.typography.headlineSmall,
- fontWeight = FontWeight.Bold,
- color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.padding(bottom = 16.dp)
- )
+ Dialog(onDismissRequest = onDismiss) {
+ Surface(
+ shape = RoundedCornerShape(28.dp),
+ color = MaterialTheme.colorScheme.surfaceContainerHigh,
+ tonalElevation = 6.dp,
+ modifier = Modifier.testTag("ThemePickerDialog")
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(24.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.settings_theme_dialog_title),
+ style = MaterialTheme.typography.headlineSmall,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.onSurface,
+ modifier = Modifier.padding(bottom = 16.dp)
+ )
- ThemeOption(
- title = stringResource(R.string.settings_theme_light_title),
- subtitle = stringResource(R.string.settings_theme_light_subtitle),
- icon = Icons.Default.LightMode,
- isSelected = currentTheme == "Light",
- onClick = {
- onThemeSelected("Light")
- onDismiss()
- })
+ ThemeOption(
+ title = stringResource(R.string.settings_theme_light_title),
+ subtitle = stringResource(R.string.settings_theme_light_subtitle),
+ icon = Icons.Default.LightMode,
+ isSelected = currentTheme == "Light",
+ onClick = {
+ onThemeSelected("Light")
+ onDismiss()
+ }
+ )
- Spacer(modifier = Modifier.height(8.dp))
+ Spacer(modifier = Modifier.height(8.dp))
- ThemeOption(
- title = stringResource(R.string.settings_theme_dark_title),
- subtitle = stringResource(R.string.settings_theme_dark_subtitle),
- icon = Icons.Default.DarkMode,
- isSelected = currentTheme == "Dark",
- onClick = {
- onThemeSelected("Dark")
- onDismiss()
- })
+ ThemeOption(
+ title = stringResource(R.string.settings_theme_dark_title),
+ subtitle = stringResource(R.string.settings_theme_dark_subtitle),
+ icon = Icons.Default.DarkMode,
+ isSelected = currentTheme == "Dark",
+ onClick = {
+ onThemeSelected("Dark")
+ onDismiss()
+ }
+ )
- Spacer(modifier = Modifier.height(8.dp))
+ Spacer(modifier = Modifier.height(8.dp))
- ThemeOption(
- title = stringResource(R.string.settings_theme_system_title),
- subtitle = stringResource(R.string.settings_theme_system_subtitle),
- icon = Icons.Default.Brightness4,
- isSelected = currentTheme == "System",
- onClick = {
- onThemeSelected("System")
- onDismiss()
- })
- }
- }
- }
+ ThemeOption(
+ title = stringResource(R.string.settings_theme_system_title),
+ subtitle = stringResource(R.string.settings_theme_system_subtitle),
+ icon = Icons.Default.Brightness4,
+ isSelected = currentTheme == "System",
+ onClick = {
+ onThemeSelected("System")
+ onDismiss()
+ }
+ )
+ }
+ }
+ }
}
@Composable
private fun ThemeOption(
- title: String, subtitle: String, icon: ImageVector, isSelected: Boolean, onClick: () -> Unit
+ title: String,
+ subtitle: String,
+ icon: ImageVector,
+ isSelected: Boolean,
+ onClick: () -> Unit
) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clip(RoundedCornerShape(16.dp))
- .background(
- if (isSelected) {
- MaterialTheme.colorScheme.primaryContainer
- } else {
- MaterialTheme.colorScheme.surface
- }
- )
- .clickable(onClick = onClick)
- .padding(16.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Icon(
- imageVector = icon, contentDescription = null, tint = if (isSelected) {
- MaterialTheme.colorScheme.onPrimaryContainer
- } else {
- MaterialTheme.colorScheme.onSurfaceVariant
- }, modifier = Modifier.size(24.dp)
- )
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(RoundedCornerShape(16.dp))
+ .background(
+ if (isSelected) {
+ MaterialTheme.colorScheme.primaryContainer
+ } else {
+ MaterialTheme.colorScheme.surface
+ }
+ )
+ .clickable(onClick = onClick)
+ .padding(16.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null,
+ tint = if (isSelected) {
+ MaterialTheme.colorScheme.onPrimaryContainer
+ } else {
+ MaterialTheme.colorScheme.onSurfaceVariant
+ },
+ modifier = Modifier.size(24.dp)
+ )
- Spacer(modifier = Modifier.width(16.dp))
+ Spacer(modifier = Modifier.width(16.dp))
- Column(modifier = Modifier.weight(1f)) {
- Text(
- text = title,
- style = MaterialTheme.typography.bodyMediumEmphasized,
- fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
- color = if (isSelected) {
- MaterialTheme.colorScheme.onPrimaryContainer
- } else {
- MaterialTheme.colorScheme.onSurface
- }
- )
- Text(
- text = subtitle,
- style = MaterialTheme.typography.bodySmall,
- color = if (isSelected) {
- MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.7f)
- } else {
- MaterialTheme.colorScheme.onSurfaceVariant
- }
- )
- }
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = title,
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ fontWeight = if (isSelected) FontWeight.SemiBold else FontWeight.Normal,
+ color = if (isSelected) {
+ MaterialTheme.colorScheme.onPrimaryContainer
+ } else {
+ MaterialTheme.colorScheme.onSurface
+ }
+ )
+ Text(
+ text = subtitle,
+ style = MaterialTheme.typography.bodySmall,
+ color = if (isSelected) {
+ MaterialTheme.colorScheme.onPrimaryContainer.copy(alpha = 0.7f)
+ } else {
+ MaterialTheme.colorScheme.onSurfaceVariant
+ }
+ )
+ }
- if (isSelected) {
- RadioButton(
- selected = true, onClick = null, colors = RadioButtonDefaults.colors(
- selectedColor = MaterialTheme.colorScheme.primary
- )
- )
- }
- }
+ if (isSelected) {
+ RadioButton(
+ selected = true,
+ onClick = null,
+ colors = RadioButtonDefaults.colors(
+ selectedColor = MaterialTheme.colorScheme.primary
+ )
+ )
+ }
+ }
}
@Composable
fun TypographyPickerDialog(
- currentTypography: String,
- onTypographySelected: (String) -> Unit,
- onDismiss: () -> Unit,
+ currentTypography: String,
+ onTypographySelected: (String) -> Unit,
+ onDismiss: () -> Unit,
) {
- Dialog(onDismissRequest = onDismiss) {
- Surface(
- shape = RoundedCornerShape(28.dp),
- color = MaterialTheme.colorScheme.surfaceContainerHigh,
- tonalElevation = 6.dp,
- modifier = Modifier.testTag("TypographyPickerDialog")
- ) {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .padding(24.dp)
- ) {
- Text(
- text = stringResource(R.string.settings_typography_dialog_title),
- style = MaterialTheme.typography.headlineSmall,
- fontWeight = FontWeight.Bold,
- color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.padding(bottom = 16.dp)
- )
+ Dialog(onDismissRequest = onDismiss) {
+ Surface(
+ shape = RoundedCornerShape(28.dp),
+ color = MaterialTheme.colorScheme.surfaceContainerHigh,
+ tonalElevation = 6.dp,
+ modifier = Modifier.testTag("TypographyPickerDialog")
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(24.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.settings_typography_dialog_title),
+ style = MaterialTheme.typography.headlineSmall,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.onSurface,
+ modifier = Modifier.padding(bottom = 16.dp)
+ )
- ThemeOption(
- title = stringResource(R.string.settings_typography_default_title),
- subtitle = stringResource(R.string.settings_typography_default_subtitle),
- icon = Icons.Default.TextFields,
- isSelected = currentTypography == "Default",
- onClick = {
- onTypographySelected("Default")
- onDismiss()
- }
- )
+ ThemeOption(
+ title = stringResource(R.string.settings_typography_default_title),
+ subtitle = stringResource(R.string.settings_typography_default_subtitle),
+ icon = Icons.Default.TextFields,
+ isSelected = currentTypography == "Default",
+ onClick = {
+ onTypographySelected("Default")
+ onDismiss()
+ }
+ )
- Spacer(modifier = Modifier.height(8.dp))
+ Spacer(modifier = Modifier.height(8.dp))
- ThemeOption(
- title = stringResource(R.string.settings_typography_condensed_title),
- subtitle = stringResource(R.string.settings_typography_condensed_subtitle),
- icon = Icons.Default.TextFields,
- isSelected = currentTypography == "Condensed",
- onClick = {
- onTypographySelected("Condensed")
- onDismiss()
- }
- )
+ ThemeOption(
+ title = stringResource(R.string.settings_typography_condensed_title),
+ subtitle = stringResource(R.string.settings_typography_condensed_subtitle),
+ icon = Icons.Default.TextFields,
+ isSelected = currentTypography == "Condensed",
+ onClick = {
+ onTypographySelected("Condensed")
+ onDismiss()
+ }
+ )
- Spacer(modifier = Modifier.height(8.dp))
+ Spacer(modifier = Modifier.height(8.dp))
- ThemeOption(
- title = stringResource(R.string.settings_typography_expressive_title),
- subtitle = stringResource(R.string.settings_typography_expressive_subtitle),
- icon = Icons.Default.TextFields,
- isSelected = currentTypography == "Expressive",
- onClick = {
- onTypographySelected("Expressive")
- onDismiss()
- }
- )
- }
- }
- }
+ ThemeOption(
+ title = stringResource(R.string.settings_typography_expressive_title),
+ subtitle = stringResource(R.string.settings_typography_expressive_subtitle),
+ icon = Icons.Default.TextFields,
+ isSelected = currentTypography == "Expressive",
+ onClick = {
+ onTypographySelected("Expressive")
+ onDismiss()
+ }
+ )
+ }
+ }
+ }
}
@Composable
fun RecurrentPaymentsViewModePickerDialog(
- currentMode: RecurrentPaymentsViewMode,
- onModeSelected: (RecurrentPaymentsViewMode) -> Unit,
- onDismiss: () -> Unit,
+ currentMode: RecurrentPaymentsViewMode,
+ onModeSelected: (RecurrentPaymentsViewMode) -> Unit,
+ onDismiss: () -> Unit,
) {
- Dialog(onDismissRequest = onDismiss) {
- Surface(
- shape = RoundedCornerShape(28.dp),
- color = MaterialTheme.colorScheme.surfaceContainerHigh,
- tonalElevation = 6.dp,
- modifier = Modifier.testTag("RecurrentPaymentsViewModePickerDialog")
- ) {
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .padding(24.dp)
- ) {
- Text(
- text = stringResource(R.string.settings_recurrent_payments_view_mode_dialog_title),
- style = MaterialTheme.typography.headlineSmall,
- fontWeight = FontWeight.Bold,
- color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.padding(bottom = 16.dp)
- )
+ Dialog(onDismissRequest = onDismiss) {
+ Surface(
+ shape = RoundedCornerShape(28.dp),
+ color = MaterialTheme.colorScheme.surfaceContainerHigh,
+ tonalElevation = 6.dp,
+ modifier = Modifier.testTag("RecurrentPaymentsViewModePickerDialog")
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(24.dp)
+ ) {
+ Text(
+ text = stringResource(R.string.settings_recurrent_payments_view_mode_dialog_title),
+ style = MaterialTheme.typography.headlineSmall,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colorScheme.onSurface,
+ modifier = Modifier.padding(bottom = 16.dp)
+ )
- ThemeOption(
- title = stringResource(R.string.settings_recurrent_payments_view_mode_horizontal_title),
- subtitle = stringResource(R.string.settings_recurrent_payments_view_mode_horizontal_subtitle),
- icon = Icons.Default.Repeat,
- isSelected = currentMode == RecurrentPaymentsViewMode.HORIZONTAL_LIST,
- onClick = {
- onModeSelected(RecurrentPaymentsViewMode.HORIZONTAL_LIST)
- onDismiss()
- }
- )
+ ThemeOption(
+ title = stringResource(R.string.settings_recurrent_payments_view_mode_horizontal_title),
+ subtitle = stringResource(R.string.settings_recurrent_payments_view_mode_horizontal_subtitle),
+ icon = Icons.Default.Repeat,
+ isSelected = currentMode == RecurrentPaymentsViewMode.HORIZONTAL_LIST,
+ onClick = {
+ onModeSelected(RecurrentPaymentsViewMode.HORIZONTAL_LIST)
+ onDismiss()
+ }
+ )
- Spacer(modifier = Modifier.height(8.dp))
+ Spacer(modifier = Modifier.height(8.dp))
- ThemeOption(
- title = stringResource(R.string.settings_recurrent_payments_view_mode_vertical_title),
- subtitle = stringResource(R.string.settings_recurrent_payments_view_mode_vertical_subtitle),
- icon = Icons.Default.Repeat,
- isSelected = currentMode == RecurrentPaymentsViewMode.VERTICAL_LIST,
- onClick = {
- onModeSelected(RecurrentPaymentsViewMode.VERTICAL_LIST)
- onDismiss()
- }
- )
- }
- }
- }
+ ThemeOption(
+ title = stringResource(R.string.settings_recurrent_payments_view_mode_vertical_title),
+ subtitle = stringResource(R.string.settings_recurrent_payments_view_mode_vertical_subtitle),
+ icon = Icons.Default.Repeat,
+ isSelected = currentMode == RecurrentPaymentsViewMode.VERTICAL_LIST,
+ onClick = {
+ onModeSelected(RecurrentPaymentsViewMode.VERTICAL_LIST)
+ onDismiss()
+ }
+ )
+ }
+ }
+ }
}
@Composable
private fun NotificationTimePickerDialog(
- initialHour: Int, initialMinute: Int, onDismiss: () -> Unit, onTimeSelected: (Int, Int) -> Unit
+ initialHour: Int,
+ initialMinute: Int,
+ onDismiss: () -> Unit,
+ onTimeSelected: (Int, Int) -> Unit
) {
- val context = LocalContext.current
- DisposableEffect(context, initialHour, initialMinute) {
- val dialog = TimePickerDialog(
- context,
- { _, hour, minute -> onTimeSelected(hour, minute) },
- initialHour,
- initialMinute,
- android.text.format.DateFormat.is24HourFormat(context)
- )
- dialog.setOnDismissListener { onDismiss() }
- dialog.show()
- onDispose {
- dialog.setOnDismissListener(null)
- dialog.dismiss()
- }
- }
+ val context = LocalContext.current
+ val state = rememberTimePickerState(
+ initialHour = initialHour,
+ initialMinute = initialMinute,
+ is24Hour = android.text.format.DateFormat.is24HourFormat(context),
+ )
+ Dialog(onDismissRequest = onDismiss) {
+ Surface(
+ shape = MaterialTheme.shapes.extraLarge,
+ color = MaterialTheme.colorScheme.surfaceContainerHigh,
+ ) {
+ Column(modifier = Modifier.padding(24.dp)) {
+ TimePicker(state = state)
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ horizontalArrangement = Arrangement.End,
+ ) {
+ TextButton(onClick = onDismiss) {
+ Text(stringResource(R.string.settings_time_picker_cancel))
+ }
+ Spacer(modifier = Modifier.width(8.dp))
+ TextButton(onClick = {
+ onTimeSelected(state.hour, state.minute)
+ onDismiss()
+ }) {
+ Text(stringResource(R.string.settings_time_picker_confirm))
+ }
+ }
+ }
+ }
+ }
}
@Composable
private fun RecurrentPaymentsViewMode.label(): String {
- return when (this) {
- RecurrentPaymentsViewMode.HORIZONTAL_LIST -> stringResource(R.string.settings_recurrent_payments_view_mode_horizontal_title)
- RecurrentPaymentsViewMode.VERTICAL_LIST -> stringResource(R.string.settings_recurrent_payments_view_mode_vertical_title)
- }
+ return when (this) {
+ RecurrentPaymentsViewMode.HORIZONTAL_LIST -> stringResource(
+ R.string.settings_recurrent_payments_view_mode_horizontal_title
+ )
+ RecurrentPaymentsViewMode.VERTICAL_LIST -> stringResource(
+ R.string.settings_recurrent_payments_view_mode_vertical_title
+ )
+ }
}
private fun Context.copyAppEnvironmentMetadataToClipboard() {
- val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- clipboard.setPrimaryClip(
- ClipData.newPlainText(
- "Minus app environment metadata",
- buildAppEnvironmentMetadata(),
- )
- )
+ val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ clipboard.setPrimaryClip(
+ ClipData.newPlainText(
+ "Minus app environment metadata",
+ buildAppEnvironmentMetadata(),
+ )
+ )
}
private fun formatNotificationTime(
- context: Context, hour: Int, minute: Int
+ context: Context,
+ hour: Int,
+ minute: Int
): String {
- val pattern = if (android.text.format.DateFormat.is24HourFormat(context)) "HH:mm" else "h:mm a"
- return LocalTime.of(hour, minute)
- .format(DateTimeFormatter.ofPattern(pattern, Locale.getDefault()))
+ val pattern = if (android.text.format.DateFormat.is24HourFormat(context)) "HH:mm" else "h:mm a"
+ return LocalTime.of(hour, minute)
+ .format(DateTimeFormatter.ofPattern(pattern, Locale.getDefault()))
}
@PreviewLightDark
@Composable
private fun PreviewSettings() {
- MinusTheme {
- Settings(
- currentTheme = "System",
- currentTypography = "Expressive",
- isMaterialYouEnabled = true,
- isCreditQuickToggleFeatureEnabled = false,
- recurrentPaymentsViewMode = RecurrentPaymentsViewMode.HORIZONTAL_LIST,
- notificationHour = 9,
- notificationMinute = 0,
- recurrentNotificationHour = 8,
- recurrentNotificationMinute = 0,
- exactAlarmEnabled = true,
- onThemeChange = {},
- onTypographyChange = {},
- onMaterialYouToggle = {},
- onCreditQuickToggleFeatureToggle = {},
- onRecurrentPaymentsViewModeChange = {},
- onNotificationTimeChange = { _, _ -> },
- onRecurrentNotificationTimeChange = { _, _ -> },
- onOpenExactAlarmSettings = {},
- periodMappingMode = PeriodMappingMode.ACTIVE_BUDGET,
- onPeriodMappingModeChange = {})
- }
-}
\ No newline at end of file
+ MinusTheme {
+ Settings(
+ currentTheme = "System",
+ currentTypography = "Expressive",
+ isMaterialYouEnabled = true,
+ isCreditQuickToggleFeatureEnabled = false,
+ recurrentPaymentsViewMode = RecurrentPaymentsViewMode.HORIZONTAL_LIST,
+ notificationHour = 9,
+ notificationMinute = 0,
+ recurrentNotificationHour = 8,
+ recurrentNotificationMinute = 0,
+ exactAlarmEnabled = true,
+ notificationPermissionGranted = true,
+ onThemeChange = {},
+ onTypographyChange = {},
+ onMaterialYouToggle = {},
+ onCreditQuickToggleFeatureToggle = {},
+ onRecurrentPaymentsViewModeChange = {},
+ onNotificationTimeChange = { _, _ -> },
+ onRecurrentNotificationTimeChange = { _, _ -> },
+ onOpenExactAlarmSettings = {},
+ onOpenNotificationSettings = {},
+ periodMappingMode = PeriodMappingMode.ACTIVE_BUDGET,
+ onPeriodMappingModeChange = {}
+ )
+ }
+}
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsScreen.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsScreen.kt
index 362e5a0..95fbdee 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsScreen.kt
@@ -3,10 +3,14 @@ package com.serranoie.app.minus.presentation.ui.settings
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.serranoie.app.minus.presentation.ui.settings.csv.CsvTransferEntryPoint
import com.serranoie.app.minus.presentation.util.LocalCensorMode
@@ -21,6 +25,7 @@ fun SettingsScreen(
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
+ val lifecycleOwner = LocalLifecycleOwner.current
val isCensored = LocalCensorMode.current
val importLauncher = rememberLauncherForActivityResult(
@@ -37,6 +42,18 @@ fun SettingsScreen(
viewModel.setImportLauncher(importLauncher)
}
+ DisposableEffect(lifecycleOwner) {
+ val observer = LifecycleEventObserver { _, event ->
+ if (event == Lifecycle.Event.ON_RESUME) {
+ viewModel.refreshNotificationPermission()
+ }
+ }
+ lifecycleOwner.lifecycle.addObserver(observer)
+ onDispose {
+ lifecycleOwner.lifecycle.removeObserver(observer)
+ }
+ }
+
LaunchedEffect(Unit) {
viewModel.effects.collect { effect ->
when (effect) {
@@ -65,6 +82,7 @@ fun SettingsScreen(
recurrentNotificationHour = uiState.recurrentNotificationHour,
recurrentNotificationMinute = uiState.recurrentNotificationMinute,
exactAlarmEnabled = uiState.exactAlarmEnabled,
+ notificationPermissionGranted = uiState.notificationPermissionGranted,
onThemeChange = viewModel::onThemeChange,
onTypographyChange = viewModel::onTypographyChange,
onMaterialYouToggle = viewModel::onMaterialYouToggle,
@@ -73,6 +91,10 @@ fun SettingsScreen(
onNotificationTimeChange = viewModel::onNotificationTimeChange,
onRecurrentNotificationTimeChange = viewModel::onRecurrentNotificationTimeChange,
onOpenExactAlarmSettings = viewModel::onOpenExactAlarmSettings,
+ onOpenNotificationSettings = {
+ viewModel.onOpenAppSettings()
+ viewModel.refreshNotificationPermission()
+ },
periodMappingMode = uiState.periodMappingMode,
onPeriodMappingModeChange = viewModel::onPeriodMappingModeChange,
onExportCsv = viewModel::onExportCsv,
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsViewModel.kt
index 35bea0e..a31293f 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsViewModel.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/SettingsViewModel.kt
@@ -1,11 +1,14 @@
package com.serranoie.app.minus.presentation.ui.settings
+import android.Manifest
import android.app.AlarmManager
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.activity.result.ActivityResultLauncher
+import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.datastore.preferences.core.edit
import androidx.lifecycle.ViewModel
@@ -37,6 +40,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import logcat.logcat
import javax.inject.Inject
import android.provider.Settings as AndroidSettings
@@ -51,6 +55,7 @@ data class SettingsUiState(
val recurrentNotificationHour: Int = 8,
val recurrentNotificationMinute: Int = 0,
val exactAlarmEnabled: Boolean = true,
+ val notificationPermissionGranted: Boolean = false,
val periodMappingMode: PeriodMappingMode = PeriodMappingMode.ACTIVE_BUDGET,
)
@@ -77,6 +82,38 @@ class SettingsViewModel @Inject constructor(
init {
loadPreferences()
+ refreshNotificationPermission()
+ }
+
+ /**
+ * Re-checks POST_NOTIFICATIONS (Android 13+) so the Settings row reflects
+ * the latest state when the user returns from the system app-info screen.
+ */
+ fun refreshNotificationPermission() {
+ val granted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS,
+ ) == PackageManager.PERMISSION_GRANTED
+ } else {
+ // Pre-Tiramisu devices grant by default.
+ true
+ }
+ logcat("ISAAC:Settings") { "refreshNotificationPermission -> granted=$granted" }
+ _uiState.update { it.copy(notificationPermissionGranted = granted) }
+ }
+
+ /**
+ * Opens the system app-info page for this package so the user can
+ * enable/deny POST_NOTIFICATIONS, exact alarms, etc.
+ */
+ fun onOpenAppSettings() {
+ logcat("ISAAC:Settings") { "onOpenAppSettings" }
+ val intent = Intent(AndroidSettings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = "package:${context.packageName}".toUri()
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ context.startActivity(intent)
}
fun setCsvTransferManager(manager: CsvTransferManager) {
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/components/NotificationPermissionItem.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/components/NotificationPermissionItem.kt
new file mode 100644
index 0000000..0c2da21
--- /dev/null
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/settings/components/NotificationPermissionItem.kt
@@ -0,0 +1,105 @@
+package com.serranoie.app.minus.presentation.ui.settings.components
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.CheckCircle
+import androidx.compose.material.icons.filled.NotificationsActive
+import androidx.compose.material.icons.filled.NotificationsOff
+import androidx.compose.material.icons.rounded.KeyboardArrowRight
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.serranoie.app.minus.R
+import com.serranoie.app.minus.presentation.ui.theme.component.CustomPaddedListItem
+import com.serranoie.app.minus.presentation.ui.theme.component.PaddedListItemPosition
+
+@Composable
+fun NotificationPermissionItem(
+ granted: Boolean,
+ onClick: () -> Unit,
+ position: PaddedListItemPosition,
+) {
+ CustomPaddedListItem(
+ onClick = onClick,
+ position = position,
+ borderStroke = if (!granted) {
+ BorderStroke(1.dp, MaterialTheme.colorScheme.error)
+ } else {
+ null
+ },
+ ) {
+ Icon(
+ imageVector = if (granted) Icons.Default.NotificationsActive else Icons.Default.NotificationsOff,
+ contentDescription = null,
+ tint = if (granted) {
+ MaterialTheme.colorScheme.primary
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(modifier = Modifier.weight(1f)) {
+ Text(
+ text = stringResource(R.string.settings_notification_permission_title),
+ style = MaterialTheme.typography.bodyMediumEmphasized,
+ color = if (granted) {
+ MaterialTheme.colorScheme.onSurface
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ Text(
+ text = if (granted) {
+ stringResource(R.string.settings_notification_permission_granted_subtitle)
+ } else {
+ stringResource(R.string.settings_notification_permission_denied_subtitle)
+ },
+ style = MaterialTheme.typography.bodySmall,
+ color = if (granted) {
+ MaterialTheme.colorScheme.onSurfaceVariant
+ } else {
+ MaterialTheme.colorScheme.error
+ }
+ )
+ }
+ if (!granted) {
+ Icon(
+ imageVector = Icons.Rounded.KeyboardArrowRight,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.onSurface,
+ )
+ } else {
+ Icon(
+ imageVector = Icons.Default.CheckCircle,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewNotificationPermissionItem() {
+ Column {
+ NotificationPermissionItem(
+ granted = true,
+ onClick = {},
+ position = PaddedListItemPosition.First,
+ )
+
+ NotificationPermissionItem(
+ granted = false,
+ onClick = {},
+ position = PaddedListItemPosition.Last,
+ )
+ }
+}
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/Type.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/Type.kt
index 51da2aa..09e1bf6 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/Type.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/Type.kt
@@ -12,585 +12,758 @@ import androidx.compose.ui.unit.sp
import com.serranoie.app.minus.R
val GoogleSansFlex = FontFamily(
- Font(R.font.google_sans_flex, FontWeight.Normal),
- Font(R.font.google_sans_flex, FontWeight.Medium),
- Font(R.font.google_sans_flex, FontWeight.SemiBold),
- Font(R.font.google_sans_flex, FontWeight.Bold)
+ Font(R.font.google_sans_flex, FontWeight.Normal),
+ Font(R.font.google_sans_flex, FontWeight.Medium),
+ Font(R.font.google_sans_flex, FontWeight.SemiBold),
+ Font(R.font.google_sans_flex, FontWeight.Bold)
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplayLargeEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(155f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(155f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplayMediumEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(132f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(132f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplaySmallEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(125f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(125f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineLargeEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(800), FontVariation.width(150f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(800),
+ FontVariation.width(150f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineMediumEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(150f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(150f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineSmallEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(135f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(135f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleLargeEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(135f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(135f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleMediumEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(135f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(135f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleSmallEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(115f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(115f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodyLargeEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(115f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(115f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodyMediumEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(115f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(115f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodySmallEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(115f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(115f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelLargeEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(115f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(115f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelMediumEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(125f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(125f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelSmallEmphasized = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(125f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(125f)
+ )
+ )
)
// Condensed Font Families - width below 100 for narrow appearance
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplayLargeCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(65f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(65f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplayMediumCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(75f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(75f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexDisplaySmallCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(75f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(75f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineLargeCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(800), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(800),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineMediumCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexHeadlineSmallCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleLargeCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(700), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(700),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleMediumCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexTitleSmallCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(600), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(600),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodyLargeCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(70f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(70f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodyMediumCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(80f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(80f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexBodySmallCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(85f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(85f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelLargeCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(75f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(75f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelMediumCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(65f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(65f)
+ )
+ )
)
@OptIn(ExperimentalTextApi::class)
val GoogleSansFlexLabelSmallCondensed = FontFamily(
- Font(
- R.font.google_sans_flex, variationSettings = FontVariation.Settings(
- FontVariation.weight(500), FontVariation.width(75f)
- )
- )
+ Font(
+ R.font.google_sans_flex,
+ variationSettings = FontVariation.Settings(
+ FontVariation.weight(500),
+ FontVariation.width(75f)
+ )
+ )
)
val Typography = Typography(
- displayLarge = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 57.sp,
- lineHeight = 64.sp,
- letterSpacing = (-0.25).sp
- ), displayMedium = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 45.sp,
- lineHeight = 52.sp,
- letterSpacing = 0.sp
- ), displaySmall = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 36.sp,
- lineHeight = 44.sp,
- letterSpacing = 0.sp
- ),
-
- headlineLarge = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Bold,
- fontSize = 32.sp,
- lineHeight = 40.sp,
- letterSpacing = 0.sp
- ), headlineMedium = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Bold,
- fontSize = 28.sp,
- lineHeight = 36.sp,
- letterSpacing = 0.sp
- ), headlineSmall = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.SemiBold,
- fontSize = 24.sp,
- lineHeight = 32.sp,
- letterSpacing = 0.sp
- ),
-
- titleLarge = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.SemiBold,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ), titleMedium = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Medium,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.15.sp
- ), titleSmall = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Medium,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.1.sp
- ),
-
- bodyLarge = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp
- ), bodyMedium = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.25.sp
- ), bodySmall = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Normal,
- fontSize = 12.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.4.sp
- ),
-
- labelLarge = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Medium,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.1.sp
- ), labelMedium = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Medium,
- fontSize = 12.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- ), labelSmall = TextStyle(
- fontFamily = GoogleSansFlex,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- )
+ displayLarge = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 57.sp,
+ lineHeight = 64.sp,
+ letterSpacing = (-0.25).sp
+ ),
+ displayMedium = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 45.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp
+ ),
+ displaySmall = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp
+ ),
+
+ headlineLarge = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Bold,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineMedium = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Bold,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineSmall = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.sp
+ ),
+
+ titleLarge = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ titleMedium = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Medium,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ ),
+ titleSmall = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Medium,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.1.sp
+ ),
+
+ bodyLarge = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ ),
+ bodyMedium = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.25.sp
+ ),
+ bodySmall = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Normal,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.4.sp
+ ),
+
+ labelLarge = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Medium,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.1.sp
+ ),
+ labelMedium = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Medium,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = GoogleSansFlex,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
)
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
fun Typography.withEmphasizedStyles(): Typography {
- return this.copy(
- displayLargeEmphasized = TextStyle(
- fontFamily = GoogleSansFlexDisplayLargeEmphasized,
- fontSize = 64.sp,
- lineHeight = 72.sp,
- letterSpacing = 0.sp
- ), displayMediumEmphasized = TextStyle(
- fontFamily = GoogleSansFlexDisplayMediumEmphasized,
- fontSize = 52.sp,
- lineHeight = 60.sp,
- letterSpacing = 0.sp
- ), displaySmallEmphasized = TextStyle(
- fontFamily = GoogleSansFlexDisplaySmallEmphasized,
- fontSize = 44.sp,
- lineHeight = 52.sp,
- letterSpacing = 0.sp
- ),
-
- // Emphasized Headline - Bold and wide for attention-grabbing headers
- headlineLargeEmphasized = TextStyle(
- fontFamily = GoogleSansFlexHeadlineLargeEmphasized,
- fontSize = 36.sp,
- lineHeight = 44.sp,
- letterSpacing = 0.sp
- ), headlineMediumEmphasized = TextStyle(
- fontFamily = GoogleSansFlexHeadlineMediumEmphasized,
- fontSize = 32.sp,
- lineHeight = 40.sp,
- letterSpacing = 0.sp
- ), headlineSmallEmphasized = TextStyle(
- fontFamily = GoogleSansFlexHeadlineSmallEmphasized,
- fontSize = 28.sp,
- lineHeight = 36.sp,
- letterSpacing = 0.sp
- ), titleLargeEmphasized = TextStyle(
- fontFamily = GoogleSansFlexTitleLargeEmphasized,
- fontSize = 24.sp,
- lineHeight = 32.sp,
- letterSpacing = 0.15.sp
- ), titleMediumEmphasized = TextStyle(
- fontFamily = GoogleSansFlexTitleMediumEmphasized,
- fontSize = 18.sp,
- lineHeight = 26.sp,
- letterSpacing = 0.2.sp
- ), titleSmallEmphasized = TextStyle(
- fontFamily = GoogleSansFlexTitleSmallEmphasized,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.15.sp
- ), bodyLargeEmphasized = TextStyle(
- fontFamily = GoogleSansFlexBodyLargeEmphasized,
- fontSize = 18.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.6.sp
- ), bodyMediumEmphasized = TextStyle(
- fontFamily = GoogleSansFlexBodyMediumEmphasized,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.4.sp
- ), bodySmallEmphasized = TextStyle(
- fontFamily = GoogleSansFlexBodySmallEmphasized,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.5.sp
- ), labelLargeEmphasized = TextStyle(
- fontFamily = GoogleSansFlexLabelLargeEmphasized,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.15.sp
- ), labelMediumEmphasized = TextStyle(
- fontFamily = GoogleSansFlexLabelMediumEmphasized,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.6.sp
- ), labelSmallEmphasized = TextStyle(
- fontFamily = GoogleSansFlexLabelSmallEmphasized,
- fontSize = 12.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.6.sp
- )
- )
+ return this.copy(
+ displayLargeEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexDisplayLargeEmphasized,
+ fontSize = 64.sp,
+ lineHeight = 72.sp,
+ letterSpacing = 0.sp
+ ),
+ displayMediumEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexDisplayMediumEmphasized,
+ fontSize = 52.sp,
+ lineHeight = 60.sp,
+ letterSpacing = 0.sp
+ ),
+ displaySmallEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexDisplaySmallEmphasized,
+ fontSize = 44.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp
+ ),
+
+ // Emphasized Headline - Bold and wide for attention-grabbing headers
+ headlineLargeEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineLargeEmphasized,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineMediumEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineMediumEmphasized,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineSmallEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineSmallEmphasized,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp
+ ),
+ titleLargeEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexTitleLargeEmphasized,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.15.sp
+ ),
+ titleMediumEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexTitleMediumEmphasized,
+ fontSize = 18.sp,
+ lineHeight = 26.sp,
+ letterSpacing = 0.2.sp
+ ),
+ titleSmallEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexTitleSmallEmphasized,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ ),
+ bodyLargeEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexBodyLargeEmphasized,
+ fontSize = 18.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.6.sp
+ ),
+ bodyMediumEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexBodyMediumEmphasized,
+ fontSize = 16.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.4.sp
+ ),
+ bodySmallEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexBodySmallEmphasized,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.5.sp
+ ),
+ labelLargeEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexLabelLargeEmphasized,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ ),
+ labelMediumEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexLabelMediumEmphasized,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.6.sp
+ ),
+ labelSmallEmphasized = TextStyle(
+ fontFamily = GoogleSansFlexLabelSmallEmphasized,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.6.sp
+ )
+ )
}
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
fun Typography.withCondensedStyles(): Typography {
- return Typography(
- displayLarge = TextStyle(
- fontFamily = GoogleSansFlexDisplayLargeCondensed,
- fontSize = 64.sp,
- lineHeight = 72.sp,
- letterSpacing = 0.sp
- ),
- displayMedium = TextStyle(
- fontFamily = GoogleSansFlexDisplayMediumCondensed,
- fontSize = 52.sp,
- lineHeight = 60.sp,
- letterSpacing = 0.sp
- ),
- displaySmall = TextStyle(
- fontFamily = GoogleSansFlexDisplaySmallCondensed,
- fontSize = 44.sp,
- lineHeight = 52.sp,
- letterSpacing = 0.sp
- ),
- headlineLarge = TextStyle(
- fontFamily = GoogleSansFlexHeadlineLargeCondensed,
- fontSize = 36.sp,
- lineHeight = 44.sp,
- letterSpacing = 0.sp
- ),
- headlineMedium = TextStyle(
- fontFamily = GoogleSansFlexHeadlineMediumCondensed,
- fontSize = 32.sp,
- lineHeight = 40.sp,
- letterSpacing = 0.sp
- ),
- headlineSmall = TextStyle(
- fontFamily = GoogleSansFlexHeadlineSmallCondensed,
- fontSize = 28.sp,
- lineHeight = 36.sp,
- letterSpacing = 0.sp
- ),
- titleLarge = TextStyle(
- fontFamily = GoogleSansFlexTitleLargeCondensed,
- fontSize = 24.sp,
- lineHeight = 32.sp,
- letterSpacing = 0.15.sp
- ),
- titleMedium = TextStyle(
- fontFamily = GoogleSansFlexTitleMediumCondensed,
- fontSize = 18.sp,
- lineHeight = 26.sp,
- letterSpacing = 0.2.sp
- ),
- titleSmall = TextStyle(
- fontFamily = GoogleSansFlexTitleSmallCondensed,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.15.sp
- ),
- bodyLarge = TextStyle(
- fontFamily = GoogleSansFlexBodyLargeCondensed,
- fontSize = 18.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.6.sp
- ),
- bodyMedium = TextStyle(
- fontFamily = GoogleSansFlexBodyMediumCondensed,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.4.sp
- ),
- bodySmall = TextStyle(
- fontFamily = GoogleSansFlexBodySmallCondensed,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.5.sp
- ),
- labelLarge = TextStyle(
- fontFamily = GoogleSansFlexLabelLargeCondensed,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.15.sp
- ),
- labelMedium = TextStyle(
- fontFamily = GoogleSansFlexLabelMediumCondensed,
- fontSize = 14.sp,
- lineHeight = 20.sp,
- letterSpacing = 0.6.sp
- ),
- labelSmall = TextStyle(
- fontFamily = GoogleSansFlexLabelSmallCondensed,
- fontSize = 12.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.6.sp
- )
- )
+ return Typography(
+ displayLarge = TextStyle(
+ fontFamily = GoogleSansFlexDisplayLargeCondensed,
+ fontSize = 64.sp,
+ lineHeight = 72.sp,
+ letterSpacing = 0.sp
+ ),
+ displayMedium = TextStyle(
+ fontFamily = GoogleSansFlexDisplayMediumCondensed,
+ fontSize = 52.sp,
+ lineHeight = 60.sp,
+ letterSpacing = 0.sp
+ ),
+ displaySmall = TextStyle(
+ fontFamily = GoogleSansFlexDisplaySmallCondensed,
+ fontSize = 44.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineLarge = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineLargeCondensed,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineMedium = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineMediumCondensed,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp
+ ),
+ headlineSmall = TextStyle(
+ fontFamily = GoogleSansFlexHeadlineSmallCondensed,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp
+ ),
+ titleLarge = TextStyle(
+ fontFamily = GoogleSansFlexTitleLargeCondensed,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.15.sp
+ ),
+ titleMedium = TextStyle(
+ fontFamily = GoogleSansFlexTitleMediumCondensed,
+ fontSize = 18.sp,
+ lineHeight = 26.sp,
+ letterSpacing = 0.2.sp
+ ),
+ titleSmall = TextStyle(
+ fontFamily = GoogleSansFlexTitleSmallCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ ),
+ bodyLarge = TextStyle(
+ fontFamily = GoogleSansFlexBodyLargeCondensed,
+ fontSize = 18.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.6.sp
+ ),
+ bodyMedium = TextStyle(
+ fontFamily = GoogleSansFlexBodyMediumCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.4.sp
+ ),
+ bodySmall = TextStyle(
+ fontFamily = GoogleSansFlexBodySmallCondensed,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.5.sp
+ ),
+ labelLarge = TextStyle(
+ fontFamily = GoogleSansFlexLabelLargeCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ ),
+ labelMedium = TextStyle(
+ fontFamily = GoogleSansFlexLabelMediumCondensed,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.6.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = GoogleSansFlexLabelSmallCondensed,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.6.sp
+ )
+ )
}
-val Typography.displayLargeCondensed: TextStyle get() = displayLarge.copy(fontFamily = GoogleSansFlexDisplayLargeCondensed, fontSize = 64.sp, lineHeight = 72.sp, letterSpacing = 0.sp)
-val Typography.displayMediumCondensed: TextStyle get() = displayMedium.copy(fontFamily = GoogleSansFlexDisplayMediumCondensed, fontSize = 52.sp, lineHeight = 60.sp, letterSpacing = 0.sp)
-val Typography.displaySmallCondensed: TextStyle get() = displaySmall.copy(fontFamily = GoogleSansFlexDisplaySmallCondensed, fontSize = 44.sp, lineHeight = 52.sp, letterSpacing = 0.sp)
-
-val Typography.headlineLargeCondensed: TextStyle get() = headlineLarge.copy(fontFamily = GoogleSansFlexHeadlineLargeCondensed, fontSize = 36.sp, lineHeight = 44.sp, letterSpacing = 0.sp)
-val Typography.headlineMediumCondensed: TextStyle get() = headlineMedium.copy(fontFamily = GoogleSansFlexHeadlineMediumCondensed, fontSize = 32.sp, lineHeight = 40.sp, letterSpacing = 0.sp)
-val Typography.headlineSmallCondensed: TextStyle get() = headlineSmall.copy(fontFamily = GoogleSansFlexHeadlineSmallCondensed, fontSize = 28.sp, lineHeight = 36.sp, letterSpacing = 0.sp)
-
-val Typography.titleLargeCondensed: TextStyle get() = titleLarge.copy(fontFamily = GoogleSansFlexTitleLargeCondensed, fontSize = 24.sp, lineHeight = 32.sp, letterSpacing = 0.15.sp)
-val Typography.titleMediumCondensed: TextStyle get() = titleMedium.copy(fontFamily = GoogleSansFlexTitleMediumCondensed, fontSize = 18.sp, lineHeight = 26.sp, letterSpacing = 0.2.sp)
-val Typography.titleSmallCondensed: TextStyle get() = titleSmall.copy(fontFamily = GoogleSansFlexTitleSmallCondensed, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp)
-
-val Typography.bodyLargeCondensed: TextStyle get() = bodyLarge.copy(fontFamily = GoogleSansFlexBodyLargeCondensed, fontSize = 18.sp, lineHeight = 28.sp, letterSpacing = 0.6.sp)
-val Typography.bodyMediumCondensed: TextStyle get() = bodyMedium.copy(fontFamily = GoogleSansFlexBodyMediumCondensed, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.4.sp)
-val Typography.bodySmallCondensed: TextStyle get() = bodySmall.copy(fontFamily = GoogleSansFlexBodySmallCondensed, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.5.sp)
-
-val Typography.labelLargeCondensed: TextStyle get() = labelLarge.copy(fontFamily = GoogleSansFlexLabelLargeCondensed, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp)
-val Typography.labelMediumCondensed: TextStyle get() = labelMedium.copy(fontFamily = GoogleSansFlexLabelMediumCondensed, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.6.sp)
-val Typography.labelSmallCondensed: TextStyle get() = labelSmall.copy(fontFamily = GoogleSansFlexLabelSmallCondensed, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.6.sp)
+val Typography.displayLargeCondensed: TextStyle
+ get() = displayLarge.copy(
+ fontFamily = GoogleSansFlexDisplayLargeCondensed,
+ fontSize = 64.sp,
+ lineHeight = 72.sp,
+ letterSpacing = 0.sp
+ )
+val Typography.displayMediumCondensed: TextStyle
+ get() = displayMedium.copy(
+ fontFamily = GoogleSansFlexDisplayMediumCondensed,
+ fontSize = 52.sp,
+ lineHeight = 60.sp,
+ letterSpacing = 0.sp
+ )
+val Typography.displaySmallCondensed: TextStyle
+ get() = displaySmall.copy(
+ fontFamily = GoogleSansFlexDisplaySmallCondensed,
+ fontSize = 44.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp
+ )
+
+val Typography.headlineLargeCondensed: TextStyle
+ get() = headlineLarge.copy(
+ fontFamily = GoogleSansFlexHeadlineLargeCondensed,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp
+ )
+val Typography.headlineMediumCondensed: TextStyle
+ get() = headlineMedium.copy(
+ fontFamily = GoogleSansFlexHeadlineMediumCondensed,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp
+ )
+val Typography.headlineSmallCondensed: TextStyle
+ get() = headlineSmall.copy(
+ fontFamily = GoogleSansFlexHeadlineSmallCondensed,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp
+ )
+
+val Typography.titleLargeCondensed: TextStyle
+ get() = titleLarge.copy(
+ fontFamily = GoogleSansFlexTitleLargeCondensed,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.15.sp
+ )
+val Typography.titleMediumCondensed: TextStyle
+ get() = titleMedium.copy(
+ fontFamily = GoogleSansFlexTitleMediumCondensed,
+ fontSize = 18.sp,
+ lineHeight = 26.sp,
+ letterSpacing = 0.2.sp
+ )
+val Typography.titleSmallCondensed: TextStyle
+ get() = titleSmall.copy(
+ fontFamily = GoogleSansFlexTitleSmallCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ )
+
+val Typography.bodyLargeCondensed: TextStyle
+ get() = bodyLarge.copy(
+ fontFamily = GoogleSansFlexBodyLargeCondensed,
+ fontSize = 18.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.6.sp
+ )
+val Typography.bodyMediumCondensed: TextStyle
+ get() = bodyMedium.copy(
+ fontFamily = GoogleSansFlexBodyMediumCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.4.sp
+ )
+val Typography.bodySmallCondensed: TextStyle
+ get() = bodySmall.copy(
+ fontFamily = GoogleSansFlexBodySmallCondensed,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.5.sp
+ )
+
+val Typography.labelLargeCondensed: TextStyle
+ get() = labelLarge.copy(
+ fontFamily = GoogleSansFlexLabelLargeCondensed,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.15.sp
+ )
+val Typography.labelMediumCondensed: TextStyle
+ get() = labelMedium.copy(
+ fontFamily = GoogleSansFlexLabelMediumCondensed,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.6.sp
+ )
+val Typography.labelSmallCondensed: TextStyle
+ get() = labelSmall.copy(
+ fontFamily = GoogleSansFlexLabelSmallCondensed,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.6.sp
+ )
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
val ExpressiveTypography = Typography.withEmphasizedStyles()
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/component/SettingsGroup.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/component/SettingsGroup.kt
index 1b0542a..68c17cf 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/component/SettingsGroup.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/theme/component/SettingsGroup.kt
@@ -5,6 +5,7 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
+import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
@@ -61,8 +62,8 @@ fun FlexibleListGroup(
) {
Column(
modifier = modifier
- .padding(16.dp)
- .padding(vertical = 8.dp)
+ .padding(16.dp)
+ .padding(vertical = 8.dp)
) {
title?.let {
Text(
@@ -108,9 +109,9 @@ fun ListItem(
Column {
Row(
modifier = Modifier
- .fillMaxWidth()
- .clickable(onClick = onClick)
- .padding(16.dp),
+ .fillMaxWidth()
+ .clickable(onClick = onClick)
+ .padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
leadingIcon?.invoke()
@@ -160,9 +161,9 @@ fun CustomSettingsItem(
) {
Row(
modifier = Modifier
- .fillMaxWidth()
- .clickable(onClick = onClick)
- .padding(16.dp),
+ .fillMaxWidth()
+ .clickable(onClick = onClick)
+ .padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
content = content
)
@@ -234,13 +235,13 @@ fun PaddedListItem(
tonalElevation = 2.dp,
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = Modifier
- .fillMaxWidth()
- .clip(shape)
+ .fillMaxWidth()
+ .clip(shape)
) {
Row(
modifier = Modifier
- .clickable { onClick() }
- .padding(16.dp),
+ .clickable { onClick() }
+ .padding(16.dp),
verticalAlignment = Alignment.CenterVertically) {
Icon(imageVector = icon, contentDescription = null)
Spacer(modifier = Modifier.width(16.dp))
@@ -276,6 +277,7 @@ fun CustomPaddedListItem(
background: Color = MaterialTheme.colorScheme.surfaceContainer,
contentColor: Color = MaterialTheme.colorScheme.onSurface,
onLongClick: (() -> Unit)? = null,
+ borderStroke: BorderStroke? = null,
content: @Composable RowScope.() -> Unit
) {
val shape = when (position) {
@@ -295,17 +297,18 @@ fun CustomPaddedListItem(
shape = shape,
color = background,
contentColor = contentColor,
+ border = borderStroke,
modifier = modifier
- .fillMaxWidth()
- .clip(shape)
+ .fillMaxWidth()
+ .clip(shape)
) {
Row(
modifier = Modifier
- .combinedClickable(
- onClick = onClick,
- onLongClick = onLongClick,
- )
- .padding(horizontal = 16.dp, vertical = 12.dp),
+ .combinedClickable(
+ onClick = onClick,
+ onLongClick = onLongClick,
+ )
+ .padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
content = content
)
@@ -348,19 +351,17 @@ fun CustomPaddedExpandableItem(
tonalElevation = 4.dp,
color = MaterialTheme.colorScheme.surfaceContainer,
modifier = modifier
- .fillMaxWidth()
- .clip(shape)
+ .fillMaxWidth()
+ .clip(shape)
) {
Column {
- // Default content - always clickable
Row(
modifier = Modifier
- .clickable { onToggleExpanded() }
- .padding(16.dp),
+ .clickable { onToggleExpanded() }
+ .padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
content = defaultContent)
- // Expanded content - only shown when expanded
AnimatedVisibility(
visible = isExpanded,
enter = expandVertically() + fadeIn(),
@@ -374,17 +375,10 @@ fun CustomPaddedExpandableItem(
}
}
-/**
- * Enum to define the position of an item in a padded list for proper corner rounding.
- */
enum class PaddedListItemPosition {
First, Middle, Last, Single
}
-data class SettingItem(
- val title: String, val subtitle: String? = null, val icon: ImageVector, val onClick: () -> Unit
-)
-
@Preview(showBackground = true)
@Composable
fun FlexibleSettingsGroupPreview() {
@@ -439,8 +433,8 @@ fun FlexibleSettingsGroupPreview() {
// Any other composable can go here
Box(
modifier = Modifier
- .fillMaxWidth()
- .padding(16.dp)
+ .fillMaxWidth()
+ .padding(16.dp)
) {
Text(
text = "You can put any composable content here!",
diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/wallet/Wallet.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/wallet/Wallet.kt
index 8ef0eed..40a0679 100644
--- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/wallet/Wallet.kt
+++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/wallet/Wallet.kt
@@ -13,39 +13,37 @@ import com.serranoie.app.minus.presentation.ui.budget.BudgetViewModel
import com.serranoie.app.minus.presentation.ui.editor.EditBudgetContent
import com.serranoie.app.minus.presentation.ui.theme.component.wallet.WalletStatusBarStub
-const val WALLET_SHEET = "wallet"
-
@Composable
fun Wallet(
- forceChange: Boolean = false,
- activityResultRegistryOwner: ActivityResultRegistryOwner? = null,
- budgetViewModel: BudgetViewModel = hiltViewModel(),
- onClose: () -> Unit = {},
- onOnboardingComplete: () -> Unit = {},
+ forceChange: Boolean = false,
+ activityResultRegistryOwner: ActivityResultRegistryOwner? = null,
+ budgetViewModel: BudgetViewModel = hiltViewModel(),
+ onClose: () -> Unit = {},
+ onOnboardingComplete: () -> Unit = {},
) {
- val uiState by budgetViewModel.uiState.collectAsStateWithLifecycle()
- val budgetSettings = uiState.budgetSettings
+ val uiState by budgetViewModel.uiState.collectAsStateWithLifecycle()
+ val budgetSettings = uiState.budgetSettings
- Column(modifier = Modifier.fillMaxSize()) {
- WalletStatusBarStub()
- Surface(modifier = Modifier.fillMaxSize()) {
- EditBudgetContent(
- budgetSettings = budgetSettings,
- title = if (budgetSettings != null) "Editar presupuesto" else "Nuevo presupuesto",
- buttonLabel = if (budgetSettings != null) "Actualizar" else "Aplicar",
- showPreviousValuesChip = budgetSettings != null,
- onBack = onClose,
- onApply = { newSettings ->
- budgetViewModel.saveBudgetSettings(
- newSettings,
- forceNewPeriodBoundary = forceChange || budgetSettings == null
- )
- if (forceChange || budgetSettings == null) {
- onOnboardingComplete()
- }
- onClose()
- },
- )
- }
- }
+ Column(modifier = Modifier.fillMaxSize()) {
+ WalletStatusBarStub()
+ Surface(modifier = Modifier.fillMaxSize()) {
+ EditBudgetContent(
+ budgetSettings = budgetSettings,
+ title = if (budgetSettings != null) "Editar presupuesto" else "Nuevo presupuesto",
+ buttonLabel = if (budgetSettings != null) "Actualizar" else "Aplicar",
+ showPreviousValuesChip = budgetSettings != null,
+ onBack = onClose,
+ onApply = { newSettings ->
+ budgetViewModel.saveBudgetSettings(
+ newSettings,
+ forceNewPeriodBoundary = forceChange || budgetSettings == null
+ )
+ if (forceChange || budgetSettings == null) {
+ onOnboardingComplete()
+ }
+ onClose()
+ },
+ )
+ }
+ }
}
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index c7ef356..4b73032 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -211,9 +211,15 @@
La notificación se mostrará el día que termina el período a esta hora.
Hora de pagos recurrentes
La revisión diaria de pagos recurrentes se ejecuta a esta hora.
+ Permiso de notificaciones
+ Concedido — recibirás notificaciones
+ Denegado — toca para abrir los ajustes del sistema y permitir las notificaciones
+ Abrir
Alarmas exactas
Habilitado para intentar mostrar notificaciones a la hora seleccionada.
Desactivado; Android puede retrasar la notificación
+ Cancelar
+ Aceptar
Acerca de
Obtenga más información sobre la aplicación y su desarrollo.
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 4950bd1..1bd7c09 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -215,9 +215,15 @@
La notification sera affichée le jour de fin de période à cette heure
Heure des paiements récurrents
La vérification quotidienne des paiements récurrents s’exécute à cette heure
+ Autorisation de notifications
+ Accordée — vous recevrez des notifications
+ Refusée — appuyez pour ouvrir les paramètres système et autoriser les notifications
+ Ouvrir
Alarmes exactes
Activé pour essayer d\'afficher les notifications à l\'heure sélectionnée
Désactivé ; Android peut retarder la notification
+ Annuler
+ OK
À propos
En savoir plus sur l\'application et son développement
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dc62cd3..4987c1a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -242,9 +242,15 @@
The notification will be shown on the period end date at this time
Recurring payments time
Daily recurring payment checks run at this time
+ Notifications permission
+ Granted — you will receive notifications
+ Denied — tap to open system settings and allow notifications
+ Open
Exact alarms
Enabled to try showing notifications at the selected time
Disabled; Android may delay the notification
+ Cancel
+ OK
About
Learn more about the app and its development
diff --git a/app/src/test/java/com/serranoie/app/minus/presentation/ui/screenshot/SettingsScreenshotTest.kt b/app/src/test/java/com/serranoie/app/minus/presentation/ui/screenshot/SettingsScreenshotTest.kt
index ef5ee3d..4939dc6 100644
--- a/app/src/test/java/com/serranoie/app/minus/presentation/ui/screenshot/SettingsScreenshotTest.kt
+++ b/app/src/test/java/com/serranoie/app/minus/presentation/ui/screenshot/SettingsScreenshotTest.kt
@@ -3,7 +3,6 @@ package com.serranoie.app.minus.presentation.ui.screenshot
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
import app.cash.paparazzi.DeviceConfig
import app.cash.paparazzi.Paparazzi
import com.android.ide.common.rendering.api.SessionParams
@@ -111,6 +110,10 @@ class SettingsScreenshotTest {
onResetTutorial = {},
onBugReportClick = {},
onBack = {},
+ isCensored = false,
+ notificationPermissionGranted = true,
+ onOpenNotificationSettings = {},
+ onNavigateToChangelog = {},
)
}
}
diff --git a/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDarkThemeWithCreditFeature.png b/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDarkThemeWithCreditFeature.png
index 149bb37..60596b0 100644
Binary files a/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDarkThemeWithCreditFeature.png and b/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDarkThemeWithCreditFeature.png differ
diff --git a/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDefaultState.png b/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDefaultState.png
index aaaa46f..b789588 100644
Binary files a/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDefaultState.png and b/app/src/test/snapshots/images/com.serranoie.app.minus.presentation.ui.screenshot_SettingsScreenshotTest_settingsDefaultState.png differ