4e097b1b4521

chaos destroy screen: red header 'THIS IS YOUR LAST CHANCE', three single-sentence warnings in breach red, solid red 'DESTROY MY VAULT FOREVER' button, 'No — take me back' escape (v2.7.11)

time
2026-07-28 01:25 UTC · 2 months ago
machine
koh2
agent
claude-MiniMax-M3
session
sync red indicator port from browser
parent
e8637519f572
2 files app/build.gradle+2 −2app/src/main/java/com/peachpasswords/ui/settings/PanicScreen.kt+82 −14
app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616         applicationId "com.peachpasswords"1717         minSdk 261818         targetSdk 3519-        versionCode 24013720-        versionName "2.7.10"19+        versionCode 24013820+        versionName "2.7.11"2121 2222         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323         vectorDrawables {

view file

app/src/main/java/com/peachpasswords/ui/settings/PanicScreen.kt+82 −14
@@ -35,7 +35,6 @@3535 import androidx.hilt.navigation.compose.hiltViewModel3636 import androidx.lifecycle.ViewModel3737 import androidx.lifecycle.viewModelScope38-import com.peachpasswords.ui.components.PeachField3938 import com.peachpasswords.ui.components.RuneGridBackground4039 import com.peachpasswords.ui.components.PeachTopBar4140 import com.peachpasswords.ui.theme.LocalPeachAccent@@ -131,7 +130,7 @@131130                     when (step) {132131                         1 -> Step1(onCancel = onBack, onContinue = { step = 2 })133132                         2 -> Step2(entryCount = entryCount, onBack = { step = 1 }, onContinue = { step = 3 })134-                        else -> Step3(onDestroy = { vm.destroy(onDestroyed) })133+                        else -> Step3(onBack = { step = 2 }, onDestroy = { vm.destroy(onDestroyed) })135134                     }136135                 }137136             }@@ -179,19 +178,88 @@179178 }180179 181180 @Composable182-private fun Step3(onDestroy: () -> Unit) {183-    var typed by remember { mutableStateOf("") }184-    val confirmed = typed == "DESTROY"181+private fun Step3(onBack: () -> Unit, onDestroy: () -> Unit) {182+    // Chaos: the final step is designed to look like a point of no return.183+    // Bright red header, three single-sentence warnings, one solid red button.184+    // The user has already confirmed at Step1 and Step2; this screen is185+    // deliberately stark rather than carrying a third confirmation gate, so186+    // the only escape is the "No — take me back" line under the button.187+    Column(modifier = Modifier.fillMaxSize()) {188+        // Red header bar — the visual claim that this screen is different.189+        Box(190+            modifier = Modifier191+                .fillMaxWidth()192+                .background(peachColors.Breach)193+                .padding(vertical = 12.dp, horizontal = PeachSpacing.lg),194+            contentAlignment = Alignment.Center,195+        ) {196+            Text(197+                "THIS IS YOUR LAST CHANCE",198+                color = peachColors.ShellTopSolid,199+                style = PeachType.sortPill.copy(200+                    fontSize = 12.sp,201+                    fontStyle = FontStyle.Italic,202+                ),203+            )204+        }205+        Spacer(Modifier.height(PeachSpacing.lg))206+        Text(207+            "Your vault is about to be permanently destroyed.",208+            color = peachColors.T0,209+            style = PeachType.body,210+        )211+        Spacer(Modifier.height(PeachSpacing.lg))212+        Text("There is no recovery.", color = peachColors.Breach, style = PeachType.body)213+        Text("There is no support.", color = peachColors.Breach, style = PeachType.body)214+        Text("There is no undo.", color = peachColors.Breach, style = PeachType.body)215+        Spacer(Modifier.height(PeachSpacing.lg))216+        // Hairline divider, matches the body-copy t3 token used elsewhere.217+        Box(218+            modifier = Modifier219+                .fillMaxWidth()220+                .height(1.dp)221+                .background(peachColors.T3.copy(alpha = 0.25f)),222+        )223+        Spacer(Modifier.weight(1f))224+        ChaosDestroyButton("DESTROY MY VAULT FOREVER", onClick = onDestroy)225+        Spacer(Modifier.height(PeachSpacing.sm))226+        Box(227+            modifier = Modifier.fillMaxWidth(),228+            contentAlignment = Alignment.Center,229+        ) {230+            Text(231+                "No — take me back",232+                color = peachColors.T2,233+                style = PeachType.sortPill.copy(fontSize = 11.sp),234+                modifier = Modifier235+                    .clip(RoundedCornerShape(999.dp))236+                    .clickable(onClick = onBack)237+                    .padding(horizontal = PeachSpacing.lg, vertical = 8.dp),238+            )239+        }240+    }241+}185242 186-    Headline("type DESTROY to confirm", 28.sp, peachColors.T0)187-    Spacer(Modifier.height(PeachSpacing.lg))188-    PeachField(189-        label = "confirmation",190-        value = typed,191-        onValueChange = { typed = it },192-    )193-    Spacer(Modifier.height(PeachSpacing.xl))194-    DangerButton("Destroy vault", enabled = confirmed, onClick = onDestroy)243+@Composable244+private fun ChaosDestroyButton(label: String, onClick: () -> Unit) {245+    Box(246+        modifier = Modifier247+            .fillMaxWidth()248+            .clip(RoundedCornerShape(10.dp))249+            .background(peachColors.Breach)250+            .clickable(onClick = onClick)251+            .padding(vertical = 14.dp),252+        contentAlignment = Alignment.Center,253+    ) {254+        Text(255+            label,256+            color = peachColors.ShellTopSolid,257+            style = PeachType.sortPill.copy(258+                fontSize = 12.sp,259+                fontStyle = FontStyle.Italic,260+            ),261+        )262+    }195263 }196264 197265 @Composable

view file