package com.peachpasswords.ui.settings import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.ArrowBack import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember 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.text.TextStyle import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.peachpasswords.ui.components.PeachField import com.peachpasswords.ui.components.PeachTopBar import com.peachpasswords.ui.theme.LocalPeachAccent import com.peachpasswords.ui.theme.LocalPeachColors import com.peachpasswords.ui.theme.PeachSpacing import com.peachpasswords.ui.theme.peachColors import com.peachpasswords.ui.theme.peachDark import com.peachpasswords.ui.theme.PeachType import com.peachpasswords.vault.VaultRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class PanicViewModel @Inject constructor(private val vault: VaultRepository) : ViewModel() { val entryCount: Int get() = vault.getEntries().size fun destroy(onDone: () -> Unit) = viewModelScope.launch { vault.destroyVault(); onDone() } } @Composable fun PanicScreen( onBack: () -> Unit, onDestroyed: () -> Unit, vm: PanicViewModel = hiltViewModel(), ) { var step by remember { mutableStateOf(1) } val entryCount = remember { vm.entryCount } // Panic always renders dark regardless of app theme: its tokens must stay // readable on the intentional near-black field below (keep the user's accent). val accent = LocalPeachAccent.current val darkPalette = remember(accent) { peachDark(accent) } CompositionLocalProvider(LocalPeachColors provides darkPalette) { // The panic flow is intentionally cold: no bloom, a flat near-black field so // it reads as a dead-end rather than another lit-up screen in the app. Box(modifier = Modifier.fillMaxSize().background(Color(0xFF0C0A06))) { Column( modifier = Modifier .fillMaxSize() .systemBarsPadding() .padding(horizontal = PeachSpacing.lg, vertical = PeachSpacing.md), ) { PeachTopBar( title = "Panic", leading = { Icon( Icons.AutoMirrored.Rounded.ArrowBack, contentDescription = "back", tint = peachColors.T0, modifier = Modifier .size(22.dp) .clip(RoundedCornerShape(PeachSpacing.sm)) .clickable(onClick = onBack), ) }, ) Box( modifier = Modifier.fillMaxSize().padding(horizontal = PeachSpacing.sm), contentAlignment = Alignment.Center, ) { Column(verticalArrangement = Arrangement.Center) { when (step) { 1 -> Step1(onCancel = onBack, onContinue = { step = 2 }) 2 -> Step2(entryCount = entryCount, onBack = { step = 1 }, onContinue = { step = 3 }) else -> Step3(onDestroy = { vm.destroy(onDestroyed) }) } } } } } } } @Composable private fun Step1(onCancel: () -> Unit, onContinue: () -> Unit) { Headline("destroy vault", 44.sp, peachColors.Breach) Spacer(Modifier.height(PeachSpacing.lg)) Text( "This will permanently delete your vault and all saved passwords from this device. This cannot be undone.", color = peachColors.T1, style = PeachType.body, ) Spacer(Modifier.height(PeachSpacing.xl)) Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(PeachSpacing.sm), ) { GhostButton("Cancel", peachColors.T1, onCancel) DangerButton("I understand, continue", enabled = true, onClick = onContinue) } } @Composable private fun Step2(entryCount: Int, onBack: () -> Unit, onContinue: () -> Unit) { Headline("are you sure?", 32.sp, peachColors.Breach) Spacer(Modifier.height(PeachSpacing.lg)) Text( "You will lose access to all $entryCount saved passwords.", color = peachColors.T1, style = PeachType.body, ) Spacer(Modifier.height(PeachSpacing.xl)) Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(PeachSpacing.sm), ) { GhostButton("Go back", peachColors.T1, onBack) DangerButton("Yes, destroy it", enabled = true, onClick = onContinue) } } @Composable private fun Step3(onDestroy: () -> Unit) { var typed by remember { mutableStateOf("") } val confirmed = typed == "DESTROY" Headline("type DESTROY to confirm", 28.sp, peachColors.T0) Spacer(Modifier.height(PeachSpacing.lg)) PeachField( label = "confirmation", value = typed, onValueChange = { typed = it }, ) Spacer(Modifier.height(PeachSpacing.xl)) DangerButton("Destroy vault", enabled = confirmed, onClick = onDestroy) } @Composable private fun Headline(text: String, fontSize: androidx.compose.ui.unit.TextUnit, color: Color) { Text( text, color = color, style = TextStyle( fontFamily = PeachType.Display, fontStyle = FontStyle.Italic, fontSize = fontSize, ), ) } @Composable private fun GhostButton(label: String, color: Color, onClick: () -> Unit) { Box( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(999.dp)) .border(1.dp, color.copy(alpha = 0.4f), RoundedCornerShape(999.dp)) .clickable(onClick = onClick) .padding(horizontal = PeachSpacing.lg, vertical = 11.dp), contentAlignment = Alignment.Center, ) { Text(label, color = color, style = PeachType.sortPill.copy(fontSize = 11.sp)) } } @Composable private fun DangerButton(label: String, enabled: Boolean, onClick: () -> Unit) { val alpha = if (enabled) 1f else 0.4f Box( modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(999.dp)) .background(peachColors.BreachBg.copy(alpha = peachColors.BreachBg.alpha * alpha)) .border(1.dp, peachColors.Breach.copy(alpha = 0.55f * alpha), RoundedCornerShape(999.dp)) .clickable(enabled = enabled, onClick = onClick) .padding(horizontal = PeachSpacing.lg, vertical = 11.dp), contentAlignment = Alignment.Center, ) { Text( label, color = peachColors.Breach.copy(alpha = alpha), style = PeachType.sortPill.copy(fontSize = 11.sp), ) } }