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 @@ + + + - QuotePage( - quote = QuoteStub.quote1, - modifier = Modifier.padding(innerPadding) - ) - } - } + //AppNavigator() + //QuizPage() + QuotePage(QuoteStub.quote15) } } } diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt index b05fbb3..552ad3e 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt @@ -8,73 +8,90 @@ object UserStub { username = "Aragorn123", email = "aragorn@example.com", date = "2022-01-15", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user2 = User( id = 2, username = "Legolas456", email = "legolas@example.com", date = "2021-05-23", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-fantaisie_1045-186.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-fantaisie_1045-186.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user3 = User( id = 3, username = "Gandalf789", email = "gandalf@example.com", date = "2020-09-10", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-fantaisie_1045-187.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-fantaisie_1045-187.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user4 = User( id = 4, username = "FrodoBaggins", email = "frodo@example.com", date = "2023-03-18", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-hobbit-fantaisie_1045-188.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-hobbit-fantaisie_1045-188.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user5 = User( id = 5, username = "Gimli999", email = "gimli@example.com", date = "2022-07-04", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-nain-fantaisie_1045-189.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-nain-fantaisie_1045-189.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user6 = User( id = 6, username = "Galadriel321", email = "galadriel@example.com", date = "2021-11-30", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-femme-fantaisie_1045-190.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-femme-fantaisie_1045-190.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user7 = User( id = 7, username = "Boromir654", email = "boromir@example.com", date = "2023-06-22", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-191.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-191.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user8 = User( id = 8, username = "Eowyn777", email = "eowyn@example.com", date = "2022-04-11", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerriere-femme-fantaisie_1045-192.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerriere-femme-fantaisie_1045-192.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user9 = User( id = 9, username = "Saruman888", email = "saruman@example.com", date = "2021-08-15", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-malefique-fantaisie_1045-193.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-malefique-fantaisie_1045-193.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + val user10 = User( id = 10, username = "Faramir222", email = "faramir@example.com", date = "2023-02-08", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg" - ) + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 + + val user11 = User( + id = 10, + username = "dev", + email = "testeur@example.com", + date = "2023-02-08", + imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg", + password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 val allUsers: List = 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 40b2f04..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,7 +1,176 @@ package com.example.what_the_fantasy.ui.screens +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +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.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.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 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() { -} \ No newline at end of file +fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit) { + + val users = UserStub.allUsers; + + + Box( + modifier = Modifier + .fillMaxSize() + .background(colorBackground), + contentAlignment = Alignment.Center + ){ + Column( + modifier = Modifier + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradienBox) + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + 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 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)) { + OutlinedTextField( + value = identifiant, + onValueChange = { identifiant = it }, + label = { Text(textIdentifiant) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), + shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + ) + } + return identifiant; +} + +@Composable +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 + Column(modifier = Modifier.padding(top = 10.dp)) { + OutlinedTextField( + value = passwd, + onValueChange = { passwd = it }, + label = { Text(textpasswd) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { passwordVisible = !passwordVisible }) { + } + }, + shape = RoundedCornerShape(16.dp) // Bords arrondis + ) + } + return passwd; +} + + +@Composable +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 = { validLogin(id, passwd, userStub, navController) }, + colors = ButtonDefaults.buttonColors(containerColor = colorButton), + modifier = Modifier + .fillMaxWidth(), + ) { + Text(title, fontSize = size.sp, color = colorText) + } +} + + +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: () -> Unit){ + val title = stringResource(id = titleResId) + Text( + text = title, + fontSize = size.sp, + color = color, + modifier = Modifier.clickable { + navController()// rediriger vers la page de création de compte + } + ) +} 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 a80fed3..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,447 @@ 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 +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +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.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.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.Edit +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.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +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.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +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.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() {} \ No newline at end of file +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 + .fillMaxSize() + .background(Color(0xFF100C1B)), + contentAlignment = Alignment.Center + ) { + Column( + modifier = Modifier + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradient) + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + // Titre + TitlePageComponent(R.string.titleProfile, 20, Color.White) + SpaceHeightComponent(16) + + // Image de profil + ImageProfil(user[index].imgUrl, 120, 2, Color.White) + SpaceHeightComponent(16) + + EditUsername(user[index].username)// Édition du Username + SpaceHeightComponent(16) + + EditEmail(user[index].email)// Édition du Email + Spacer(modifier = Modifier.height(8.dp)) + + EditPasswd() + SpaceHeightComponent(16) + + // Bouton + ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White) + SpaceHeightComponent(16) + ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White) + SpaceHeightComponent(16) + ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White) + + } + } +} + + +@Composable +fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : Color){ + + AsyncImage( + model = imgProfil, + contentDescription = "Photo de profil", + modifier = Modifier + .size(size.dp) + .clip(CircleShape) + ) +} + +@Composable +fun EditEmail(userEmail: String) { + var email by remember { mutableStateOf(userEmail) } + var isEditingEmail by remember { mutableStateOf(false) } + var emailError by remember { mutableStateOf(false) } + + if (isEditingEmail) { + EmailEditingField( + email = email, + onEmailChange = { newEmail -> + email = newEmail + emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() + }, + onDone = { + if (!emailError) isEditingEmail = false + }, + emailError = emailError + ) + } else { + 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(userName: String) { + var username by remember { mutableStateOf(userName) } + var isEditingUsername by remember { mutableStateOf(false) } + + if (isEditingUsername) { + UsernameEditingField( + username = username, + onUsernameChange = { username = it }, + onDone = { isEditingUsername = false } + ) + } else { + 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() { + 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) { + 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 + } + } + ) + } else { + DisplayPassword(onEdit = { isEditingPassword = true }) + } +} + +@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 + ) + + 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) + Button( + onClick = { /* Action */ }, + colors = ButtonDefaults.buttonColors(containerColor = colorButton), + modifier = Modifier.fillMaxWidth(), + ) { + Text(text, fontSize = size.sp, color = colorTexte) + } +} \ No newline at end of file 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 bc7854f..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 @@ -1,6 +1,102 @@ package com.example.what_the_fantasy.ui.screens -import androidx.compose.runtime.Composable +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +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.* +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.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import com.example.what_the_fantasy.data.local.QuestionStub @Composable -fun QuizPage() {} \ No newline at end of file +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)), + start = Offset(0f, 1000f), + end = Offset(1000f, 0f) + ) + + 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)) + .padding(16.dp) + ) { + Column( + modifier = Modifier + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + val question = questions[idCurrentQuestion] + + Column ( + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier.fillMaxWidth() + ) { + 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)) + } + } + + } + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt index e673348..474691c 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt @@ -9,12 +9,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import com.example.what_the_fantasy.R import com.example.what_the_fantasy.data.model.Quote @Composable -fun QuotePage(quote : Quote, modifier: Modifier) { - Column(modifier = modifier.padding(10.dp).drawBehind { +fun QuotePage(quote : Quote) { + Column(modifier = Modifier.padding(10.dp).drawBehind { drawRoundRect( Color(70,190,115), cornerRadius = CornerRadius(10.dp.toPx()) @@ -26,11 +28,11 @@ fun QuotePage(quote : Quote, modifier: Modifier) { ) InfoQuoteText( - name = "@string/source", + nameId = R.string.source, text = quote.source ) InfoQuoteText( - name = "@string/charac", + nameId = R.string.charac, text = quote.character ) Text( @@ -41,10 +43,10 @@ fun QuotePage(quote : Quote, modifier: Modifier) { } @Composable -fun InfoQuoteText(name : String, text : String){ +fun InfoQuoteText(nameId : Int, text : String){ Column{ Text( - text = name + text = stringResource(id = nameId) ) Text( 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 ce60fcf..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 @@ -1,6 +1,196 @@ package com.example.what_the_fantasy.ui.screens +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +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.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +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.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 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() {} \ No newline at end of file +fun SignUpPage(navController: NavController) { + + + Box( + modifier = Modifier + .fillMaxSize() + .background(colorBackground), + contentAlignment = Alignment.Center + ){ + Column( + modifier = Modifier + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradienBox) + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + + TitlePageComponent(R.string.titleSignUp, 20,Color.White) + IdentifiantTextFieldSign(R.string.IdentifiantLogin) + EmailTextFieldSign("Email*") + PassWdTextFieldSign(R.string.PasswdLogin) + PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp) + SpaceHeightComponent(16) + ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black) + SpaceHeightComponent(16) + CreateAccountButtonSign(R.string.ButtonLogin,12, Color.White, navController = navController) + + } + } +} + + + + +@Composable +fun IdentifiantTextFieldSign(textIdentifiantResId : Int){ + val textIdentifiant = stringResource(id = textIdentifiantResId) + var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ + + Column(modifier = Modifier.padding(top = 16.dp)) { + OutlinedTextField( + value = identifiant, + onValueChange = { identifiant = it }, + label = { Text(textIdentifiant) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), + shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + ) + } +} + +@Composable +fun EmailTextFieldSign(textIdentifiant : String){ + var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ + Column(modifier = Modifier.padding(top = 16.dp)) { + OutlinedTextField( + value = identifiant, + onValueChange = { identifiant = it }, + label = { Text(textIdentifiant) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), + shape = RoundedCornerShape(16.dp) // Bords arrondis + ) + } +} + +@Composable +fun PassWdTextFieldSign(textpasswdResId : Int){ + 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 + Column(modifier = Modifier.padding(top = 10.dp)) { + OutlinedTextField( + value = passwd, + onValueChange = { passwd = it }, + label = { Text(textpasswd) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { passwordVisible = !passwordVisible }) { + } + }, + shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + ) + } +} + +@Composable +fun PassWdConfirmTextFieldSign(textpasswdResId : Int){ + 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 + Column(modifier = Modifier.padding(top = 10.dp)) { + OutlinedTextField( + value = passwd, + onValueChange = { passwd = it }, + label = { Text(textpasswd) }, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), + visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { passwordVisible = !passwordVisible }) { + } + }, + shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + ) + } +} + + + +@Composable +fun ConnexionButtonSign(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ + val title = stringResource(id = titleResId) + Button( + onClick = { /* Action */ }, + colors = ButtonDefaults.buttonColors(containerColor = colorButton), + modifier = Modifier + .fillMaxWidth(), + ) { + Text(title, fontSize = size.sp, color = colorText) + } +} + +@Composable +fun CreateAccountButtonSign(titleResId: Int, size: Int, color: Color, navController: NavController) { + val title = stringResource(id = titleResId) + Text( + text = title, + fontSize = size.sp, + color = color, + modifier = Modifier.clickable { + navController.popBackStack() // Revenir à la page précédente + } + ) +} 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/app/src/main/res/values-fr/strings.xml b/What_The_Fantasy/app/src/main/res/values-fr/strings.xml index 09b94f4..f8ac1fc 100644 --- a/What_The_Fantasy/app/src/main/res/values-fr/strings.xml +++ b/What_The_Fantasy/app/src/main/res/values-fr/strings.xml @@ -4,6 +4,31 @@ Film Jeu Vidéo Série + + //Page Quote Personnage Source + + //Page Login + Connexion au compte + Votre identifiant* + Votre mot de passe* + Se connecter + Créer son compte + + //Page Sign Up + Inscription + Confirmer mot de passe* + S\'inscrire + + //Page Profil + Profil + Suggérer une citation + Changer la langue + Se Déconnecter + Nouveau mot de passe + Confirmer le nouveau mot de passe + Sauvegarder + L\'adress email est invalide + Les mots de passe ne correspondent pas \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/res/values/strings.xml b/What_The_Fantasy/app/src/main/res/values/strings.xml index 784f992..2fdf6dd 100644 --- a/What_The_Fantasy/app/src/main/res/values/strings.xml +++ b/What_The_Fantasy/app/src/main/res/values/strings.xml @@ -3,6 +3,31 @@ Movie Video Game Series + + //Page Quote Character Source + + //Page Login + Account login + Your username* + Your password* + Login + Create your account + + //Page Sign Up + Account creation + Confirm your password* + Create + + //Page Profil + Profile + Suggest a quote + Change Language + Disconnect + New password + Confirm password + Save + Invalid email address + Passwords do not match \ No newline at end of file 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" }