1+ package fr.utbm.sy43.pilulito.ui.screens
2+
3+ import androidx.compose.foundation.layout.*
4+ import androidx.compose.foundation.rememberScrollState
5+ import androidx.compose.foundation.shape.RoundedCornerShape
6+ import androidx.compose.foundation.verticalScroll
7+ import androidx.compose.material3.*
8+ import androidx.compose.runtime.*
9+ import androidx.compose.ui.Alignment
10+ import androidx.compose.ui.Modifier
11+ import androidx.compose.ui.graphics.Color
12+ import androidx.compose.ui.text.font.FontWeight
13+ import androidx.compose.ui.text.input.PasswordVisualTransformation
14+ import androidx.compose.ui.unit.dp
15+ import androidx.compose.ui.unit.sp
16+ import androidx.lifecycle.viewmodel.compose.viewModel
17+ import androidx.navigation.NavHostController
18+ import fr.utbm.sy43.pilulito.ui.AppViewModelProvider
19+ import fr.utbm.sy43.pilulito.ui.components.NavBarComponent
20+ import fr.utbm.sy43.pilulito.ui.components.TopBarComponent
21+ import fr.utbm.sy43.pilulito.ui.navigation.Route
22+ import fr.utbm.sy43.pilulito.ui.theme.LocalThemeState
23+ import fr.utbm.sy43.pilulito.viewmodels.SettingsViewModel
24+
25+
26+ private val Orange = Color (0xFFFF6C00 )
27+ private val OrangeLight = Color (0xFFFFF3EC )
28+ private val CardBg = Color (0xFFFAFAFA )
29+
30+ @Composable
31+ fun SettingsScreen (
32+ navController : NavHostController ,
33+ viewModel : SettingsViewModel = viewModel(factory = AppViewModelProvider .Factory )
34+ ) {
35+ val uiState by viewModel.uiState.collectAsState()
36+ val themeState = LocalThemeState .current
37+
38+ Column (modifier = Modifier .fillMaxSize()) {
39+ TopBarComponent (navController)
40+
41+ Column (
42+ modifier = Modifier
43+ .weight(1f )
44+ .fillMaxWidth()
45+ .verticalScroll(rememberScrollState())
46+ .padding(20 .dp),
47+ verticalArrangement = Arrangement .spacedBy(20 .dp)
48+ ) {
49+ Text (
50+ text = " Settings" ,
51+ fontSize = 24 .sp,
52+ fontWeight = FontWeight .Bold ,
53+ color = Orange
54+ )
55+
56+
57+ SettingsCard (title = " Appearance" ) {
58+ Row (
59+ modifier = Modifier .fillMaxWidth(),
60+ horizontalArrangement = Arrangement .SpaceBetween ,
61+ verticalAlignment = Alignment .CenterVertically
62+ ) {
63+ Column {
64+ Text (" Dark mode" , fontSize = 16 .sp, fontWeight = FontWeight .Medium )
65+ Text (
66+ if (themeState.isDark) " Dark theme enabled"
67+ else " Light theme enabled" ,
68+ fontSize = 13 .sp,
69+ color = Color .Gray
70+ )
71+ }
72+ Switch (
73+ checked = themeState.isDark,
74+ onCheckedChange = { themeState.isDark = it },
75+ colors = SwitchDefaults .colors(
76+ checkedThumbColor = Color .White ,
77+ checkedTrackColor = Orange ,
78+ uncheckedThumbColor = Color .White ,
79+ uncheckedTrackColor = Color .LightGray
80+ )
81+ )
82+ }
83+ }
84+
85+ SettingsCard (title = " Change email" ) {
86+ Text (
87+ text = " Current: ${uiState.email} " ,
88+ fontSize = 13 .sp,
89+ color = Color .Gray
90+ )
91+ Spacer (Modifier .height(8 .dp))
92+ OutlinedTextField (
93+ value = uiState.newEmail,
94+ onValueChange = { viewModel.onNewEmailChanged(it) },
95+ label = { Text (" New email" ) },
96+ singleLine = true ,
97+ modifier = Modifier .fillMaxWidth(),
98+ colors = settingsFieldColors()
99+ )
100+ Spacer (Modifier .height(8 .dp))
101+ Button (
102+ onClick = { viewModel.saveEmail() },
103+ modifier = Modifier .fillMaxWidth(),
104+ shape = RoundedCornerShape (12 .dp),
105+ colors = ButtonDefaults .buttonColors(containerColor = Orange )
106+ ) {
107+ Text (" Update email" )
108+ }
109+ }
110+
111+ SettingsCard (title = " Change password" ) {
112+ OutlinedTextField (
113+ value = uiState.newPassword,
114+ onValueChange = { viewModel.onNewPasswordChanged(it) },
115+ label = { Text (" New password" ) },
116+ singleLine = true ,
117+ visualTransformation = PasswordVisualTransformation (),
118+ modifier = Modifier .fillMaxWidth(),
119+ colors = settingsFieldColors()
120+ )
121+ Spacer (Modifier .height(8 .dp))
122+ OutlinedTextField (
123+ value = uiState.confirmPassword,
124+ onValueChange = { viewModel.onConfirmPasswordChanged(it) },
125+ label = { Text (" Confirm password" ) },
126+ singleLine = true ,
127+ visualTransformation = PasswordVisualTransformation (),
128+ modifier = Modifier .fillMaxWidth(),
129+ colors = settingsFieldColors()
130+ )
131+ Spacer (Modifier .height(8 .dp))
132+ Button (
133+ onClick = { viewModel.savePassword() },
134+ modifier = Modifier .fillMaxWidth(),
135+ shape = RoundedCornerShape (12 .dp),
136+ colors = ButtonDefaults .buttonColors(containerColor = Orange )
137+ ) {
138+ Text (" Update password" )
139+ }
140+ }
141+
142+ uiState.successMessage?.let {
143+ Text (it, color = Color (0xFF4CAF50 ), fontSize = 14 .sp, fontWeight = FontWeight .Medium )
144+ }
145+ uiState.errorMessage?.let {
146+ Text (it, color = MaterialTheme .colorScheme.error, fontSize = 14 .sp)
147+ }
148+
149+ Spacer (Modifier .height(8 .dp))
150+ }
151+
152+ var showDeleteDialog by remember { mutableStateOf(false ) }
153+
154+ if (showDeleteDialog) {
155+ AlertDialog (
156+ onDismissRequest = { showDeleteDialog = false },
157+ shape = RoundedCornerShape (20 .dp),
158+ title = { Text (" Delete account" , fontWeight = FontWeight .Bold ) },
159+ text = { Text (" This action is permanent. Your account will be deleted." ) },
160+ confirmButton = {
161+ TextButton (onClick = {
162+ viewModel.deleteAccount()
163+ navController.navigate(Route .Login .route) {
164+ popUpTo(0 ) { inclusive = true }
165+ }
166+ }) {
167+ Text (" Delete" , color = Color (0xFFE53935 ), fontWeight = FontWeight .Bold )
168+ }
169+ },
170+ dismissButton = {
171+ TextButton (onClick = { showDeleteDialog = false }) {
172+ Text (" Cancel" )
173+ }
174+ }
175+ )
176+ }
177+
178+ Button (
179+ onClick = { showDeleteDialog = true },
180+ modifier = Modifier .fillMaxWidth().height(56 .dp),
181+ shape = RoundedCornerShape (16 .dp),
182+ colors = ButtonDefaults .buttonColors(
183+ containerColor = Color (0xFFE53935 ).copy(alpha = 0.1f ),
184+ contentColor = Color (0xFFE53935 )
185+ )
186+ ) {
187+ Text (" Delete account" , fontSize = 16 .sp, fontWeight = FontWeight .Bold )
188+ }
189+
190+ NavBarComponent (navController)
191+ }
192+ }
193+
194+ @Composable
195+ private fun SettingsCard (title : String , content : @Composable ColumnScope .() -> Unit ) {
196+ Card (
197+ shape = RoundedCornerShape (20 .dp),
198+ colors = CardDefaults .cardColors(containerColor = CardBg ),
199+ elevation = CardDefaults .cardElevation(0 .dp),
200+ modifier = Modifier .fillMaxWidth()
201+ ) {
202+ Column (
203+ modifier = Modifier .padding(16 .dp),
204+ verticalArrangement = Arrangement .spacedBy(4 .dp)
205+ ) {
206+ Text (title, fontSize = 14 .sp, color = Color .Gray )
207+ Spacer (Modifier .height(4 .dp))
208+ content()
209+ }
210+ }
211+ }
212+
213+ @Composable
214+ private fun settingsFieldColors () = OutlinedTextFieldDefaults .colors(
215+ focusedBorderColor = Orange ,
216+ unfocusedBorderColor = Color (0xFFDDDDDD ),
217+ focusedLabelColor = Orange
218+ )
0 commit comments