commit
ec4b03649d
@ -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,7 +1,176 @@
|
|||||||
package com.example.what_the_fantasy.ui.screens
|
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.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
|
@Composable
|
||||||
fun LoginPage() {
|
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<User>, 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<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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
@ -1,6 +1,447 @@
|
|||||||
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.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.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
|
@Composable
|
||||||
fun ProfilPage() {}
|
fun ProfilPage(index: Int, navController: NavController) {
|
||||||
|
val gradient = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé
|
||||||
|
start = Offset(0f, 1000f), // Départ en bas à gauche
|
||||||
|
end = Offset(1000f, 0f) // Fin en haut à droite
|
||||||
|
)
|
||||||
|
val user = UserStub.allUsers
|
||||||
|
//val index = 2 // Pour changer l'utilisateur pour le moment
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,102 @@
|
|||||||
package com.example.what_the_fantasy.ui.screens
|
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
|
@Composable
|
||||||
fun QuizPage() {}
|
fun QuizPage(navController: NavController) {
|
||||||
|
val questions = QuestionStub.allQuestions
|
||||||
|
var idCurrentQuestion by remember { mutableIntStateOf(0) }
|
||||||
|
var pts by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
|
val gradient = Brush.linearGradient(
|
||||||
|
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)),
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,196 @@
|
|||||||
package com.example.what_the_fantasy.ui.screens
|
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.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
|
@Composable
|
||||||
fun SignUpPage() {}
|
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
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 13 KiB |
Loading…
Reference in new issue