diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/editor/Editor.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/editor/Editor.kt index 4f4a0ba..ea953b4 100644 --- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/editor/Editor.kt +++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/editor/Editor.kt @@ -35,6 +35,8 @@ import androidx.compose.material.icons.rounded.CreditCard import androidx.compose.material.icons.rounded.EventRepeat import androidx.compose.material.icons.rounded.Settings import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Badge +import androidx.compose.material3.BadgedBox import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults @@ -84,6 +86,7 @@ import com.serranoie.app.minus.presentation.ui.theme.component.AutoResizeBasicTe import com.serranoie.app.minus.presentation.ui.theme.component.budget.BudgetPill import com.serranoie.app.minus.presentation.ui.theme.component.numpad.EditStage import com.serranoie.app.minus.presentation.ui.theme.displayLargeCondensed +import com.serranoie.app.minus.presentation.util.LocalCensorMode import com.serranoie.app.minus.presentation.util.Utils.weakHapticFeedback import com.serranoie.app.minus.presentation.util.symbolOnlyCurrencyFormat import kotlinx.coroutines.delay @@ -241,6 +244,7 @@ fun Editor( } if (showSettingsButton) { + val isCensored = LocalCensorMode.current IconButton( onClick = { onOpenSettings() @@ -248,12 +252,16 @@ fun Editor( }, modifier = Modifier.size(48.dp) ) { - Icon( - imageVector = Icons.Rounded.Settings, - contentDescription = "Settings", - tint = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.size(28.dp), - ) + BadgedBox( + badge = { if (isCensored) Badge() }, + ) { + Icon( + imageVector = Icons.Rounded.Settings, + contentDescription = "Settings", + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(28.dp), + ) + } } } } diff --git a/app/src/main/java/com/serranoie/app/minus/presentation/ui/home/MainScreenContent.kt b/app/src/main/java/com/serranoie/app/minus/presentation/ui/home/MainScreenContent.kt index 2164767..d832aa9 100644 --- a/app/src/main/java/com/serranoie/app/minus/presentation/ui/home/MainScreenContent.kt +++ b/app/src/main/java/com/serranoie/app/minus/presentation/ui/home/MainScreenContent.kt @@ -28,6 +28,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.BarChart import androidx.compose.material.icons.rounded.Settings +import androidx.compose.material3.Badge +import androidx.compose.material3.BadgedBox import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api @@ -97,6 +99,7 @@ import com.serranoie.app.minus.presentation.ui.theme.component.numpad.Numpad import com.serranoie.app.minus.presentation.ui.theme.isNightMode import com.serranoie.app.minus.presentation.ui.tutorial.FirstLaunchTutorialStage import com.serranoie.app.minus.presentation.ui.tutorial.FIRST_LAUNCH_TUTORIAL_STAGE_KEY +import com.serranoie.app.minus.presentation.util.LocalCensorMode import com.serranoie.app.minus.presentation.util.StatusBarPadding import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -339,7 +342,14 @@ private fun MainNavigationRail( modifier = itemModifier, selected = false, onClick = onNavigateToSettings, - icon = { Icon(Icons.Rounded.Settings, contentDescription = "Settings") }, + icon = { + val isCensored = LocalCensorMode.current + BadgedBox( + badge = { if (isCensored) Badge() }, + ) { + Icon(Icons.Rounded.Settings, contentDescription = "Settings") + } + }, label = { Text("Settings") }) Spacer(Modifier.weight(1f)) } 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 febf374..cd3517d 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 @@ -6,6 +6,7 @@ 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.Column @@ -38,12 +39,15 @@ 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.outlined.RemoveRedEye +import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MediumTopAppBar +import androidx.compose.material3.OutlinedCard import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButtonDefaults import androidx.compose.material3.Scaffold @@ -65,6 +69,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext @@ -81,6 +86,7 @@ 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.theme.MinusTheme +import com.serranoie.app.minus.presentation.ui.theme.bodySmallCondensed import com.serranoie.app.minus.presentation.ui.theme.component.CustomPaddedExpandableItem import com.serranoie.app.minus.presentation.ui.theme.component.CustomPaddedListItem import com.serranoie.app.minus.presentation.ui.theme.component.PaddedListGroup @@ -89,15 +95,16 @@ import com.serranoie.app.minus.presentation.ui.theme.labelLargeCondensed import com.serranoie.app.minus.presentation.util.Utils import com.serranoie.app.minus.presentation.util.Utils.toggleFeedback import com.serranoie.app.minus.presentation.util.Utils.weakHapticFeedback +import kotlinx.coroutines.launch import java.time.LocalTime import java.time.format.DateTimeFormatter import java.util.Locale -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun Settings( modifier: Modifier = Modifier, + isCensored: Boolean = false, currentTheme: String, currentTypography: String, isMaterialYouEnabled: Boolean, @@ -176,6 +183,50 @@ fun Settings( .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) 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 8ea93a3..fdbef9e 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 @@ -8,6 +8,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.serranoie.app.minus.presentation.util.LocalCensorMode import dagger.hilt.android.EntryPointAccessors @Composable @@ -18,6 +19,7 @@ fun SettingsScreen( ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val context = LocalContext.current + val isCensored = LocalCensorMode.current val importLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenDocument(), @@ -50,6 +52,7 @@ fun SettingsScreen( } Settings( + isCensored = isCensored, currentTheme = uiState.currentTheme, currentTypography = uiState.currentTypography, isMaterialYouEnabled = uiState.isMaterialYouEnabled, @@ -76,4 +79,4 @@ fun SettingsScreen( onBugReportClick = viewModel::onBugReportClick, onBack = viewModel::onBack, ) -} +} \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1aa65d9..5f9a0d1 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -167,6 +167,11 @@ Con el tiempo, aprende cuánto puedes ahorrar y cuánto puedes gastar. Continuar Recurrente + Modo de censura activo + Todos tus valores financieros están difuminados. + Entendido + Modo privado activado + Cubre la parte superior del teléfono (donde está la cámara) con la mano durante un segundo para desactivarlo. Selecciona el periodo %1$d días · %2$s - %3$s diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d932d9a..e23c888 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -170,6 +170,11 @@ Avec le temps, apprenez combien vous pouvez économiser et dépenser. Continuer Récurrent + Mode censure activé + Toutes vos valeurs financières sont floutées. + Compris + Mode privé activé + Couvrez le haut du téléphone (là où se trouve l\'appareil photo) avec votre main pendant environ une seconde pour l\'éteindre. Sélectionnez la période diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bed7db4..045e39a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -190,6 +190,11 @@ Over time, learn how much you can save and how much you can spend. Continue Recurrent + Censor mode is active + All your financial values are currently blurred. + Got it + Privacy mode activated + Cover the top of the phone (where the camera sits) with your hand for about a second to turn it off. Select the period