Merge remote-tracking branch 'refs/remotes/origin/master'

pull/45/head
kevin.modejar 1 month ago
commit 48ea6659fa

@ -1,2 +1,42 @@
# WF-Android # Projet Android What the Fantasy
# Description
L'application mobile **What the Fantasy** est une application pour android permettant aux utilisateurs de découvrir des citations célèbres du monde de la fantasy. En plus de pouvoir lire et apprécier les citations, les utilisateurs peuvent créer un compte pour interagir avec elles en les likant, en les commentant, et en participant à des quiz à thème ou aléatoires.
### Fonctionnalités principales
- **Découverte de citations** : Parcourez une large sélection de citations tirées de l'univers de la fantasy.
- **Interaction avec les citations** : Les utilisateurs connectés peuvent **liker** et **commenter** les citations.
- **Création de compte utilisateur** : Inscription et connexion des utilisateurs pour accéder à des fonctionnalités supplémentaires.
- **Quiz interactifs** : Les utilisateurs peuvent participer à des quiz à thème (par exemple, quiz sur les personnages de la fantasy) ou un quiz aléatoire pour deviner qui a dit une citation parmi une liste d'auteurs célèbres.
## Prérequis
Avant d'exécuter l'application sur votre android, vous devez avoir installé les éléments suivants sur votre machine :
- **Android Studio** : L'IDE officiel des applications Android
- [Installation d'Android Studio](https://developer.android.com/studio?hl=fr)
## Installation
### 1. Cloner le dépôt
Clonez le dépôt Git sur votre machine locale avec la commande suivante :
```bash
git clone https://codefirst.iut.uca.fr/git/WhatTheFantasy/WF-Android.git
```
### 2. Lancer l'application à travers Android Studio
Une fois le projet ouvert dans Android Studio, lancer le build du projet, soit sur votre smartphone android physique, soit par un émulateur intégré à Android Studio
## Auteurs
BRONGNIART Kentin<br/>
BEAULATON Léni<br/>
ROCHER Maxime<br/>
MONDEJAR Kevin<br/>
GUICHARD-MONTGUERS Louis<br/>
NGUYEN Tommy<br/>

@ -1,6 +1,7 @@
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlinx.serialization)
} }
android { android {

@ -0,0 +1,16 @@
package com.example.what_the_fantasy.Logs
import android.util.Log
import com.example.what_the_fantasy.data.model.User
class LogsUsers{
fun logDebugDisplayUsers(users : List<User>, titleLog : String){
for(user in users){
Log.e(titleLog, "User created: ${user.username} => ${user.email} => ${user.imgUrl} => ${user.language}")
}
}
fun logDebugDisplayUser(user : User, titleLog : String){
Log.e(titleLog, "User created: ${user.username} => ${user.email}")
}
}

@ -4,19 +4,8 @@ import android.os.Bundle
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
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavController
import com.example.what_the_fantasy.ui.navigations.AppNavigator 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.ProfilPage
import com.example.what_the_fantasy.ui.screens.QuizPage
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -25,7 +14,6 @@ class MainActivity : ComponentActivity() {
setContent { setContent {
What_The_FantasyTheme { What_The_FantasyTheme {
AppNavigator() AppNavigator()
//QuizPage()
} }
} }
} }

@ -0,0 +1,126 @@
package com.example.what_the_fantasy.data.local
import com.example.what_the_fantasy.data.model.Quiz
object QuizStub {
val quiz1 = Quiz(
id = 1,
name = "Quiz Seigneur des Anneaux",
questions = listOf(
QuestionStub.question1,
QuestionStub.question4,
QuestionStub.question8,
QuestionStub.question9
),
img = "lotr"
)
val quiz2 = Quiz(
id = 2,
name = "Quiz Harry Potter",
questions = listOf(
QuestionStub.question2,
QuestionStub.question7,
QuestionStub.question10
),
img = "hp"
)
val quiz3 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz4 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz5 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz6 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz7 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz8 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz9 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz10 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val quiz11 = Quiz(
id = 3,
name = "Quiz Divers Fantasy",
questions = listOf(
QuestionStub.question3,
QuestionStub.question5,
QuestionStub.question6
),
img = "quiz"
)
val allQuizzes: List<Quiz> = listOf(quiz1, quiz2, quiz3, quiz4, quiz5, quiz6, quiz7, quiz8, quiz9, quiz10, quiz11)
fun getQuizById(id: Int): Quiz? {
return allQuizzes.find { it.id == id }
}
}

@ -1,6 +1,8 @@
package com.example.what_the_fantasy.data.local package com.example.what_the_fantasy.data.local
import com.example.what_the_fantasy.data.model.Quote import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.data.model.SrcType
object QuoteStub { object QuoteStub {
@ -8,181 +10,221 @@ object QuoteStub {
id = 1, id = 1,
content = "All we have to decide is what to do with the time that is given us.", content = "All we have to decide is what to do with the time that is given us.",
likes = 466, likes = 466,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.gandalf.name, character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
date = 2000,
type = SrcType.Movie,
imgUrl = CharacterStub.gandalf.imgUrl imgUrl = CharacterStub.gandalf.imgUrl
) )
val quote2 = Quote( val quote2 = Quote(
id = 2, id = 2,
content = "A wizard is never late, nor is he early, he arrives precisely when he means to.", content = "A wizard is never late, nor is he early, he arrives precisely when he means to.",
likes = 467, likes = 467,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.gandalf.name, character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.gandalf.imgUrl imgUrl = CharacterStub.gandalf.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote3 = Quote( val quote3 = Quote(
id = 3, id = 3,
content = "Even the smallest person can change the course of the future.", content = "Even the smallest person can change the course of the future.",
likes = 466, likes = 466,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.galadriel.name, character = CharacterStub.galadriel.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.galadriel.imgUrl imgUrl = CharacterStub.galadriel.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote4 = Quote( val quote4 = Quote(
id = 4, id = 4,
content = "I would rather share one lifetime with you than face all the ages of this world alone.", content = "I would rather share one lifetime with you than face all the ages of this world alone.",
likes = 120, likes = 120,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.arwen.name, character = CharacterStub.arwen.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.arwen.imgUrl imgUrl = CharacterStub.arwen.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote5 = Quote( val quote5 = Quote(
id = 5, id = 5,
content = "Faithless is he that says farewell when the road darkens.", content = "Faithless is he that says farewell when the road darkens.",
likes = 150, likes = 150,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.gimli.name, character = CharacterStub.gimli.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.gimli.imgUrl imgUrl = CharacterStub.gimli.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote6 = Quote( val quote6 = Quote(
id = 6, id = 6,
content = "It's a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there's no knowing where you might be swept off to.", content = "It's a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there's no knowing where you might be swept off to.",
likes = 200, likes = 200,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.frodoBaggins.name, character = CharacterStub.frodoBaggins.name,
source = "The Lord of the Rings: The Fellowship of the Ring", source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.frodoBaggins.imgUrl imgUrl = CharacterStub.frodoBaggins.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote7 = Quote( val quote7 = Quote(
id = 7, id = 7,
content = "I am no man.", content = "I am no man.",
likes = 300, likes = 300,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.eowyn.name, character = CharacterStub.eowyn.name,
source = "The Lord of the Rings: The Return of the King", source = "The Lord of the Rings: The Return of the King",
imgUrl = CharacterStub.eowyn.imgUrl imgUrl = CharacterStub.eowyn.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote8 = Quote( val quote8 = Quote(
id = 8, id = 8,
content = "The world is changed. I feel it in the water. I feel it in the earth. I smell it in the air.", content = "The world is changed. I feel it in the water. I feel it in the earth. I smell it in the air.",
likes = 400, likes = 400,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.treebeard.name, character = CharacterStub.treebeard.name,
source = "The Lord of the Rings: The Two Towers", source = "The Lord of the Rings: The Two Towers",
imgUrl = CharacterStub.treebeard.imgUrl imgUrl = CharacterStub.treebeard.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote9 = Quote( val quote9 = Quote(
id = 9, id = 9,
content = "We wants it, we needs it. Must have the precious.", content = "We wants it, we needs it. Must have the precious.",
likes = 500, likes = 500,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.gollum.name, character = CharacterStub.gollum.name,
source = "The Lord of the Rings: The Two Towers", source = "The Lord of the Rings: The Two Towers",
imgUrl = CharacterStub.gollum.imgUrl imgUrl = CharacterStub.gollum.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote10 = Quote( val quote10 = Quote(
id = 10, id = 10,
content = "The board is set, the pieces are moving. We come to it at last, the great battle of our time.", content = "The board is set, the pieces are moving. We come to it at last, the great battle of our time.",
likes = 600, likes = 600,
language = "en", language = SrcLanguage.vo,
character = CharacterStub.gandalf.name, character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Return of the King", source = "The Lord of the Rings: The Return of the King",
imgUrl = CharacterStub.gandalf.imgUrl imgUrl = CharacterStub.gandalf.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote11 = Quote( val quote11 = Quote(
id = 11, id = 11,
content = "Un grand pouvoir implique de grandes responsabilités.", content = "Un grand pouvoir implique de grandes responsabilités.",
likes = 466, likes = 466,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.aragorn.name, character = CharacterStub.aragorn.name,
source = "Spider-Man", source = "Spider-Man",
imgUrl = CharacterStub.aragorn.imgUrl imgUrl = CharacterStub.aragorn.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote12 = Quote( val quote12 = Quote(
id = 12, id = 12,
content = "Que la Force soit avec toi.", content = "Que la Force soit avec toi.",
likes = 467, likes = 467,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.legolas.name, character = CharacterStub.legolas.name,
source = "Star Wars", source = "Star Wars",
imgUrl = CharacterStub.legolas.imgUrl imgUrl = CharacterStub.legolas.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote13 = Quote( val quote13 = Quote(
id = 13, id = 13,
content = "La magie est partout. Il suffit de savoir où la trouver.", content = "La magie est partout. Il suffit de savoir où la trouver.",
likes = 466, likes = 466,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.gandalf.name, character = CharacterStub.gandalf.name,
source = "Harry Potter", source = "Harry Potter",
imgUrl = CharacterStub.gandalf.imgUrl imgUrl = CharacterStub.gandalf.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote14 = Quote( val quote14 = Quote(
id = 14, id = 14,
content = "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.", content = "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.",
likes = 120, likes = 120,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.frodoBaggins.name, character = CharacterStub.frodoBaggins.name,
source = "Le Seigneur des Anneaux", source = "Le Seigneur des Anneaux",
imgUrl = CharacterStub.frodoBaggins.imgUrl imgUrl = CharacterStub.frodoBaggins.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote15 = Quote( val quote15 = Quote(
id = 15, id = 15,
content = "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.", content = "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.",
likes = 150, likes = 150,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.gimli.name, character = CharacterStub.gimli.name,
source = "Star Wars", source = "Star Wars",
imgUrl = CharacterStub.gimli.imgUrl imgUrl = CharacterStub.gimli.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote16 = Quote( val quote16 = Quote(
id = 16, id = 16,
content = "La vie est une aventure audacieuse ou rien du tout.", content = "La vie est une aventure audacieuse ou rien du tout.",
likes = 200, likes = 200,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.galadriel.name, character = CharacterStub.galadriel.name,
source = "Helen Keller", source = "Helen Keller",
imgUrl = CharacterStub.galadriel.imgUrl imgUrl = CharacterStub.galadriel.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote17 = Quote( val quote17 = Quote(
id = 17, id = 17,
content = "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.", content = "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.",
likes = 300, likes = 300,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.boromir.name, character = CharacterStub.boromir.name,
source = "Nelson Mandela", source = "Nelson Mandela",
imgUrl = CharacterStub.boromir.imgUrl imgUrl = CharacterStub.boromir.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote18 = Quote( val quote18 = Quote(
id = 18, id = 18,
content = "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.", content = "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.",
likes = 400, likes = 400,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.eowyn.name, character = CharacterStub.eowyn.name,
source = "Albert Einstein", source = "Albert Einstein",
imgUrl = CharacterStub.eowyn.imgUrl imgUrl = CharacterStub.eowyn.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote19 = Quote( val quote19 = Quote(
id = 19, id = 19,
content = "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.", content = "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.",
likes = 500, likes = 500,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.saruman.name, character = CharacterStub.saruman.name,
source = "Dalaï Lama", source = "Dalaï Lama",
imgUrl = CharacterStub.saruman.imgUrl imgUrl = CharacterStub.saruman.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val quote20 = Quote( val quote20 = Quote(
id = 20, id = 20,
content = "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.", content = "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.",
likes = 600, likes = 600,
language = "fr", language = SrcLanguage.fr,
character = CharacterStub.samwiseGamgee.name, character = CharacterStub.samwiseGamgee.name,
source = "Gandhi", source = "Gandhi",
imgUrl = CharacterStub.samwiseGamgee.imgUrl imgUrl = CharacterStub.samwiseGamgee.imgUrl,
date = 2000,
type = SrcType.Movie,
) )
val allQuotes: List<Quote> = listOf( val allQuotes: List<Quote> = listOf(

@ -1,97 +1,23 @@
package com.example.what_the_fantasy.data.local package com.example.what_the_fantasy.data.local
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.data.model.User import com.example.what_the_fantasy.data.model.User
object UserStub { object UserStub {
val user1 = User( //LE MOT DE PASSE POUR TOUS LES UTILISATEURS EST : 1234
id = 1, val users: MutableList<User> = mutableListOf(
username = "Aragorn123", User(1, "Aragorn123", "aragorn@example.com", "2022-01-15", "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.fr), //1234
email = "aragorn@example.com", User(2, "Legolas456", "legolas@example.com", "2021-05-23", "https://img.freepik.com/vecteurs-libre/personnage-elfe-fantaisie_1045-186.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.fr),//1234
date = "2022-01-15", User(3, "Gandalf789", "gandalf@example.com", "2020-09-10", "https://img.freepik.com/vecteurs-libre/personnage-magicien-fantaisie_1045-187.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.fr),//1234
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg", User(4, "FrodoBaggins", "frodo@example.com", "2023-03-18", "https://img.freepik.com/vecteurs-libre/personnage-hobbit-fantaisie_1045-188.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.fr),//1234
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 User(5, "Gimli999", "gimli@example.com", "2022-07-04", "https://img.freepik.com/vecteurs-libre/personnage-nain-fantaisie_1045-189.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
User(6, "Galadriel321", "galadriel@example.com", "2021-11-30", "https://img.freepik.com/vecteurs-libre/personnage-elfe-femme-fantaisie_1045-190.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
val user2 = User( User(7, "Boromir654", "boromir@example.com", "2023-06-22", "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-191.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
id = 2, User(8, "Eowyn777", "eowyn@example.com", "2022-04-11", "https://img.freepik.com/vecteurs-libre/personnage-guerriere-femme-fantaisie_1045-192.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
username = "Legolas456", User(9, "Saruman888", "saruman@example.com", "2021-08-15", "https://img.freepik.com/vecteurs-libre/personnage-magicien-malefique-fantaisie_1045-193.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
email = "legolas@example.com", User(10, "Faramir222", "faramir@example.com", "2023-02-08", "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.vo),//1234
date = "2021-05-23", User(11, "dev", "testeur@example.com", "2023-02-08", "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg", "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4", SrcLanguage.fr)//1234
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-fantaisie_1045-186.jpg?size=338&ext=jpg", )
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user3 = User(
id = 3,
username = "Gandalf789",
email = "gandalf@example.com",
date = "2020-09-10",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-fantaisie_1045-187.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user4 = User(
id = 4,
username = "FrodoBaggins",
email = "frodo@example.com",
date = "2023-03-18",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-hobbit-fantaisie_1045-188.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user5 = User(
id = 5,
username = "Gimli999",
email = "gimli@example.com",
date = "2022-07-04",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-nain-fantaisie_1045-189.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user6 = User(
id = 6,
username = "Galadriel321",
email = "galadriel@example.com",
date = "2021-11-30",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-femme-fantaisie_1045-190.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user7 = User(
id = 7,
username = "Boromir654",
email = "boromir@example.com",
date = "2023-06-22",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-191.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user8 = User(
id = 8,
username = "Eowyn777",
email = "eowyn@example.com",
date = "2022-04-11",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerriere-femme-fantaisie_1045-192.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user9 = User(
id = 9,
username = "Saruman888",
email = "saruman@example.com",
date = "2021-08-15",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-magicien-malefique-fantaisie_1045-193.jpg?size=338&ext=jpg",
password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234
val user10 = User(
id = 10,
username = "Faramir222",
email = "faramir@example.com",
date = "2023-02-08",
imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg",
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(
user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11
)
} }

@ -0,0 +1,8 @@
package com.example.what_the_fantasy.data.model
class Quiz (
val id : Int,
val name : String,
val questions : List<Question>,
val img : String
)

@ -1,11 +1,16 @@
package com.example.what_the_fantasy.data.model package com.example.what_the_fantasy.data.model
import java.util.Date
data class Quote ( data class Quote (
val id: Int, val id: Int,
val content: String, val content: String,
val likes: Int, val likes: Int,
val language: String, val language: SrcLanguage,
val character: String, val character: String,
val source: String, val source: String,
val imgUrl: String val imgUrl: String,
val type: SrcType,
val date: Int
) )

@ -0,0 +1,6 @@
package com.example.what_the_fantasy.data.model
enum class SrcLanguage {
fr,
vo
}

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

@ -0,0 +1,22 @@
package com.example.what_the_fantasy.data.services
import com.example.what_the_fantasy.data.local.UserStub.users
import com.example.what_the_fantasy.data.model.User
interface IServices {
fun EditUsername(username : String, index : Int)
fun EditEmail(email : String, index : Int)
fun EditPasswd(passwd : String, index : Int)
fun EditImage(imageURL : String, index : Int)
fun CreateUser(username : String, email : String, passwd : String, services : IServices) : Boolean
fun getFavorite(username: String)
fun getAllUsers(): List<User>
fun getUserById(id: Int): User?
fun SearchQuote(quote : String)
}

@ -0,0 +1,41 @@
package com.example.what_the_fantasy.data.services
import com.example.what_the_fantasy.data.model.User
class ServicesAPI : IServices {
override fun EditUsername(username: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditEmail(email: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditPasswd(passwd: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditImage(imageURL: String, index : Int) {
TODO("Not yet implemented")
}
override fun CreateUser(username: String, email: String, passwd: String, services: IServices) : Boolean {
TODO("Not yet implemented")
}
override fun SearchQuote(quote: String) {
TODO("Not yet implemented")
}
override fun getFavorite(username: String) {
TODO("Not yet implemented")
}
override fun getAllUsers(): List<User> {
TODO("Not yet implemented")
}
override fun getUserById(id: Int): User? {
TODO("Not yet implemented")
}
}

@ -0,0 +1,89 @@
package com.example.what_the_fantasy.data.services
import android.annotation.SuppressLint
import android.util.Log
import com.example.what_the_fantasy.data.local.UserStub
import com.example.what_the_fantasy.data.local.UserStub.users
import com.example.what_the_fantasy.data.model.User
import com.example.what_the_fantasy.Logs.LogsUsers
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.ui.components.hashPassword
import java.time.LocalDate
class ServicesStub : IServices {
val logsUser = LogsUsers() //gestion des logs pour les utilisateurs
override fun EditUsername(username: String, index : Int) {
val user = getUserById(index)
user?.username = username
//Afficher tous les users
logsUser.logDebugDisplayUsers(getAllUsers(), "UsernameUpdate")
}
override fun EditEmail(email: String,index : Int) {
val user = getUserById(index)
user?.email = email
//Afficher tous les users
logsUser.logDebugDisplayUsers(getAllUsers(), "EmailUpdate")
}
override fun EditPasswd(passwd: String,index : Int) {
val user = getUserById(index)
val passwordhash = hashPassword(passwd)
user?.password = passwordhash
//Afficher tous les users en log
logsUser.logDebugDisplayUsers(getAllUsers(), "PasswordUpdate")
}
override fun EditImage(imageURL: String,index : Int) {
TODO("Not yet implemented")
}
override fun CreateUser(username: String, email: String, passwd: String, services : IServices) : Boolean {
val date =dateDuJour()
val passwordhash = hashPassword(passwd)
val userStub = services.getAllUsers()
val nbUser = userStub.size
for (user in userStub) {
if (user.username == username) {
return false
}
}
val user = User(nbUser+1,username, email, date,randomImage(userStub), passwordhash, SrcLanguage.vo)
users.add(user)//ajout au stub
//Afficher tous les users
logsUser.logDebugDisplayUsers(users, "CreateUser")
return true
}
override fun getAllUsers(): List<User> = users
override fun getUserById(id: Int): User? {
return (users.find { it.id == id+1 })
}
override fun SearchQuote(quote: String) {
TODO("Not yet implemented")
}
override fun getFavorite(username: String) {
TODO("Not yet implemented")
}
//------------------------------------------------------
@SuppressLint("NewApi")
fun dateDuJour(): String {
val date = LocalDate.now()
return date.toString()
}
fun randomImage(usersImage : List<User>) : String{
return "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg"
}
}

@ -0,0 +1,64 @@
package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.AccountCircle
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
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.res.painterResource
import androidx.compose.ui.unit.dp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.ui.theme.colorButtonNav
import com.example.what_the_fantasy.ui.theme.colorNavBar
@Composable
fun BackBar(navBack : () ->Unit ,
content : @Composable ()-> Unit ){
Column(
modifier = Modifier
.fillMaxSize()
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(colorNavBar),
Arrangement.SpaceBetween,
verticalAlignment = Alignment.Bottom
) {
IconButton(onClick = {navBack()},
modifier = Modifier
.size(60.dp)
) {
Icon(Icons.Rounded.ArrowBack,
contentDescription = "Back",
modifier = Modifier
.size(60.dp)
)
}
}
Box(modifier = Modifier.background(Color.Black).fillMaxHeight()) {
content()
}
}
}

@ -0,0 +1,68 @@
package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.ui.theme.gradienBox
@Composable
fun LittleQuoteComponent(quote : Quote){
Row(
modifier = Modifier
.fillMaxWidth(0.9f)
.clip(RoundedCornerShape(16.dp))
.background(gradienBox)
) {
val sizeTextInfoQuote = 13
val lineHeightText = 12
val sizeTextQuote = 16
AsyncImage(
model = quote.imgUrl,
contentDescription = "Quote picture",
modifier = Modifier
.size(130.dp)
.clip(RoundedCornerShape(16.dp))
)
Column(modifier = Modifier.padding(10.dp)) {
TextInfoQuote(
quote.content,
sizeTextQuote,
lineHeightText
)
SpaceHeightComponent(40)
TextInfoQuote("${stringResource(R.string.dateQuote)} : ${quote.date}", sizeTextInfoQuote, lineHeightText)
TextInfoQuote("${quote.type} : ${quote.source}", sizeTextInfoQuote, lineHeightText)
TextInfoQuote("${stringResource(R.string.CharacterQuote)}: ${quote.character}", sizeTextInfoQuote, lineHeightText)
}
}
}
@Composable
fun TextInfoQuote(text : String, fontSizeText : Int, lineHeightText : Int){
Text(text,
color = Color.White,
fontSize = fontSizeText.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
lineHeight = lineHeightText.sp)
}

@ -1,4 +1,153 @@
package com.example.what_the_fantasy.ui.components package com.example.what_the_fantasy.ui.components
class NavBar { import androidx.compose.foundation.background
} import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.NavigationBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
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.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.ui.theme.*
@Composable
fun NavBar(onProfile : Boolean = false ,
onFavorite : Boolean = false ,
onAccueil : Boolean = false ,
onQuiz : Boolean = false ,
index:Int,
navControllerProfil: (Int) -> Unit,
navControllerFavorite:(Int) -> Unit,
navControllerAccueil: (Int) -> Unit,
navControllerQuiz: (Int) -> Unit,
content : @Composable ()-> Unit ) {
var theme by remember { mutableStateOf(true) }
Column(
modifier = Modifier
.fillMaxSize()
) {
NavigationBar(
modifier = Modifier
.fillMaxWidth(),
containerColor = colorNavBar
) {
Row(
modifier = Modifier
.fillMaxWidth(),
Arrangement.SpaceBetween,
verticalAlignment = Alignment.Bottom
) {
ButtonIconVectorInt(Icons.Rounded.AccountCircle,"Profile",navControllerProfil,index,onProfile)
IconButton(onClick = { theme=!theme},
modifier = Modifier.size(60.dp)
.clip(RoundedCornerShape(0))
) {
Icon(painterResource(
if(theme)R.drawable.dark_mode_toggle_icon
else R.drawable.light_mode_toggle_icon),
contentDescription = "Dark mode",
modifier = Modifier.fillMaxSize(),
tint = Color.White
)
}
}
}
Box(modifier = Modifier.background(Color.Black).fillMaxHeight(0.90f)){
content()
}
BottomAppBar (modifier = Modifier
.fillMaxSize(),
containerColor = colorNavBar
) {
Row(modifier = Modifier
.fillMaxSize(),
horizontalArrangement = Arrangement.SpaceAround,
verticalAlignment = Alignment.CenterVertically
) {
ButtonIconPainterInt(painterResource(
if(onFavorite)R.drawable.favorite_button_full
else R.drawable.favorite_button_empty
),"Favorite",navControllerFavorite,index,onFavorite)
ButtonIconPainterInt(painterResource(
if(onAccueil)R.drawable.home_button_full
else R.drawable.home_button_empty
),"Accueil",navControllerAccueil,index,onAccueil)
ButtonIconPainterInt(painterResource(
if(onQuiz)R.drawable.quiz_button_full
else R.drawable.quiz_button_empty
),"Quiz",navControllerQuiz,index,onQuiz)
}
}
}
}
@Composable
fun ButtonIconVectorInt(img : ImageVector, name : String, nav : (Int)->Unit ,index: Int,onPage : Boolean){
IconButton(onClick = {nav(index)},
enabled = !onPage,
colors = IconButtonColors(Color.Transparent, colorButtonNav,//couleur quand il n'est pas selectionné
Color.Transparent, colorButtonNavSelected),//couleur quand il est selectionné
modifier = Modifier
.size(60.dp)
) {
Icon(img,
contentDescription = name,
modifier = Modifier
.fillMaxSize()
)
}
}
@Composable
fun ButtonIconPainterInt(img : Painter, name : String, nav : (Int)->Unit,index: Int,onPage : Boolean){
IconButton(onClick = {nav(index)},
enabled = !onPage,
colors = IconButtonColors(Color.Transparent,colorButtonNav,//couleur quand il n'est pas selectionné
Color.Transparent, colorButtonNavSelected),//couleur quand il est selectionné
modifier = Modifier
.size(60.dp)
) {
Icon(img,
contentDescription = name,
modifier = Modifier
.fillMaxSize()
)
}
}

@ -1,21 +1,28 @@
package com.example.what_the_fantasy.ui.components package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable 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.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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@Composable @Composable
fun TitlePageComponent(titleResId : Int, size : Int, color : Color) { fun TitlePageComponent(titleResId: Int, color: Color) {
val title = stringResource(id = titleResId) val title = stringResource(id = titleResId)
Text( Text(
text = title, text = title,
fontSize = size.sp, fontSize = 20.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = color color = color,
textAlign = TextAlign.Center,
) )
} }

@ -0,0 +1,14 @@
package com.example.what_the_fantasy.ui.components
import java.security.MessageDigest
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) }
}

@ -4,57 +4,143 @@ import androidx.compose.runtime.Composable
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.screens.AccueilPage 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.FavoritePage
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
import com.example.what_the_fantasy.ui.screens.QuizEndPage
import com.example.what_the_fantasy.ui.screens.QuizMenu
import com.example.what_the_fantasy.ui.screens.QuizPage 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.QuotePage
import com.example.what_the_fantasy.ui.screens.SearchPage 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.SignUpPage
import com.example.what_the_fantasy.ui.screens.SubmitQuotePage import com.example.what_the_fantasy.ui.screens.SubmitQuotePage
import kotlinx.serialization.Serializable
@Serializable
data class Accueil(val userIndex: Int)
@Serializable
data object Login
@Serializable
data class Favorite(val userIndex: Int)
@Serializable
data class Profil(val userIndex: Int)
@Serializable
data class QuizMenu(val userIndex: Int)
@Serializable
data class Quiz(val userIndex : Int, val idQuiz : Int)
@Serializable
data class QuizEnd(val userIndex : Int, val idQuiz : Int,val pts : Int)
@Serializable
data object Quote
@Serializable
data object Search
@Serializable
data object SignUp
@Serializable
data object SubmitQuote
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 @Composable
fun AppNavigator() { fun AppNavigator() {
val navController = rememberNavController() val navController = rememberNavController()
val services = ServicesStub()
NavHost(navController, startDestination = Destination.Login.route) { NavHost(navController, startDestination = Login) {
composable(Destination.Login.route) { composable<Login> {
LoginPage( LoginPage(
navControllerSignUp = { navController.navigate(Destination.SignUp.route) }, navControllerSignUp = { navController.navigate(SignUp) },
navControllerProfil = { userIndex -> navControllerProfil = { userIndex ->
navController.navigate(Destination.Profil.createRoute(userIndex)) // Passe l'index à Profil navController.navigate(Profil(userIndex)) {
// Vider pile de navigation pour empêcher le retour à la page Login
popUpTo(Login) { inclusive = true }
}
},
services = services
)
}
composable<Accueil> {
val accueil: Accueil = it.toRoute()
AccueilPage(
index = accueil.userIndex,
navFavorite = { navController.navigate(Favorite(accueil.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(accueil.userIndex)) },
navProfil = { navController.navigate(Profil(accueil.userIndex)) }
) }
composable<Favorite> {
val favorite: Favorite = it.toRoute()
FavoritePage(
index = favorite.userIndex,
navAccueil ={ navController.navigate( Accueil(favorite.userIndex) ) },
navQuiz = { navController.navigate(QuizMenu(favorite.userIndex)) },
navProfil = { navController.navigate(Profil(favorite.userIndex)) },
navQuote = {navController.navigate(Quote)}
) }
composable<Profil>{
val profil:Profil = it.toRoute()
ProfilPage(
index = profil.userIndex,
navFavorite = { navController.navigate(Favorite(profil.userIndex)) },
navAccueil ={ navController.navigate( Accueil(profil.userIndex) ) },
navQuiz = { navController.navigate( QuizMenu(profil.userIndex)) },
navUnLog = {
navController.navigate(Login) {
// Vider pile de navigation pour empêcher le retour à la page profil
popUpTo(profil) { inclusive = true }
}
},
services = services
)
}
composable<Quote> { QuotePage() }
composable<Search> { SearchPage() }
composable<SignUp> { SignUpPage(
navControllerLogin = {
navController.navigate(Login){
// Vider pile de navigation pour empêcher le retour à la page Sign up
popUpTo(Login) { inclusive = true }
}
},services) }
composable<SubmitQuote> { SubmitQuotePage() }
composable<QuizMenu> {
val quizMenu:QuizMenu=it.toRoute()
QuizMenu(
index = quizMenu.userIndex,
navAccueil = { navController.navigate( Accueil(quizMenu.userIndex) ) },
navFavorite = { navController.navigate(Favorite(quizMenu.userIndex)) },
navProfil = { navController.navigate(Profil(quizMenu.userIndex)) },
navControllerQuiz = { idQuiz ->
navController.navigate(Quiz(quizMenu.userIndex,idQuiz))
} }
) )
} }
composable(Destination.Accueil.route) { AccueilPage() } composable<Quiz> {
composable(Destination.Favorite.route) { FavoritePage() } val quiz:Quiz=it.toRoute()
composable(Destination.Profil.route) { backStackEntry -> QuizPage(
// Récupère l'index passé dans la route index = quiz.userIndex,
val userIndex = backStackEntry.arguments?.getString("userIndex")?.toInt() ?: -1 navAccueil = { navController.navigate( Accueil(quiz.userIndex) ) },
ProfilPage(index = userIndex, navController = navController) navFavorite = { navController.navigate(Favorite(quiz.userIndex)) },
navProfil = { navController.navigate(Profil(quiz.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(quiz.userIndex)) },
navControllerQuizEnd = { idQuiz, pts ->
navController.navigate(QuizEnd(quiz.userIndex,idQuiz, pts))
},
idQuiz = quiz.idQuiz
)
}
composable<QuizEnd> {
val quizEnd: QuizEnd = it.toRoute()
QuizEndPage(
idQuiz = quizEnd.idQuiz,
points = quizEnd.pts,
index = quizEnd.userIndex,
navAccueil = { navController.navigate( Accueil(quizEnd.userIndex) ) },
navFavorite = { navController.navigate(Favorite(quizEnd.userIndex)) },
navProfil = { navController.navigate(Profil(quizEnd.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(quizEnd.userIndex)) }
)
} }
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,6 +1,42 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable 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.unit.sp
import com.example.what_the_fantasy.data.services.IServices
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.theme.colorBackground
@Composable @Composable
fun AccueilPage() {} fun AccueilPage(
index: Int,
navFavorite:(Int) -> Unit,
navQuiz: (Int) -> Unit,
navProfil:(Int) -> Unit
) {
NavBar(onAccueil = true,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = { },
navControllerProfil = navProfil,
navControllerQuiz = navQuiz
){
Box(
modifier = Modifier
.fillMaxSize()
.background(colorBackground),
contentAlignment = Alignment.Center
){
Column {
Text("Accueil", color = Color.White, fontSize = 20.sp)
}
}
}
}

@ -1,6 +1,74 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
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.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable 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.unit.dp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.local.QuoteStub
import com.example.what_the_fantasy.ui.components.LittleQuoteComponent
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.components.TitlePageComponent
import com.example.what_the_fantasy.ui.theme.colorBackground
@Composable @Composable
fun FavoritePage() {} fun FavoritePage(
index: Int,
navAccueil: (Int) -> Unit,
navQuiz: (Int) -> Unit,
navProfil: (Int) -> Unit,
navQuote:() -> Unit
) {
NavBar(
onFavorite = true,
index = index,
navControllerFavorite = { },
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz ,
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(colorBackground),
contentAlignment = Alignment.Center
) {
Column(modifier = Modifier
.padding(top = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
TitlePageComponent(R.string.TitleFavorite, Color.White)
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF100C1B))
.padding(top = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
items(QuoteStub.allQuotes) { quote ->
Column (Modifier.clickable { navQuote()}){
LittleQuoteComponent(quote)
Spacer(modifier = Modifier.height(16.dp))
}
}
}
}
}
}
}

@ -5,14 +5,18 @@ 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.Row
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.layout.width
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.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -39,17 +43,19 @@ 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.local.UserStub
import com.example.what_the_fantasy.data.model.User import com.example.what_the_fantasy.data.model.User
import com.example.what_the_fantasy.data.services.IServices
import com.example.what_the_fantasy.data.services.ServicesStub
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.SpaceHeightComponent
import com.example.what_the_fantasy.ui.components.TitlePageComponent import com.example.what_the_fantasy.ui.components.TitlePageComponent
import com.example.what_the_fantasy.ui.components.hashPassword
import com.example.what_the_fantasy.ui.theme.colorBackground import com.example.what_the_fantasy.ui.theme.colorBackground
import com.example.what_the_fantasy.ui.theme.gradienBox import com.example.what_the_fantasy.ui.theme.gradienBox
import java.security.MessageDigest import java.security.MessageDigest
@Composable @Composable
fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit) { fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit, services : IServices) {
val users = services.getAllUsers()
val users = UserStub.allUsers;
Box( Box(
modifier = Modifier modifier = Modifier
@ -67,11 +73,9 @@ fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Uni
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
TitlePageComponent(R.string.titleLogin, 20,Color.White) TitlePageComponent(R.string.titleLogin, Color.White)
val identifiant =IdentifiantTextField(R.string.IdentifiantLogin) SpaceHeightComponent(20)
val passwd = PassWdTextField(R.string.PasswdLogin) ConnexionButtonLogin(users,IdentifiantTextField(R.string.IdentifiantLogin), PassWdTextField(R.string.PasswdLogin), R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil)
SpaceHeightComponent(16)
ConnexionButtonLogin(users,identifiant, passwd, R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil)
SpaceHeightComponent(16) SpaceHeightComponent(16)
CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp) CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp)
} }
@ -94,7 +98,7 @@ fun IdentifiantTextField(textIdentifiantResId : Int) : String{
.fillMaxWidth() .fillMaxWidth()
.padding(top = 8.dp), .padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis shape = RoundedCornerShape(16.dp) // Bords arrondis
) )
} }
return identifiant; return identifiant;
@ -105,7 +109,7 @@ 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
Column(modifier = Modifier.padding(top = 10.dp)) { Column(modifier = Modifier.padding(top = 10.dp, bottom = 30.dp)) {
OutlinedTextField( OutlinedTextField(
value = passwd, value = passwd,
onValueChange = { passwd = it }, onValueChange = { passwd = it },
@ -129,41 +133,38 @@ fun PassWdTextField(textpasswdResId : Int) : String{
@Composable @Composable
fun ConnexionButtonLogin(userStub : List<User>, id : String, passwd : String, titleResId : Int, size : Int, colorButton : Color, colorText : Color, navController: (Int) -> Unit){ 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)
var showError by remember { mutableStateOf(false) }
Button( Button(
onClick = { validLogin(id, passwd, userStub, navController) }, onClick = { showError = !validLogin(id, passwd, userStub, navController)
},
colors = ButtonDefaults.buttonColors(containerColor = colorButton), colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
Text(title, fontSize = size.sp, color = colorText) Text(title, fontSize = size.sp, color = colorText)
} }
if(showError){
ErrorMessageProfileComponent(R.string.ErrorLogin)
}
} }
fun validLogin(identifiant : String, passwd : String, users : List<User>, navController: (Int) -> Unit){ fun validLogin(identifiant : String, passwd : String, users : List<User>, navController: (Int) -> Unit): Boolean {
users.forEachIndexed { index, user -> users.forEachIndexed { index, user ->
val hashPassWd = hashPassword(passwd) val hashPassWd = hashPassword(passwd)
if (user.username == identifiant && user.password == hashPassWd) { if (user.username == identifiant && user.password == hashPassWd) {
// Utilise l'index pour naviguer à la position correspondante
navController(index) // Passer l'index à la fonction navController navController(index) // Passer l'index à la fonction navController
return true
} }
} }
return false
} }
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: () -> Unit){ 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,
@ -173,4 +174,4 @@ fun CreateAccountButton(titleResId : Int, size : Int, color : Color, navControll
navController()// rediriger vers la page de création de compte navController()// rediriger vers la page de création de compte
} }
) )
} }

@ -26,7 +26,9 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.rounded.Face
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.Icon
@ -61,68 +63,82 @@ 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.QuestionStub
import com.example.what_the_fantasy.data.local.UserStub import com.example.what_the_fantasy.data.local.UserStub
import com.example.what_the_fantasy.data.services.IServices
//import com.example.what_the_fantasy.data.local.UserStub.users
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.components.ErrorMessageProfileComponent import com.example.what_the_fantasy.ui.components.ErrorMessageProfileComponent
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.components.SpaceHeightComponent 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.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.gradienBox
@Composable @Composable
fun ProfilPage(index: Int, navController: NavController) { fun ProfilPage(index: Int,
val gradient = Brush.linearGradient( navFavorite: (Int) -> Unit,
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé navAccueil: (Int) -> Unit,
start = Offset(0f, 1000f), // Départ en bas à gauche navQuiz: (Int) -> Unit,
end = Offset(1000f, 0f) // Fin en haut à droite navUnLog: () -> Unit,
) services: IServices
val user = UserStub.allUsers ) {
//val index = 2 // Pour changer l'utilisateur pour le moment val user = services.getUserById(index) ?: return
Box( NavBar(onProfile = true,
modifier = Modifier index = index,
.fillMaxSize() navControllerFavorite = navFavorite,
.background(Color(0xFF100C1B)), navControllerAccueil = navAccueil,
contentAlignment = Alignment.Center navControllerProfil = {},
navControllerQuiz = navQuiz
) { ) {
Column(
Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth(0.9f) .fillMaxSize()
.padding(20.dp) .background(Color(0xFF100C1B)),
.clip(RoundedCornerShape(16.dp)) contentAlignment = Alignment.Center
.background(gradient)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Column(
modifier = Modifier
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(gradienBox)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Titre // Titre
TitlePageComponent(R.string.titleProfile, 20, Color.White) TitlePageComponent(R.string.titleProfile, Color.White)
SpaceHeightComponent(16) SpaceHeightComponent(16)
// Image de profil // Image de profil
ImageProfil(user[index].imgUrl, 120, 2, Color.White) ImageProfil(user.imgUrl, 120)
SpaceHeightComponent(16) SpaceHeightComponent(16)
EditUsername(user[index].username)// Édition du Username EditUsername(user.username, index, services)// Édition du Username
SpaceHeightComponent(16) SpaceHeightComponent(16)
EditEmail(user[index].email)// Édition du Email EditEmail(user.email,index, services)// Édition du Email
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
EditPasswd() EditPasswd(index, services)
SpaceHeightComponent(16) SpaceHeightComponent(16)
// Bouton // Bouton
ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White) //ButtonProfile(R.string.ButtonAddQuoteprofile, 18, Color.Black, Color.White,navUnLog) // Pas encore de navigation definie
SpaceHeightComponent(16) //SpaceHeightComponent(16)
ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White) ButtonProfile(R.string.ButtonLanguageprofile, 18, Color.Black, Color.White,navUnLog) // Pas encore de navigation definie
SpaceHeightComponent(16) SpaceHeightComponent(16)
ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White) ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White, navUnLog)
}
} }
} }
} }
@Composable @Composable
fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : Color){ fun ImageProfil(imgProfil : String, size :Int){
AsyncImage( AsyncImage(
model = imgProfil, model = imgProfil,
@ -134,20 +150,27 @@ fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : C
} }
@Composable @Composable
fun EditEmail(userEmail: String) { fun EditEmail(userEmail: String, index: Int, service: IServices) {
var email by remember { mutableStateOf(userEmail) } var email by remember { mutableStateOf(userEmail) }
var isEditingEmail by remember { mutableStateOf(false) } var isEditingEmail by remember { mutableStateOf(false) }
var emailError by remember { mutableStateOf(false) } var emailError by remember { mutableStateOf(false) }
fun onDoneEditing() {
service.EditEmail(email, index)
isEditingEmail = false
}
if (isEditingEmail) { if (isEditingEmail) {
EmailEditingField( EmailEditingField(
email = email, email = email,
onEmailChange = { newEmail -> onEmailChange = { newEmail ->
email = newEmail email = newEmail
emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() // Validation email
}, },
onDone = { onDone = {
if (!emailError) isEditingEmail = false if (!emailError) {
onDoneEditing()
}
}, },
emailError = emailError emailError = emailError
) )
@ -178,7 +201,7 @@ fun EmailEditingField(
), ),
trailingIcon = { trailingIcon = {
IconButton(onClick = { if (!emailError) onDone() }) { IconButton(onClick = { if (!emailError) onDone() }) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") Icon(imageVector = Icons.Default.CheckCircle, contentDescription = "Valider")
} }
}, },
isError = emailError isError = emailError
@ -213,18 +236,21 @@ fun DisplayEmail(email: String, onEdit: () -> Unit) {
@Composable @Composable
fun EditUsername(userName: String) { fun EditUsername(userName: String, index: Int, service : IServices) {
var username by remember { mutableStateOf(userName) } var username by remember { mutableStateOf(userName) }
var isEditingUsername by remember { mutableStateOf(false) } var isEditingUsername by remember { mutableStateOf(false) }
fun onDoneEditing() {
service.EditUsername(username, index)
isEditingUsername = false
}
if (isEditingUsername) { if (isEditingUsername) {
UsernameEditingField( UsernameEditingField(
username = username, username = username,
onUsernameChange = { username = it }, onUsernameChange = { username = it },
onDone = { isEditingUsername = false } onDone = { onDoneEditing() }
) )
} else { } else {
DisplayUsername(username = username, onEdit = { isEditingUsername = true }) DisplayUsername(username = username, onEdit = { isEditingUsername = true })
@ -247,11 +273,11 @@ fun UsernameEditingField(
imeAction = ImeAction.Done imeAction = ImeAction.Done
), ),
keyboardActions = KeyboardActions( keyboardActions = KeyboardActions(
onDone = { onDone() } // Quand on appuie sur "Done", on met fin à l'édition onDone = { onDone() }
), ),
trailingIcon = { trailingIcon = {
IconButton(onClick = { onDone() }) { IconButton(onClick = { onDone() }) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") Icon(imageVector = Icons.Default.CheckCircle, contentDescription = "Valider")
} }
} }
) )
@ -280,18 +306,22 @@ fun DisplayUsername(username: String, onEdit: () -> Unit) {
@Composable @Composable
fun EditPasswd() { fun EditPasswd(index: Int, service: IServices) {
var password by remember { mutableStateOf("*******") } var password by remember { mutableStateOf("*******") } // Mot de passe actuel (affiché comme un masque)
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) }
// Fonction pour finaliser l'édition du mot de passe et appeler la méthode EditPasswd2
fun onDoneEditing() {
// Appeler EditPasswd pour mettre à jour le mot de passe de l'utilisateur
service.EditPasswd(newPassword, index)
isEditingPassword = false
}
if (isEditingPassword) { if (isEditingPassword) {
PasswordEditingFields( PasswordEditingFields(
newPassword = newPassword, newPassword = newPassword,
@ -299,20 +329,19 @@ fun EditPasswd() {
onNewPasswordChange = { newPassword = it }, onNewPasswordChange = { newPassword = it },
onConfirmPasswordChange = { onConfirmPasswordChange = {
confirmPassword = it confirmPassword = it
passwordError = newPassword != it passwordError = newPassword != it // Vérifier si les mots de passe correspondent
}, },
passwordVisible = passwordVisible, passwordVisible = passwordVisible,
onPasswordVisibilityChange = { passwordVisible = it }, onPasswordVisibilityChange = { passwordVisible = it },
passwordError = passwordError, passwordError = passwordError,
onDone = { onDone = {
if (!passwordError && newPassword.isNotEmpty()) { if (!passwordError && newPassword.isNotEmpty()) {
password = newPassword onDoneEditing() // Appeler la fonction onDoneEditing() pour mettre à jour le mot de passe
isEditingPassword = false
} }
} }
) )
} else { } else {
DisplayPassword(onEdit = { isEditingPassword = true }) DisplayPassword(onEdit = { isEditingPassword = true }) // Afficher l'option pour modifier le mot de passe
} }
} }
@ -429,16 +458,11 @@ fun DisplayPassword(onEdit: () -> Unit) {
} }
} }
@Composable @Composable
fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color){ fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color,navController: () -> Unit){
val text = stringResource(id = textResId) val text = stringResource(id = textResId)
Button( Button(
onClick = { /* Action */ }, onClick = { navController() },
colors = ButtonDefaults.buttonColors(containerColor = colorButton), colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { ) {

@ -1,139 +0,0 @@
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)
}
}
}

@ -2,6 +2,7 @@ package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -24,6 +25,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
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.QuestionStub
import com.example.what_the_fantasy.data.local.QuizStub
import com.example.what_the_fantasy.ui.components.NavBar
val gradient = Brush.linearGradient( val gradient = Brush.linearGradient(
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)),
@ -31,133 +34,111 @@ val gradient = Brush.linearGradient(
end = Offset(1000f, 0f) end = Offset(1000f, 0f)
) )
@Composable @Composable
fun QuizEndPage(points: Int, idQuiz: Int) { fun QuizEndPage(
Column( idQuiz: Int,
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B)) points: Int,
) { index: Int,
// Bandeau supérieur navFavorite: (Int) -> Unit,
Row( navAccueil: (Int) -> Unit,
modifier = Modifier navProfil:(Int) -> Unit,
.fillMaxWidth() navQuiz: (Int) -> Unit,
.weight(0.1f) ) {
.background(Color(0xFF300052)) NavBar(onQuiz = true,
.padding(20.dp), index = index,
horizontalArrangement = Arrangement.SpaceBetween, navControllerFavorite = navFavorite,
verticalAlignment = Alignment.CenterVertically navControllerAccueil = navAccueil,
) { navControllerProfil = navProfil,
IconButton(onClick = { }) { navControllerQuiz = navQuiz) {
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( Column(
modifier = Modifier modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
.weight(0.8f)
.padding(horizontal = 50.dp, vertical = 20.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text(
text = "▶ Résultats ◀", // Contenu principal
color = Color.White, Column(
style = TextStyle(fontSize = 25.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center)
)
Spacer(modifier = Modifier.height(16.dp))
Column (
modifier = Modifier modifier = Modifier
.background(brush = gradient, shape = RoundedCornerShape(20.dp)) .weight(0.8f)
.padding(30.dp) .padding(horizontal = 50.dp, vertical = 20.dp)
.fillMaxSize(), .fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text ( Text(
text = "Quiz N°$idQuiz", text = "▶ Résultats ◀",
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, color = Color.White,
style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) style = TextStyle(
) fontSize = 25.sp,
Text ( fontWeight = FontWeight.Bold,
text = "Nombres de bonnes réponses : $points", textAlign = TextAlign.Center
color = Color.White, )
style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center)
) )
Row ( Spacer(modifier = Modifier.height(16.dp))
Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .background(brush = gradient, shape = RoundedCornerShape(20.dp))
horizontalArrangement = Arrangement.SpaceAround .padding(30.dp)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) { ) {
// Bouton Quiz Précédent val quiz = QuizStub.getQuizById(idQuiz)
Image( val nbQuestions = quiz?.questions?.size
painter = painterResource(id = R.drawable.quiz), Text(
contentDescription = "Profil", text = "${quiz?.name}",
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) color = Color.White,
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
) )
// Bouton Retour Menu Quiz Text(
Image( text = "Nombres de Questions : $nbQuestions",
painter = painterResource(id = R.drawable.quiz), color = Color.White,
contentDescription = "Profil", style = TextStyle(
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) fontSize = 15.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
) )
// Bouton Quiz Suivant Text(
Image( text = "Nombres de bonnes réponses : $points",
painter = painterResource(id = R.drawable.quiz), color = Color.White,
contentDescription = "Profil", style = TextStyle(
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) fontSize = 15.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
) )
}
} val pourcentage = (points.toDouble() / nbQuestions!!) * 100
}
// Bandeau inférieur val note = when {
Row( pourcentage == 100.0 -> "S"
modifier = Modifier pourcentage >= 70.0 -> "A"
.fillMaxWidth() pourcentage >= 40.0 -> "B"
.weight(0.1f) else -> "C"
.background(Color(0xFF300052)) }
.padding(20.dp),
horizontalArrangement = Arrangement.SpaceAround, println("Note obtenue : $note")
verticalAlignment = Alignment.CenterVertically
) { Box(
// Bouton Likes contentAlignment = Alignment.Center,
Image( modifier = Modifier
painter = painterResource(id = R.drawable.quiz), .size(100.dp)
contentDescription = "Bouton", .background(Color.White, shape = RoundedCornerShape(50.dp))
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) ) {
) Text(
// Bouton WhatTheFantasy text = note,
Image( color = Color.Red,
painter = painterResource(id = R.drawable.quiz), style = TextStyle(
contentDescription = "Bouton", fontSize = 40.sp,
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) fontWeight = FontWeight.Bold,
) textAlign = TextAlign.Center
// Bouton Quiz )
Image( )
painter = painterResource(id = R.drawable.quiz), }
contentDescription = "Bouton", }
modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) }
)
} }
} }
} }

@ -0,0 +1,132 @@
package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
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.QuizStub
import com.example.what_the_fantasy.data.services.IServices
import com.example.what_the_fantasy.ui.components.NavBar
@Composable
fun QuizMenu( index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navProfil:(Int) -> Unit,
navControllerQuiz: (Int) -> Unit
) {
NavBar(onQuiz = true,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = { }
) {
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
) {
// Contenu princiapl
Column(
modifier = Modifier
.weight(0.9f)
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "▶ Menu des Quiz ◀",
color = Color.White,
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
Spacer(Modifier.height(20.dp))
Column(
modifier = Modifier
.background(brush = gradient, shape = RoundedCornerShape(20.dp))
.fillMaxSize()
.padding(vertical = 30.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
val quizzes = QuizStub.allQuizzes.chunked(2)
val context = LocalContext.current
for (rowQuizzes in quizzes) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
for (quiz in rowQuizzes) {
val imageResId = context.resources.getIdentifier(
quiz.img,
"drawable",
context.packageName
)
Column(
modifier = Modifier
.size(width = 150.dp, height = 145.dp)
.clickable { navControllerQuiz(quiz.id) },
) {
Image(
painter = painterResource(id = imageResId),
contentDescription = quiz.name,
modifier = Modifier
.size(width = 150.dp, height = 100.dp)
.clip(shape = RoundedCornerShape(20.dp)),
contentScale = ContentScale.Crop
)
Spacer(Modifier.height(10.dp))
Text(
text = quiz.name,
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
color = Color.White
)
)
}
}
}
Spacer(Modifier.height(30.dp))
}
}
}
}
}
}

@ -1,14 +1,11 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.Image
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.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape 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.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -16,14 +13,32 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset 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.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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import com.example.what_the_fantasy.R
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.local.QuizStub
import com.example.what_the_fantasy.ui.components.BackBar
import com.example.what_the_fantasy.ui.components.NavBar
@Composable @Composable
fun QuizPage(navController: NavController) { fun QuizPage(
val questions = QuestionStub.allQuestions index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navProfil:(Int) -> Unit,
navQuiz: (Int) -> Unit,
navControllerQuizEnd: (Int, Int) -> Unit,
idQuiz: Int
) {
val quiz = QuizStub.getQuizById(idQuiz)
val questions = quiz?.questions ?: emptyList()
var idCurrentQuestion by remember { mutableIntStateOf(0) } var idCurrentQuestion by remember { mutableIntStateOf(0) }
var pts by remember { mutableIntStateOf(0) } var pts by remember { mutableIntStateOf(0) }
@ -44,59 +59,92 @@ fun QuizPage(navController: NavController) {
if (answer == correctAnswer) pts++ if (answer == correctAnswer) pts++
if (idCurrentQuestion < questions.size - 1) idCurrentQuestion++ if (idCurrentQuestion < questions.size - 1) idCurrentQuestion++
else navController.popBackStack() // Retour menu else navControllerQuizEnd(idQuiz, pts) // Retour menu
} }
NavBar(onQuiz = true,
Box( index = index,
modifier = Modifier navControllerFavorite = navFavorite,
.fillMaxSize() navControllerAccueil = navAccueil,
.background(Color(0xFF100C1B)) navControllerProfil = navProfil,
.padding(16.dp) navControllerQuiz = navQuiz
){
Column (
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
) { ) {
Column( // Contenu princiapl
modifier = Modifier Column(
.fillMaxSize(), modifier = Modifier
horizontalAlignment = Alignment.CenterHorizontally .weight(0.8f)
) { .fillMaxWidth()
val question = questions[idCurrentQuestion] .padding(horizontal = 50.dp, vertical = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally
Column (
horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Box( val question = questions[idCurrentQuestion]
modifier = Modifier.fillMaxWidth()
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
IconButton( if (quiz != null) {
onClick = { navController.popBackStack() }, Text(
modifier = Modifier.align(Alignment.TopStart) text = "${quiz.name}",
) { color = Color.White,
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Retour", tint = Color.White) style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
} }
} Spacer(Modifier.height(20.dp))
Text("Question ${question.id}", color = Color.White, fontSize = 18.sp, modifier = Modifier.padding(top = 20.dp)) Column(
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 modifier = Modifier
.width(220.dp) .background(brush = gradient, shape = RoundedCornerShape(20.dp)),
.height(50.dp) horizontalAlignment = Alignment.CenterHorizontally
.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) Text(
"Question ${idCurrentQuestion + 1}",
color = Color.White,
fontSize = 18.sp,
modifier = Modifier.padding(top = 20.dp),
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
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(Color.White, shape = RoundedCornerShape(16.dp))
.clickable { onAnswerSelected(answer) }
.padding(horizontal = 8.dp),
contentAlignment = Alignment.Center
) {
Text(answer, color = Color.Black, fontSize = 18.sp)
}
Spacer(modifier = Modifier.height(60.dp))
}
}
} }
Spacer(modifier = Modifier.height(60.dp))
} }
} }
} }
} }
} }

@ -1,6 +1,8 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import com.example.what_the_fantasy.ui.components.NavBar
@Composable @Composable
fun QuotePage() {} fun QuotePage() {
}

@ -1,6 +1,8 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import com.example.what_the_fantasy.ui.components.NavBar
@Composable @Composable
fun SearchPage() {} fun SearchPage() {
}

@ -15,8 +15,11 @@ 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.material.icons.filled.Check
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
@ -40,15 +43,23 @@ 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.data.services.IServices
import com.example.what_the_fantasy.ui.components.SpaceHeightComponent 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.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.colorBackground
import com.example.what_the_fantasy.ui.theme.gradienBox import com.example.what_the_fantasy.ui.theme.gradienBox
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.components.ErrorMessageProfileComponent
import com.example.what_the_fantasy.ui.components.hashPassword
@Composable @Composable
fun SignUpPage(navController: NavController) { fun SignUpPage(navControllerLogin: () -> Unit, services : IServices) {
var username by remember { mutableStateOf("") }
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
Box( Box(
modifier = Modifier modifier = Modifier
@ -66,15 +77,15 @@ fun SignUpPage(navController: NavController) {
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
TitlePageComponent(R.string.titleSignUp, 20,Color.White) TitlePageComponent(R.string.titleSignUp,Color.White)
IdentifiantTextFieldSign(R.string.IdentifiantLogin) IdentifiantTextFieldSign(R.string.IdentifiantLogin,identifiant = username,onValueChange = { username = it })
EmailTextFieldSign("Email*") EmailTextFieldSign(R.string.EmailSignUp, email, onValueChange = { email = it })
PassWdTextFieldSign(R.string.PasswdLogin) PassWdTextFieldSign(R.string.PasswdLogin,password, onValueChange = { password = it },passwordVisible,onPasswordVisibilityChange = { passwordVisible = !passwordVisible })
PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp) PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp,confirmPassword,onValueChange = { confirmPassword = it },passwordVisible,onPasswordVisibilityChange = { passwordVisible = !passwordVisible })
SpaceHeightComponent(16) SpaceHeightComponent(16)
ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black) ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black, username, email, password, confirmPassword, services, navControllerLogin)
SpaceHeightComponent(16) SpaceHeightComponent(16)
CreateAccountButtonSign(R.string.ButtonLogin,12, Color.White, navController = navController) ReturnLogin(R.string.ButtonLogin,12, Color.White, navController = navControllerLogin)
} }
} }
@ -84,50 +95,47 @@ fun SignUpPage(navController: NavController) {
@Composable @Composable
fun IdentifiantTextFieldSign(textIdentifiantResId : Int){ fun IdentifiantTextFieldSign(textIdentifiantResId : Int, identifiant: String, onValueChange: (String) -> Unit){
val textIdentifiant = stringResource(id = textIdentifiantResId) val textIdentifiant = stringResource(id = textIdentifiantResId)
var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ
Column(modifier = Modifier.padding(top = 16.dp)) { Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField( OutlinedTextField(
value = identifiant, value = identifiant,
onValueChange = { identifiant = it }, onValueChange = onValueChange,
label = { Text(textIdentifiant) }, label = { Text(textIdentifiant) },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 8.dp), .padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis shape = RoundedCornerShape(16.dp)
) )
} }
} }
@Composable @Composable
fun EmailTextFieldSign(textIdentifiant : String){ fun EmailTextFieldSign(textIdentifiantResId: Int, email: String, onValueChange: (String) -> Unit){
var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ val textIdentifiant = stringResource(id = textIdentifiantResId)
Column(modifier = Modifier.padding(top = 16.dp)) { Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField( OutlinedTextField(
value = identifiant, value = email,
onValueChange = { identifiant = it }, onValueChange = onValueChange,
label = { Text(textIdentifiant) }, label = { Text(textIdentifiant) },
modifier = Modifier modifier = Modifier
.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)
) )
} }
} }
@Composable @Composable
fun PassWdTextFieldSign(textpasswdResId : Int){ fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){
val textpasswd = stringResource(id = textpasswdResId) 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)) { Column(modifier = Modifier.padding(top = 10.dp)) {
OutlinedTextField( OutlinedTextField(
value = passwd, value = passwd,
onValueChange = { passwd = it }, onValueChange = onValueChange,
label = { Text(textpasswd) }, label = { Text(textpasswd) },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -135,23 +143,22 @@ fun PassWdTextFieldSign(textpasswdResId : Int){
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = { trailingIcon = {
IconButton(onClick = { passwordVisible = !passwordVisible }) { IconButton(onClick = onPasswordVisibilityChange) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider")
} }
}, },
shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis shape = RoundedCornerShape(16.dp)
) )
} }
} }
@Composable @Composable
fun PassWdConfirmTextFieldSign(textpasswdResId : Int){ fun PassWdConfirmTextFieldSign(textpasswdResId : Int,confirmPassword: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){
val textpasswd = stringResource(id = textpasswdResId) 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)) { Column(modifier = Modifier.padding(top = 10.dp)) {
OutlinedTextField( OutlinedTextField(
value = passwd, value = confirmPassword,
onValueChange = { passwd = it }, onValueChange = onValueChange,
label = { Text(textpasswd) }, label = { Text(textpasswd) },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -159,38 +166,101 @@ fun PassWdConfirmTextFieldSign(textpasswdResId : Int){
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = { trailingIcon = {
IconButton(onClick = { passwordVisible = !passwordVisible }) { IconButton(onClick = onPasswordVisibilityChange) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider")
} }
}, },
shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis shape = RoundedCornerShape(16.dp)
) )
} }
} }
// Validation de email
fun isValidEmail(email: String): Boolean {
val emailRegex = "[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}"
return email.matches(emailRegex.toRegex())
}
// Vérification mots de passe
fun arePasswordsMatching(password: String, confirmPassword: String): Boolean {
return password == confirmPassword
}
@Composable @Composable
fun ConnexionButtonSign(titleResId : Int, size : Int, colorButton : Color, colorText : Color){ fun ConnexionButtonSign(
titleResId: Int,
size: Int,
colorButton: Color,
colorText: Color,
username: String,
email: String,
password: String,
confirmPassword: String,
service: IServices,
navController: ()-> Unit
) {
val title = stringResource(id = titleResId) val title = stringResource(id = titleResId)
var emailError by remember { mutableStateOf(false) }
var passwordError by remember { mutableStateOf(false) }
var passwordErrorEmpty by remember { mutableStateOf(false) }
var usernameErrorEmpty by remember { mutableStateOf(false) }
var usernameErrorExist by remember { mutableStateOf(false) }
Button( Button(
onClick = { /* Action */ }, onClick = {
emailError = !isValidEmail(email)
passwordError = !arePasswordsMatching(password, confirmPassword)
usernameErrorEmpty = username.isBlank()
passwordErrorEmpty = password.isBlank() || confirmPassword.isBlank()
if (!emailError && !passwordError && !usernameErrorEmpty && !passwordErrorEmpty) {
usernameErrorExist = !service.CreateUser(username, email, password, service)
if(!usernameErrorExist){
navController() // retour à la page login
}
}
},
colors = ButtonDefaults.buttonColors(containerColor = colorButton), colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier modifier = Modifier.fillMaxWidth(),
.fillMaxWidth(),
) { ) {
Text(title, fontSize = size.sp, color = colorText) Text(title, fontSize = size.sp, color = colorText)
} }
// Afficher erreurs
if (usernameErrorEmpty) {
ErrorMessageProfileComponent(R.string.ErrorUserEmptySignUp)
}
if (usernameErrorExist) {
ErrorMessageProfileComponent(R.string.ErrorUserExistSignUp)
}
if (emailError) {
ErrorMessageProfileComponent(R.string.ErrorEmailSignUp)
}
if (passwordError) {
ErrorMessageProfileComponent(R.string.ErrorPasswordSignUp)
}
if (passwordErrorEmpty) {
ErrorMessageProfileComponent(R.string.ErrorPasswordEmpty)
}
} }
@Composable @Composable
fun CreateAccountButtonSign(titleResId: Int, size: Int, color: Color, navController: NavController) { fun ReturnLogin(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.popBackStack() // Revenir à la page précédente navController() // Revenir à la page login
} }
) )
} }

@ -1,6 +1,8 @@
package com.example.what_the_fantasy.ui.screens package com.example.what_the_fantasy.ui.screens
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import com.example.what_the_fantasy.ui.components.NavBar
@Composable @Composable
fun SubmitQuotePage() {} fun SubmitQuotePage() {
}

@ -3,6 +3,7 @@ package com.example.what_the_fantasy.ui.theme
import androidx.compose.ui.geometry.Offset 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 com.example.what_the_fantasy.R
val Purple80 = Color(0xFFD0BCFF) val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC) val PurpleGrey80 = Color(0xFFCCC2DC)
@ -11,9 +12,15 @@ 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( val gradienBox = 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 colorBackground = Color(0xFF100C1B) val colorBackground = Color(0xFF100C1B)
val colorNavBar = Color.Black
val colorButtonNavSelected= Color(0xFFC8C8C8)
val colorButtonNav = Color.White

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="39dp"
android:height="19dp"
android:viewportWidth="39"
android:viewportHeight="19">
<path
android:pathData="M25.655,1.196H11.58C9.495,1.196 7.6,2.098 6.226,3.55C4.852,5.003 4,7.006 4,9.212C4,11.416 4.852,13.42 6.226,14.872C7.6,16.325 9.495,17.226 11.58,17.226H24.79C26.263,18.341 28.065,19 30.003,19H30.015C32.486,19 34.734,17.931 36.361,16.21C37.988,14.489 39,12.114 39,9.5C39,6.887 37.99,4.51 36.359,2.792C34.73,1.07 32.483,0 30.015,0H30.003C28.43,0 26.946,0.435 25.655,1.196ZM30.482,8.22L30.512,8.226C30.568,7.977 30.705,7.779 30.925,7.637C31.143,7.493 31.371,7.451 31.609,7.51L31.616,7.479C31.379,7.42 31.192,7.274 31.057,7.043C30.922,6.81 30.882,6.57 30.938,6.32L30.908,6.312C30.852,6.563 30.715,6.761 30.496,6.904C30.277,7.047 30.048,7.089 29.811,7.029L29.804,7.06C30.042,7.12 30.228,7.266 30.364,7.497C30.5,7.728 30.538,7.968 30.482,8.22ZM33.003,9.432L33.039,9.441C33.109,9.126 33.282,8.878 33.557,8.699C33.832,8.519 34.118,8.466 34.416,8.541L34.425,8.503C34.127,8.428 33.893,8.246 33.723,7.954C33.553,7.663 33.503,7.36 33.573,7.046L33.537,7.037C33.467,7.352 33.294,7.599 33.019,7.779C32.744,7.959 32.457,8.012 32.16,7.937L32.151,7.976C32.449,8.05 32.683,8.232 32.852,8.523C33.023,8.814 33.073,9.118 33.003,9.432ZM30.351,5.022C29.279,5.577 28.507,6.703 28.417,8.053C28.283,10.068 29.719,11.816 31.625,11.958C32.529,12.025 33.377,11.718 34.032,11.161C34.357,10.885 34.693,11.128 34.551,11.476C33.777,13.386 31.923,14.66 29.852,14.505C27.235,14.311 25.263,11.91 25.446,9.143C25.622,6.491 27.724,4.458 30.212,4.481C30.67,4.486 30.767,4.807 30.351,5.022ZM30.003,1.123H30.015C34.373,1.123 37.939,4.892 37.939,9.5C37.939,14.108 34.369,17.878 30.015,17.878H30.003C25.65,17.878 22.08,14.108 22.08,9.5C22.08,4.892 25.645,1.123 30.003,1.123Z"
android:fillColor="#ffffff"/>
</vector>

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="33dp"
android:viewportWidth="32"
android:viewportHeight="33">
<path
android:pathData="M16,3.628C24.322,-5.496 45.127,10.47 16,31C-13.127,10.472 7.679,-5.496 16,3.628Z"
android:strokeWidth="2"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#ffffff"/>
</vector>

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:viewportWidth="30"
android:viewportHeight="30">
<path
android:pathData="M15,2.628C23.322,-6.496 44.127,9.47 15,30C-14.127,9.472 6.679,-6.496 15,2.628Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="239dp"
android:height="143dp"
android:viewportWidth="239"
android:viewportHeight="143">
<path
android:pathData="M161.92,11.53C158.02,11.53 154.18,12.27 150.4,13.74C146.73,15.21 142.78,17.42 138.55,20.37C139.1,21.5 139.55,22.86 139.88,24.45C140.22,25.92 140.38,27.62 140.38,29.54C140.38,33.96 139.55,39.46 137.88,46.03C136.32,52.6 134.26,59.57 131.7,66.94C129.14,74.3 126.42,81.55 123.52,88.69C120.63,95.83 117.9,102.23 115.34,107.9H111V99.57C111.11,96.06 111.17,92.32 111.17,88.35C111.28,84.27 111.34,80.36 111.34,76.62C111.45,72.77 111.5,69.54 111.5,66.94C113.73,60.25 115.62,54.08 117.18,48.41C118.74,42.63 119.52,37.53 119.52,33.11C119.52,27.79 118.01,23.6 115.01,20.54C112.12,17.48 106.94,15.95 99.48,15.95C94.59,15.95 90.36,16.74 86.8,18.33C83.24,19.8 79.51,22.07 75.61,25.13C77.62,31.02 79.17,36.57 80.29,41.78C81.51,46.99 82.4,52.38 82.96,57.93C81.07,66.54 78.67,75.32 75.78,84.27C73,93.22 70.05,101.1 66.93,107.9H62.59C62.59,103.82 62.65,99.34 62.76,94.47C62.98,89.6 63.09,84.56 63.09,79.34C63.09,71.3 62.76,63.31 62.09,55.38C61.53,47.33 60.25,40.03 58.25,33.45C56.25,26.77 53.24,21.44 49.24,17.48C45.23,13.51 39.83,11.53 33.04,11.53C23.25,11.53 14.57,14.47 7,20.37C11.45,23.43 15.01,27.39 17.68,32.26C20.36,37.14 22.36,42.58 23.69,48.58C25.03,54.59 25.92,60.87 26.36,67.45C26.81,74.02 27.03,80.53 27.03,86.99C27.03,91.18 26.98,95.72 26.87,100.59V118.26C26.87,125.63 29.2,130.96 33.88,134.24C38.55,137.41 46.51,139 57.75,139C63.65,139 68.99,138.21 73.78,136.62C78.56,135.15 82.96,133.28 86.96,131.01C88.86,133.73 91.86,135.71 95.98,136.96C100.21,138.32 105.94,139 113.17,139C121.74,139 128.92,137.64 134.71,134.92C140.61,132.2 145.73,128.58 150.07,124.04L147.73,114.69C149.4,110.62 151.51,105.8 154.07,100.25C156.74,94.7 159.47,88.8 162.25,82.57C165.04,76.23 167.65,69.88 170.1,63.54C172.66,57.19 174.72,51.19 176.28,45.52M170.12,62.92C171.86,63.54 173.63,64.06 175.43,64.46C177.77,64.53 180.41,64.54 183.36,64.51C186.45,64.4 189.14,64.25 191.41,64.07C191.54,65.61 191.43,67.15 191.08,68.69C190.87,70.15 190.66,71.32 190.46,72.2C189.27,77.49 186.55,80.93 182.3,82.52C178.17,84.14 173.64,84.39 168.7,83.28C166.46,82.77 164.41,82.19 162.56,81.54M161.45,11.53C174.63,10.18 225.12,8.37 233.62,6C234.54,11.09 235,15.38 235,18.88C235,23.85 233.68,28.09 231.04,31.6C228.39,35.1 224.83,37.75 220.35,39.56C215.99,41.26 194.72,42.73 189.32,42.73C185.75,42.73 171.26,43.4 171.26,43.4"
android:strokeWidth="8"
android:fillColor="#00000000">
<aapt:attr name="android:strokeColor">
<gradient
android:startX="235"
android:startY="139"
android:endX="-4.21"
android:endY="114.21"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
</vector>

@ -0,0 +1,49 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="227dp"
android:height="133dp"
android:viewportWidth="227"
android:viewportHeight="133">
<path
android:pathData="M50.53,133C39.34,133 31.41,131.41 26.76,128.24C22.11,124.96 19.78,119.63 19.78,112.26C19.78,105.24 19.78,99.35 19.78,94.59C19.89,89.72 19.94,85.18 19.94,80.99C19.94,74.53 19.72,68.02 19.28,61.45C18.84,54.87 17.95,48.59 16.62,42.58C15.29,36.58 13.3,31.14 10.64,26.26C7.98,21.39 4.43,17.43 0,14.37C7.53,8.47 16.18,5.53 25.93,5.53C32.69,5.53 38.06,7.51 42.05,11.48C46.04,15.44 49.03,20.77 51.03,27.45C53.02,34.03 54.29,41.33 54.85,49.38C55.51,57.31 55.85,65.3 55.85,73.34C55.85,78.56 55.73,83.6 55.51,88.47C55.4,93.34 55.35,97.82 55.35,101.9H59.67C62.77,95.1 65.71,87.22 68.48,78.27C71.36,69.32 73.74,60.54 75.62,51.93C75.07,46.38 74.18,40.99 72.96,35.78C71.86,30.57 70.31,25.02 68.31,19.13C72.19,16.07 75.9,13.8 79.45,12.33C82.99,10.74 87.2,9.95 92.08,9.95C99.5,9.95 104.65,11.48 107.54,14.54C110.53,17.6 112.02,21.79 112.02,27.11C112.02,31.53 111.25,36.63 109.7,42.41C108.14,48.08 106.26,54.25 104.04,60.94C104.04,63.54 103.99,66.77 103.88,70.62C103.88,74.36 103.82,78.27 103.71,82.35C103.71,86.32 103.66,90.06 103.55,93.57C103.55,97.08 103.55,99.86 103.55,101.9H107.87C110.42,96.23 113.13,89.83 116.01,82.69C118.89,75.55 121.61,68.3 124.16,60.94C126.71,53.57 128.76,46.6 130.31,40.03C131.97,33.46 132.8,27.96 132.8,23.54C132.8,21.62 132.63,19.92 132.3,18.45C131.97,16.86 131.52,15.5 130.97,14.37C135.18,11.42 139.12,9.21 142.77,7.74C146.54,6.27 150.36,5.53 154.24,5.53C160.33,5.53 164.6,7.34 167.04,10.97C169.59,14.48 170.86,19.07 170.86,24.73C170.86,28.93 170.09,33.86 168.53,39.52C166.98,45.19 164.93,51.19 162.38,57.54C159.95,63.88 157.34,70.23 154.57,76.57C151.8,82.8 149.09,88.7 146.43,94.25C143.88,99.8 141.77,104.62 140.11,108.69L142.44,118.04C138.12,122.58 133.02,126.2 127.15,128.92C121.39,131.64 114.24,133 105.71,133C98.5,133 92.8,132.32 88.59,130.96C84.49,129.71 81.5,127.73 79.61,125.01C75.62,127.28 71.25,129.15 66.48,130.62C61.72,132.21 56.4,133 50.53,133Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="227"
android:startY="133"
android:endX="-11.19"
android:endY="108.42"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M162.4,56.92C160.67,56.29 158.96,55.55 157.27,54.71L149.45,73.09C151.24,73.96 153.05,74.78 154.88,75.54C156.72,76.19 158.76,76.77 160.99,77.28C165.9,78.39 170.42,78.14 174.53,76.52C178.76,74.93 181.47,71.49 182.66,66.2C182.86,65.32 183.06,64.15 183.27,62.69C183.62,61.15 183.73,59.61 183.6,58.07C181.34,58.25 178.66,58.4 175.59,58.51C172.65,58.54 170.02,58.53 167.69,58.46C165.9,58.06 164.14,57.54 162.4,56.92Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="227"
android:startY="133"
android:endX="-11.19"
android:endY="108.42"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M184.59,9.27C173.3,10.43 161.1,6.56 161.1,6.56V31.48C161.1,31.48 168.02,34.47 171.22,35.37C174.54,36.28 177.97,36.73 181.52,36.73C186.89,36.73 208.07,35.26 212.41,33.56C216.88,31.75 220.42,29.1 223.05,25.6C225.68,22.09 227,17.85 227,12.88C227,9.38 226.54,5.09 225.63,0C217.16,2.37 197.71,7.92 184.59,9.27Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="227"
android:startY="133"
android:endX="-11.19"
android:endY="108.42"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="39dp"
android:height="19dp"
android:viewportWidth="39"
android:viewportHeight="19">
<path
android:pathData="M9.752,0H9.765C11.443,0 13.028,0.42 14.412,1.158H30.437C32.79,1.158 34.931,2.096 36.483,3.609C38.036,5.12 39,7.206 39,9.5C39,11.795 38.036,13.88 36.485,15.392L36.453,15.42C34.903,16.916 32.775,17.842 30.437,17.842H14.415C13.031,18.579 11.446,19 9.765,19H9.752C7.07,19 4.631,17.931 2.864,16.21C1.098,14.489 0,12.114 0,9.5C0,6.886 1.097,4.51 2.863,2.789L2.933,2.728C4.696,1.043 7.106,0 9.752,0ZM9.298,4.038C9.298,3.894 9.359,3.762 9.457,3.667C9.665,3.462 10.01,3.463 10.22,3.667L10.231,3.678C10.325,3.776 10.378,3.904 10.378,4.038V4.999C10.378,5.144 10.318,5.276 10.22,5.371C10.01,5.575 9.666,5.575 9.457,5.371C9.407,5.322 9.367,5.264 9.34,5.201C9.312,5.137 9.298,5.068 9.298,4.999V4.038ZM9.759,6.351C10.652,6.351 11.459,6.704 12.044,7.274C12.628,7.844 12.991,8.631 12.991,9.5C12.991,10.37 12.629,11.156 12.044,11.726C11.459,12.296 10.652,12.649 9.759,12.649C8.866,12.649 8.059,12.296 7.473,11.726C6.889,11.156 6.526,10.37 6.526,9.5C6.526,8.63 6.889,7.844 7.473,7.274C8.059,6.705 8.867,6.351 9.759,6.351ZM5.468,5.955C5.368,5.856 5.311,5.723 5.311,5.583C5.311,5.294 5.553,5.057 5.851,5.057C5.989,5.057 6.127,5.108 6.232,5.211L6.929,5.891C6.98,5.939 7.019,5.997 7.047,6.061C7.074,6.125 7.088,6.193 7.088,6.262C7.088,6.396 7.034,6.531 6.929,6.634C6.879,6.683 6.82,6.722 6.754,6.748C6.689,6.775 6.619,6.789 6.548,6.788C6.411,6.788 6.273,6.737 6.167,6.635L5.468,5.955ZM4.152,9.948C4.004,9.948 3.868,9.889 3.771,9.794C3.56,9.591 3.561,9.254 3.771,9.051L3.782,9.041C3.882,8.948 4.014,8.897 4.152,8.897H5.138C5.209,8.897 5.279,8.91 5.345,8.937C5.41,8.963 5.47,9.002 5.52,9.051C5.57,9.099 5.61,9.158 5.637,9.221C5.664,9.285 5.678,9.354 5.678,9.423C5.678,9.568 5.617,9.7 5.52,9.795C5.419,9.893 5.281,9.948 5.138,9.948H4.152ZM6.119,13.679C6.069,13.728 6.01,13.767 5.944,13.793C5.879,13.819 5.809,13.833 5.738,13.833C5.44,13.833 5.198,13.599 5.198,13.308C5.198,13.173 5.25,13.039 5.356,12.936L6.065,12.246C6.165,12.154 6.297,12.102 6.435,12.102C6.578,12.102 6.716,12.158 6.817,12.257C6.918,12.355 6.975,12.489 6.975,12.629C6.975,12.761 6.923,12.896 6.817,12.999L6.119,13.679ZM10.219,14.962C10.219,15.106 10.158,15.239 10.06,15.333C9.851,15.538 9.506,15.538 9.297,15.333L9.287,15.322C9.192,15.225 9.139,15.096 9.139,14.962V14.001C9.139,13.856 9.2,13.725 9.297,13.63C9.507,13.426 9.851,13.426 10.061,13.63C10.162,13.728 10.218,13.862 10.219,14.001V14.962ZM14.048,13.046C14.099,13.094 14.138,13.152 14.165,13.216C14.192,13.28 14.206,13.348 14.206,13.417C14.206,13.706 13.964,13.943 13.667,13.943C13.529,13.943 13.39,13.892 13.285,13.79L12.587,13.11C12.486,13.011 12.429,12.877 12.43,12.738C12.43,12.448 12.672,12.212 12.969,12.212C13.106,12.212 13.244,12.264 13.35,12.366L14.048,13.046ZM15.365,9.052C15.512,9.052 15.649,9.112 15.746,9.206C15.957,9.41 15.956,9.746 15.746,9.95L15.735,9.96C15.635,10.052 15.503,10.104 15.365,10.104H14.379C14.23,10.104 14.094,10.045 13.997,9.95C13.787,9.746 13.787,9.41 13.997,9.206C14.047,9.157 14.107,9.118 14.172,9.092C14.238,9.065 14.308,9.052 14.379,9.052H15.365ZM13.398,5.321C13.499,5.222 13.636,5.167 13.779,5.167C14.076,5.167 14.32,5.404 14.32,5.693C14.32,5.827 14.267,5.962 14.162,6.064L13.452,6.755C13.352,6.847 13.219,6.898 13.082,6.898C12.784,6.898 12.542,6.662 12.542,6.372C12.542,6.239 12.595,6.104 12.7,6.001L13.398,5.321ZM16.001,2.214C16.226,2.397 16.443,2.59 16.65,2.792C18.419,4.51 19.517,6.886 19.517,9.5C19.517,12.114 18.418,14.489 16.653,16.21C16.446,16.411 16.23,16.604 16.005,16.786H30.437C32.48,16.786 34.34,15.977 35.694,14.672L35.718,14.646C37.074,13.325 37.916,11.503 37.916,9.5C37.916,7.497 37.074,5.675 35.718,4.354C34.365,3.033 32.494,2.214 30.437,2.214H16.001ZM9.752,1.122H9.765C14.495,1.122 18.364,4.892 18.364,9.5C18.364,14.108 14.49,17.878 9.765,17.878H9.752C5.027,17.878 1.152,14.108 1.152,9.5C1.152,4.892 5.022,1.122 9.752,1.122Z"
android:fillColor="#000000"
android:fillType="evenOdd"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 284 KiB

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="32dp"
android:viewportWidth="22"
android:viewportHeight="32">
<path
android:pathData="M14.086,20.901C12.995,20.24 12.641,20.24 9.633,20.901C9.85,19.378 9.633,17.655 9.633,16.564C9.633,15.071 10.297,14.441 11.234,13.46C12.172,12.48 12.641,11.463 12.641,10.41C12.641,9.65 12.419,8.964 11.977,8.351C11.534,7.739 10.753,7.432 9.633,7.432C8.721,7.432 7.823,7.739 6.938,8.351C6.078,8.964 5.362,10.103 4.789,11.77C3.513,11.647 2.563,11.206 1.938,10.446C1.313,9.687 1,8.817 1,7.837C1,6.783 1.339,5.729 2.016,4.676C2.719,3.622 3.773,2.752 5.18,2.066C6.612,1.355 8.396,1 10.531,1C13.083,1 15.115,1.404 16.625,2.213C18.162,3.022 19.268,4.063 19.945,5.337C20.648,6.611 21,7.935 21,9.307C21,10.851 20.74,12.272 20.219,13.571C19.724,14.845 19.034,15.948 18.148,16.879C17.289,17.81 16.326,18.533 15.258,19.047C14.19,19.562 14.713,20.462 14.086,20.901ZM10.705,31C9.507,31 8.504,30.632 7.697,29.897C6.915,29.138 6.525,28.219 6.525,27.141C6.525,26.307 6.746,25.548 7.189,24.862C7.632,24.151 8.218,23.575 8.947,23.134C9.702,22.693 10.535,22.472 11.447,22.472C12.645,22.472 13.634,22.852 14.415,23.612C15.223,24.347 15.626,25.254 15.626,26.332C15.626,27.141 15.405,27.9 14.962,28.611C14.52,29.322 13.921,29.897 13.165,30.338C12.436,30.779 11.616,31 10.705,31Z"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="30dp"
android:viewportWidth="20"
android:viewportHeight="30">
<path
android:pathData="M13.086,19.901C11.995,19.24 11.641,19.24 8.633,19.901C8.85,18.378 8.633,16.655 8.633,15.564C8.633,14.071 9.297,13.441 10.234,12.46C11.172,11.48 11.641,10.463 11.641,9.41C11.641,8.65 11.419,7.964 10.977,7.351C10.534,6.739 9.753,6.432 8.633,6.432C7.721,6.432 6.823,6.739 5.938,7.351C5.078,7.964 4.362,9.103 3.789,10.77C2.513,10.647 1.563,10.206 0.938,9.446C0.313,8.687 0,7.817 0,6.837C0,5.783 0.339,4.729 1.016,3.676C1.719,2.622 2.773,1.752 4.18,1.066C5.612,0.355 7.396,0 9.531,0C12.083,0 14.115,0.404 15.625,1.213C17.162,2.022 18.268,3.063 18.945,4.337C19.648,5.611 20,6.935 20,8.307C20,9.851 19.74,11.272 19.219,12.571C18.724,13.845 18.034,14.948 17.148,15.879C16.289,16.81 15.325,17.533 14.258,18.047C13.19,18.562 13.713,19.462 13.086,19.901ZM9.705,30C8.507,30 7.504,29.632 6.697,28.897C5.915,28.138 5.525,27.219 5.525,26.141C5.525,25.307 5.746,24.548 6.189,23.862C6.632,23.151 7.218,22.575 7.947,22.134C8.702,21.693 9.535,21.472 10.447,21.472C11.645,21.472 12.634,21.852 13.415,22.612C14.223,23.347 14.626,24.254 14.626,25.332C14.626,26.141 14.405,26.9 13.962,27.611C13.52,28.322 12.921,28.897 12.165,29.338C11.436,29.779 10.616,30 9.705,30Z"
android:fillColor="#ffffff"/>
</vector>

@ -11,11 +11,18 @@
<string name="PasswdLogin">Votre mot de passe*</string> <string name="PasswdLogin">Votre mot de passe*</string>
<string name="ButtonLogin">Se connecter</string> <string name="ButtonLogin">Se connecter</string>
<string name="ButtonCreateLogin">Créer son compte</string> <string name="ButtonCreateLogin">Créer son compte</string>
<string name="ErrorLogin">Identifiant ou mot de passe incorrect</string>
//Page Sign Up //Page Sign Up
<string name="titleSignUp">Inscription</string> <string name="titleSignUp">Inscription</string>
<string name="ConfirmPassWdSignUp">Confirmer mot de passe*</string> <string name="ConfirmPassWdSignUp">Confirmer mot de passe*</string>
<string name="ButtonSignUp">S\'inscrire</string> <string name="ButtonSignUp">S\'inscrire</string>
<string name="EmailSignUp">Email*</string>
<string name="ErrorEmailSignUp">Email invalide</string>
<string name="ErrorPasswordSignUp">Les mots de passe ne correspondent pas</string>
<string name="ErrorUserEmptySignUp">Le nom d\'utilisateur ne peut pas être vide</string>
<string name="ErrorUserExistSignUp">Le nom d\'utilisateur n\'est pas disponible</string>
<string name="ErrorPasswordEmpty">Vous devez mettre un mot de passe</string>
//Page Profil //Page Profil
<string name="titleProfile">Profil</string> <string name="titleProfile">Profil</string>
@ -27,4 +34,13 @@
<string name="ButtonSaveprofile">Sauvegarder</string> <string name="ButtonSaveprofile">Sauvegarder</string>
<string name="ErrorEmailprofile">L\'adress email est invalide</string> <string name="ErrorEmailprofile">L\'adress email est invalide</string>
<string name="Errorpasswdprofile">Les mots de passe ne correspondent pas</string> <string name="Errorpasswdprofile">Les mots de passe ne correspondent pas</string>
//Component quote
<string name="dateQuote">Date</string>
<string name="CharacterQuote">Personnage</string>
//Page Favori
<string name="TitleFavorite">Favoris</string>
</resources> </resources>

@ -5,6 +5,10 @@
<color name="purple_700">#FF3700B3</color> <color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color> <color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color> <color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="black">#FF100C1B</color>
<color name="light_purple">#FF7B1FA2</color>
<color name="dark_blue">#FF311B92</color>
</resources> </resources>

@ -10,11 +10,18 @@
<string name="PasswdLogin">Your password*</string> <string name="PasswdLogin">Your password*</string>
<string name="ButtonLogin">Login</string> <string name="ButtonLogin">Login</string>
<string name="ButtonCreateLogin">Create your account</string> <string name="ButtonCreateLogin">Create your account</string>
<string name="ErrorLogin">Incorrect username or password</string>
//Page Sign Up //Page Sign Up
<string name="titleSignUp">Account creation</string> <string name="titleSignUp">Account creation</string>
<string name="ConfirmPassWdSignUp">Confirm your password*</string> <string name="ConfirmPassWdSignUp">Confirm your password*</string>
<string name="ButtonSignUp">Create</string> <string name="ButtonSignUp">Create</string>
<string name="EmailSignUp">Your email*</string>
<string name="ErrorEmailSignUp">Invalid email</string>
<string name="ErrorPasswordSignUp">Passwords do not match</string>
<string name="ErrorUserEmptySignUp">Username cannot be empty</string>
<string name="ErrorUserExistSignUp">Username is not available</string>
<string name="ErrorPasswordEmpty">You must put a password</string>
//Page Profil //Page Profil
<string name="titleProfile">Profile</string> <string name="titleProfile">Profile</string>
@ -27,4 +34,11 @@
<string name="ErrorEmailprofile">Invalid email address</string> <string name="ErrorEmailprofile">Invalid email address</string>
<string name="Errorpasswdprofile">Passwords do not match</string> <string name="Errorpasswdprofile">Passwords do not match</string>
//Component quote
<string name="dateQuote">Date</string>
<string name="CharacterQuote">Character</string>
//Page Favori
<string name="TitleFavorite">Favorites</string>
</resources> </resources>

@ -38,4 +38,4 @@ androidx-navigation-common-android = { group = "androidx.navigation", name = "na
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}

Loading…
Cancel
Save