diff --git a/README.md b/README.md index 6210e70..b0bfd5d 100644 --- a/README.md +++ b/README.md @@ -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
+BEAULATON Léni
+ROCHER Maxime
+MONDEJAR Kevin
+GUICHARD-MONTGUERS Louis
+NGUYEN Tommy
+ \ No newline at end of file diff --git a/What_The_Fantasy/app/build.gradle.kts b/What_The_Fantasy/app/build.gradle.kts index 4b7e70e..eb95a8a 100644 --- a/What_The_Fantasy/app/build.gradle.kts +++ b/What_The_Fantasy/app/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlinx.serialization) } android { diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/Logs/LogsUsers.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/Logs/LogsUsers.kt new file mode 100644 index 0000000..1ae774c --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/Logs/LogsUsers.kt @@ -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, 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}") + } +} diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/MainActivity.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/MainActivity.kt index 408f0d9..cbed7f2 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/MainActivity.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/MainActivity.kt @@ -4,19 +4,8 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent 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.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() { override fun onCreate(savedInstanceState: Bundle?) { @@ -25,7 +14,6 @@ class MainActivity : ComponentActivity() { setContent { What_The_FantasyTheme { AppNavigator() - //QuizPage() } } } diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuizStub.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuizStub.kt new file mode 100644 index 0000000..7e47169 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuizStub.kt @@ -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 = listOf(quiz1, quiz2, quiz3, quiz4, quiz5, quiz6, quiz7, quiz8, quiz9, quiz10, quiz11) + + fun getQuizById(id: Int): Quiz? { + return allQuizzes.find { it.id == id } + } +} diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuoteStub.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuoteStub.kt index cc321e5..2922816 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuoteStub.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/QuoteStub.kt @@ -1,6 +1,8 @@ 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.SrcLanguage +import com.example.what_the_fantasy.data.model.SrcType object QuoteStub { @@ -8,181 +10,221 @@ object QuoteStub { id = 1, content = "All we have to decide is what to do with the time that is given us.", likes = 466, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.gandalf.name, source = "The Lord of the Rings: The Fellowship of the Ring", + date = 2000, + type = SrcType.Movie, imgUrl = CharacterStub.gandalf.imgUrl ) val quote2 = Quote( id = 2, content = "A wizard is never late, nor is he early, he arrives precisely when he means to.", likes = 467, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.gandalf.name, 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( id = 3, content = "Even the smallest person can change the course of the future.", likes = 466, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.galadriel.name, 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( id = 4, content = "I would rather share one lifetime with you than face all the ages of this world alone.", likes = 120, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.arwen.name, 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( id = 5, content = "Faithless is he that says farewell when the road darkens.", likes = 150, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.gimli.name, 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( 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.", likes = 200, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.frodoBaggins.name, 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( id = 7, content = "I am no man.", likes = 300, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.eowyn.name, 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( 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.", likes = 400, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.treebeard.name, 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( id = 9, content = "We wants it, we needs it. Must have the precious.", likes = 500, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.gollum.name, 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( id = 10, content = "The board is set, the pieces are moving. We come to it at last, the great battle of our time.", likes = 600, - language = "en", + language = SrcLanguage.vo, character = CharacterStub.gandalf.name, 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( id = 11, content = "Un grand pouvoir implique de grandes responsabilités.", likes = 466, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.aragorn.name, source = "Spider-Man", - imgUrl = CharacterStub.aragorn.imgUrl + imgUrl = CharacterStub.aragorn.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote12 = Quote( id = 12, content = "Que la Force soit avec toi.", likes = 467, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.legolas.name, source = "Star Wars", - imgUrl = CharacterStub.legolas.imgUrl + imgUrl = CharacterStub.legolas.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote13 = Quote( id = 13, content = "La magie est partout. Il suffit de savoir où la trouver.", likes = 466, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.gandalf.name, source = "Harry Potter", - imgUrl = CharacterStub.gandalf.imgUrl + imgUrl = CharacterStub.gandalf.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote14 = Quote( id = 14, content = "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.", likes = 120, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.frodoBaggins.name, source = "Le Seigneur des Anneaux", - imgUrl = CharacterStub.frodoBaggins.imgUrl + imgUrl = CharacterStub.frodoBaggins.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote15 = Quote( id = 15, content = "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.", likes = 150, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.gimli.name, source = "Star Wars", - imgUrl = CharacterStub.gimli.imgUrl + imgUrl = CharacterStub.gimli.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote16 = Quote( id = 16, content = "La vie est une aventure audacieuse ou rien du tout.", likes = 200, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.galadriel.name, source = "Helen Keller", - imgUrl = CharacterStub.galadriel.imgUrl + imgUrl = CharacterStub.galadriel.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote17 = Quote( id = 17, content = "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.", likes = 300, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.boromir.name, source = "Nelson Mandela", - imgUrl = CharacterStub.boromir.imgUrl + imgUrl = CharacterStub.boromir.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote18 = Quote( id = 18, content = "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.", likes = 400, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.eowyn.name, source = "Albert Einstein", - imgUrl = CharacterStub.eowyn.imgUrl + imgUrl = CharacterStub.eowyn.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote19 = Quote( id = 19, content = "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.", likes = 500, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.saruman.name, source = "Dalaï Lama", - imgUrl = CharacterStub.saruman.imgUrl + imgUrl = CharacterStub.saruman.imgUrl, + date = 2000, + type = SrcType.Movie, ) val quote20 = Quote( id = 20, content = "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.", likes = 600, - language = "fr", + language = SrcLanguage.fr, character = CharacterStub.samwiseGamgee.name, source = "Gandhi", - imgUrl = CharacterStub.samwiseGamgee.imgUrl + imgUrl = CharacterStub.samwiseGamgee.imgUrl, + date = 2000, + type = SrcType.Movie, ) val allQuotes: List = listOf( diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt index 552ad3e..da7fe1c 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/local/UserStub.kt @@ -1,97 +1,23 @@ 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 object UserStub { - val user1 = User( - id = 1, - username = "Aragorn123", - email = "aragorn@example.com", - date = "2022-01-15", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg", - password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 - - val user2 = User( - id = 2, - username = "Legolas456", - email = "legolas@example.com", - date = "2021-05-23", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-elfe-fantaisie_1045-186.jpg?size=338&ext=jpg", - 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 + //LE MOT DE PASSE POUR TOUS LES UTILISATEURS EST : 1234 + val users: MutableList = mutableListOf( + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + ) - val user11 = User( - id = 10, - username = "dev", - email = "testeur@example.com", - date = "2023-02-08", - imgUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg", - password = "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4") // 1234 - val allUsers: List = listOf( - user1, user2, user3, user4, user5, user6, user7, user8, user9, user10, user11 - ) } \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quiz.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quiz.kt new file mode 100644 index 0000000..bfea084 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quiz.kt @@ -0,0 +1,8 @@ +package com.example.what_the_fantasy.data.model + +class Quiz ( + val id : Int, + val name : String, + val questions : List, + val img : String +) \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quote.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quote.kt index 8db4084..75da8b1 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quote.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/Quote.kt @@ -1,11 +1,16 @@ package com.example.what_the_fantasy.data.model +import java.util.Date + data class Quote ( val id: Int, val content: String, val likes: Int, - val language: String, + val language: SrcLanguage, val character: String, val source: String, - val imgUrl: String + val imgUrl: String, + val type: SrcType, + val date: Int + ) \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/SrcLanguage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/SrcLanguage.kt new file mode 100644 index 0000000..7c27fbb --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/SrcLanguage.kt @@ -0,0 +1,6 @@ +package com.example.what_the_fantasy.data.model + +enum class SrcLanguage { + fr, + vo +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt index ce4cb2f..2749a1c 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/model/User.kt @@ -6,5 +6,6 @@ class User( var email:String, var date:String, val imgUrl: String, - val password: String -) + var password: String, + val language : SrcLanguage +) \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/IServices.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/IServices.kt new file mode 100644 index 0000000..1b66358 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/IServices.kt @@ -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 + + fun getUserById(id: Int): User? + + fun SearchQuote(quote : String) + + + +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesAPI.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesAPI.kt new file mode 100644 index 0000000..25cd320 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesAPI.kt @@ -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 { + TODO("Not yet implemented") + } + + override fun getUserById(id: Int): User? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesStub.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesStub.kt new file mode 100644 index 0000000..70745e7 --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/data/services/ServicesStub.kt @@ -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 = 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) : String{ + return "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg" + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/BackBar.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/BackBar.kt new file mode 100644 index 0000000..c2deeda --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/BackBar.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/LittleQuoteComponent.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/LittleQuoteComponent.kt new file mode 100644 index 0000000..3f9481c --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/LittleQuoteComponent.kt @@ -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) +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/NavBar.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/NavBar.kt index dedbd00..8d89f41 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/NavBar.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/NavBar.kt @@ -1,4 +1,153 @@ package com.example.what_the_fantasy.ui.components -class NavBar { -} \ No newline at end of file +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() + ) + } +} + diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt index 86aad8f..50c1ac7 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/TitleComponents.kt @@ -1,21 +1,28 @@ package com.example.what_the_fantasy.ui.components +import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource 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 @Composable -fun TitlePageComponent(titleResId : Int, size : Int, color : Color) { +fun TitlePageComponent(titleResId: Int, color: Color) { val title = stringResource(id = titleResId) Text( text = title, - fontSize = size.sp, + fontSize = 20.sp, fontWeight = FontWeight.Bold, - color = color + color = color, + textAlign = TextAlign.Center, + ) } diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/hashPassword.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/hashPassword.kt new file mode 100644 index 0000000..2f46a9d --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/components/hashPassword.kt @@ -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) } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt index d7c38e5..169f329 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/navigations/AppNavigator.kt @@ -4,57 +4,143 @@ import androidx.compose.runtime.Composable import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable 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.FavoritePage import com.example.what_the_fantasy.ui.screens.LoginPage import com.example.what_the_fantasy.ui.screens.ProfilPage +import com.example.what_the_fantasy.ui.screens.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.QuotePage import com.example.what_the_fantasy.ui.screens.SearchPage import com.example.what_the_fantasy.ui.screens.SignUpPage import com.example.what_the_fantasy.ui.screens.SubmitQuotePage +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 fun AppNavigator() { val navController = rememberNavController() - - NavHost(navController, startDestination = Destination.Login.route) { - composable(Destination.Login.route) { + val services = ServicesStub() + NavHost(navController, startDestination = Login) { + composable { LoginPage( - navControllerSignUp = { navController.navigate(Destination.SignUp.route) }, + navControllerSignUp = { navController.navigate(SignUp) }, 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 { + 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 { + 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{ + 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 { QuotePage() } + composable { SearchPage() } + composable { SignUpPage( + navControllerLogin = { + navController.navigate(Login){ + // Vider pile de navigation pour empêcher le retour à la page Sign up + popUpTo(Login) { inclusive = true } + } + },services) } + composable { SubmitQuotePage() } + + composable { + 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(Destination.Favorite.route) { FavoritePage() } - composable(Destination.Profil.route) { backStackEntry -> - // Récupère l'index passé dans la route - val userIndex = backStackEntry.arguments?.getString("userIndex")?.toInt() ?: -1 - ProfilPage(index = userIndex, navController = navController) + composable { + val quiz:Quiz=it.toRoute() + QuizPage( + index = quiz.userIndex, + navAccueil = { navController.navigate( Accueil(quiz.userIndex) ) }, + 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 { + 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() } } } - diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/AccueilPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/AccueilPage.kt index 8fd4c97..f56508f 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/AccueilPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/AccueilPage.kt @@ -1,6 +1,42 @@ 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.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 -fun AccueilPage() {} \ No newline at end of file +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) + } + } + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/FavoritePage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/FavoritePage.kt index 72c2e72..2d34fb8 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/FavoritePage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/FavoritePage.kt @@ -1,6 +1,74 @@ 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.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 -fun FavoritePage() {} \ No newline at end of file +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)) + } + + } + } + } + } + } +} + + + diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt index d5d3fd7..fca9d38 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/LoginPage.kt @@ -5,14 +5,18 @@ 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.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text 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.data.local.UserStub 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.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.gradienBox import java.security.MessageDigest @Composable -fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit) { - - val users = UserStub.allUsers; - +fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit, services : IServices) { + val users = services.getAllUsers() Box( modifier = Modifier @@ -67,11 +73,9 @@ fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Uni horizontalAlignment = Alignment.CenterHorizontally ) { - TitlePageComponent(R.string.titleLogin, 20,Color.White) - val identifiant =IdentifiantTextField(R.string.IdentifiantLogin) - val passwd = PassWdTextField(R.string.PasswdLogin) - SpaceHeightComponent(16) - ConnexionButtonLogin(users,identifiant, passwd, R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil) + TitlePageComponent(R.string.titleLogin, Color.White) + SpaceHeightComponent(20) + ConnexionButtonLogin(users,IdentifiantTextField(R.string.IdentifiantLogin), PassWdTextField(R.string.PasswdLogin), R.string.ButtonLogin,18, Color.White, Color.Black,navControllerProfil) SpaceHeightComponent(16) CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp) } @@ -94,7 +98,7 @@ fun IdentifiantTextField(textIdentifiantResId : Int) : String{ .fillMaxWidth() .padding(top = 8.dp), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), - shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + shape = RoundedCornerShape(16.dp) // Bords arrondis ) } return identifiant; @@ -105,7 +109,7 @@ fun PassWdTextField(textpasswdResId : Int) : String{ val textpasswd = stringResource(id = textpasswdResId) var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer - Column(modifier = Modifier.padding(top = 10.dp)) { + Column(modifier = Modifier.padding(top = 10.dp, bottom = 30.dp)) { OutlinedTextField( value = passwd, onValueChange = { passwd = it }, @@ -129,41 +133,38 @@ fun PassWdTextField(textpasswdResId : Int) : String{ @Composable fun ConnexionButtonLogin(userStub : List, id : String, passwd : String, titleResId : Int, size : Int, colorButton : Color, colorText : Color, navController: (Int) -> Unit){ val title = stringResource(id = titleResId) + var showError by remember { mutableStateOf(false) } Button( - onClick = { validLogin(id, passwd, userStub, navController) }, + onClick = { showError = !validLogin(id, passwd, userStub, navController) + }, colors = ButtonDefaults.buttonColors(containerColor = colorButton), modifier = Modifier .fillMaxWidth(), ) { Text(title, fontSize = size.sp, color = colorText) } + + if(showError){ + ErrorMessageProfileComponent(R.string.ErrorLogin) + } } -fun validLogin(identifiant : String, passwd : String, users : List, navController: (Int) -> Unit){ +fun validLogin(identifiant : String, passwd : String, users : List, navController: (Int) -> Unit): Boolean { + + users.forEachIndexed { index, user -> val hashPassWd = hashPassword(passwd) if (user.username == identifiant && user.password == hashPassWd) { - // Utilise l'index pour naviguer à la position correspondante navController(index) // Passer l'index à la fonction navController + 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 -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) Text( 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 } ) -} +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt index c2c0702..b122258 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/ProfilPage.kt @@ -26,7 +26,9 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.rounded.Face import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults 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.data.local.QuestionStub 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.NavBar import com.example.what_the_fantasy.ui.components.SpaceHeightComponent import com.example.what_the_fantasy.ui.components.TitlePageComponent import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme +import com.example.what_the_fantasy.ui.theme.gradienBox @Composable -fun ProfilPage(index: Int, navController: NavController) { - val gradient = Brush.linearGradient( - colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé - start = Offset(0f, 1000f), // Départ en bas à gauche - end = Offset(1000f, 0f) // Fin en haut à droite - ) - val user = UserStub.allUsers - //val index = 2 // Pour changer l'utilisateur pour le moment - - Box( - modifier = Modifier - .fillMaxSize() - .background(Color(0xFF100C1B)), - contentAlignment = Alignment.Center +fun ProfilPage(index: Int, + navFavorite: (Int) -> Unit, + navAccueil: (Int) -> Unit, + navQuiz: (Int) -> Unit, + navUnLog: () -> Unit, + services: IServices +) { + val user = services.getUserById(index) ?: return + + NavBar(onProfile = true, + index = index, + navControllerFavorite = navFavorite, + navControllerAccueil = navAccueil, + navControllerProfil = {}, + navControllerQuiz = navQuiz ) { - Column( + + Box( modifier = Modifier - .fillMaxWidth(0.9f) - .padding(20.dp) - .clip(RoundedCornerShape(16.dp)) - .background(gradient) - .padding(20.dp), - horizontalAlignment = Alignment.CenterHorizontally + .fillMaxSize() + .background(Color(0xFF100C1B)), + contentAlignment = Alignment.Center ) { + Column( + modifier = Modifier + .fillMaxWidth(0.9f) + .padding(20.dp) + .clip(RoundedCornerShape(16.dp)) + .background(gradienBox) + .padding(20.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { // Titre - TitlePageComponent(R.string.titleProfile, 20, Color.White) + TitlePageComponent(R.string.titleProfile, Color.White) SpaceHeightComponent(16) // Image de profil - ImageProfil(user[index].imgUrl, 120, 2, Color.White) + ImageProfil(user.imgUrl, 120) SpaceHeightComponent(16) - EditUsername(user[index].username)// Édition du Username + EditUsername(user.username, index, services)// Édition du Username SpaceHeightComponent(16) - EditEmail(user[index].email)// Édition du Email + EditEmail(user.email,index, services)// Édition du Email Spacer(modifier = Modifier.height(8.dp)) - EditPasswd() + EditPasswd(index, services) SpaceHeightComponent(16) // Bouton - ButtonProfile(R.string.ButtonAddQuoteprofile,18, Color.Black, Color.White) - SpaceHeightComponent(16) - ButtonProfile(R.string.ButtonLanguageprofile,18, Color.Black, Color.White) + //ButtonProfile(R.string.ButtonAddQuoteprofile, 18, Color.Black, Color.White,navUnLog) // Pas encore de navigation definie + //SpaceHeightComponent(16) + ButtonProfile(R.string.ButtonLanguageprofile, 18, Color.Black, Color.White,navUnLog) // Pas encore de navigation definie SpaceHeightComponent(16) - ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White) + ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White, navUnLog) + } } } } @Composable -fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : Color){ +fun ImageProfil(imgProfil : String, size :Int){ AsyncImage( model = imgProfil, @@ -134,20 +150,27 @@ fun ImageProfil(imgProfil : String, size :Int, sizeBorber : Int, colorBorder : C } @Composable -fun EditEmail(userEmail: String) { +fun EditEmail(userEmail: String, index: Int, service: IServices) { var email by remember { mutableStateOf(userEmail) } var isEditingEmail by remember { mutableStateOf(false) } var emailError by remember { mutableStateOf(false) } + fun onDoneEditing() { + service.EditEmail(email, index) + isEditingEmail = false + } + if (isEditingEmail) { EmailEditingField( email = email, onEmailChange = { newEmail -> email = newEmail - emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() + emailError = !Patterns.EMAIL_ADDRESS.matcher(newEmail).matches() // Validation email }, onDone = { - if (!emailError) isEditingEmail = false + if (!emailError) { + onDoneEditing() + } }, emailError = emailError ) @@ -178,7 +201,7 @@ fun EmailEditingField( ), trailingIcon = { IconButton(onClick = { if (!emailError) onDone() }) { - Icon(imageVector = Icons.Default.Check, contentDescription = "Valider") + Icon(imageVector = Icons.Default.CheckCircle, contentDescription = "Valider") } }, isError = emailError @@ -213,18 +236,21 @@ fun DisplayEmail(email: String, onEdit: () -> Unit) { - - @Composable -fun EditUsername(userName: String) { +fun EditUsername(userName: String, index: Int, service : IServices) { var username by remember { mutableStateOf(userName) } var isEditingUsername by remember { mutableStateOf(false) } + fun onDoneEditing() { + service.EditUsername(username, index) + isEditingUsername = false + } + if (isEditingUsername) { UsernameEditingField( username = username, onUsernameChange = { username = it }, - onDone = { isEditingUsername = false } + onDone = { onDoneEditing() } ) } else { DisplayUsername(username = username, onEdit = { isEditingUsername = true }) @@ -247,11 +273,11 @@ fun UsernameEditingField( imeAction = ImeAction.Done ), keyboardActions = KeyboardActions( - onDone = { onDone() } // Quand on appuie sur "Done", on met fin à l'édition + onDone = { onDone() } ), trailingIcon = { 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 -fun EditPasswd() { - var password by remember { mutableStateOf("*******") } +fun EditPasswd(index: Int, service: IServices) { + var password by remember { mutableStateOf("*******") } // Mot de passe actuel (affiché comme un masque) var isEditingPassword by remember { mutableStateOf(false) } var newPassword by remember { mutableStateOf("") } var confirmPassword by remember { mutableStateOf("") } var passwordVisible by remember { mutableStateOf(false) } var passwordError by remember { mutableStateOf(false) } + // 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) { PasswordEditingFields( newPassword = newPassword, @@ -299,20 +329,19 @@ fun EditPasswd() { onNewPasswordChange = { newPassword = it }, onConfirmPasswordChange = { confirmPassword = it - passwordError = newPassword != it + passwordError = newPassword != it // Vérifier si les mots de passe correspondent }, passwordVisible = passwordVisible, onPasswordVisibilityChange = { passwordVisible = it }, passwordError = passwordError, onDone = { if (!passwordError && newPassword.isNotEmpty()) { - password = newPassword - isEditingPassword = false + onDoneEditing() // Appeler la fonction onDoneEditing() pour mettre à jour le mot de passe } } ) } 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 -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) Button( - onClick = { /* Action */ }, + onClick = { navController() }, colors = ButtonDefaults.buttonColors(containerColor = colorButton), modifier = Modifier.fillMaxWidth(), ) { diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt deleted file mode 100644 index b237afd..0000000 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizAccueil.kt +++ /dev/null @@ -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) - } - } -} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt index 359e7f7..6578b17 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizEndPage.kt @@ -2,6 +2,7 @@ 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.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -24,6 +25,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.what_the_fantasy.R import com.example.what_the_fantasy.data.local.QuestionStub +import com.example.what_the_fantasy.data.local.QuizStub +import com.example.what_the_fantasy.ui.components.NavBar val gradient = Brush.linearGradient( colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), @@ -31,133 +34,111 @@ val gradient = Brush.linearGradient( end = Offset(1000f, 0f) ) - - @Composable -fun QuizEndPage(points: Int, idQuiz: Int) { - Column( - modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B)) - ) { - // Bandeau supérieur - Row( - modifier = Modifier - .fillMaxWidth() - .weight(0.1f) - .background(Color(0xFF300052)) - .padding(20.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - IconButton(onClick = { }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Retour", tint = Color.White) - } - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Profil", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) - ) - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Profil", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) - ) - } - - // Contenu principal +fun QuizEndPage( + idQuiz: Int, + points: Int, + index: Int, + navFavorite: (Int) -> Unit, + navAccueil: (Int) -> Unit, + navProfil:(Int) -> Unit, + navQuiz: (Int) -> Unit, +) { + NavBar(onQuiz = true, + index = index, + navControllerFavorite = navFavorite, + navControllerAccueil = navAccueil, + navControllerProfil = navProfil, + navControllerQuiz = navQuiz) { Column( - modifier = Modifier - .weight(0.8f) - .padding(horizontal = 50.dp, vertical = 20.dp) - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally + modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B)) ) { - Text( - text = "▶ Résultats ◀", - color = Color.White, - style = TextStyle(fontSize = 25.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) - ) - Spacer(modifier = Modifier.height(16.dp)) - Column ( + + // Contenu principal + Column( modifier = Modifier - .background(brush = gradient, shape = RoundedCornerShape(20.dp)) - .padding(30.dp) - .fillMaxSize(), + .weight(0.8f) + .padding(horizontal = 50.dp, vertical = 20.dp) + .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - Text ( - text = "Quiz N°$idQuiz", - color = Color.White, - style = TextStyle(fontSize = 25.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) - ) - - val nbQuestions = QuestionStub.allQuestions.size - - Text ( - text = "Nombres de Questions : $nbQuestions", + Text( + text = "▶ Résultats ◀", color = Color.White, - style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) - ) - Text ( - text = "Nombres de bonnes réponses : $points", - color = Color.White, - style = TextStyle(fontSize = 15.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center) + style = TextStyle( + fontSize = 25.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) ) - Row ( + Spacer(modifier = Modifier.height(16.dp)) + Column( modifier = Modifier - .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceAround + .background(brush = gradient, shape = RoundedCornerShape(20.dp)) + .padding(30.dp) + .fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.SpaceEvenly ) { - // Bouton Quiz Précédent - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Profil", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + val quiz = QuizStub.getQuizById(idQuiz) + val nbQuestions = quiz?.questions?.size + Text( + text = "${quiz?.name}", + color = Color.White, + style = TextStyle( + fontSize = 25.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) ) - // Bouton Retour Menu Quiz - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Profil", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + Text( + text = "Nombres de Questions : $nbQuestions", + color = Color.White, + style = TextStyle( + fontSize = 15.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) ) - // Bouton Quiz Suivant - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Profil", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) + Text( + text = "Nombres de bonnes réponses : $points", + color = Color.White, + style = TextStyle( + fontSize = 15.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) ) - } - } - } + val pourcentage = (points.toDouble() / nbQuestions!!) * 100 - // Bandeau inférieur - Row( - modifier = Modifier - .fillMaxWidth() - .weight(0.1f) - .background(Color(0xFF300052)) - .padding(20.dp), - horizontalArrangement = Arrangement.SpaceAround, - verticalAlignment = Alignment.CenterVertically - ) { - // Bouton Likes - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Bouton", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) - ) - // Bouton WhatTheFantasy - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Bouton", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) - ) - // Bouton Quiz - Image( - painter = painterResource(id = R.drawable.quiz), - contentDescription = "Bouton", - modifier = Modifier.size(50.dp).background(Color.Yellow, CircleShape) - ) + val note = when { + pourcentage == 100.0 -> "S" + pourcentage >= 70.0 -> "A" + pourcentage >= 40.0 -> "B" + else -> "C" + } + + println("Note obtenue : $note") + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .size(100.dp) + .background(Color.White, shape = RoundedCornerShape(50.dp)) + ) { + Text( + text = note, + color = Color.Red, + style = TextStyle( + fontSize = 40.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + ) + } + } + } } } } diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizMenu.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizMenu.kt new file mode 100644 index 0000000..99c50af --- /dev/null +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizMenu.kt @@ -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)) + } + } + } + } + } +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt index 4317669..e20a5f2 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuizPage.kt @@ -1,14 +1,11 @@ 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.* +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -16,14 +13,32 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import 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.QuizStub +import com.example.what_the_fantasy.ui.components.BackBar +import com.example.what_the_fantasy.ui.components.NavBar @Composable -fun QuizPage(navController: NavController) { - val questions = QuestionStub.allQuestions +fun QuizPage( + 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 pts by remember { mutableIntStateOf(0) } @@ -44,59 +59,92 @@ fun QuizPage(navController: NavController) { if (answer == correctAnswer) pts++ if (idCurrentQuestion < questions.size - 1) idCurrentQuestion++ - else navController.popBackStack() // Retour menu + else navControllerQuizEnd(idQuiz, pts) // Retour menu } - - Box( - modifier = Modifier - .fillMaxSize() - .background(Color(0xFF100C1B)) - .padding(16.dp) + NavBar(onQuiz = true, + index = index, + navControllerFavorite = navFavorite, + navControllerAccueil = navAccueil, + navControllerProfil = navProfil, + navControllerQuiz = navQuiz + ){ + Column ( + modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B)) ) { - Column( - modifier = Modifier - .fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally - ) { - val question = questions[idCurrentQuestion] - - Column ( - horizontalAlignment = Alignment.CenterHorizontally, + // Contenu princiapl + Column( + modifier = Modifier + .weight(0.8f) + .fillMaxWidth() + .padding(horizontal = 50.dp, vertical = 20.dp), + horizontalAlignment = Alignment.CenterHorizontally ) { - Box( - modifier = Modifier.fillMaxWidth() + val question = questions[idCurrentQuestion] + + Column( + horizontalAlignment = Alignment.CenterHorizontally, ) { - IconButton( - onClick = { navController.popBackStack() }, - modifier = Modifier.align(Alignment.TopStart) - ) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Retour", tint = Color.White) + if (quiz != null) { + Text( + text = "▶ ${quiz.name} ◀", + color = Color.White, + style = TextStyle( + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + ) } - } - Text("Question ${question.id}", color = Color.White, fontSize = 18.sp, modifier = Modifier.padding(top = 20.dp)) - Text("Points : $pts", color = Color.White, fontSize = 18.sp, modifier = Modifier.padding(top = 40.dp)) - Text(question.question, color = Color.White, fontSize = 22.sp, modifier = Modifier.padding(40.dp)) - } - Column ( - modifier = Modifier - .padding(top = 30.dp) - ) { - listOf(question.ansA, question.ansB, question.ansC, question.ansD).forEach { answer -> - Box( + Spacer(Modifier.height(20.dp)) + Column( modifier = Modifier - .width(220.dp) - .height(50.dp) - .background(brush = gradient, shape = RoundedCornerShape(16.dp)) - .clickable { onAnswerSelected(answer) } - .padding(horizontal = 8.dp), - contentAlignment = Alignment.Center + .background(brush = gradient, shape = RoundedCornerShape(20.dp)), + horizontalAlignment = Alignment.CenterHorizontally ) { - 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)) } } - } } } \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt index cfb1d2f..078c936 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/QuotePage.kt @@ -1,6 +1,8 @@ package com.example.what_the_fantasy.ui.screens import androidx.compose.runtime.Composable +import com.example.what_the_fantasy.ui.components.NavBar @Composable -fun QuotePage() {} \ No newline at end of file +fun QuotePage() { +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SearchPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SearchPage.kt index 9b8d6ac..3d081c1 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SearchPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SearchPage.kt @@ -1,6 +1,8 @@ package com.example.what_the_fantasy.ui.screens import androidx.compose.runtime.Composable +import com.example.what_the_fantasy.ui.components.NavBar @Composable -fun SearchPage() {} \ No newline at end of file +fun SearchPage() { +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt index 3e77782..13d5ca8 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SignUpPage.kt @@ -15,8 +15,11 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text @@ -40,15 +43,23 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController import com.example.what_the_fantasy.R +import com.example.what_the_fantasy.data.services.IServices import com.example.what_the_fantasy.ui.components.SpaceHeightComponent import com.example.what_the_fantasy.ui.components.TitlePageComponent import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme import com.example.what_the_fantasy.ui.theme.colorBackground import com.example.what_the_fantasy.ui.theme.gradienBox +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 -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( modifier = Modifier @@ -66,15 +77,15 @@ fun SignUpPage(navController: NavController) { horizontalAlignment = Alignment.CenterHorizontally ) { - TitlePageComponent(R.string.titleSignUp, 20,Color.White) - IdentifiantTextFieldSign(R.string.IdentifiantLogin) - EmailTextFieldSign("Email*") - PassWdTextFieldSign(R.string.PasswdLogin) - PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp) + TitlePageComponent(R.string.titleSignUp,Color.White) + IdentifiantTextFieldSign(R.string.IdentifiantLogin,identifiant = username,onValueChange = { username = it }) + EmailTextFieldSign(R.string.EmailSignUp, email, onValueChange = { email = it }) + PassWdTextFieldSign(R.string.PasswdLogin,password, onValueChange = { password = it },passwordVisible,onPasswordVisibilityChange = { passwordVisible = !passwordVisible }) + PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp,confirmPassword,onValueChange = { confirmPassword = it },passwordVisible,onPasswordVisibilityChange = { passwordVisible = !passwordVisible }) 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) - 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 -fun IdentifiantTextFieldSign(textIdentifiantResId : Int){ +fun IdentifiantTextFieldSign(textIdentifiantResId : Int, identifiant: String, onValueChange: (String) -> Unit){ val textIdentifiant = stringResource(id = textIdentifiantResId) - var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ Column(modifier = Modifier.padding(top = 16.dp)) { OutlinedTextField( value = identifiant, - onValueChange = { identifiant = it }, + onValueChange = onValueChange, label = { Text(textIdentifiant) }, modifier = Modifier .fillMaxWidth() .padding(top = 8.dp), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), - shape = RoundedCornerShape(16.dp) // 🔹 Bords arrondis + shape = RoundedCornerShape(16.dp) ) } } @Composable -fun EmailTextFieldSign(textIdentifiant : String){ - var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ +fun EmailTextFieldSign(textIdentifiantResId: Int, email: String, onValueChange: (String) -> Unit){ + val textIdentifiant = stringResource(id = textIdentifiantResId) Column(modifier = Modifier.padding(top = 16.dp)) { OutlinedTextField( - value = identifiant, - onValueChange = { identifiant = it }, + value = email, + onValueChange = onValueChange, label = { Text(textIdentifiant) }, modifier = Modifier .fillMaxWidth() .padding(top = 8.dp), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email), - shape = RoundedCornerShape(16.dp) // Bords arrondis + shape = RoundedCornerShape(16.dp) ) } } @Composable -fun PassWdTextFieldSign(textpasswdResId : Int){ +fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){ val textpasswd = stringResource(id = textpasswdResId) - var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ - var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer Column(modifier = Modifier.padding(top = 10.dp)) { OutlinedTextField( value = passwd, - onValueChange = { passwd = it }, + onValueChange = onValueChange, label = { Text(textpasswd) }, modifier = Modifier .fillMaxWidth() @@ -135,23 +143,22 @@ fun PassWdTextFieldSign(textpasswdResId : Int){ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), 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 -fun PassWdConfirmTextFieldSign(textpasswdResId : Int){ +fun PassWdConfirmTextFieldSign(textpasswdResId : Int,confirmPassword: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){ val textpasswd = stringResource(id = textpasswdResId) - var passwd by remember { mutableStateOf("") } // Stocke la valeur du champ - var passwordVisible by remember { mutableStateOf(false) } // État pour afficher/masquer Column(modifier = Modifier.padding(top = 10.dp)) { OutlinedTextField( - value = passwd, - onValueChange = { passwd = it }, + value = confirmPassword, + onValueChange = onValueChange, label = { Text(textpasswd) }, modifier = Modifier .fillMaxWidth() @@ -159,38 +166,101 @@ fun PassWdConfirmTextFieldSign(textpasswdResId : Int){ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(), 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 -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) + 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( - 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), - modifier = Modifier - .fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), ) { 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 -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) Text( text = title, fontSize = size.sp, color = color, modifier = Modifier.clickable { - navController.popBackStack() // Revenir à la page précédente + navController() // Revenir à la page login } ) } diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SubmitQuotePage.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SubmitQuotePage.kt index 0b88b35..dd6dce6 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SubmitQuotePage.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/screens/SubmitQuotePage.kt @@ -1,6 +1,8 @@ package com.example.what_the_fantasy.ui.screens import androidx.compose.runtime.Composable +import com.example.what_the_fantasy.ui.components.NavBar @Composable -fun SubmitQuotePage() {} \ No newline at end of file +fun SubmitQuotePage() { +} \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt index 41c8deb..d8343f5 100644 --- a/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt +++ b/What_The_Fantasy/app/src/main/java/com/example/what_the_fantasy/ui/theme/Color.kt @@ -3,6 +3,7 @@ package com.example.what_the_fantasy.ui.theme import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import com.example.what_the_fantasy.R val Purple80 = Color(0xFFD0BCFF) val PurpleGrey80 = Color(0xFFCCC2DC) @@ -11,9 +12,15 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) val Pink40 = Color(0xFF7D5260) + val gradienBox = Brush.linearGradient( colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé start = Offset(0f, 1000f), // Départ en bas à gauche end = Offset(1000f, 0f) // Fin en haut à droite ) -val colorBackground = Color(0xFF100C1B) \ No newline at end of file +val colorBackground = Color(0xFF100C1B) + +val colorNavBar = Color.Black + +val colorButtonNavSelected= Color(0xFFC8C8C8) +val colorButtonNav = Color.White \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/res/drawable/dark_mode_toggle_icon.xml b/What_The_Fantasy/app/src/main/res/drawable/dark_mode_toggle_icon.xml new file mode 100644 index 0000000..752f388 --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/dark_mode_toggle_icon.xml @@ -0,0 +1,9 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/favorite_button_empty.xml b/What_The_Fantasy/app/src/main/res/drawable/favorite_button_empty.xml new file mode 100644 index 0000000..33a5dda --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/favorite_button_empty.xml @@ -0,0 +1,12 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/favorite_button_full.xml b/What_The_Fantasy/app/src/main/res/drawable/favorite_button_full.xml new file mode 100644 index 0000000..3443b39 --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/favorite_button_full.xml @@ -0,0 +1,10 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/home_button_empty.xml b/What_The_Fantasy/app/src/main/res/drawable/home_button_empty.xml new file mode 100644 index 0000000..1eba6f8 --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/home_button_empty.xml @@ -0,0 +1,23 @@ + + + + + + + + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/home_button_full.xml b/What_The_Fantasy/app/src/main/res/drawable/home_button_full.xml new file mode 100644 index 0000000..c2959b3 --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/home_button_full.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/hp.jpg b/What_The_Fantasy/app/src/main/res/drawable/hp.jpg new file mode 100644 index 0000000..38165f4 Binary files /dev/null and b/What_The_Fantasy/app/src/main/res/drawable/hp.jpg differ diff --git a/What_The_Fantasy/app/src/main/res/drawable/light_mode_toggle_icon.xml b/What_The_Fantasy/app/src/main/res/drawable/light_mode_toggle_icon.xml new file mode 100644 index 0000000..8e171be --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/light_mode_toggle_icon.xml @@ -0,0 +1,10 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/lotr.jpg b/What_The_Fantasy/app/src/main/res/drawable/lotr.jpg new file mode 100644 index 0000000..642d326 Binary files /dev/null and b/What_The_Fantasy/app/src/main/res/drawable/lotr.jpg differ diff --git a/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg b/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg index d0bcef9..3c41482 100644 Binary files a/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg and b/What_The_Fantasy/app/src/main/res/drawable/quiz.jpg differ diff --git a/What_The_Fantasy/app/src/main/res/drawable/quiz_button_empty.xml b/What_The_Fantasy/app/src/main/res/drawable/quiz_button_empty.xml new file mode 100644 index 0000000..a1e039a --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/quiz_button_empty.xml @@ -0,0 +1,11 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/drawable/quiz_button_full.xml b/What_The_Fantasy/app/src/main/res/drawable/quiz_button_full.xml new file mode 100644 index 0000000..dd8a0a4 --- /dev/null +++ b/What_The_Fantasy/app/src/main/res/drawable/quiz_button_full.xml @@ -0,0 +1,9 @@ + + + diff --git a/What_The_Fantasy/app/src/main/res/values-fr/strings.xml b/What_The_Fantasy/app/src/main/res/values-fr/strings.xml index 9d55b61..84332fa 100644 --- a/What_The_Fantasy/app/src/main/res/values-fr/strings.xml +++ b/What_The_Fantasy/app/src/main/res/values-fr/strings.xml @@ -11,11 +11,18 @@ Votre mot de passe* Se connecter Créer son compte + Identifiant ou mot de passe incorrect //Page Sign Up Inscription Confirmer mot de passe* S\'inscrire + Email* + Email invalide + Les mots de passe ne correspondent pas + Le nom d\'utilisateur ne peut pas être vide + Le nom d\'utilisateur n\'est pas disponible + Vous devez mettre un mot de passe //Page Profil Profil @@ -27,4 +34,13 @@ Sauvegarder L\'adress email est invalide Les mots de passe ne correspondent pas + + + //Component quote + Date + Personnage + + + //Page Favori + Favoris \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/res/values/colors.xml b/What_The_Fantasy/app/src/main/res/values/colors.xml index f8c6127..86395c4 100644 --- a/What_The_Fantasy/app/src/main/res/values/colors.xml +++ b/What_The_Fantasy/app/src/main/res/values/colors.xml @@ -5,6 +5,10 @@ #FF3700B3 #FF03DAC5 #FF018786 - #FF000000 #FFFFFFFF + + + #FF100C1B + #FF7B1FA2 + #FF311B92 \ No newline at end of file diff --git a/What_The_Fantasy/app/src/main/res/values/strings.xml b/What_The_Fantasy/app/src/main/res/values/strings.xml index c9ab3e1..2fcce63 100644 --- a/What_The_Fantasy/app/src/main/res/values/strings.xml +++ b/What_The_Fantasy/app/src/main/res/values/strings.xml @@ -10,11 +10,18 @@ Your password* Login Create your account + Incorrect username or password //Page Sign Up Account creation Confirm your password* Create + Your email* + Invalid email + Passwords do not match + Username cannot be empty + Username is not available + You must put a password //Page Profil Profile @@ -27,4 +34,11 @@ Invalid email address Passwords do not match + //Component quote + Date + Character + + //Page Favori + Favorites + \ No newline at end of file diff --git a/What_The_Fantasy/gradle/libs.versions.toml b/What_The_Fantasy/gradle/libs.versions.toml index 258393f..2c630fb 100644 --- a/What_The_Fantasy/gradle/libs.versions.toml +++ b/What_The_Fantasy/gradle/libs.versions.toml @@ -38,4 +38,4 @@ androidx-navigation-common-android = { group = "androidx.navigation", name = "na [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } - +kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}