@@ -4,20 +4,20 @@ import androidx.compose.foundation.layout.Arrangement
44import androidx.compose.foundation.layout.Column
55import androidx.compose.foundation.layout.Row
66import androidx.compose.foundation.layout.Spacer
7- import androidx.compose.foundation.layout.fillMaxSize
7+ import androidx.compose.foundation.layout.fillMaxWidth
88import androidx.compose.foundation.layout.height
99import androidx.compose.foundation.layout.padding
1010import androidx.compose.foundation.layout.size
11- import androidx.compose.foundation.layout.wrapContentSize
12- import androidx.compose.foundation.rememberScrollState
13- import androidx.compose.foundation.shape.CircleShape
14- import androidx.compose.foundation.verticalScroll
11+ import androidx.compose.foundation.shape.RoundedCornerShape
1512import androidx.compose.material3.Button
13+ import androidx.compose.material3.ButtonDefaults
14+ import androidx.compose.material3.Card
15+ import androidx.compose.material3.CardDefaults
16+ import androidx.compose.material3.Icon
1617import androidx.compose.material3.MaterialTheme
17- import androidx.compose.material3.OutlinedButton
1818import androidx.compose.material3.OutlinedTextField
19- import androidx.compose.material3.Surface
2019import androidx.compose.material3.Text
20+ import androidx.compose.material3.TextButton
2121import androidx.compose.runtime.Composable
2222import androidx.compose.runtime.collectAsState
2323import androidx.compose.runtime.getValue
@@ -26,72 +26,155 @@ import androidx.compose.runtime.remember
2626import androidx.compose.runtime.setValue
2727import androidx.compose.ui.Alignment
2828import androidx.compose.ui.Modifier
29- import androidx.compose.ui.draw.clip
30- import androidx.compose.ui.layout.ContentScale
29+ import androidx.compose.ui.graphics.vector.ImageVector
30+ import androidx.compose.ui.text.SpanStyle
31+ import androidx.compose.ui.text.buildAnnotatedString
32+ import androidx.compose.ui.text.font.FontFamily
33+ import androidx.compose.ui.text.font.FontWeight
3134import androidx.compose.ui.text.style.TextAlign
35+ import androidx.compose.ui.text.withStyle
3236import androidx.compose.ui.unit.dp
3337import androidx.compose.ui.window.Dialog
34- import coil3.compose.AsyncImage
35- import neth.iecal.trease.models.TimerStatus
3638import neth.iecal.trease.viewmodels.HomeScreenViewModel
37-
39+ import org.jetbrains.compose.resources.painterResource
40+ import trease.composeapp.generated.resources.Res
41+ import trease.composeapp.generated.resources.outline_arrow_forward_ios_24
3842
3943@Composable
40- fun WarningBeforeQuit (viewModel : HomeScreenViewModel ,onDismissed : ()-> Unit ,onQuitConfirmed : () -> Unit ) {
44+ fun WarningBeforeQuit (
45+ viewModel : HomeScreenViewModel ,
46+ onDismissed : () -> Unit ,
47+ onQuitConfirmed : () -> Unit
48+ ) {
4149 val timeRemaining by viewModel.remainingSeconds.collectAsState()
4250 val goalFocus by viewModel.selectedMinutes.collectAsState()
4351
44- var typeText by remember { mutableStateOf(" " ) }
45- var quitterText by remember { mutableStateOf(" I am nub" ) }
46- Dialog (
47- onDismissRequest = {
48- onDismissed()
49- }
50- ){
51- Surface (modifier = Modifier .wrapContentSize().verticalScroll(rememberScrollState())) {
52- Column (modifier = Modifier .padding(32 .dp),
53- horizontalAlignment = Alignment .CenterHorizontally ,
54- verticalArrangement = Arrangement .Center ) {
52+ // Logic to calculate elapsed time
53+ val elapsedSeconds = (goalFocus * 60L ) - timeRemaining
54+ val elapsedFormatted = viewModel.formatTime(elapsedSeconds)
5555
56- Text (" The tree will wither.." , style = MaterialTheme .typography.headlineLarge,textAlign = TextAlign .Center )
56+ // Validation State
57+ var typeText by remember { mutableStateOf(" " ) }
58+ val quitterText by remember { mutableStateOf(" I am nub" ) }
59+ val isMatch = typeText == quitterText
5760
58- AsyncImage (
59- model = " https://trease-focus.github.io/cache-trees/images/${viewModel.selectedTree.value} _grid.png" ,
60- contentDescription = " Tree" ,
61- contentScale = ContentScale .Crop ,
62- modifier = Modifier .size(280 .dp)
61+ Dialog (onDismissRequest = { onDismissed() }) {
62+ Card (
63+ shape = RoundedCornerShape (24 .dp),
64+ modifier = Modifier
65+ .fillMaxWidth()
66+ .padding(16 .dp)
67+ ) {
68+ Column (
69+ modifier = Modifier
70+ .padding(24 .dp)
71+ .fillMaxWidth(),
72+ horizontalAlignment = Alignment .CenterHorizontally ,
73+ verticalArrangement = Arrangement .spacedBy(16 .dp)
74+ ) {
75+ Text (
76+ text = " The tree will wither..." ,
77+ style = MaterialTheme .typography.headlineSmall,
78+ fontWeight = FontWeight .Bold ,
79+ textAlign = TextAlign .Center ,
6380 )
6481
65- Text (" You've already focused ${viewModel.formatTime((goalFocus* 60L ) - (timeRemaining))} minutes." +
66- " Its only a short way until $goalFocus minutes..." +
67- " Please type \" $quitterText \" below to unlock the quit button" ,
68- textAlign = TextAlign .Center )
82+ Row (
83+ modifier = Modifier .fillMaxWidth(),
84+ horizontalArrangement = Arrangement .SpaceEvenly
85+ ) {
86+ WarningStatItem (
87+ value = elapsedFormatted,
88+ label = " Focused"
89+ )
90+ WarningStatItem (
91+ value = " ${goalFocus} m" ,
92+ label = " Goal"
93+ )
94+ }
6995
70- Spacer (modifier = Modifier .height(16 .dp))
96+ Text (
97+ text = buildAnnotatedString {
98+ append(" To confirm giving up, type \" " )
99+ withStyle(style = SpanStyle (
100+ fontWeight = FontWeight .Bold ,
101+ color = MaterialTheme .colorScheme.error
102+ )) {
103+ append(quitterText)
104+ }
105+ append(" \" below." )
106+ },
107+ style = MaterialTheme .typography.bodyMedium,
108+ textAlign = TextAlign .Center ,
109+ color = MaterialTheme .colorScheme.onSurfaceVariant
110+ )
71111
72112 OutlinedTextField (
73113 value = typeText,
74- onValueChange = {typeText= it}
114+ onValueChange = { typeText = it },
115+ placeholder = { Text (quitterText, color = MaterialTheme .colorScheme.outline.copy(alpha = 0.5f )) },
116+ singleLine = true ,
117+ shape = RoundedCornerShape (12 .dp),
118+ modifier = Modifier .fillMaxWidth()
75119 )
76- Spacer (modifier = Modifier .height(16 .dp))
77120
78- Row (horizontalArrangement = Arrangement .spacedBy(8 .dp, Alignment .CenterHorizontally ),){
79- OutlinedButton (onClick = {
80- onQuitConfirmed()
81- onDismissed()
82- },
83- enabled = typeText== quitterText ){
84- Text (" QUIT" )
121+ Spacer (modifier = Modifier .height(8 .dp))
122+
123+ Row (
124+ modifier = Modifier .fillMaxWidth(),
125+ horizontalArrangement = Arrangement .spacedBy(12 .dp)
126+ ) {
127+ Button (
128+ onClick = { onDismissed() },
129+ modifier = Modifier .weight(1f ),
130+ shape = RoundedCornerShape (12 .dp)
131+ ) {
132+ Text (" Resume" )
85133 }
86- Button (onClick = {
87- onDismissed()
88- }){
89- Text (" Close" )
134+
135+ TextButton (
136+ onClick = {
137+ onQuitConfirmed()
138+ onDismissed()
139+ },
140+ enabled = isMatch,
141+ modifier = Modifier .weight(1f ),
142+ shape = RoundedCornerShape (12 .dp),
143+ colors = ButtonDefaults .textButtonColors(
144+ contentColor = MaterialTheme .colorScheme.error,
145+ disabledContentColor = MaterialTheme .colorScheme.error.copy(alpha = 0.3f )
146+ )
147+ ) {
148+ Text (" Give Up" )
90149 }
91150 }
92-
93151 }
94-
95152 }
96153 }
154+ }
155+
156+ @Composable
157+ private fun WarningStatItem (
158+ value : String ,
159+ label : String
160+ ) {
161+ Column (horizontalAlignment = Alignment .CenterHorizontally ) {
162+ Icon (
163+ painter = painterResource( Res .drawable.outline_arrow_forward_ios_24),
164+ contentDescription = null ,
165+ tint = MaterialTheme .colorScheme.onSurfaceVariant,
166+ modifier = Modifier .size(20 .dp)
167+ )
168+ Text (
169+ text = value,
170+ style = MaterialTheme .typography.titleMedium,
171+ fontWeight = FontWeight .SemiBold ,
172+ color = MaterialTheme .colorScheme.onSurface
173+ )
174+ Text (
175+ text = label,
176+ style = MaterialTheme .typography.labelSmall,
177+ color = MaterialTheme .colorScheme.onSurfaceVariant
178+ )
179+ }
97180}
0 commit comments