diff --git a/What_The_Fantasy/app/build.gradle.kts b/What_The_Fantasy/app/build.gradle.kts index 994366b..4b7e70e 100644 --- a/What_The_Fantasy/app/build.gradle.kts +++ b/What_The_Fantasy/app/build.gradle.kts @@ -50,7 +50,7 @@ android { } dependencies { - + implementation(libs.bcrypt) // pour hacher les mdp implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) @@ -68,4 +68,7 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + implementation(libs.coil.compose) //gére les url des image + implementation(kotlin("script-runtime")) + } \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/AndroidManifest.xml b/What_The_Fantasy/app/src/main/AndroidManifest.xml index 1aef3bb..5dbf082 100644 --- a/What_The_Fantasy/app/src/main/AndroidManifest.xml +++ b/What_The_Fantasy/app/src/main/AndroidManifest.xml @@ -1,6 +1,9 @@ + + + = listOf( - user1, user2, user3, user4, user5, user6, user7, user8, user9, user10 + user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11 ) } \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt index 10af186..ce4cb2f 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt @@ -5,5 +5,6 @@ class User( var username:String, var email:String, var date:String, - val imgUrl: String + val imgUrl: String, + val password: String ) diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/ErrorMessageComponent.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/ErrorMessageComponent.kt new file mode 100644 index 0000000..6498a73 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/ErrorMessageComponent.kt @@ -0,0 +1,22 @@ +package com.example.what_the_fantasy.ui.components + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + + +@Composable +fun ErrorMessageProfileComponent(titleResId : Int) { + val textError = stringResource(id = titleResId) + Text( + text = textError, + color = Color.Red, + fontSize = 12.sp, + modifier = Modifier.padding(top = 4.dp) + ) +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/SpaceComponent.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/SpaceComponent.kt new file mode 100644 index 0000000..d9a69d7 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/SpaceComponent.kt @@ -0,0 +1,15 @@ +package com.example.what_the_fantasy.ui.components + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SpaceHeightComponent(height : Int){ + Spacer( + modifier = Modifier + .height(height.dp)) // Ajoute un espacement +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt new file mode 100644 index 0000000..86aad8f --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt @@ -0,0 +1,21 @@ +package com.example.what_the_fantasy.ui.components + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + + + +@Composable +fun TitlePageComponent(titleResId : Int, size : Int, color : Color) { + val title = stringResource(id = titleResId) + Text( + text = title, + fontSize = size.sp, + fontWeight = FontWeight.Bold, + color = color + ) +} diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt new file mode 100644 index 0000000..d7c38e5 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt @@ -0,0 +1,60 @@ +package com.example.what_the_fantasy.ui.navigations + +import androidx.compose.runtime.Composable +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.example.what_the_fantasy.ui.screens.AccueilPage +import com.example.what_the_fantasy.ui.screens.FavoritePage +import com.example.what_the_fantasy.ui.screens.LoginPage +import com.example.what_the_fantasy.ui.screens.ProfilPage +import com.example.what_the_fantasy.ui.screens.QuizPage +import com.example.what_the_fantasy.ui.screens.QuotePage +import com.example.what_the_fantasy.ui.screens.SearchPage +import com.example.what_the_fantasy.ui.screens.SignUpPage +import com.example.what_the_fantasy.ui.screens.SubmitQuotePage + + + +sealed class Destination(val route: String) { + data object Login : Destination("Login") + data object Accueil : Destination("Accueil") + data object Favorite : Destination("Favorite") + data object Profil : Destination("Profil/{userIndex}") { // Ajout du paramètre userIndex + fun createRoute(userIndex: Int) = "Profil/$userIndex" // Fonction pour créer la route avec l'index + } + data object Quiz : Destination("Quiz") + data object Quote : Destination("Quote") + data object Search : Destination("Search") + data object SignUp : Destination("SignUp") + data object SubmitQuote : Destination("SubmitQuote") +} + +@Composable +fun AppNavigator() { + val navController = rememberNavController() + + NavHost(navController, startDestination = Destination.Login.route) { + composable(Destination.Login.route) { + LoginPage( + navControllerSignUp = { navController.navigate(Destination.SignUp.route) }, + navControllerProfil = { userIndex -> + navController.navigate(Destination.Profil.createRoute(userIndex)) // Passe l'index à Profil + } + ) + } + composable(Destination.Accueil.route) { AccueilPage() } + composable(Destination.Favorite.route) { FavoritePage() } + composable(Destination.Profil.route) { backStackEntry -> + // Récupère l'index passé dans la route + val userIndex = backStackEntry.arguments?.getString("userIndex")?.toInt() ?: -1 + ProfilPage(index = userIndex, navController = navController) + } + composable(Destination.Quiz.route) { QuizPage(navController) } + composable(Destination.Quote.route) { QuotePage() } + composable(Destination.Search.route) { SearchPage() } + composable(Destination.SignUp.route) { SignUpPage(navController) } + composable(Destination.SubmitQuote.route) { SubmitQuotePage() } + } +} + diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt index 2596711..d5d3fd7 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt @@ -1,29 +1,20 @@ package com.example.what_the_fantasy.ui.screens -import android.os.Bundle -import android.text.style.BackgroundColorSpan -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable 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.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text -import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -36,66 +27,62 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import com.example.what_the_fantasy.R +import com.example.what_the_fantasy.data.local.UserStub +import com.example.what_the_fantasy.data.model.User +import com.example.what_the_fantasy.ui.components.SpaceHeightComponent +import com.example.what_the_fantasy.ui.components.TitlePageComponent +import com.example.what_the_fantasy.ui.theme.colorBackground +import com.example.what_the_fantasy.ui.theme.gradienBox +import java.security.MessageDigest @Composable -fun LoginPage(navController : NavController) { +fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit) { + + val users = UserStub.allUsers; - val gradient = Brush.linearGradient( - colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé - start = Offset(0f, 1000f), // Départ en bas à gauche - end = Offset(1000f, 0f) // Fin en haut à droite - ) Box( modifier = Modifier .fillMaxSize() - .background(Color(0xFF100C1B)), + .background(colorBackground), contentAlignment = Alignment.Center ){ Column( modifier = Modifier - .fillMaxWidth(0.9f) // Ajuste la largeur - .padding(20.dp) // Marge extérieure - .clip(RoundedCornerShape(16.dp)) // Arrondi les angles - .background(gradient) // Ajoute un fond blanc - .padding(20.dp), // Padding interne + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradienBox) + .padding(20.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - TitlePage(R.string.titleLogin, 20,Color.White) - IdentifiantTextField(R.string.IdentifiantLogin) - PassWdTextField(R.string.PasswdLogin) - Space(16) - ConnexionButtonLogin(R.string.ButtonLogin,18, Color.White, Color.Black) - Space(16) - CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navController) - + TitlePageComponent(R.string.titleLogin, 20,Color.White) + val identifiant =IdentifiantTextField(R.string.IdentifiantLogin) + val passwd = PassWdTextField(R.string.PasswdLogin) + SpaceHeightComponent(16) + ConnexionButtonLogin(users,identifiant, passwd, R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil) + SpaceHeightComponent(16) + CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp) } } } -@Composable -fun Space(height : Int){ - Spacer( - modifier = Modifier - .height(height.dp)) // Ajoute un espacement -} + @Composable -fun IdentifiantTextField(textIdentifiantResId : Int){ +fun IdentifiantTextField(textIdentifiantResId : Int) : String{ val textIdentifiant = stringResource(id = textIdentifiantResId) var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ Column(modifier = Modifier.padding(top = 16.dp)) { @@ -110,10 +97,11 @@ fun IdentifiantTextField(textIdentifiantResId : Int){ shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis ) } + return identifiant; } @Composable -fun PassWdTextField(textpasswdResId : Int){ +fun PassWdTextField(textpasswdResId : Int) : String{ val textpasswd = stringResource(id = textpasswdResId) var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer @@ -131,27 +119,18 @@ fun PassWdTextField(textpasswdResId : Int){ IconButton(onClick = { passwordVisible = !passwordVisible }) { } }, - shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + shape = RoundedCornerShape(16.dp) // Bords arrondis ) } + return passwd; } -@Composable -fun TitlePage(titleResId : Int, size : Int, color : Color){ - val title = stringResource(id = titleResId) - Text( - text = title, - fontSize = size.sp, - fontWeight = FontWeight.Bold, - color = color - ) -} @Composable -fun ConnexionButtonLogin(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ +fun ConnexionButtonLogin(userStub : List, id : String, passwd : String, titleResId : Int, size : Int, colorButton : Color, colorText : Color, navController: (Int) -> Unit){ val title = stringResource(id = titleResId) Button( - onClick = { /* Action */ }, + onClick = { validLogin(id, passwd, userStub, navController) }, colors = ButtonDefaults.buttonColors(containerColor = colorButton), modifier = Modifier .fillMaxWidth(), @@ -160,26 +139,38 @@ fun ConnexionButtonLogin(titleResId : Int, size : Int, colorButton : Color, colo } } + +fun validLogin(identifiant : String, passwd : String, users : List, navController: (Int) -> Unit){ + users.forEachIndexed { index, user -> + val hashPassWd = hashPassword(passwd) + if (user.username == identifiant && user.password == hashPassWd) { + // Utilise l'index pour naviguer à la position correspondante + navController(index) // Passer l'index à la fonction navController + } + } +} + +fun hashPassword(password: String): String { + // SHA-256 + val digest = MessageDigest.getInstance("SHA-256") + + // Convertir mdp en bytes et appliquer le hash + val hashedBytes = digest.digest(password.toByteArray()) + + // Convertir le tableau de bytes en une chaîne hexadécimale + return hashedBytes.joinToString("") { "%02x".format(it) } +} + + @Composable -fun CreateAccountButton(titleResId : Int, size : Int, color : Color, navController: NavController){ +fun CreateAccountButton(titleResId : Int, size : Int, color : Color, navController: () -> Unit){ val title = stringResource(id = titleResId) Text( text = title, fontSize = size.sp, color = color, modifier = Modifier.clickable { - navController.navigate("signup")// rediriger vers la page de création de compte + navController()// rediriger vers la page de création de compte } ) } - -@Composable -fun AppNavigator() { - val navController = rememberNavController() - - NavHost(navController, startDestination = "login") { - composable("login") { LoginPage(navController) } - composable("signup") { SignUpPage(navController) } - } - -} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt index ea753fd..c2c0702 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt @@ -1,6 +1,9 @@ package com.example.what_the_fantasy.ui.screens +import android.content.Context import android.os.Bundle +import android.util.Patterns +import android.widget.ImageView import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -54,16 +57,24 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import coil.compose.AsyncImage import com.example.what_the_fantasy.R +import com.example.what_the_fantasy.data.local.QuestionStub +import com.example.what_the_fantasy.data.local.UserStub +import com.example.what_the_fantasy.ui.components.ErrorMessageProfileComponent +import com.example.what_the_fantasy.ui.components.SpaceHeightComponent +import com.example.what_the_fantasy.ui.components.TitlePageComponent import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme @Composable -fun ProfilPage() { +fun ProfilPage(index: Int, navController: NavController) { val gradient = Brush.linearGradient( colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé start = Offset(0f, 1000f), // Départ en bas à gauche end = Offset(1000f, 0f) // Fin en haut à droite ) + val user = UserStub.allUsers + //val index = 2 // Pour changer l'utilisateur pour le moment Box( modifier = Modifier @@ -82,30 +93,27 @@ fun ProfilPage() { ) { // Titre - TitleProfil(R.string.titleProfile, 20, Color.White) - SpaceProfil(16) + TitlePageComponent(R.string.titleProfile, 20, Color.White) + SpaceHeightComponent(16) // Image de profil - val id = R.drawable.ic_launcher_foreground - ImageProfil(id, 120, 2, Color.White) + ImageProfil(user[index].imgUrl, 120, 2, Color.White) + SpaceHeightComponent(16) + EditUsername(user[index].username)// Édition du Username + SpaceHeightComponent(16) - SpaceProfil(16) - - EditUsername()// Édition du Username - SpaceProfil(16) - - EditEmail()// Édition du Email + EditEmail(user[index].email)// Édition du Email Spacer(modifier = Modifier.height(8.dp)) EditPasswd() - SpaceProfil(16) + SpaceHeightComponent(16) // Bouton ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White) - SpaceProfil(16) + SpaceHeightComponent(16) ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White) - SpaceProfil(16) + SpaceHeightComponent(16) ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White) } @@ -114,254 +122,318 @@ fun ProfilPage() { @Composable -fun SpaceProfil(height : Int){ - Spacer( - modifier = Modifier - .height(height.dp)) // Ajoute un espacement -} - - -@Composable -fun TitleProfil(titleResId : Int, size : Int, color : Color){ - val title = stringResource(id = titleResId) - Text( - text = title, - fontSize = size.sp, - fontWeight = FontWeight.Bold, - color = color - ) -} +fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : Color){ -@Composable -fun ImageProfil(imgProfil : Int, size :Int, sizeBorber : Int, colorBorder : Color){ - Image( - painter = painterResource(imgProfil), + AsyncImage( + model = imgProfil, contentDescription = "Photo de profil", modifier = Modifier .size(size.dp) .clip(CircleShape) - .border(sizeBorber.dp, colorBorder, CircleShape) ) } - @Composable -fun EditEmail(){ - var email by remember { mutableStateOf("user@example.com") } - var isEditingEmail by remember { mutableStateOf(false) } // État d'édition +fun EditEmail(userEmail: String) { + var email by remember { mutableStateOf(userEmail) } + var isEditingEmail by remember { mutableStateOf(false) } var emailError by remember { mutableStateOf(false) } if (isEditingEmail) { - OutlinedTextField( - value = email, - onValueChange = { - email = it - emailError = !android.util.Patterns.EMAIL_ADDRESS.matcher(it).matches() + EmailEditingField( + email = email, + onEmailChange = { newEmail -> + email = newEmail + emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() }, - modifier = Modifier.fillMaxWidth(), - textStyle = TextStyle(color = Color.White, fontSize = 18.sp), - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Email, // ✅ Clavier spécialisé pour email - imeAction = ImeAction.Done - ), - keyboardActions = KeyboardActions( - onDone = { if (!emailError) isEditingEmail = false } // ✅ Fermer si l'email est valide - ), - trailingIcon = { - IconButton(onClick = { if (!emailError) isEditingEmail = false }) { - Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") - } + onDone = { + if (!emailError) isEditingEmail = false }, - isError = emailError // ✅ Afficher l'erreur si l'email est invalide + emailError = emailError ) - if (emailError) { - val text = stringResource(id = R.string.ErrorEmailprofile) - Text( - text = text, - color = Color.Red, - fontSize = 12.sp, - modifier = Modifier.padding(top = 4.dp) - ) - } } else { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { isEditingEmail = true } - ) { - Text( - text = email, - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Icon( - imageVector = Icons.Default.Edit, - contentDescription = "Modifier", - tint = Color.White, - modifier = Modifier.size(16.dp).padding(start = 8.dp) - ) - } + DisplayEmail(email = email, onEdit = { isEditingEmail = true }) + } +} + +@Composable +fun EmailEditingField( + email: String, + onEmailChange: (String) -> Unit, + onDone: () -> Unit, + emailError: Boolean +) { + OutlinedTextField( + value = email, + onValueChange = onEmailChange, + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle(color = Color.White, fontSize = 18.sp), + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Email, + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { onDone() } + ), + trailingIcon = { + IconButton(onClick = { if (!emailError) onDone() }) { + Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") + } + }, + isError = emailError + ) + + if (emailError) { + ErrorMessageProfileComponent(R.string.ErrorEmailprofile) + } +} + + +@Composable +fun DisplayEmail(email: String, onEdit: () -> Unit) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { onEdit() } + ) { + Text( + text = email, + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Icon( + imageVector = Icons.Default.Edit, + contentDescription = "Modifier", + tint = Color.White, + modifier = Modifier.size(16.dp).padding(start = 8.dp) + ) } } + + + @Composable -fun EditUsername(){ - var username by remember { mutableStateOf("Username") } - var isEditingUsername by remember { mutableStateOf(false) } // État d'édition +fun EditUsername(userName: String) { + var username by remember { mutableStateOf(userName) } + var isEditingUsername by remember { mutableStateOf(false) } if (isEditingUsername) { - OutlinedTextField( - value = username, - onValueChange = { username = it }, - modifier = Modifier.fillMaxWidth(), - textStyle = TextStyle(color = Color.White, fontSize = 18.sp), - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy( - imeAction = ImeAction.Done - ), - keyboardActions = KeyboardActions( - onDone = { isEditingUsername = false } // Quand on appuie sur "Done" - ), - trailingIcon = { - IconButton(onClick = { isEditingUsername = false }) { - Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") - } - } + UsernameEditingField( + username = username, + onUsernameChange = { username = it }, + onDone = { isEditingUsername = false } ) } else { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { isEditingUsername = true } - ) { - Text( - text = username, - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Icon( - imageVector = Icons.Default.Edit, - contentDescription = "Modifier", - tint = Color.White, - modifier = Modifier.size(16.dp).padding(start = 8.dp) - ) + DisplayUsername(username = username, onEdit = { isEditingUsername = true }) + } +} + +@Composable +fun UsernameEditingField( + username: String, + onUsernameChange: (String) -> Unit, + onDone: () -> Unit +) { + OutlinedTextField( + value = username, + onValueChange = onUsernameChange, + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle(color = Color.White, fontSize = 18.sp), + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy( + imeAction = ImeAction.Done + ), + keyboardActions = KeyboardActions( + onDone = { onDone() } // Quand on appuie sur "Done", on met fin à l'édition + ), + trailingIcon = { + IconButton(onClick = { onDone() }) { + Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") + } } + ) +} + +@Composable +fun DisplayUsername(username: String, onEdit: () -> Unit) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { onEdit() } + ) { + Text( + text = username, + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Icon( + imageVector = Icons.Default.Edit, + contentDescription = "Modifier", + tint = Color.White, + modifier = Modifier.size(16.dp).padding(start = 8.dp) + ) } } + + + + @Composable -fun EditPasswd(){ +fun EditPasswd() { var password by remember { mutableStateOf("*******") } var isEditingPassword by remember { mutableStateOf(false) } var newPassword by remember { mutableStateOf("") } var confirmPassword by remember { mutableStateOf("") } var passwordVisible by remember { mutableStateOf(false) } var passwordError by remember { mutableStateOf(false) } + if (isEditingPassword) { - Column { - val text = stringResource(id = R.string.NewPasswdprofile) - OutlinedTextField( - value = newPassword, - onValueChange = { newPassword = it }, - label = { Text(text) }, - modifier = Modifier.fillMaxWidth(), - textStyle = TextStyle(color = Color.White, fontSize = 18.sp), - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Password, - imeAction = ImeAction.Next - ), - visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), - trailingIcon = { - IconButton(onClick = { passwordVisible = !passwordVisible }) { - - } + PasswordEditingFields( + newPassword = newPassword, + confirmPassword = confirmPassword, + onNewPasswordChange = { newPassword = it }, + onConfirmPasswordChange = { + confirmPassword = it + passwordError = newPassword != it + }, + passwordVisible = passwordVisible, + onPasswordVisibilityChange = { passwordVisible = it }, + passwordError = passwordError, + onDone = { + if (!passwordError && newPassword.isNotEmpty()) { + password = newPassword + isEditingPassword = false } - ) - - Spacer(modifier = Modifier.height(8.dp)) - val textConfirm = stringResource(id = R.string.ConfirmNewPasswdprofile) - OutlinedTextField( - value = confirmPassword, - onValueChange = { - confirmPassword = it - passwordError = newPassword != it - }, - - label = { Text(textConfirm) }, - modifier = Modifier.fillMaxWidth(), - textStyle = TextStyle(color = Color.White, fontSize = 18.sp), - singleLine = true, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Password, - imeAction = ImeAction.Done - ), - keyboardActions = KeyboardActions( - onDone = { if (!passwordError && newPassword.isNotEmpty()) { - password = newPassword - isEditingPassword = false - }} - ), - visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), - trailingIcon = { - IconButton(onClick = { passwordVisible = !passwordVisible }) { - - } - }, - isError = passwordError - ) - - if (passwordError) { - val text = stringResource(id = R.string.Errorpasswdprofile) - Text( - text = text, - color = Color.Red, - fontSize = 12.sp, - modifier = Modifier.padding(top = 4.dp) - ) } + ) + } else { + DisplayPassword(onEdit = { isEditingPassword = true }) + } +} - Spacer(modifier = Modifier.height(8.dp)) +@Composable +fun PasswordEditingFields( + newPassword: String, + confirmPassword: String, + onNewPasswordChange: (String) -> Unit, + onConfirmPasswordChange: (String) -> Unit, + passwordVisible: Boolean, + onPasswordVisibilityChange: (Boolean) -> Unit, + passwordError: Boolean, + onDone: () -> Unit +) { + Column { + val text = stringResource(id = R.string.NewPasswdprofile) + PasswordTextField( + value = newPassword, + onValueChange = onNewPasswordChange, + label = text, + passwordVisible = passwordVisible, + onPasswordVisibilityChange = onPasswordVisibilityChange + ) - Button( - onClick = { - if (!passwordError && newPassword.isNotEmpty()) { - password = newPassword - isEditingPassword = false - } - }, - colors = ButtonDefaults.buttonColors(containerColor = Color.White), - modifier = Modifier.fillMaxWidth() - ) { - val text = stringResource(id = R.string.ButtonSaveprofile) - Text(text, fontSize = 18.sp, color = Color.Black) - } - } - } else { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { isEditingPassword = true } - ) { - Text( - text = password, - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - color = Color.White - ) - Icon( - imageVector = Icons.Default.Edit, - contentDescription = "Modifier", - tint = Color.White, - modifier = Modifier.size(16.dp).padding(start = 8.dp) - ) + Spacer(modifier = Modifier.height(8.dp)) + + val textConfirm = stringResource(id = R.string.ConfirmNewPasswdprofile) + PasswordTextField( + value = confirmPassword, + onValueChange = onConfirmPasswordChange, + label = textConfirm, + passwordVisible = passwordVisible, + onPasswordVisibilityChange = onPasswordVisibilityChange, + isError = passwordError, + onDone = onDone + ) + + if (passwordError) { + ErrorMessageProfileComponent(R.string.Errorpasswdprofile) } + + Spacer(modifier = Modifier.height(8.dp)) + + SaveButton(onClick = onDone) + } +} + +@Composable +fun PasswordTextField( + value: String, + onValueChange: (String) -> Unit, + label: String, + passwordVisible: Boolean, + onPasswordVisibilityChange: (Boolean) -> Unit, + isError: Boolean = false, + onDone: (() -> Unit)? = null +) { + OutlinedTextField( + value = value, + onValueChange = onValueChange, + label = { Text(label) }, + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle(color = Color.White, fontSize = 18.sp), + singleLine = true, + keyboardOptions = KeyboardOptions.Default.copy( + keyboardType = KeyboardType.Password, + imeAction = if (onDone != null) ImeAction.Done else ImeAction.Next + ), + keyboardActions = onDone?.let { + KeyboardActions(onDone = { it() }) + } ?: KeyboardActions.Default, + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { onPasswordVisibilityChange(!passwordVisible) }) { + // Ajout d'une icône pour montrer/masquer le mot de passe + } + }, + isError = isError + ) +} + +@Composable +fun SaveButton(onClick: () -> Unit) { + Button( + onClick = onClick, + colors = ButtonDefaults.buttonColors(containerColor = Color.White), + modifier = Modifier.fillMaxWidth() + ) { + val text = stringResource(id = R.string.ButtonSaveprofile) + Text(text, + fontSize = 18.sp, + color = Color.Black) + } +} + +@Composable +fun DisplayPassword(onEdit: () -> Unit) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { onEdit() } + ) { + Text( + text = "*****", + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = Color.White + ) + Icon( + imageVector = Icons.Default.Edit, + contentDescription = "Modifier", + tint = Color.White, + modifier = Modifier.size(16.dp).padding(start = 8.dp) + ) } } + + + + @Composable fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color){ val text = stringResource(id = textResId) diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt new file mode 100644 index 0000000..b237afd --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt @@ -0,0 +1,139 @@ +package com.example.what_the_fantasy.ui.screens + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.example.what_the_fantasy.R + + +@Composable +fun QuizAccueil(navController: NavController) { + Row( + modifier = Modifier + .fillMaxSize() + .background(Color(0xFF100C1B)) + .padding(top = 100.dp) + ) { + Spacer(modifier = Modifier.weight(0.1f)) + + Column( + modifier = Modifier + .weight(0.9f) + .fillMaxHeight(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .size(width = 150.dp, height = 100.dp) + .padding(8.dp) + .clickable { + navController.navigate("quizPage") + } + ) { + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Quiz 1", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + } + + Box( + modifier = Modifier + .size(width = 150.dp, height = 100.dp) + .padding(8.dp) + .clickable { + + navController.navigate("quizPage") + } + ) { + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Quiz 2", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + } + } + + Spacer(modifier = Modifier.width(10.dp)) + + Column( + modifier = Modifier + .weight(0.9f) + .fillMaxHeight(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .size(width = 150.dp, height = 100.dp) + .padding(8.dp) + .clickable { + navController.navigate("quizPage") + } + ) { + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Quiz 3", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + } + + Box( + modifier = Modifier + .size(width = 150.dp, height = 100.dp) + .padding(8.dp) + .clickable { + navController.navigate("quizPage") + } + ) { + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Quiz 4", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + } + } + + Spacer(modifier = Modifier.weight(0.1f)) + } +} + +@Composable +fun QuizApp() { + val navController = rememberNavController() + + NavHost(navController = navController, startDestination = "quizEndPage") { + composable("quizAccueil") { + QuizAccueil(navController = navController) + } + composable("quizPage") { + QuizPage(navController = navController) + } + composable("quizEndPage") { + QuizEndPage(5, 1) + } + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt new file mode 100644 index 0000000..359e7f7 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt @@ -0,0 +1,163 @@ +package com.example.what_the_fantasy.ui.screens + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.what_the_fantasy.R +import com.example.what_the_fantasy.data.local.QuestionStub + +val gradient = Brush.linearGradient( + colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), + start = Offset(0f, 1000f), + end = Offset(1000f, 0f) +) + + + +@Composable +fun QuizEndPage(points: Int, idQuiz: Int) { + Column( + modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B)) + ) { + // Bandeau supérieur + Row( + modifier = Modifier + .fillMaxWidth() + .weight(0.1f) + .background(Color(0xFF300052)) + .padding(20.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = { }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Retour", tint = Color.White) + } + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Profil", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Profil", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + } + + // Contenu principal + Column( + modifier = Modifier + .weight(0.8f) + .padding(horizontal = 50.dp, vertical = 20.dp) + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "▶ Résultats ◀", + color = Color.White, + style = TextStyle(fontSize = 25.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) + ) + Spacer(modifier = Modifier.height(16.dp)) + Column ( + modifier = Modifier + .background(brush = gradient, shape = RoundedCornerShape(20.dp)) + .padding(30.dp) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text ( + text = "Quiz N°$idQuiz", + color = Color.White, + style = TextStyle(fontSize = 25.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) + ) + + val nbQuestions = QuestionStub.allQuestions.size + + Text ( + text = "Nombres de Questions : $nbQuestions", + color = Color.White, + style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) + ) + Text ( + text = "Nombres de bonnes réponses : $points", + color = Color.White, + style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) + ) + Row ( + modifier = Modifier + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceAround + ) { + // Bouton Quiz Précédent + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Profil", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + // Bouton Retour Menu Quiz + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Profil", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + // Bouton Quiz Suivant + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Profil", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + } + + } + } + + // Bandeau inférieur + Row( + modifier = Modifier + .fillMaxWidth() + .weight(0.1f) + .background(Color(0xFF300052)) + .padding(20.dp), + horizontalArrangement = Arrangement.SpaceAround, + verticalAlignment = Alignment.CenterVertically + ) { + // Bouton Likes + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Bouton", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + // Bouton WhatTheFantasy + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Bouton", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + // Bouton Quiz + Image( + painter = painterResource(id = R.drawable.quiz), + contentDescription = "Bouton", + modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + ) + } + } +} diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt index a342a02..4317669 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt @@ -2,22 +2,15 @@ package com.example.what_the_fantasy.ui.screens import androidx.compose.foundation.background 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.Row -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.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors -import androidx.compose.material3.ButtonDefaults +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -25,83 +18,85 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.NavController import com.example.what_the_fantasy.data.local.QuestionStub -import com.example.what_the_fantasy.data.model.Question @Composable -fun QuizPage() { +fun QuizPage(navController: NavController) { + val questions = QuestionStub.allQuestions + var idCurrentQuestion by remember { mutableIntStateOf(0) } + var pts by remember { mutableIntStateOf(0) } + val gradient = Brush.linearGradient( - colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé - start = Offset(0f, 1000f), // Départ en bas à gauche - end = Offset(1000f, 0f) // Fin en haut à droite + colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), + start = Offset(0f, 1000f), + end = Offset(1000f, 0f) ) - val questions = QuestionStub.allQuestions + fun onAnswerSelected(answer: String) { + val currentQuestion = questions[idCurrentQuestion] + val correctAnswer = mapOf( + "A" to currentQuestion.ansA, + "B" to currentQuestion.ansB, + "C" to currentQuestion.ansC, + "D" to currentQuestion.ansD + )[currentQuestion.correctAns] + + if (answer == correctAnswer) pts++ + if (idCurrentQuestion < questions.size - 1) idCurrentQuestion++ + else navController.popBackStack() // Retour menu + } Box( modifier = Modifier .fillMaxSize() - .background(Color(0xFF100C1B)) // Fond global de l'écran - .padding(16.dp) // Marges autour de tout le contenu + .background(Color(0xFF100C1B)) + .padding(16.dp) ) { - // Numéro de la question en haut - Text( - text = "Question numéro : " + questions.first().id.toString(), - color = Color.White, - fontSize = 18.sp, // Taille réduite pour tenir sur un écran portrait - modifier = Modifier - .align(Alignment.TopCenter) // Position en haut au centre - .padding(top = 16.dp) // Un peu d'espace en haut - ) - - // Contenu centré, mais avec une gestion plus équilibrée du placement Column( modifier = Modifier - .fillMaxSize() - .padding(top = 48.dp), // Réduit l'espace entre le numéro de la question et la question elle-même - verticalArrangement = Arrangement.Center, // Centre verticalement - horizontalAlignment = Alignment.CenterHorizontally // Centre horizontalement + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally ) { - // Question principale - Text( - text = questions.first().question, - color = Color.White, - fontSize = 22.sp, // Taille plus petite pour tenir sur un écran portrait - modifier = Modifier.padding(bottom = 16.dp) // Réduit l'espacement entre la question et les réponses - ) + val question = questions[idCurrentQuestion] - // Liste des réponses - val answers = listOf( - questions.first().ansA, - questions.first().ansB, - questions.first().ansC, - questions.first().ansD - ) - - // Pour chaque réponse, on applique une Box avec un espacement uniforme - answers.forEach { answer -> + Column ( + horizontalAlignment = Alignment.CenterHorizontally, + ) { Box( - modifier = Modifier - .width(220.dp) // Largeur plus petite pour que ça tienne mieux - .height(50.dp) // Hauteur ajustée - .background( - brush = gradient, - shape = RoundedCornerShape(16.dp) // Coins arrondis - ) - .clickable { /* Action pour la réponse */ } - .padding(horizontal = 8.dp), // Padding interne - contentAlignment = Alignment.Center + modifier = Modifier.fillMaxWidth() ) { - Text( - text = answer, - color = Color.White, - fontSize = 18.sp // Taille du texte ajustée pour un écran portrait - ) + IconButton( + onClick = { navController.popBackStack() }, + modifier = Modifier.align(Alignment.TopStart) + ) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Retour", tint = Color.White) + } + } + Text("Question ${question.id}", color = Color.White, fontSize = 18.sp, modifier = Modifier.padding(top = 20.dp)) + Text("Points : $pts", color = Color.White, fontSize = 18.sp, modifier = Modifier.padding(top = 40.dp)) + Text(question.question, color = Color.White, fontSize = 22.sp, modifier = Modifier.padding(40.dp)) + } + Column ( + modifier = Modifier + .padding(top = 30.dp) + ) { + listOf(question.ansA, question.ansB, question.ansC, question.ansD).forEach { answer -> + Box( + modifier = Modifier + .width(220.dp) + .height(50.dp) + .background(brush = gradient, shape = RoundedCornerShape(16.dp)) + .clickable { onAnswerSelected(answer) } + .padding(horizontal = 8.dp), + contentAlignment = Alignment.Center + ) { + Text(answer, color = Color.White, fontSize = 18.sp) + } + Spacer(modifier = Modifier.height(60.dp)) } - Spacer(modifier = Modifier.height(16.dp)) // Espacement réduit entre les réponses } + } } -} - - +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt index 7ed5121..3e77782 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt @@ -40,52 +40,47 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import com.example.what_the_fantasy.R +import com.example.what_the_fantasy.ui.components.SpaceHeightComponent +import com.example.what_the_fantasy.ui.components.TitlePageComponent import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme +import com.example.what_the_fantasy.ui.theme.colorBackground +import com.example.what_the_fantasy.ui.theme.gradienBox @Composable fun SignUpPage(navController: NavController) { - val gradient = Brush.linearGradient( - colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé - start = Offset(0f, 1000f), // Départ en bas à gauche - end = Offset(1000f, 0f) // Fin en haut à droite - ) + Box( modifier = Modifier .fillMaxSize() - .background(Color(0xFF100C1B)), + .background(colorBackground), contentAlignment = Alignment.Center ){ Column( modifier = Modifier - .fillMaxWidth(0.9f) // Ajuste la largeur - .padding(20.dp) // Marge extérieure - .clip(RoundedCornerShape(16.dp)) // Arrondi les angles - .background(gradient) // Ajoute un fond blanc - .padding(20.dp), // Padding interne + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradienBox) + .padding(20.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - TitlePage(R.string.titleSignUp, 20,Color.White) + TitlePageComponent(R.string.titleSignUp, 20,Color.White) IdentifiantTextFieldSign(R.string.IdentifiantLogin) EmailTextFieldSign("Email*") PassWdTextFieldSign(R.string.PasswdLogin) PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp) - SpaceSign(16) + SpaceHeightComponent(16) ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black) - SpaceSign(16) + SpaceHeightComponent(16) CreateAccountButtonSign(R.string.ButtonLogin,12, Color.White, navController = navController) } } } -@Composable -fun SpaceSign(height : Int){ - Spacer( - modifier = Modifier - .height(height.dp)) // Ajoute un espacement -} + @Composable @@ -119,7 +114,7 @@ fun EmailTextFieldSign(textIdentifiant : String){ .fillMaxWidth() .padding(top = 8.dp), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), - shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + shape = RoundedCornerShape(16.dp) // Bords arrondis ) } } @@ -172,15 +167,7 @@ fun PassWdConfirmTextFieldSign(textpasswdResId : Int){ } } -//@Composable -//fun TitleSign(title : String, size : Int, color : Color){ -// Text( -// text = title, -// fontSize = size.sp, -// fontWeight = FontWeight.Bold, -// color = color -// ) -//} + @Composable fun ConnexionButtonSign(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt index 02f6d8b..41c8deb 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt @@ -1,5 +1,7 @@ package com.example.what_the_fantasy.ui.theme +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color val Purple80 = Color(0xFFD0BCFF) @@ -8,4 +10,10 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) +val gradienBox = Brush.linearGradient( + colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé + start = Offset(0f, 1000f), // Départ en bas à gauche + end = Offset(1000f, 0f) // Fin en haut à droite +) +val colorBackground = Color(0xFF100C1B) \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg b/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg new file mode 100644 index 0000000..d0bcef9 Binary files /dev/null and b/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg differ diff --git a/What_The_Fantasy/build.gradle.kts b/What_The_Fantasy/build.gradle.kts index 922f551..7f09f7c 100644 --- a/What_The_Fantasy/build.gradle.kts +++ b/What_The_Fantasy/build.gradle.kts @@ -2,4 +2,4 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false -} \ No newline at end of file +} diff --git a/What_The_Fantasy/gradle/libs.versions.toml b/What_The_Fantasy/gradle/libs.versions.toml index 302bb60..258393f 100644 --- a/What_The_Fantasy/gradle/libs.versions.toml +++ b/What_The_Fantasy/gradle/libs.versions.toml @@ -1,5 +1,8 @@ [versions] agp = "8.6.0" +bcrypt = "0.4" +coilCompose = "2.2.1" + kotlin = "1.9.0" coreKtx = "1.10.1" junit = "4.13.2" @@ -13,6 +16,9 @@ navigationCommonAndroid = "2.9.0-alpha05" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +bcrypt = { module = "org.mindrot:jbcrypt", version.ref = "bcrypt" } +coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" } + junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }