reslution conflict

pull/38/head
kevin.modejar 2 months ago
commit 89f9286d20

@ -50,7 +50,7 @@ android {
} }
dependencies { dependencies {
implementation(libs.bcrypt) // pour hacher les mdp
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)
@ -68,4 +68,7 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4) androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.coil.compose) //gére les url des image
implementation(kotlin("script-runtime"))
} }

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application <application
android:allowBackup="true" android:allowBackup="true"

@ -11,7 +11,8 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.example.what_the_fantasy.ui.screens.AppNavigator import androidx.navigation.NavController
import com.example.what_the_fantasy.ui.navigations.AppNavigator
import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme
import com.example.what_the_fantasy.ui.screens.LoginPage 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.ProfilPage
@ -23,19 +24,11 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
What_The_FantasyTheme { What_The_FantasyTheme {
//AppNavigator() // Accès à la page login et SingUp (pour le moment) AppNavigator()
ProfilPage() //Accès à la page profil
//QuizPage() //QuizPage()
} }
} }
} }
} }
@Composable
fun Title(title: String, modifier: Modifier = Modifier) {
Text(
text = "Welcome to $title!",
modifier = modifier
)
}

@ -8,73 +8,90 @@ object UserStub {
username = "Aragorn123", username = "Aragorn123",
email = "aragorn@example.com", email = "aragorn@example.com",
date = "2022-01-15", 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( val user2 = User(
id = 2, id = 2,
username = "Legolas456", username = "Legolas456",
email = "legolas@example.com", email = "legolas@example.com",
date = "2021-05-23", 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( val user3 = User(
id = 3, id = 3,
username = "Gandalf789", username = "Gandalf789",
email = "gandalf@example.com", email = "gandalf@example.com",
date = "2020-09-10", 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( val user4 = User(
id = 4, id = 4,
username = "FrodoBaggins", username = "FrodoBaggins",
email = "frodo@example.com", email = "frodo@example.com",
date = "2023-03-18", 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( val user5 = User(
id = 5, id = 5,
username = "Gimli999", username = "Gimli999",
email = "gimli@example.com", email = "gimli@example.com",
date = "2022-07-04", 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( val user6 = User(
id = 6, id = 6,
username = "Galadriel321", username = "Galadriel321",
email = "galadriel@example.com", email = "galadriel@example.com",
date = "2021-11-30", 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( val user7 = User(
id = 7, id = 7,
username = "Boromir654", username = "Boromir654",
email = "boromir@example.com", email = "boromir@example.com",
date = "2023-06-22", 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( val user8 = User(
id = 8, id = 8,
username = "Eowyn777", username = "Eowyn777",
email = "eowyn@example.com", email = "eowyn@example.com",
date = "2022-04-11", 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( val user9 = User(
id = 9, id = 9,
username = "Saruman888", username = "Saruman888",
email = "saruman@example.com", email = "saruman@example.com",
date = "2021-08-15", 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( val user10 = User(
id = 10, id = 10,
username = "Faramir222", username = "Faramir222",
email = "faramir@example.com", email = "faramir@example.com",
date = "2023-02-08", 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<User> = listOf( val allUsers: List<User> = listOf(
user1, user2, user3, user4, user5, user6, user7, user8, user9, user10 user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11
) )
} }

@ -5,5 +5,6 @@ class User(
var username:String, var username:String,
var email:String, var email:String,
var date:String, var date:String,
val imgUrl: String val imgUrl: String,
val password: String
) )

@ -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)
)
}

@ -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
}

@ -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
)
}

@ -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() }
}
}

@ -1,29 +1,20 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import android.os.Bundle import android.util.Log
import android.text.style.BackgroundColorSpan
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf 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.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource 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.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import com.example.what_the_fantasy.R 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 @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( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color(0xFF100C1B)), .background(colorBackground),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
){ ){
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth(0.9f) // Ajuste la largeur .fillMaxWidth(0.9f)
.padding(20.dp) // Marge extérieure .padding(20.dp)
.clip(RoundedCornerShape(16.dp)) // Arrondi les angles .clip(RoundedCornerShape(16.dp))
.background(gradient) // Ajoute un fond blanc .background(gradienBox)
.padding(20.dp), // Padding interne .padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
TitlePage(R.string.titleLogin, 20,Color.White) TitlePageComponent(R.string.titleLogin, 20,Color.White)
IdentifiantTextField(R.string.IdentifiantLogin) val identifiant =IdentifiantTextField(R.string.IdentifiantLogin)
PassWdTextField(R.string.PasswdLogin) val passwd = PassWdTextField(R.string.PasswdLogin)
Space(16) SpaceHeightComponent(16)
ConnexionButtonLogin(R.string.ButtonLogin,18, Color.White, Color.Black) ConnexionButtonLogin(users,identifiant, passwd, R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil)
Space(16) SpaceHeightComponent(16)
CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navController) CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp)
} }
} }
} }
@Composable
fun Space(height : Int){
Spacer(
modifier = Modifier
.height(height.dp)) // Ajoute un espacement
}
@Composable @Composable
fun IdentifiantTextField(textIdentifiantResId : Int){ fun IdentifiantTextField(textIdentifiantResId : Int) : String{
val textIdentifiant = stringResource(id = textIdentifiantResId) val textIdentifiant = stringResource(id = textIdentifiantResId)
var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ
Column(modifier = Modifier.padding(top = 16.dp)) { Column(modifier = Modifier.padding(top = 16.dp)) {
@ -110,10 +97,11 @@ fun IdentifiantTextField(textIdentifiantResId : Int){
shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis
) )
} }
return identifiant;
} }
@Composable @Composable
fun PassWdTextField(textpasswdResId : Int){ fun PassWdTextField(textpasswdResId : Int) : String{
val textpasswd = stringResource(id = textpasswdResId) val textpasswd = stringResource(id = textpasswdResId)
var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ
var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer
@ -131,27 +119,18 @@ fun PassWdTextField(textpasswdResId : Int){
IconButton(onClick = { passwordVisible = !passwordVisible }) { 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 @Composable
fun ConnexionButtonLogin(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ fun ConnexionButtonLogin(userStub : List<User>, id : String, passwd : String, titleResId : Int, size : Int, colorButton : Color, colorText : Color, navController: (Int) -> Unit){
val title = stringResource(id = titleResId) val title = stringResource(id = titleResId)
Button( Button(
onClick = { /* Action */ }, onClick = { validLogin(id, passwd, userStub, navController) },
colors = ButtonDefaults.buttonColors(containerColor = colorButton), colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth(),
@ -160,26 +139,38 @@ fun ConnexionButtonLogin(titleResId : Int, size : Int, colorButton : Color, colo
} }
} }
fun validLogin(identifiant : String, passwd : String, users : List<User>, 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 @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) val title = stringResource(id = titleResId)
Text( Text(
text = title, text = title,
fontSize = size.sp, fontSize = size.sp,
color = color, color = color,
modifier = Modifier.clickable { 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) }
}
}

@ -1,6 +1,9 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.util.Patterns
import android.widget.ImageView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.example.what_the_fantasy.R 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 import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme
@Composable @Composable
fun ProfilPage() { fun ProfilPage(index: Int, navController: NavController) {
val gradient = Brush.linearGradient( val gradient = Brush.linearGradient(
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé
start = Offset(0f, 1000f), // Départ en bas à gauche start = Offset(0f, 1000f), // Départ en bas à gauche
end = Offset(1000f, 0f) // Fin en haut à droite end = Offset(1000f, 0f) // Fin en haut à droite
) )
val user = UserStub.allUsers
//val index = 2 // Pour changer l'utilisateur pour le moment
Box( Box(
modifier = Modifier modifier = Modifier
@ -82,30 +93,27 @@ fun ProfilPage() {
) { ) {
// Titre // Titre
TitleProfil(R.string.titleProfile, 20, Color.White) TitlePageComponent(R.string.titleProfile, 20, Color.White)
SpaceProfil(16) SpaceHeightComponent(16)
// Image de profil // Image de profil
val id = R.drawable.ic_launcher_foreground ImageProfil(user[index].imgUrl, 120, 2, Color.White)
ImageProfil(id, 120, 2, Color.White) SpaceHeightComponent(16)
EditUsername(user[index].username)// Édition du Username
SpaceHeightComponent(16)
SpaceProfil(16) EditEmail(user[index].email)// Édition du Email
EditUsername()// Édition du Username
SpaceProfil(16)
EditEmail()// Édition du Email
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
EditPasswd() EditPasswd()
SpaceProfil(16) SpaceHeightComponent(16)
// Bouton // Bouton
ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White) ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White)
SpaceProfil(16) SpaceHeightComponent(16)
ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White) ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White)
SpaceProfil(16) SpaceHeightComponent(16)
ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White) ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White)
} }
@ -114,254 +122,318 @@ fun ProfilPage() {
@Composable @Composable
fun SpaceProfil(height : Int){ fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : Color){
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
)
}
@Composable AsyncImage(
fun ImageProfil(imgProfil : Int, size :Int, sizeBorber : Int, colorBorder : Color){ model = imgProfil,
Image(
painter = painterResource(imgProfil),
contentDescription = "Photo de profil", contentDescription = "Photo de profil",
modifier = Modifier modifier = Modifier
.size(size.dp) .size(size.dp)
.clip(CircleShape) .clip(CircleShape)
.border(sizeBorber.dp, colorBorder, CircleShape)
) )
} }
@Composable @Composable
fun EditEmail(){ fun EditEmail(userEmail: String) {
var email by remember { mutableStateOf("user@example.com") } var email by remember { mutableStateOf(userEmail) }
var isEditingEmail by remember { mutableStateOf(false) } // État d'édition var isEditingEmail by remember { mutableStateOf(false) }
var emailError by remember { mutableStateOf(false) } var emailError by remember { mutableStateOf(false) }
if (isEditingEmail) { if (isEditingEmail) {
OutlinedTextField( EmailEditingField(
value = email, email = email,
onValueChange = { onEmailChange = { newEmail ->
email = it email = newEmail
emailError = !android.util.Patterns.EMAIL_ADDRESS.matcher(it).matches() emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches()
}, },
modifier = Modifier.fillMaxWidth(), onDone = {
textStyle = TextStyle(color = Color.White, fontSize = 18.sp), if (!emailError) isEditingEmail = false
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")
}
}, },
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 { } else {
Row( DisplayEmail(email = email, onEdit = { isEditingEmail = true })
verticalAlignment = Alignment.CenterVertically, }
modifier = Modifier.clickable { isEditingEmail = true } }
) {
Text( @Composable
text = email, fun EmailEditingField(
fontSize = 18.sp, email: String,
fontWeight = FontWeight.Bold, onEmailChange: (String) -> Unit,
color = Color.White onDone: () -> Unit,
) emailError: Boolean
Icon( ) {
imageVector = Icons.Default.Edit, OutlinedTextField(
contentDescription = "Modifier", value = email,
tint = Color.White, onValueChange = onEmailChange,
modifier = Modifier.size(16.dp).padding(start = 8.dp) 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 @Composable
fun EditUsername(){ fun EditUsername(userName: String) {
var username by remember { mutableStateOf("Username") } var username by remember { mutableStateOf(userName) }
var isEditingUsername by remember { mutableStateOf(false) } // État d'édition var isEditingUsername by remember { mutableStateOf(false) }
if (isEditingUsername) { if (isEditingUsername) {
OutlinedTextField( UsernameEditingField(
value = username, username = username,
onValueChange = { username = it }, onUsernameChange = { username = it },
modifier = Modifier.fillMaxWidth(), onDone = { isEditingUsername = false }
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")
}
}
) )
} else { } else {
Row( DisplayUsername(username = username, onEdit = { isEditingUsername = true })
verticalAlignment = Alignment.CenterVertically, }
modifier = Modifier.clickable { isEditingUsername = true } }
) {
Text( @Composable
text = username, fun UsernameEditingField(
fontSize = 18.sp, username: String,
fontWeight = FontWeight.Bold, onUsernameChange: (String) -> Unit,
color = Color.White onDone: () -> Unit
) ) {
Icon( OutlinedTextField(
imageVector = Icons.Default.Edit, value = username,
contentDescription = "Modifier", onValueChange = onUsernameChange,
tint = Color.White, modifier = Modifier.fillMaxWidth(),
modifier = Modifier.size(16.dp).padding(start = 8.dp) 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 @Composable
fun EditPasswd(){ fun EditPasswd() {
var password by remember { mutableStateOf("*******") } var password by remember { mutableStateOf("*******") }
var isEditingPassword by remember { mutableStateOf(false) } var isEditingPassword by remember { mutableStateOf(false) }
var newPassword by remember { mutableStateOf("") } var newPassword by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") } var confirmPassword by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) } var passwordVisible by remember { mutableStateOf(false) }
var passwordError by remember { mutableStateOf(false) } var passwordError by remember { mutableStateOf(false) }
if (isEditingPassword) { if (isEditingPassword) {
Column { PasswordEditingFields(
val text = stringResource(id = R.string.NewPasswdprofile) newPassword = newPassword,
OutlinedTextField( confirmPassword = confirmPassword,
value = newPassword, onNewPasswordChange = { newPassword = it },
onValueChange = { newPassword = it }, onConfirmPasswordChange = {
label = { Text(text) }, confirmPassword = it
modifier = Modifier.fillMaxWidth(), passwordError = newPassword != it
textStyle = TextStyle(color = Color.White, fontSize = 18.sp), },
singleLine = true, passwordVisible = passwordVisible,
keyboardOptions = KeyboardOptions.Default.copy( onPasswordVisibilityChange = { passwordVisible = it },
keyboardType = KeyboardType.Password, passwordError = passwordError,
imeAction = ImeAction.Next onDone = {
), if (!passwordError && newPassword.isNotEmpty()) {
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), password = newPassword
trailingIcon = { isEditingPassword = false
IconButton(onClick = { passwordVisible = !passwordVisible }) {
}
} }
)
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( Spacer(modifier = Modifier.height(8.dp))
onClick = {
if (!passwordError && newPassword.isNotEmpty()) { val textConfirm = stringResource(id = R.string.ConfirmNewPasswdprofile)
password = newPassword PasswordTextField(
isEditingPassword = false value = confirmPassword,
} onValueChange = onConfirmPasswordChange,
}, label = textConfirm,
colors = ButtonDefaults.buttonColors(containerColor = Color.White), passwordVisible = passwordVisible,
modifier = Modifier.fillMaxWidth() onPasswordVisibilityChange = onPasswordVisibilityChange,
) { isError = passwordError,
val text = stringResource(id = R.string.ButtonSaveprofile) onDone = onDone
Text(text, fontSize = 18.sp, color = Color.Black) )
}
} if (passwordError) {
} else { ErrorMessageProfileComponent(R.string.Errorpasswdprofile)
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))
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 @Composable
fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color){ fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color){
val text = stringResource(id = textResId) val text = stringResource(id = textResId)

@ -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)
}
}
}

@ -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)
)
}
}
}

@ -2,22 +2,15 @@ package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
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.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button import androidx.compose.material.icons.Icons
import androidx.compose.material3.ButtonColors import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ButtonDefaults 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.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset 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.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp 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.local.QuestionStub
import com.example.what_the_fantasy.data.model.Question
@Composable @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( val gradient = Brush.linearGradient(
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)),
start = Offset(0f, 1000f), // Départ en bas à gauche start = Offset(0f, 1000f),
end = Offset(1000f, 0f) // Fin en haut à droite 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( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color(0xFF100C1B)) // Fond global de l'écran .background(Color(0xFF100C1B))
.padding(16.dp) // Marges autour de tout le contenu .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( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize(),
.padding(top = 48.dp), // Réduit l'espace entre le numéro de la question et la question elle-même horizontalAlignment = Alignment.CenterHorizontally
verticalArrangement = Arrangement.Center, // Centre verticalement
horizontalAlignment = Alignment.CenterHorizontally // Centre horizontalement
) { ) {
// Question principale val question = questions[idCurrentQuestion]
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
)
// Liste des réponses Column (
val answers = listOf( horizontalAlignment = Alignment.CenterHorizontally,
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 ->
Box( Box(
modifier = Modifier modifier = Modifier.fillMaxWidth()
.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
) { ) {
Text( IconButton(
text = answer, onClick = { navController.popBackStack() },
color = Color.White, modifier = Modifier.align(Alignment.TopStart)
fontSize = 18.sp // Taille du texte ajustée pour un écran portrait ) {
) 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
} }
} }
} }
} }

@ -40,52 +40,47 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.example.what_the_fantasy.R 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.What_The_FantasyTheme
import com.example.what_the_fantasy.ui.theme.colorBackground
import com.example.what_the_fantasy.ui.theme.gradienBox
@Composable @Composable
fun SignUpPage(navController: NavController) { 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( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(Color(0xFF100C1B)), .background(colorBackground),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
){ ){
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth(0.9f) // Ajuste la largeur .fillMaxWidth(0.9f)
.padding(20.dp) // Marge extérieure .padding(20.dp)
.clip(RoundedCornerShape(16.dp)) // Arrondi les angles .clip(RoundedCornerShape(16.dp))
.background(gradient) // Ajoute un fond blanc .background(gradienBox)
.padding(20.dp), // Padding interne .padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
TitlePage(R.string.titleSignUp, 20,Color.White) TitlePageComponent(R.string.titleSignUp, 20,Color.White)
IdentifiantTextFieldSign(R.string.IdentifiantLogin) IdentifiantTextFieldSign(R.string.IdentifiantLogin)
EmailTextFieldSign("Email*") EmailTextFieldSign("Email*")
PassWdTextFieldSign(R.string.PasswdLogin) PassWdTextFieldSign(R.string.PasswdLogin)
PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp) PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp)
SpaceSign(16) SpaceHeightComponent(16)
ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black) ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black)
SpaceSign(16) SpaceHeightComponent(16)
CreateAccountButtonSign(R.string.ButtonLogin,12, Color.White, navController = navController) CreateAccountButtonSign(R.string.ButtonLogin,12, Color.White, navController = navController)
} }
} }
} }
@Composable
fun SpaceSign(height : Int){
Spacer(
modifier = Modifier
.height(height.dp)) // Ajoute un espacement
}
@Composable @Composable
@ -119,7 +114,7 @@ fun EmailTextFieldSign(textIdentifiant : String){
.fillMaxWidth() .fillMaxWidth()
.padding(top = 8.dp), .padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), 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 @Composable
fun ConnexionButtonSign(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ fun ConnexionButtonSign(titleResId : Int, size : Int, colorButton : Color, colorText : Color){

@ -1,5 +1,7 @@
package com.example.what_the_fantasy.ui.theme 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 import androidx.compose.ui.graphics.Color
val Purple80 = Color(0xFFD0BCFF) val Purple80 = Color(0xFFD0BCFF)
@ -8,4 +10,10 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4) val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71) val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260) 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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -2,4 +2,4 @@
plugins { plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
} }

@ -1,5 +1,8 @@
[versions] [versions]
agp = "8.6.0" agp = "8.6.0"
bcrypt = "0.4"
coilCompose = "2.2.1"
kotlin = "1.9.0" kotlin = "1.9.0"
coreKtx = "1.10.1" coreKtx = "1.10.1"
junit = "4.13.2" junit = "4.13.2"
@ -13,6 +16,9 @@ navigationCommonAndroid = "2.9.0-alpha05"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } 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" } junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }

Loading…
Cancel
Save