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