Compare commits

..

No commits in common. 'master' and 'NavBar' have entirely different histories.

@ -51,7 +51,6 @@ android {
}
dependencies {
implementation("io.coil-kt:coil-compose:1.4.0")
implementation(libs.bcrypt) // pour hacher les mdp
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
@ -63,7 +62,6 @@ dependencies {
implementation(libs.androidx.material3)
implementation(libs.androidx.navigation.compose)
implementation(libs.androidx.navigation.common.android)
implementation(libs.engage.core)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
@ -71,10 +69,7 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.coil.compose) //gére les url des images
implementation(libs.coil.compose) //gére les url des image
implementation(kotlin("script-runtime"))
//ViewModel
implementation(libs.android.lifecycle.viewmodel)
implementation(libs.android.lifecycle.viewmodel.runtime.ktx)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

@ -1,26 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="202"
android:viewportHeight="202">
<group android:scaleX="1.2"
android:scaleY="1.2"
android:translateX="-20.2"
android:translateY="-20.2">
<path
android:pathData="M30,0L172,0A26,26 0,0 1,198 26L198,168A26,26 0,0 1,172 194L30,194A26,26 0,0 1,4 168L4,26A26,26 0,0 1,30 0z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="198"
android:startY="194"
android:endX="-6.98"
android:endY="181.61"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>

File diff suppressed because one or more lines are too long

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 66 KiB

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

@ -5,7 +5,6 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import com.example.what_the_fantasy.ui.navigations.AppNavigator
import com.example.what_the_fantasy.ui.screens.QuotePage
import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme
class MainActivity : ComponentActivity() {

@ -1,34 +0,0 @@
package com.example.what_the_fantasy.data.local
import com.example.what_the_fantasy.data.local.UserStub.users
import com.example.what_the_fantasy.data.model.Comment
import com.example.what_the_fantasy.data.model.User
object CommentStub {
val comments: MutableList<Comment> = mutableListOf(
Comment("Franchement, si la Force était avec moi, je n'aurais jamais perdu mes clés ce matin !", users[0].username, "21-12-2005", users[0].imgUrl),
Comment("Je pourrais vraiment utiliser un peu de Force pour mes révisions !", users[10].username, "22-12-2005", users[10].imgUrl),
Comment("Si la Force était vraiment avec moi, je serais déjà en vacances !", users[2].username, "23-12-2005", users[2].imgUrl),
Comment("Avec toute cette Force, je devrais pouvoir arrêter de procrastiner !", users[3].username, "24-12-2005", users[3].imgUrl),
Comment("La vie, c'est comme une boîte de chocolats… mais parfois tu tombes sur le chocolat que tu détestes.", users[4].username, "25-12-2005", users[4].imgUrl),
Comment("Ce qui est drôle, c'est que moi, je choisis toujours les chocolats que je veux. Pas de surprise !", users[5].username, "26-12-2005", users[5].imgUrl),
Comment("La vie, c'est comme une boîte de chocolats… mais parfois les petits chocolats ont un goût étrange.", users[6].username, "27-12-2005", users[6].imgUrl),
Comment("J'aimerais juste éviter la noix au fond de la boîte, c'est toujours le pire chocolat.", users[7].username, "28-12-2005", users[7].imgUrl),
Comment("Est-ce que ça veut dire que je suis en train d'exister juste parce que je suis en train de lire ça ? 🤔", users[8].username, "29-12-2005", users[8].imgUrl),
Comment("Ah, Descartes… c'est fou, mais à chaque fois que je pense trop, je me sens plus perdu !", users[9].username, "30-12-2005", users[9].imgUrl),
Comment("Ouais, mais parfois j'aimerais bien être juste un peu plus je suis et un peu moins je pense", users[0].username, "31-12-2005", users[0].imgUrl),
Comment("Je pense donc je suis… Mais je me demande parfois si je suis vraiment ce que je pense !", users[1].username, "01-01-2006", users[1].imgUrl),
Comment("La montagne, c'est mon tas de linge à laver… et les petites pierres, ce sont mes excuses pour ne pas m'en occuper.", users[2].username, "02-01-2006", users[2].imgUrl),
Comment("La montagne, c'est mon carnet de tâches… et j'ai perdu ma motivation pour enlever les petites pierres.", users[3].username, "03-01-2006", users[3].imgUrl),
Comment("Ok, mais parfois, les petites pierres deviennent des montagnes en elles-mêmes...", users[4].username, "04-01-2006", users[4].imgUrl),
Comment("C'est facile à dire, mais je suis toujours coincé à déplacer la première petite pierre.", users[5].username, "05-01-2006", users[5].imgUrl),
Comment("Et c'est aussi là qu'on reconnaît ceux qui ne répondent pas aux messages.", users[6].username, "06-01-2006", users[6].imgUrl),
Comment("C'est vrai… mais parfois, même les vrais amis se cachent sous un coussin pendant les moments difficiles.", users[7].username, "07-01-2006", users[7].imgUrl),
Comment("Les vrais amis, c'est ceux qui viennent t'aider à déplacer des meubles quand tu déménages. 😉", users[8].username, "08-01-2006", users[8].imgUrl),
Comment("Je préfère qu'un ami vienne avec des pizzas pendant l'adversité. C'est plus mon genre.", users[9].username, "09-01-2006", users[9].imgUrl)
)
}

@ -1,19 +0,0 @@
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 DailyQuoteStub {
val dailyQuote = Quote(
id = 1,
content = "All we have to decide is what to do with the time that is given us.",
likes = 466,
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
)
}

@ -1,21 +0,0 @@
package com.example.what_the_fantasy.data.local
import com.example.what_the_fantasy.data.local.QuoteStub.quotes
import com.example.what_the_fantasy.data.local.UserStub.users
import com.example.what_the_fantasy.data.model.Favorite
object FavoriteStub {
val favorites: MutableList<Favorite> = mutableListOf(
Favorite(users[0], mutableListOf(quotes[0], quotes[1], quotes[12])), // Aragorn123 aime ces citations
Favorite(users[1], mutableListOf(quotes[5], quotes[6], quotes[7])), // Legolas456 aime ces citations
Favorite(users[2], mutableListOf(quotes[8], quotes[9], quotes[10])), // Gandalf789 aime ces citations
Favorite(users[3], mutableListOf(quotes[11], quotes[12], quotes[13])), // FrodoBaggins aime ces citations
Favorite(users[4], mutableListOf(quotes[14], quotes[15], quotes[16])), // Gimli999 aime ces citations
Favorite(users[5], mutableListOf(quotes[17], quotes[18], quotes[19])), // Galadriel321 aime ces citations
Favorite(users[6], mutableListOf(quotes[17], quotes[2], quotes[7])), // Boromir654 aime ces citations
Favorite(users[7], mutableListOf(quotes[3], quotes[4], quotes[10])), // Eowyn777 aime ces citations
Favorite(users[8], mutableListOf(quotes[6], quotes[8], quotes[9])), // Saruman888 aime ces citations
Favorite(users[9], mutableListOf(quotes[5], quotes[13], quotes[15])), // Faramir222 aime ces citations
Favorite(users[10], mutableListOf(quotes[12], quotes[17], quotes[16])) // dev aime ces citations
)
}

@ -97,6 +97,4 @@ object QuestionStub {
val allQuestions: List<Question> = listOf(
question1, question2, question3, question4, question5, question6, question7, question8, question9, question10
)
val shuffleRandomQuestions: List<Question> = allQuestions.shuffled().take(10)
}

@ -1,72 +1,192 @@
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 {
val quotes: MutableList<Quote> = mutableListOf(
Quote(1, "All we have to decide is what to do with the time that is given us.", 466, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(2, "A wizard is never late, nor is he early, he arrives precisely when he means to.", 467, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(3, "Even the smallest person can change the course of the future.", 466, SrcLanguage.vo, CharacterStub.galadriel.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(4, "I would rather share one lifetime with you than face all the ages of this world alone.", 120, SrcLanguage.vo, CharacterStub.arwen.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.arwen.imgUrl, SrcType.Movie, 2000),
Quote(5, "Faithless is he that says farewell when the road darkens.", 150, SrcLanguage.vo, CharacterStub.gimli.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(6, "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.", 200, SrcLanguage.vo, CharacterStub.frodoBaggins.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(7, "I am no man.", 300, SrcLanguage.vo, CharacterStub.eowyn.name, "The Lord of the Rings: The Return of the King", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(8, "The world is changed. I feel it in the water. I feel it in the earth. I smell it in the air.", 400, SrcLanguage.vo, CharacterStub.treebeard.name, "The Lord of the Rings: The Two Towers", CharacterStub.treebeard.imgUrl, SrcType.Movie, 2000),
Quote(9, "We wants it, we needs it. Must have the precious.", 500, SrcLanguage.vo, CharacterStub.gollum.name, "The Lord of the Rings: The Two Towers", CharacterStub.gollum.imgUrl, SrcType.Movie, 2000),
Quote(10, "The board is set, the pieces are moving. We come to it at last, the great battle of our time.", 600, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Return of the King", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(11, "Un grand pouvoir implique de grandes responsabilités.", 466, SrcLanguage.vf, CharacterStub.aragorn.name, "Spider-Man", CharacterStub.aragorn.imgUrl, SrcType.Series, 2000),
Quote(12, "Que la Force soit avec toi.", 467, SrcLanguage.vf, CharacterStub.legolas.name, "Star Wars", CharacterStub.legolas.imgUrl, SrcType.Movie, 2000),
Quote(13, "La magie est partout. Il suffit de savoir où la trouver.", 466, SrcLanguage.vf, CharacterStub.gandalf.name, "Harry Potter", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(14, "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.", 120, SrcLanguage.vf, CharacterStub.frodoBaggins.name, "Le Seigneur des Anneaux", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(15, "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.", 150, SrcLanguage.vf, CharacterStub.gimli.name, "Star Wars", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(16, "La vie est une aventure audacieuse ou rien du tout.", 200, SrcLanguage.vf, CharacterStub.galadriel.name, "Helen Keller", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(17, "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.", 300, SrcLanguage.vf, CharacterStub.boromir.name, "Nelson Mandela", CharacterStub.boromir.imgUrl, SrcType.Movie, 2000),
Quote(18, "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.", 400, SrcLanguage.vf, CharacterStub.eowyn.name, "Albert Einstein", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(19, "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.", 500, SrcLanguage.vo, CharacterStub.saruman.name, "Dalaï Lama", CharacterStub.saruman.imgUrl, SrcType.Movie, 2000),
Quote(20, "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.", 600, SrcLanguage.vo, CharacterStub.samwiseGamgee.name, "Gandhi", CharacterStub.samwiseGamgee.imgUrl, SrcType.Movie, 2000),
Quote(21, "All we have to decide is what to do with the time that is given us.", 466, SrcLanguage.vf, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(22, "A wizard is never late, nor is he early, he arrives precisely when he means to.", 467, SrcLanguage.vf, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(23, "Even the smallest person can change the course of the future.", 466, SrcLanguage.vf, CharacterStub.galadriel.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(24, "I would rather share one lifetime with you than face all the ages of this world alone.", 120, SrcLanguage.vf, CharacterStub.arwen.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.arwen.imgUrl, SrcType.Movie, 2000),
Quote(25, "Faithless is he that says farewell when the road darkens.", 150, SrcLanguage.vf, CharacterStub.gimli.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(26, "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.", 200, SrcLanguage.vf, CharacterStub.frodoBaggins.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(27, "I am no man.", 300, SrcLanguage.vf, CharacterStub.eowyn.name, "The Lord of the Rings: The Return of the King", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(28, "The world is changed. I feel it in the water. I feel it in the earth. I smell it in the air.", 400, SrcLanguage.vf, CharacterStub.treebeard.name, "The Lord of the Rings: The Two Towers", CharacterStub.treebeard.imgUrl, SrcType.Movie, 2000),
Quote(29, "We wants it, we needs it. Must have the precious.", 500, SrcLanguage.vf, CharacterStub.gollum.name, "The Lord of the Rings: The Two Towers", CharacterStub.gollum.imgUrl, SrcType.Movie, 2000),
Quote(30, "The board is set, the pieces are moving. We come to it at last, the great battle of our time.", 600, SrcLanguage.vf, CharacterStub.gandalf.name, "The Lord of the Rings: The Return of the King", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(31, "Un grand pouvoir implique de grandes responsabilités.", 466, SrcLanguage.vo, CharacterStub.aragorn.name, "Spider-Man", CharacterStub.aragorn.imgUrl, SrcType.Series, 2000),
Quote(32, "Que la Force soit avec toi.", 467, SrcLanguage.vo, CharacterStub.legolas.name, "Star Wars", CharacterStub.legolas.imgUrl, SrcType.Movie, 2000),
Quote(33, "La magie est partout. Il suffit de savoir où la trouver.", 466, SrcLanguage.vo, CharacterStub.gandalf.name, "Harry Potter", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(34, "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.", 120, SrcLanguage.vo, CharacterStub.frodoBaggins.name, "Le Seigneur des Anneaux", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(35, "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.", 150, SrcLanguage.vo, CharacterStub.gimli.name, "Star Wars", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(36, "La vie est une aventure audacieuse ou rien du tout.", 200, SrcLanguage.vo, CharacterStub.galadriel.name, "Helen Keller", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(37, "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.", 300, SrcLanguage.vo, CharacterStub.boromir.name, "Nelson Mandela", CharacterStub.boromir.imgUrl, SrcType.Movie, 2000),
Quote(38, "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.", 400, SrcLanguage.vo, CharacterStub.eowyn.name, "Albert Einstein", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(39, "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.", 500, SrcLanguage.vf, CharacterStub.saruman.name, "Dalaï Lama", CharacterStub.saruman.imgUrl, SrcType.Movie, 2000),
Quote(40, "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.", 600, SrcLanguage.vf, CharacterStub.samwiseGamgee.name, "Gandhi", CharacterStub.samwiseGamgee.imgUrl, SrcType.Movie, 2000),
Quote(41, "All we have to decide is what to do with the time that is given us.", 466, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(42, "A wizard is never late, nor is he early, he arrives precisely when he means to.", 467, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(43, "Even the smallest person can change the course of the future.", 466, SrcLanguage.vo, CharacterStub.galadriel.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(44, "I would rather share one lifetime with you than face all the ages of this world alone.", 120, SrcLanguage.vo, CharacterStub.arwen.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.arwen.imgUrl, SrcType.Movie, 2000),
Quote(45, "Faithless is he that says farewell when the road darkens.", 150, SrcLanguage.vo, CharacterStub.gimli.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(46, "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.", 200, SrcLanguage.vo, CharacterStub.frodoBaggins.name, "The Lord of the Rings: The Fellowship of the Ring", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(47, "I am no man.", 300, SrcLanguage.vo, CharacterStub.eowyn.name, "The Lord of the Rings: The Return of the King", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(48, "The world is changed. I feel it in the water. I feel it in the earth. I smell it in the air.", 400, SrcLanguage.vo, CharacterStub.treebeard.name, "The Lord of the Rings: The Two Towers", CharacterStub.treebeard.imgUrl, SrcType.Movie, 2000),
Quote(49, "We wants it, we needs it. Must have the precious.", 500, SrcLanguage.vo, CharacterStub.gollum.name, "The Lord of the Rings: The Two Towers", CharacterStub.gollum.imgUrl, SrcType.Movie, 2000),
Quote(50, "The board is set, the pieces are moving. We come to it at last, the great battle of our time.", 600, SrcLanguage.vo, CharacterStub.gandalf.name, "The Lord of the Rings: The Return of the King", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(51, "Un grand pouvoir implique de grandes responsabilités.", 466, SrcLanguage.vf, CharacterStub.aragorn.name, "Spider-Man", CharacterStub.aragorn.imgUrl, SrcType.Series, 2000),
Quote(52, "Que la Force soit avec toi.", 467, SrcLanguage.vf, CharacterStub.legolas.name, "Star Wars", CharacterStub.legolas.imgUrl, SrcType.Movie, 2000),
Quote(53, "La magie est partout. Il suffit de savoir où la trouver.", 466, SrcLanguage.vf, CharacterStub.gandalf.name, "Harry Potter", CharacterStub.gandalf.imgUrl, SrcType.Movie, 2000),
Quote(54, "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.", 120, SrcLanguage.vf, CharacterStub.frodoBaggins.name, "Le Seigneur des Anneaux", CharacterStub.frodoBaggins.imgUrl, SrcType.Movie, 2000),
Quote(55, "La peur mène à la colère, la colère mène à la haine, la haine mène à la souffrance.", 150, SrcLanguage.vf, CharacterStub.gimli.name, "Star Wars", CharacterStub.gimli.imgUrl, SrcType.Movie, 2000),
Quote(56, "La vie est une aventure audacieuse ou rien du tout.", 200, SrcLanguage.vf, CharacterStub.galadriel.name, "Helen Keller", CharacterStub.galadriel.imgUrl, SrcType.Movie, 2000),
Quote(57, "Le courage n'est pas l'absence de peur, mais la capacité de vaincre ce qui fait peur.", 300, SrcLanguage.vf, CharacterStub.boromir.name, "Nelson Mandela", CharacterStub.boromir.imgUrl, SrcType.Movie, 2000),
Quote(58, "La folie, c'est de faire toujours la même chose et de s'attendre à un résultat différent.", 400, SrcLanguage.vf, CharacterStub.eowyn.name, "Albert Einstein", CharacterStub.eowyn.imgUrl, SrcType.Movie, 2000),
Quote(59, "Le bonheur n'est pas quelque chose de tout fait. Il vient de vos propres actions.", 500, SrcLanguage.vo, CharacterStub.saruman.name, "Dalaï Lama", CharacterStub.saruman.imgUrl, SrcType.Movie, 2000),
Quote(60, "La vie est un mystère qu'il faut vivre, et non un problème à résoudre.", 600, SrcLanguage.vo, CharacterStub.samwiseGamgee.name, "Gandhi", CharacterStub.samwiseGamgee.imgUrl, SrcType.Movie, 2000)
)
}
val quote1 = Quote(
id = 1,
content = "All we have to decide is what to do with the time that is given us.",
likes = 466,
language = "en",
character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
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",
character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.gandalf.imgUrl
)
val quote3 = Quote(
id = 3,
content = "Even the smallest person can change the course of the future.",
likes = 466,
language = "en",
character = CharacterStub.galadriel.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.galadriel.imgUrl
)
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",
character = CharacterStub.arwen.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.arwen.imgUrl
)
val quote5 = Quote(
id = 5,
content = "Faithless is he that says farewell when the road darkens.",
likes = 150,
language = "en",
character = CharacterStub.gimli.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.gimli.imgUrl
)
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",
character = CharacterStub.frodoBaggins.name,
source = "The Lord of the Rings: The Fellowship of the Ring",
imgUrl = CharacterStub.frodoBaggins.imgUrl
)
val quote7 = Quote(
id = 7,
content = "I am no man.",
likes = 300,
language = "en",
character = CharacterStub.eowyn.name,
source = "The Lord of the Rings: The Return of the King",
imgUrl = CharacterStub.eowyn.imgUrl
)
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",
character = CharacterStub.treebeard.name,
source = "The Lord of the Rings: The Two Towers",
imgUrl = CharacterStub.treebeard.imgUrl
)
val quote9 = Quote(
id = 9,
content = "We wants it, we needs it. Must have the precious.",
likes = 500,
language = "en",
character = CharacterStub.gollum.name,
source = "The Lord of the Rings: The Two Towers",
imgUrl = CharacterStub.gollum.imgUrl
)
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",
character = CharacterStub.gandalf.name,
source = "The Lord of the Rings: The Return of the King",
imgUrl = CharacterStub.gandalf.imgUrl
)
val quote11 = Quote(
id = 11,
content = "Un grand pouvoir implique de grandes responsabilités.",
likes = 466,
language = "fr",
character = CharacterStub.aragorn.name,
source = "Spider-Man",
imgUrl = CharacterStub.aragorn.imgUrl
)
val quote12 = Quote(
id = 12,
content = "Que la Force soit avec toi.",
likes = 467,
language = "fr",
character = CharacterStub.legolas.name,
source = "Star Wars",
imgUrl = CharacterStub.legolas.imgUrl
)
val quote13 = Quote(
id = 13,
content = "La magie est partout. Il suffit de savoir où la trouver.",
likes = 466,
language = "fr",
character = CharacterStub.gandalf.name,
source = "Harry Potter",
imgUrl = CharacterStub.gandalf.imgUrl
)
val quote14 = Quote(
id = 14,
content = "Le monde est plein de choses magiques, patientant que nos sens s'aiguisent.",
likes = 120,
language = "fr",
character = CharacterStub.frodoBaggins.name,
source = "Le Seigneur des Anneaux",
imgUrl = CharacterStub.frodoBaggins.imgUrl
)
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",
character = CharacterStub.gimli.name,
source = "Star Wars",
imgUrl = CharacterStub.gimli.imgUrl
)
val quote16 = Quote(
id = 16,
content = "La vie est une aventure audacieuse ou rien du tout.",
likes = 200,
language = "fr",
character = CharacterStub.galadriel.name,
source = "Helen Keller",
imgUrl = CharacterStub.galadriel.imgUrl
)
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",
character = CharacterStub.boromir.name,
source = "Nelson Mandela",
imgUrl = CharacterStub.boromir.imgUrl
)
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",
character = CharacterStub.eowyn.name,
source = "Albert Einstein",
imgUrl = CharacterStub.eowyn.imgUrl
)
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",
character = CharacterStub.saruman.name,
source = "Dalaï Lama",
imgUrl = CharacterStub.saruman.imgUrl
)
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",
character = CharacterStub.samwiseGamgee.name,
source = "Gandhi",
imgUrl = CharacterStub.samwiseGamgee.imgUrl
)
val allQuotes: List<Quote> = listOf(
quote1, quote2, quote3, quote4, quote5, quote6, quote7, quote8, quote9, quote10,
quote11, quote12, quote13, quote14, quote15, quote16, quote17, quote18, quote19, quote20
)
}

@ -1,21 +1,40 @@
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 {
//LE MOT DE PASSE POUR TOUS LES UTILISATEURS EST : 1234
val users: MutableList<User> = mutableListOf(
User(0, "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.vf), //1234
User(1, "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.vf),//1234
User(2, "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.vf),//1234
User(3, "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.vf),//1234
User(4, "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(5, "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(6, "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(7, "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(8, "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(9, "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(10, "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.vo)//1234
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"), //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"),//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"),//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"),//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"),//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"),//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"),//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"),//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"),//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"),//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")//1234
)
fun addUser(user: User) {
users.add(user)
}
//
// // Modifier un utilisateur
// fun updateUser(id: Int, updatedUser: User) {
// val index = users.indexOfFirst { it.id == id }
// if (index != -1) {
// users[index] = updatedUser
// }
// }
//
// // Supprimer un utilisateur
// fun removeUser(id: Int) {
// users.removeAll { it.id == id }
// }
//
}

@ -1,8 +0,0 @@
package com.example.what_the_fantasy.data.model
data class Comment(
val content : String,
val user : String,
val date : String,
val img : String
)

@ -1,6 +0,0 @@
package com.example.what_the_fantasy.data.model
class Favorite (
val user: User,
val quote: List<Quote>
)

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

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

@ -1,10 +1,7 @@
package com.example.what_the_fantasy.data.model
import androidx.compose.ui.res.stringResource
import com.example.what_the_fantasy.R
enum class SrcType (val value: String) {
Movie("movie" ),
VideoGame("videoGame"),
Series("series"),
Movie("@string/movie"),
VideoGame("@string/videoGame"),
Series("@string/series"),
}

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

@ -1,43 +1,22 @@
package com.example.what_the_fantasy.data.services
import com.example.what_the_fantasy.data.model.Favorite
import com.example.what_the_fantasy.data.model.Comment
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.local.UserStub.users
import com.example.what_the_fantasy.data.model.User
import com.example.what_the_fantasy.ui.states.AuthUserState
import kotlinx.coroutines.flow.StateFlow
interface IServices {
fun validLogin(username : String,
passwd : String,
navController: (Int) -> Unit,
initialierCurrentUser : (Int) ->Unit): Boolean
fun EditUsername(username : String, index : Int) : Boolean
fun EditEmail(email : String, index : Int) : Boolean
fun EditUsername(username : String, index : Int)
fun EditEmail(email : String, index : Int)
fun EditPasswd(passwd : String, index : Int)
fun EditImage(index : Int) : String
fun ChangeLangage(index : Int): SrcLanguage
fun isUsernameExist(username : String) : Boolean
fun isEmailExist(email : String) : Boolean
fun AddFav(userId: Int, QuoteId : Int)
fun SupFav(userId: Int, QuoteId : Int)
fun AddComment(content : String)
fun CreateUser(username : String, email : String, passwd : String) : Boolean
fun getFavorite(user: User): List<Quote>
fun EditImage(imageURL : String, index : Int)
fun CreateUser(username : String, email : String, passwd : String, services : IServices) : Boolean
fun getFavorite(username: String)
fun getAllUsers(): List<User>
fun getComment(quoteId : Int) : List<Comment>
fun getUserById(id: Int): User?
fun getQuote( id : Int): Quote?
fun SearchQuote(quote : String)
fun isFavorite(idQuote : Int, iduser: Int): Boolean
fun getAllFavorite(): List<Favorite>
fun getAllQuote(): List<Quote>
fun getSomeQuotes(nb: Int, page: Int) : MutableList<Quote>
fun search(type : String ,search:String ,indexCount: Int): List<Quote>
}

@ -1,89 +1,41 @@
package com.example.what_the_fantasy.data.services
//import com.example.what_the_fantasy.data.model.Comment
//import com.example.what_the_fantasy.data.model.Favorite
//import com.example.what_the_fantasy.data.model.Quote
//import com.example.what_the_fantasy.data.model.User
////import com.example.what_the_fantasy.ui.navigations.Destination
import com.example.what_the_fantasy.data.model.User
//class ServicesAPI : IServices {
// override fun EditUsername(username: String, index : Int): Boolean {
// TODO("Not yet implemented")
// }
//
// override fun EditEmail(email: String, index : Int): Boolean {
// 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 ChangeLangage(user: User) {
// TODO("Not yet implemented")
// }
//
// override fun AddFav(userId: Int, QuoteId: Int) {
// TODO("Not yet implemented")
// }
//
// override fun SupFav(userId: Int, QuoteId: Int) {
// TODO("Not yet implemented")
// }
//
// override fun AddComment(content: String) {
// TODO("Not yet implemented")
// }
//
// override fun CreateUser(username: String, email: String, passwd: String, services: IServices) : Boolean {
// TODO("Not yet implemented")
// }
//
// override fun getFavorite(user: User): List<Quote> {
// TODO("Not yet implemented")
// }
//
// override fun SearchQuote(quote: String) {
// TODO("Not yet implemented")
// }
//
// override fun getQuote(id: Int): Quote? {
// TODO("Not yet implemented")
// }
//
// override fun isFavorite(id: Int, user: User): Boolean {
// TODO("Not yet implemented")
// }
//
// override fun getAllFavorite(): List<Favorite> {
// TODO("Not yet implemented")
// }
//
// override fun getAllQuote(): List<Quote> {
// TODO("Not yet implemented")
// }
//
// override fun getSomeQuotes(nb: Int, page: Int): MutableList<Quote> {
// TODO("Not yet implemented")
// }
//
// override fun getAllUsers(): List<User> {
// TODO("Not yet implemented")
// }
//
// override fun getComment(quoteId: Int): List<Comment> {
// TODO("Not yet implemented")
// }
//
// override fun getUserById(id: Int): User? {
// TODO("Not yet implemented")
// }
//
// override fun search(type : String ,search:String ,indexCount: Int): List<Quote>{
// TODO("Not yet implemented")
// }
//}
class ServicesAPI : IServices {
override fun EditUsername(username: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditEmail(email: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditPasswd(passwd: String, index : Int) {
TODO("Not yet implemented")
}
override fun EditImage(imageURL: String, index : Int) {
TODO("Not yet implemented")
}
override fun CreateUser(username: String, email: String, passwd: String, services: IServices) : Boolean {
TODO("Not yet implemented")
}
override fun SearchQuote(quote: String) {
TODO("Not yet implemented")
}
override fun getFavorite(username: String) {
TODO("Not yet implemented")
}
override fun getAllUsers(): List<User> {
TODO("Not yet implemented")
}
override fun getUserById(id: Int): User? {
TODO("Not yet implemented")
}
}

@ -1,64 +1,31 @@
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.local.FavoriteStub.favorites
import com.example.what_the_fantasy.data.local.ImageStub.allImages
import com.example.what_the_fantasy.data.local.QuoteStub.quotes
import com.example.what_the_fantasy.data.model.Favorite
import com.example.what_the_fantasy.data.local.CommentStub.comments
import com.example.what_the_fantasy.data.model.Comment
import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.Logs.LogsUsers
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 validLogin(username : String,
passwd : String,
navController: (Int) -> Unit,
initialierCurrentUser : (Int) ->Unit): Boolean{
users.forEachIndexed { index, user ->
val hashPassWd = hashPassword(passwd)
if (user.username == username && user.password == hashPassWd) {
initialierCurrentUser(index)
navController(index)
//logsUser.logInformationUserConnect(user, "UserConnect")
return true
}
}
return false
}
override fun EditUsername(username: String, index : Int) : Boolean{
override fun EditUsername(username: String, index : Int) {
val user = getUserById(index)
if(!isUsernameExist(username)){
user?.username = username
return true
}
user?.username = username
//Afficher tous les users
//logsUser.logDebugUserEmail(user, "UsernameUpdate")
return false
logsUser.logDebugDisplayUsers(getAllUsers(), "UsernameUpdate")
}
override fun EditEmail(email: String,index : Int) : Boolean {
override fun EditEmail(email: String,index : Int) {
val user = getUserById(index)
user?.email = email
if(!isEmailExist(email)){
user?.email = email
return true
}
//Afficher tous les users
//logsUser.logDebugAllUsers(getAllUsers(), "EmailUpdate")
return false
logsUser.logDebugDisplayUsers(getAllUsers(), "EmailUpdate")
}
override fun EditPasswd(passwd: String,index : Int) {
@ -67,139 +34,47 @@ class ServicesStub : IServices {
user?.password = passwordhash
//Afficher tous les users en log
//logsUser.logDebugAllUsers(getAllUsers(), "PasswordUpdate")
}
override fun EditImage(index : Int) : String {
return randomImage()
logsUser.logDebugDisplayUsers(getAllUsers(), "PasswordUpdate")
}
override fun ChangeLangage(index : Int) : SrcLanguage{
if(getAllUsers()[index].langage == SrcLanguage.vo){
getAllUsers()[index].langage = SrcLanguage.vf
}
else{
getAllUsers()[index].langage = SrcLanguage.vo
}
//logsUser.logDebugUserLangage(getAllUsers()[index], "ChangeLangue")
return getAllUsers()[index].langage
}
override fun AddFav(userId: Int, QuoteId: Int) {
return
}
override fun SupFav(userId: Int, QuoteId: Int) {
return
}
override fun AddComment(content: String) {
return
override fun EditImage(imageURL: String,index : Int) {
TODO("Not yet implemented")
//comments.add(Comment(content = content,))
}
override fun CreateUser(username: String, email: String, passwd: String) : Boolean {
override fun CreateUser(username: String, email: String, passwd: String, services : IServices) : Boolean {
val date =dateDuJour()
val passwordhash = hashPassword(passwd)
val services = ServicesStub()
val userStub = services.getAllUsers()
val nbUser = userStub.size
if(username == "" || email == "" || passwd == ""){
return false
}
if(!isUsernameExist(username) && !isEmailExist(email)){
val user = User(nbUser,username, email, date,randomImage(), passwordhash, SrcLanguage.vo)
users.add(user)//ajout au stub
//Afficher tous les users
//logsUser.logDebugAllUsers(users, "CreateUser")
return true
for (user in userStub) {
if (user.username == username) {
return false
}
}
return false
}
val user = User(nbUser+1,username, email, date,randomImage(userStub), passwordhash)
users.add(user)//ajout au stub
override fun getFavorite(user: User): List<Quote> {
val favorite = favorites
return favorite[0].quote
//Afficher tous les users
logsUser.logDebugDisplayUsers(users, "CreateUser")
return true
}
override fun getAllFavorite(): List<Favorite> = favorites
override fun getAllQuote(): List<Quote> = quotes
override fun getAllUsers(): List<User> = users
override fun getComment(quoteId: Int): List<Comment> = comments
override fun getUserById(id: Int): User? {
return (users.find { it.id == id })
}
override fun getQuote(id: Int): Quote? {
return (quotes.find { it.id == id })
}
override fun getSomeQuotes(nb: Int, page: Int): MutableList<Quote> {
var nbQuote = nb
var nbPage = page
if(nb < 0) nbQuote = 1
if(nbPage < 0) nbPage = 1
val fromIndex = (nbPage - 1) * nbQuote
val toIndex = minOf(nbPage * nbQuote, quotes.size)
if (fromIndex >= quotes.size) return mutableListOf()
return quotes.subList(fromIndex, toIndex).toMutableList()
return (users.find { it.id == id+1 })
}
override fun isFavorite(idQuote: Int, idUser: Int): Boolean {
val user = getUserById(idUser) ?: return false
val quote = getFavorite(user)
return quote.find{ it.id == idQuote } != null
override fun SearchQuote(quote: String) {
TODO("Not yet implemented")
}
override fun search(type : String ,search:String ,indexCount: Int): List<Quote> {
return (getAllQuote().filter {
when (type) {
"personnage" -> {
it.character.uppercase().contains(search.uppercase())
}
"titre" -> {
it.source.uppercase().contains(search.uppercase())
}
else -> {
it.content.uppercase().contains(search.uppercase())
}
}
}.take(indexCount))
override fun getFavorite(username: String) {
TODO("Not yet implemented")
}
override fun isUsernameExist(username : String) : Boolean{
val userStub = getAllUsers()
for (user in userStub) {
if (user.username == username) {
return true
}
}
return false
}
override fun isEmailExist(email : String) : Boolean{
val userStub = getAllUsers()
for (user in userStub) {
if (user.email == email) {
return true
}
}
return false
}
//------------------------------------------------------
@SuppressLint("NewApi")
fun dateDuJour(): String {
@ -207,16 +82,7 @@ class ServicesStub : IServices {
return date.toString()
}
fun randomImage() : String{
val sizeList = allImages.size
val randomNb = (0..sizeList).random()
allImages.forEach{image ->
if(image.id == randomNb){
return image.url
}
}
return allImages[0].url
fun randomImage(usersImage : List<User>) : String{
return "https://img.freepik.com/vecteurs-libre/personnage-guerrier-homme-fantaisie_1045-194.jpg?size=338&ext=jpg"
}
}

@ -1,39 +0,0 @@
package com.example.what_the_fantasy.logs
import android.util.Log
import com.example.what_the_fantasy.data.model.User
class LogsUsers{
fun logDebugAllUsers(users : List<User>, titleLog : String){
for(user in users){
Log.d(titleLog, "User created: ${user.username} => ${user.email} => ${user.imgUrl} => ${user.langage}")
}
}
fun logDebugUserEmail(user : User?, titleLog : String){
Log.d(titleLog, "User created: ${user?.username} => ${user?.email}")
}
fun logDebugUserLangage(user : User?, titleLog : String){
Log.d(titleLog, "User Change: ${user?.username} => ${user?.langage}")
}
fun logInformationUserConnect(user : User?, titleLog : String){
Log.i(titleLog, "${user?.username} logged in")
}
fun unlogInformationUserConnect(titleLog : String){
Log.i(titleLog, "Logged out")
}
fun favoriteInformationUserTrue(titleLog : String, quoteId : Int, userId : Int){
Log.i(titleLog, "User $userId added quote $quoteId to favorites")
}
fun favoriteInformationUserFalse(titleLog : String, quoteId : Int, userId : Int){
Log.i(titleLog, "User $userId removed quote $quoteId from favorites")
}
fun shareInformationUser(titleLog : String, quoteId : Int, userId : Int){
Log.i(titleLog, "User $userId shared quote $quoteId")
}
}

@ -1,6 +0,0 @@
package com.example.what_the_fantasy.repository
import com.example.what_the_fantasy.data.services.IServices
import okhttp3.Request
class AuthRepository {}

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

@ -19,15 +19,4 @@ fun ErrorMessageProfileComponent(titleResId : Int) {
fontSize = 12.sp,
modifier = Modifier.padding(top = 4.dp)
)
}
@Composable
fun ErrorMessageSubmitQuoteComponent(titleResId: Int) {
val textError = stringResource(id = titleResId)
Text(
text = textError,
color = Color.Red,
fontSize = 12.sp,
modifier = Modifier.padding(top = 4.dp)
)
}

@ -1,17 +1,16 @@
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.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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.*
@ -19,43 +18,36 @@ import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.NavigationBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
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.ColorFilter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.rememberAsyncImagePainter
import coil.compose.rememberImagePainter
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.theme.*
@Composable
fun NavBar(onProfile : Boolean = false,
onFavorite : Boolean = false,
onAccueil : Boolean = false,
onQuiz : Boolean = false,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
navControllerProfil: () -> Unit = {},
navControllerFavorite:() -> Unit= {},
navControllerAccueil: () -> Unit= {},
navControllerQuiz: () -> Unit= {},
navControllerSearch: () -> Unit = {},
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()
@ -63,7 +55,7 @@ fun NavBar(onProfile : Boolean = false,
NavigationBar(
modifier = Modifier
.fillMaxWidth(),
containerColor = MaterialTheme.colorScheme.onPrimary
containerColor = colorNavBar
) {
Row(
modifier = Modifier
@ -71,21 +63,32 @@ fun NavBar(onProfile : Boolean = false,
Arrangement.SpaceBetween,
verticalAlignment = Alignment.Bottom
) {
ButtonIconVectorInt(currentUserState.imagePath,"Profile",navControllerProfil,onProfile)
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
)
}
ButtonIconVector(Icons.Rounded.Search,stringResource(R.string.NavSearch),navControllerSearch,false)
}
}
Box(modifier = Modifier
.background(Color.Black)
.fillMaxHeight(0.90f)){
Box(modifier = Modifier.background(Color.Black).fillMaxHeight(0.90f)){
content()
}
BottomAppBar (modifier = Modifier
.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.onPrimary
containerColor = colorNavBar
) {
Row(modifier = Modifier
.fillMaxSize(),
@ -93,20 +96,20 @@ fun NavBar(onProfile : Boolean = false,
verticalAlignment = Alignment.CenterVertically
) {
ButtonIconPainter(painterResource(
ButtonIconPainterInt(painterResource(
if(onFavorite)R.drawable.favorite_button_full
else R.drawable.favorite_button_empty
), stringResource(R.string.NavFavorite) ,navControllerFavorite,onFavorite)
),"Favorite",navControllerFavorite,index,onFavorite)
ButtonIconPainter(painterResource(
ButtonIconPainterInt(painterResource(
if(onAccueil)R.drawable.home_button_full
else R.drawable.home_button_empty
),stringResource(R.string.NavHome),navControllerAccueil,onAccueil)
),"Accueil",navControllerAccueil,index,onAccueil)
ButtonIconPainter(painterResource(
ButtonIconPainterInt(painterResource(
if(onQuiz)R.drawable.quiz_button_full
else R.drawable.quiz_button_empty
),stringResource(R.string.NavQuiz),navControllerQuiz,onQuiz)
),"Quiz",navControllerQuiz,index,onQuiz)
}
}
@ -114,57 +117,37 @@ fun NavBar(onProfile : Boolean = false,
}
@Composable
fun ButtonIconVectorInt(img : String, name : String, nav : ()->Unit ,onPage : Boolean){
IconButton(onClick = {nav()},
fun ButtonIconVectorInt(img : ImageVector, name : String, nav : (Int)->Unit ,index: Int,onPage : Boolean){
IconButton(onClick = {nav(index)},
enabled = !onPage,
colors = IconButtonColors(Color.Transparent, MaterialTheme.colorScheme.onBackground,//couleur quand il n'est pas selectionné
Color.Transparent, MaterialTheme.colorScheme.primary),//couleur quand il est selectionné
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)
) {
Image(
painter = rememberAsyncImagePainter(img),
Icon(img,
contentDescription = name,
modifier = Modifier
.fillMaxSize()
.clip(CircleShape) // Pour rendre l'image circulaire
)
}
}
@Composable
fun ButtonIconVector(img : ImageVector, name : String, nav : ()->Unit ,onPage : Boolean){
IconButton(onClick = {nav()},
enabled = !onPage,
colors = IconButtonColors(Color.Transparent, MaterialTheme.colorScheme.onBackground,//couleur quand il n'est pas selectionné
Color.Transparent, MaterialTheme.colorScheme.primary),//couleur quand il est selectionné
modifier = Modifier
.size(60.dp)
) {
Image(img,
contentDescription = name,
modifier = Modifier
.fillMaxSize()
.clip(CircleShape), // Pour rendre l'image circulaire
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary)
)
}
}
@Composable
fun ButtonIconPainter(img : Painter, name : String, nav : ()->Unit,onPage : Boolean){
IconButton(onClick = {nav()},
fun ButtonIconPainterInt(img : Painter, name : String, nav : (Int)->Unit,index: Int,onPage : Boolean){
IconButton(onClick = {nav(index)},
enabled = !onPage,
colors = IconButtonColors(Color.Transparent,MaterialTheme.colorScheme.onBackground,//couleur quand il n'est pas selectionné
Color.Transparent, MaterialTheme.colorScheme.primary),//couleur quand il est selectionné
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
.size(50.dp)
.fillMaxSize()
)
}
}
}

@ -1,92 +0,0 @@
package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
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.layout.ContentScale
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.rememberAsyncImagePainter
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.model.Quote
@Composable
fun QuoteLittle(quote: Quote, modifier: Modifier = Modifier) {
val Character = stringResource(R.string.CharacterQuote)
Row(
modifier = modifier
.fillMaxWidth()
.padding(8.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.background)
) {
Image(
painter = rememberAsyncImagePainter(quote.imgUrl),
contentDescription = "Character Image",
contentScale = ContentScale.Crop,
modifier = Modifier
.size(width = 135.dp, height = 135.dp)
.clip(
RoundedCornerShape(
topStart = 12.dp,
bottomStart = 12.dp,
topEnd = 0.dp,
bottomEnd = 0.dp
)
)
)
Column(
modifier = Modifier
.weight(1f)
.height(135.dp)
.clip(
RoundedCornerShape(
topEnd = 12.dp,
bottomEnd = 12.dp
)
)
.background(MaterialTheme.colorScheme.primary)
.padding(12.dp)
) {
Text(
text = quote.content,
color = MaterialTheme.colorScheme.onPrimary,
fontSize = 16.sp,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "${quote.type} : ${quote.source}",
color = MaterialTheme.colorScheme.onPrimary,
fontSize = 12.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = "${Character}: ${quote.character}",
color = MaterialTheme.colorScheme.onPrimary,
fontSize = 12.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
}

@ -2,6 +2,7 @@ package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@ -5,20 +5,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
@Composable
fun TitlePageComponent(titleResId: Int, color: Color) {
fun TitlePageComponent(titleResId : Int, size : Int, color : Color) {
val title = stringResource(id = titleResId)
Text(
text = title,
fontSize = 20.sp,
fontSize = size.sp,
fontWeight = FontWeight.Bold,
color = color,
textAlign = TextAlign.Center,
color = color
)
}

@ -1,28 +0,0 @@
package com.example.what_the_fantasy.ui.components
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.example.what_the_fantasy.R
@Composable
fun VisibleIconPasswordComponent(passwordVisible : Boolean){
Icon(
painterResource(
if(passwordVisible){
R.drawable.password_visible
}
else{
R.drawable.password_no_visible
}
),
contentDescription = "visible",
modifier = Modifier
.size(20.dp),
tint = MaterialTheme.colorScheme.primary
)
}

@ -1,4 +1,4 @@
package com.example.what_the_fantasy.data.services
package com.example.what_the_fantasy.ui.components
import java.security.MessageDigest

@ -1,320 +1,145 @@
package com.example.what_the_fantasy.ui.navigations
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
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.*
import com.example.what_the_fantasy.ui.viewModels.AuthUserViewModel
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.viewModels.QuoteInformationUserViewModel
import com.example.what_the_fantasy.ui.viewModels.SearchViewModel
import com.example.what_the_fantasy.ui.viewModels.SignInUserViewModel
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)
data class QuizMenu(val userIndex: Int)
@Serializable
data class Quiz(val userIndex: Int, val idQuiz: Int)
data class Quiz(val userIndex : Int, val idQuiz : Int)
@Serializable
data class QuizEnd(val userIndex: Int, val idQuiz: Int, val pts: Int)
data class QuizEnd(val userIndex : Int, val idQuiz : Int,val pts : Int)
@Serializable
data class QuizRandom(val userIndex: Int)
data object Quote
@Serializable
data class OneQuote(val quoteId: Int, val userIndex: Int)
@Serializable
data class Search(val userIndex: Int,val type : String = "contenu", val search: String = "")
data object Search
@Serializable
data object SignUp
@Serializable
data class SubmitQuote(val userIndex: Int)
@Serializable
data class RecapSubmit(val userIndex: Int,
val quoteContent : String,
val character : String,
val source : String)
data object SubmitQuote
@Composable
fun AppNavigator() {
val navController = rememberNavController()
val services = ServicesStub()
//ViewModel pour l'authentification
val authUserVM : AuthUserViewModel = viewModel()
val authState by authUserVM.userState.collectAsState()
//ViewModel pour l'inscription
val signInUserVM : SignInUserViewModel = viewModel()
val signInState by signInUserVM.userState.collectAsState()
//ViewModel pour l'utilisateur
val currentUserVM : CurrentUserViewModel = viewModel()
val currentUserState by currentUserVM.currentUserState.collectAsState()
//ViewModel pour la recherche
val searchVM : SearchViewModel = viewModel()
val searchState by searchVM.searchState.collectAsState()
//ViewModel pour les commentaires et likes des citations
val quoteInformationUserVM : QuoteInformationUserViewModel = viewModel()
val quoteInformationUserState by quoteInformationUserVM.quoteState.collectAsState()
Scaffold(
modifier = Modifier.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.onPrimary
) { paddingValues ->
Box(modifier = Modifier.padding(paddingValues)) {
NavHost(navController, startDestination = Login) {
composable<Login> {
LoginPage(
navControllerSignUp = { navController.navigate(SignUp) },
navControllerProfil = { userIndex ->
navController.navigate(Profil(userIndex)) {
popUpTo(Login) { inclusive = true }
}
},
authUserVM = authUserVM,
authState = authState,
initialierCurrentUser ={currentUserVM.initialiseCurrentUser(it)}
)
}
composable<Accueil> {
//val accueil: Accueil = it.toRoute()
AccueilPage(
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuote = { quoteId ->
navController.navigate(
OneQuote(
quoteId,
currentUserState.id
)
)
},
navSearch = { navController.navigate(Search(currentUserState.id))},
services = services,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
}
composable<Favorite> {
//val favorite: Favorite = it.toRoute()
FavoritePage(
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuote = { quoteId ->
navController.navigate(
OneQuote(
quoteId,
currentUserState.id
)
)
},
navSearch = { navController.navigate(Search(currentUserState.id))},
services = services,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
}
composable<Profil> {
val profil: Profil = it.toRoute()
ProfilPage(
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navSubmitQuote = { navController.navigate(SubmitQuote(currentUserState.id)) },
navUnLog = {
navController.navigate(Login) {
popUpTo(profil) { inclusive = true }
}
},
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navSearch = { navController.navigate(Search(profil.userIndex))},
)
}
composable<OneQuote> {
val quote: OneQuote = it.toRoute()
QuotePage(
quoteId = quote.quoteId,
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
service = services,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navSearch = { navController.navigate(Search(currentUserState.id))},
quoteInformationUserVM = quoteInformationUserVM,
quoteInformationUserState = quoteInformationUserState,
)
}
composable<Search> {
val search: Search = it.toRoute()
SearchPage(
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuote = { quoteId -> navController.navigate(OneQuote(quoteId,currentUserState.id)) },
navSearch = {type,newSearch -> navController.navigate(Search(currentUserState.id,type,newSearch))},
type = search.type,
search = search.search,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
searchVM = searchVM,
searchState = searchState
)
}
composable<SignUp> {
SignUpPage(
navControllerLogin = {
navController.navigate(Login) {
popUpTo(Login) { inclusive = true }
}
},
signInUserVM = signInUserVM,
signInState = signInState
)
}
composable<SubmitQuote> {
//val submitQuote: SubmitQuote = it.toRoute()
SubmitQuotePage(
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navRecap = { quoteContent, character, source ->
navController.navigate(
RecapSubmit(
currentUserState.id,
quoteContent,
character,
source
)
)
},
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
}
composable<RecapSubmit> {
val recapSubmit: RecapSubmit = it.toRoute()
RecapSubmitPage(
quoteContent = recapSubmit.quoteContent,
character = recapSubmit.character,
source = recapSubmit.source,
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navSearch = { navController.navigate(Search(currentUserState.id))},
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
}
composable<QuizMenu> {
//val quizMenu: QuizMenu = it.toRoute()
QuizMenu(
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navSearch = { navController.navigate(Search(currentUserState.id))},
navControllerQuiz = { idQuiz ->
navController.navigate(Quiz(currentUserState.id, idQuiz))
},
navControllerRandomQuiz = { navController.navigate(QuizRandom(currentUserState.id)) }
)
}
composable<Quiz> {
val quiz: Quiz = it.toRoute()
QuizPage(
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navControllerQuizEnd = { idQuiz, pts ->
navController.navigate(QuizEnd(currentUserState.id, idQuiz, pts))
},
navSearch = { navController.navigate(Search(currentUserState.id))},
idQuiz = quiz.idQuiz,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
}
composable<QuizEnd> {
val quizEnd: QuizEnd = it.toRoute()
QuizEndPage(
idQuiz = quizEnd.idQuiz,
points = quizEnd.pts,
navAccueil = { navController.navigate(Accueil(currentUserState.id)) },
navFavorite = { navController.navigate(Favorite(currentUserState.id)) },
navProfil = { navController.navigate(Profil(currentUserState.id)) },
navQuiz = { navController.navigate(QuizMenu(currentUserState.id)) },
navSearch = { navController.navigate(Search(currentUserState.id))},
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
NavHost(navController, startDestination = Login) {
composable<Login> {
LoginPage(
navControllerSignUp = { navController.navigate(SignUp) },
navControllerProfil = { userIndex ->
navController.navigate(Profil(userIndex)) {
// Vider pile de navigation pour empêcher le retour à la page Login
popUpTo(Login) { inclusive = true }
}
},
services = services
)
}
composable<Accueil> {
val accueil: Accueil = it.toRoute()
AccueilPage(
index = accueil.userIndex,
navFavorite = { navController.navigate(Favorite(accueil.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(accueil.userIndex)) },
navProfil = { navController.navigate(Profil(accueil.userIndex)) }
) }
composable<Favorite> {
val favorite: Favorite = it.toRoute()
FavoritePage(
index = favorite.userIndex,
navAccueil ={ navController.navigate( Accueil(favorite.userIndex) ) },
navQuiz = { navController.navigate(QuizMenu(favorite.userIndex)) },
navProfil = { navController.navigate(Profil(favorite.userIndex)) }
) }
composable<Profil>{
val profil:Profil = it.toRoute()
ProfilPage(
index = profil.userIndex,
navFavorite = { navController.navigate(Favorite(profil.userIndex)) },
navAccueil ={ navController.navigate( Accueil(profil.userIndex) ) },
navQuiz = { navController.navigate( QuizMenu(profil.userIndex)) },
navUnLog = {
navController.navigate(Login) {
// Vider pile de navigation pour empêcher le retour à la page profil
popUpTo(profil) { inclusive = true }
}
},
services = services
)
}
composable<Quote> { QuotePage() }
composable<Search> { SearchPage() }
composable<SignUp> { SignUpPage(
navControllerLogin = {
navController.navigate(Login){
// Vider pile de navigation pour empêcher le retour à la page Sign up
popUpTo(Login) { inclusive = true }
}
composable<QuizRandom> {
val quizRandom: QuizRandom = it.toRoute()
QuizRandom(
navAccueil = { navController.navigate(Accueil(quizRandom.userIndex)) },
navFavorite = { navController.navigate(Favorite(quizRandom.userIndex)) },
navProfil = { navController.navigate(Profil(quizRandom.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(quizRandom.userIndex)) },
navSearch = { navController.navigate(Search(quizRandom.userIndex)) },
navControllerQuizEnd = { idQuiz, pts ->
navController.navigate(QuizEnd(quizRandom.userIndex, idQuiz, pts))
},
currentUserVM = currentUserVM,
currentUserState = currentUserState,
)
},services) }
composable<SubmitQuote> { SubmitQuotePage() }
composable<QuizMenu> {
val quizMenu:QuizMenu=it.toRoute()
QuizMenu(
index = quizMenu.userIndex,
navAccueil = { navController.navigate( Accueil(quizMenu.userIndex) ) },
navFavorite = { navController.navigate(Favorite(quizMenu.userIndex)) },
navProfil = { navController.navigate(Profil(quizMenu.userIndex)) },
navControllerQuiz = { idQuiz ->
navController.navigate(Quiz(quizMenu.userIndex,idQuiz))
}
}
)
}
composable<Quiz> {
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<QuizEnd> {
val quizEnd: QuizEnd = it.toRoute()
QuizEndPage(
idQuiz = quizEnd.idQuiz,
points = quizEnd.pts,
index = quizEnd.userIndex,
navAccueil = { navController.navigate( Accueil(quizEnd.userIndex) ) },
navFavorite = { navController.navigate(Favorite(quizEnd.userIndex)) },
navProfil = { navController.navigate(Profil(quizEnd.userIndex)) },
navQuiz = { navController.navigate(QuizMenu(quizEnd.userIndex)) }
)
}
}
}

@ -1,148 +1,42 @@
package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
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.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.local.DailyQuoteStub
import com.example.what_the_fantasy.data.model.Quote
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.components.QuoteLittle
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.theme.colorBackground
import kotlinx.coroutines.delay
@Composable
fun AccueilPage(
navFavorite: () -> Unit,
navQuiz: () -> Unit,
navProfil: () -> Unit,
navQuote: (Int) -> Unit,
navSearch: () -> Unit,
services: IServices,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
index: Int,
navFavorite:(Int) -> Unit,
navQuiz: (Int) -> Unit,
navProfil:(Int) -> Unit
) {
val dailyQuote = DailyQuoteStub.dailyQuote
val titleDalyQuote = stringResource(R.string.TitleHomeDailyQuote)
val titleSuggestion = stringResource(R.string.TitleHomeSuggestion)
val page = remember { mutableIntStateOf(1) }
val quotes = remember { mutableStateListOf<Quote>() }
val state = rememberLazyListState()
val layoutInfo = remember { derivedStateOf { state.layoutInfo } }
val isLoading = remember { mutableStateOf(false) }
val visibleItemsInfo = layoutInfo.value.visibleItemsInfo
val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()
val lastItem = if (fullyVisibleItemsInfo.isNotEmpty()) fullyVisibleItemsInfo.last() else null
LaunchedEffect(page.intValue) {
if (!isLoading.value) {
isLoading.value = true
delay(500)
val newQuotes = services.getSomeQuotes(15, page.intValue)
val uniqueQuotes = newQuotes.filterNot { new -> quotes.any { it.id == new.id } }
if (uniqueQuotes.isNotEmpty()) {
quotes.addAll(uniqueQuotes)
} else {
println("Aucune nouvelle quote à la page ${page.intValue}, stop pagination.")
}
isLoading.value = false
}
}
NavBar(
onAccueil = true,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
NavBar(onAccueil = true,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = { },
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
) {
Column(
navControllerQuiz = navQuiz
){
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) {
LazyColumn(modifier = Modifier.weight(1f), state = state) {
item {
Column(Modifier.clickable { navQuote(dailyQuote.id) }) {
Text(
text = titleDalyQuote,
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
QuoteLittle(dailyQuote)
}
Text(
text = titleSuggestion,
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
}
items(quotes) { quote ->
if (quote.language == currentUserState.langage) {
Column(Modifier.clickable { navQuote(quote.id ) }) {
QuoteLittle(quote)
Spacer(modifier = Modifier.height(16.dp))
}
}
}
item {
if (lastItem?.index == quotes.size) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
} else {
LaunchedEffect(remember { derivedStateOf { state.firstVisibleItemIndex } }, remember { derivedStateOf { state.layoutInfo } }.value.totalItemsCount) {
if (!isLoading.value && state.layoutInfo.visibleItemsInfo.isNotEmpty()) {
val lastVisibleItem = state.layoutInfo.visibleItemsInfo.last()
if (lastVisibleItem.index >= state.layoutInfo.totalItemsCount - 1) {
page.intValue++
}
}
}
}
}
.background(colorBackground),
contentAlignment = Alignment.Center
){
Column {
Text("Accueil", color = Color.White, fontSize = 20.sp)
}
}
}
}
}

@ -1,74 +1,69 @@
package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
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.services.IServices
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.components.QuoteLittle
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.components.SpaceHeightComponent
import com.example.what_the_fantasy.ui.components.TitlePageComponent
import com.example.what_the_fantasy.ui.theme.colorBackground
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.theme.gradienBox
@Composable
fun FavoritePage(
navAccueil: () -> Unit,
navQuiz: () -> Unit,
navProfil: () -> Unit,
navQuote: (Int) -> Unit,
navSearch: () -> Unit,
services: IServices,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
index: Int,
navAccueil: (Int) -> Unit,
navQuiz: (Int) -> Unit,
navProfil:(Int) -> Unit
) {
val user = services.getUserById(currentUserState.id) ?: return
val quotes = services.getFavorite(user)
val titlePage = stringResource(R.string.TitleFavorite)
NavBar(onFavorite = true,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
index = index,
navControllerFavorite = { },
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
navControllerQuiz = navQuiz
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
contentAlignment = Alignment.TopCenter
) {
LazyColumn {
item {
Text(
text = titlePage,
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
.background(colorBackground),
contentAlignment = Alignment.Center
){
Column {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(0xFF100C1B)),
contentAlignment = Alignment.Center
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
}
items(quotes) { quote ->
Column(Modifier.clickable { navQuote(quote.id) }) {
QuoteLittle(quote)
Spacer(modifier = Modifier.height(16.dp))
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(gradienBox)
.padding(20.dp),
) {
Text("Une image")
Text("Une citation d'un personnage")
}
}
}

@ -5,9 +5,12 @@ 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
@ -17,7 +20,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -25,6 +27,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
@ -32,31 +36,31 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.what_the_fantasy.logs.LogsUsers
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.local.UserStub
import com.example.what_the_fantasy.data.model.User
import com.example.what_the_fantasy.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.data.services.hashPassword
import com.example.what_the_fantasy.ui.components.VisibleIconPasswordComponent
import com.example.what_the_fantasy.ui.states.AuthUserState
import com.example.what_the_fantasy.ui.viewModels.AuthUserViewModel
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,
authUserVM : AuthUserViewModel,
authState : AuthUserState,
initialierCurrentUser : (Int) -> Unit) {
fun LoginPage(navControllerSignUp: () -> Unit, navControllerProfil: (Int) -> Unit, services : IServices) {
val users = services.getAllUsers()
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
.background(colorBackground),
contentAlignment = Alignment.Center
){
Column(
@ -64,89 +68,80 @@ fun LoginPage(navControllerSignUp: () -> Unit,
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.onPrimary)
.background(gradienBox)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
TitlePageComponent(R.string.titleLogin, MaterialTheme.colorScheme.primary)
SpaceHeightComponent(20)
ConnexionButtonLogin(authUserVM,
IdentifiantTextField(R.string.IdentifiantLogin, authState.username){
authUserVM.setUsername(it)
}, PassWdTextField(R.string.PasswdLogin, authState.password){
authUserVM.setPassword(it)
}, R.string.ButtonLogin,18,navControllerProfil){
initialierCurrentUser(it)
}
TitlePageComponent(R.string.titleLogin, 20,Color.White)
SpaceHeightComponent(16)
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, MaterialTheme.colorScheme.primary, navControllerSignUp)
CreateAccountButton(R.string.ButtonCreateLogin,12, Color.White, navControllerSignUp)
}
}
}
@Composable
fun IdentifiantTextField(textIdentifiantResId : Int, username : String, onValueChange: (String) -> Unit ) : String{
fun IdentifiantTextField(textIdentifiantResId : Int) : String{
val textIdentifiant = stringResource(id = textIdentifiantResId)
var identifiant by remember { mutableStateOf("") } // Stocke la valeur du champ
Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField(
value = username,
onValueChange = onValueChange,
value = identifiant,
onValueChange = { identifiant = it },
label = { Text(textIdentifiant) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
maxLines = 1,
shape = RoundedCornerShape(16.dp)
shape = RoundedCornerShape(16.dp) // Bords arrondis
)
}
return username;
return identifiant;
}
@Composable
fun PassWdTextField(textpasswdResId : Int, password : String, onValueChange: (String) -> Unit) : String{
fun PassWdTextField(textpasswdResId : Int) : String{
val textpasswd = stringResource(id = textpasswdResId)
var passwordVisible by remember { mutableStateOf(false) }
Column(modifier = Modifier.padding(top = 10.dp, bottom = 30.dp)) {
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 = password,
onValueChange = onValueChange,
value = passwd,
onValueChange = { passwd = it },
label = { Text(textpasswd) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
maxLines = 1,
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { passwordVisible = !passwordVisible }) {
VisibleIconPasswordComponent(passwordVisible)
}
},
shape = RoundedCornerShape(16.dp)
shape = RoundedCornerShape(16.dp) // Bords arrondis
)
}
return password;
return passwd;
}
@Composable
fun ConnexionButtonLogin(authUserVM : AuthUserViewModel, username : String, passwd : String, titleResId : Int, size : Int, navController: (Int) -> Unit, initialierCurrentUser : (Int) -> Unit){
fun ConnexionButtonLogin(userStub : List<User>, id : String, passwd : String, titleResId : Int, size : Int, colorButton : Color, colorText : Color, navController: (Int) -> Unit){
val title = stringResource(id = titleResId)
var showError by remember { mutableStateOf(false) }
Button(
onClick = { showError = !authUserVM.validLogin(username, passwd, navController, initialierCurrentUser)
onClick = { showError = !validLogin(id, passwd, userStub, navController)
},
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.background),
colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier
.fillMaxWidth(),
) {
Text(title, fontSize = size.sp, color = MaterialTheme.colorScheme.onBackground)
Text(title, fontSize = size.sp, color = colorText)
}
if(showError){
@ -155,6 +150,20 @@ fun ConnexionButtonLogin(authUserVM : AuthUserViewModel, username : String, pass
}
fun validLogin(identifiant : String, passwd : String, users : List<User>, 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
}
@Composable
fun CreateAccountButton(titleResId : Int, size : Int, color : Color, navController: () -> Unit) {
@ -162,9 +171,9 @@ fun CreateAccountButton(titleResId : Int, size : Int, color : Color, navControll
Text(
text = title,
fontSize = size.sp,
color = MaterialTheme.colorScheme.onBackground,
color = color,
modifier = Modifier.clickable {
navController()
navController()// rediriger vers la page de création de compte
}
)
}

@ -1,8 +1,15 @@
package com.example.what_the_fantasy.ui.screens
import android.util.Log
import android.content.Context
import android.os.Bundle
import android.util.Patterns
import android.widget.ImageView
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -13,21 +20,21 @@ 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.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
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
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -37,7 +44,10 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
@ -45,44 +55,46 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.example.what_the_fantasy.logs.LogsUsers
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.components.VisibleIconPasswordComponent
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.theme.What_The_FantasyTheme
import com.example.what_the_fantasy.ui.theme.gradienBox
@Composable
fun ProfilPage(navFavorite: () -> Unit,
navAccueil: () -> Unit,
navQuiz: () -> Unit,
fun ProfilPage(index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navQuiz: (Int) -> Unit,
navUnLog: () -> Unit,
navSubmitQuote: () -> Unit,
navSearch: () -> Unit,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
services: IServices
) {
val user = services.getUserById(index) ?: return
NavBar(onProfile = true,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
navControllerProfil = {},
navControllerQuiz = navQuiz
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState()),
.background(Color(0xFF100C1B)),
contentAlignment = Alignment.Center
) {
Column(
@ -90,36 +102,34 @@ fun ProfilPage(navFavorite: () -> Unit,
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.onPrimary)
.background(gradienBox)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Titre
TitlePageComponent(R.string.titleProfile, MaterialTheme.colorScheme.onBackground)
// Titre
TitlePageComponent(R.string.titleProfile, 20, Color.White)
SpaceHeightComponent(16)
// Image de profil
ImageProfil(120, currentUserState.id, currentUserVM,currentUserState)
ImageProfil(user.imgUrl, 120)
SpaceHeightComponent(16)
EditUsername(currentUserState.username, currentUserState.id, currentUserVM)// Édition du Username
EditUsername(user.username, index, services)// Édition du Username
SpaceHeightComponent(16)
EditEmail(currentUserState.email,currentUserState.id, currentUserVM)// Édition du Email
EditEmail(user.email,index, services)// Édition du Email
Spacer(modifier = Modifier.height(8.dp))
EditPasswd(currentUserState.id, currentUserVM)
EditPasswd(index, services)
SpaceHeightComponent(16)
// Bouton
ButtonProfile(R.string.ButtonAddQuoteprofile, 18, MaterialTheme.colorScheme.onBackground,MaterialTheme.colorScheme.background,navSubmitQuote) // Pas encore de navigation definie
//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)
ButtonLanguage(R.string.ButtonLanguageprofile, 18, MaterialTheme.colorScheme.onBackground,MaterialTheme.colorScheme.background,currentUserVM, currentUserState)
SpaceHeightComponent(16)
ButtonUnLog(R.string.ButtonUnlogprofile, 18,MaterialTheme.colorScheme.onBackground, MaterialTheme.colorScheme.background, navUnLog,currentUserVM)
ButtonProfile(R.string.ButtonUnlogprofile, 18, Color.Black, Color.White, navUnLog)
}
}
@ -128,30 +138,26 @@ fun ProfilPage(navFavorite: () -> Unit,
@Composable
fun ImageProfil(size :Int,index: Int, currentUserVM: CurrentUserViewModel, currentUserState: CurrentUserState){
fun ImageProfil(imgProfil : String, size :Int){
AsyncImage(
model = currentUserState.imagePath,
model = imgProfil,
contentDescription = "Photo de profil",
modifier = Modifier
.size(size.dp)
.clip(CircleShape)
.clickable{currentUserVM.editImage(index)}
)
}
@Composable
fun EditEmail(emailState: String, index: Int, currentUserVM: CurrentUserViewModel) {
var email by remember { mutableStateOf(emailState) }
var originalEmail by remember { mutableStateOf(emailState) }
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() {
if (email != originalEmail) {
isEditingEmail = !currentUserVM.editEmail(email, index)
} else {
isEditingEmail = false
}
service.EditEmail(email, index)
isEditingEmail = false
}
if (isEditingEmail) {
@ -159,7 +165,7 @@ fun EditEmail(emailState: String, index: Int, currentUserVM: CurrentUserViewMode
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) {
@ -184,7 +190,7 @@ fun EmailEditingField(
value = email,
onValueChange = onEmailChange,
modifier = Modifier.fillMaxWidth(),
textStyle = TextStyle(color = MaterialTheme.colorScheme.primary, fontSize = 18.sp),
textStyle = TextStyle(color = Color.White, fontSize = 18.sp),
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Email,
@ -206,6 +212,7 @@ fun EmailEditingField(
}
}
@Composable
fun DisplayEmail(email: String, onEdit: () -> Unit) {
Row(
@ -216,12 +223,12 @@ fun DisplayEmail(email: String, onEdit: () -> Unit) {
text = email,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground
color = Color.White
)
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Modifier",
tint = MaterialTheme.colorScheme.primary,
tint = Color.White,
modifier = Modifier.size(16.dp).padding(start = 8.dp)
)
}
@ -229,26 +236,21 @@ fun DisplayEmail(email: String, onEdit: () -> Unit) {
@Composable
fun EditUsername(usernameState: String, index: Int, currentUserVM: CurrentUserViewModel) {
var username by remember { mutableStateOf(usernameState) }
var originalUsername by remember { mutableStateOf(usernameState) }
fun EditUsername(userName: String, index: Int, service : IServices) {
var username by remember { mutableStateOf(userName) }
var isEditingUsername by remember { mutableStateOf(false) }
fun onDoneEditing() {
if (username != originalUsername) {
isEditingUsername = !currentUserVM.editUsername(username, index)
} else {
isEditingUsername = false
}
service.EditUsername(username, index)
isEditingUsername = false
}
if (isEditingUsername) {
UsernameEditingField(
username = username,
onUsernameChange = { username = it },
onDone = { onDoneEditing() },
onDone = { onDoneEditing() }
)
} else {
DisplayUsername(username = username, onEdit = { isEditingUsername = true })
@ -265,7 +267,7 @@ fun UsernameEditingField(
value = username,
onValueChange = onUsernameChange,
modifier = Modifier.fillMaxWidth(),
textStyle = TextStyle(color = MaterialTheme.colorScheme.primary, fontSize = 18.sp),
textStyle = TextStyle(color = Color.White, fontSize = 18.sp),
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
@ -291,12 +293,12 @@ fun DisplayUsername(username: String, onEdit: () -> Unit) {
text = username,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground
color = Color.White
)
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Modifier",
tint = MaterialTheme.colorScheme.primary,
tint = Color.White,
modifier = Modifier.size(16.dp).padding(start = 8.dp)
)
}
@ -304,9 +306,9 @@ fun DisplayUsername(username: String, onEdit: () -> Unit) {
@Composable
fun EditPasswd(index: Int, currentUserVM: CurrentUserViewModel) {
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("") }
@ -316,7 +318,7 @@ fun EditPasswd(index: Int, currentUserVM: CurrentUserViewModel) {
// 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
currentUserVM.editPassword(newPassword, index)
service.EditPasswd(newPassword, index)
isEditingPassword = false
}
@ -329,20 +331,18 @@ fun EditPasswd(index: Int, currentUserVM: CurrentUserViewModel) {
confirmPassword = it
passwordError = newPassword != it // Vérifier si les mots de passe correspondent
},
passwordVisible = passwordVisible,
onPasswordVisibilityChange = { passwordVisible = it },
passwordError = passwordError,
onDone = {
if (!passwordError && newPassword.isNotEmpty()) {
onDoneEditing() // pour mettre à jour le mot de passe
onDoneEditing() // Appeler la fonction onDoneEditing() pour mettre à jour le mot de passe
}
}
)
} else {
DisplayPassword(onEdit = { isEditingPassword = true }) // pour modifier le mot de passe
DisplayPassword(onEdit = { isEditingPassword = true }) // Afficher l'option pour modifier le mot de passe
}
}
@Composable
@ -404,7 +404,7 @@ fun PasswordTextField(
onValueChange = onValueChange,
label = { Text(label) },
modifier = Modifier.fillMaxWidth(),
textStyle = TextStyle(color = MaterialTheme.colorScheme.primary, fontSize = 18.sp),
textStyle = TextStyle(color = Color.White, fontSize = 18.sp),
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Password,
@ -416,7 +416,7 @@ fun PasswordTextField(
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = { onPasswordVisibilityChange(!passwordVisible) }) {
VisibleIconPasswordComponent(passwordVisible)
// Ajout d'une icône pour montrer/masquer le mot de passe
}
},
isError = isError
@ -427,13 +427,13 @@ fun PasswordTextField(
fun SaveButton(onClick: () -> Unit) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.background),
colors = ButtonDefaults.buttonColors(containerColor = Color.White),
modifier = Modifier.fillMaxWidth()
) {
val text = stringResource(id = R.string.ButtonSaveprofile)
Text(text,
fontSize = 18.sp,
color = MaterialTheme.colorScheme.onBackground)
color = Color.Black)
}
}
@ -447,59 +447,22 @@ fun DisplayPassword(onEdit: () -> Unit) {
text = "*****",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground
color = Color.White
)
Icon(
imageVector = Icons.Default.Edit,
contentDescription = "Modifier",
tint =MaterialTheme.colorScheme.primary,
tint = Color.White,
modifier = Modifier.size(16.dp).padding(start = 8.dp)
)
}
}
@Composable
fun ButtonUnLog(textResId : Int, size :Int, colorTexte : Color,colorButton : Color, navController: () -> Unit, currentUserVM: CurrentUserViewModel){
val text = stringResource(id = textResId)
val logsUser = LogsUsers() //gestion des logs pour les utilisateurs
Button(
onClick = {
currentUserVM.clearCurrentUser()
navController()
logsUser.unlogInformationUserConnect("UserUnLog")
},
colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier.fillMaxWidth(),
) {
Text(text, fontSize = size.sp, color = colorTexte)
}
}
@Composable
fun ButtonLanguage(textResId : Int, size :Int,colorTexte : Color, colorButton : Color, currentUserVM: CurrentUserViewModel, currentUserState : CurrentUserState){
val text = stringResource(id = textResId)
Button(
onClick = {
currentUserVM.editLangue(currentUserState.id)
},
colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier.fillMaxWidth(),
) {
Text("${text} (${currentUserState.langage})", fontSize = size.sp, color = colorTexte)
}
}
@Composable
fun ButtonProfile(textResId : Int, size :Int,colorTexte : Color, colorButton : Color,navController: () -> Unit){
fun ButtonProfile(textResId : Int, size :Int, colorTexte : Color, colorButton : Color,navController: () -> Unit){
val text = stringResource(id = textResId)
Button(
onClick = {
navController()
},
onClick = { navController() },
colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier.fillMaxWidth(),
) {

@ -1,25 +1,32 @@
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.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.material3.MaterialTheme
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.local.QuestionStub
import com.example.what_the_fantasy.data.local.QuizStub
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
val gradient = Brush.linearGradient(
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)),
@ -31,23 +38,18 @@ val gradient = Brush.linearGradient(
fun QuizEndPage(
idQuiz: Int,
points: Int,
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navQuiz: () -> Unit,
navSearch: () -> Unit,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navProfil:(Int) -> Unit,
navQuiz: (Int) -> Unit,
) {
NavBar(
currentUserVM = currentUserVM,
currentUserState = currentUserState,
NavBar(onQuiz = true,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
) {
navControllerQuiz = navQuiz) {
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
) {
@ -72,16 +74,16 @@ fun QuizEndPage(
Spacer(modifier = Modifier.height(16.dp))
Column(
modifier = Modifier
.background(color = MaterialTheme.colorScheme.onPrimary, shape = RoundedCornerShape(20.dp))
.background(brush = gradient, shape = RoundedCornerShape(20.dp))
.padding(30.dp)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
val quizName = if (idQuiz == -1) "Random Quiz" else QuizStub.getQuizById(idQuiz)?.name ?: "Quiz Inconnu"
val quiz = QuizStub.getQuizById(idQuiz)
val nbQuestions = quiz?.questions?.size
Text(
text = quizName,
text = "${quiz?.name}",
color = Color.White,
style = TextStyle(
fontSize = 25.sp,
@ -89,7 +91,6 @@ fun QuizEndPage(
textAlign = TextAlign.Center
)
)
val nbQuestions = 10
Text(
text = "Nombres de Questions : $nbQuestions",
color = Color.White,

@ -2,27 +2,30 @@ 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.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
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
@ -31,49 +34,41 @@ 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
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
@Composable
fun QuizMenu(
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navControllerQuiz: (Int) -> Unit,
navSearch: () -> Unit,
navControllerRandomQuiz:() -> Unit
@Composable
fun QuizMenu( index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navProfil:(Int) -> Unit,
navControllerQuiz: (Int) -> Unit
) {
NavBar(onQuiz = true,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerSearch = navSearch
navControllerQuiz = { }
) {
Row(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.horizontalScroll(state = rememberScrollState())
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
) {
// Contenu princiapl
Column(
modifier = Modifier
.width(400.dp)
.weight(0.9f)
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "▶ Menu des Quiz ◀",
color = MaterialTheme.colorScheme.onBackground,
color = Color.White,
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
@ -83,7 +78,7 @@ fun QuizMenu(
Spacer(Modifier.height(20.dp))
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.primary, shape = RoundedCornerShape(20.dp))
.background(brush = gradient, shape = RoundedCornerShape(20.dp))
.fillMaxSize()
.padding(vertical = 30.dp)
.verticalScroll(rememberScrollState()),
@ -122,7 +117,7 @@ fun QuizMenu(
fontSize = 17.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onPrimary
color = Color.White
)
)
}
@ -132,66 +127,6 @@ fun QuizMenu(
}
}
}
Column(
modifier = Modifier
.width(400.dp)
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "▶ Mini-Jeux ◀",
color = MaterialTheme.colorScheme.onBackground,
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
Spacer(Modifier.height(20.dp))
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.onPrimary, shape = RoundedCornerShape(20.dp))
.fillMaxSize()
.padding(vertical = 30.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
val context = LocalContext.current
val imageResId = context.resources.getIdentifier(
"quiz",
"drawable",
context.packageName
)
Column(
modifier = Modifier
.size(width = 150.dp, height = 145.dp)
.clickable { navControllerRandomQuiz() },
) {
Image(
painter = painterResource(id = imageResId),
contentDescription = "Random Quiz",
modifier = Modifier
.size(width = 150.dp, height = 100.dp)
.clip(shape = RoundedCornerShape(20.dp)),
contentScale = ContentScale.Crop
)
Spacer(Modifier.height(10.dp))
Text(
text = "Random Quiz",
style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Medium,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.primary
)
)
}
}
}
}
}
}

@ -1,10 +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.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@ -12,25 +13,25 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.local.QuestionStub
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
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
@Composable
fun QuizPage(
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navQuiz: () -> Unit,
navSearch: () -> Unit,
index: Int,
navFavorite: (Int) -> Unit,
navAccueil: (Int) -> Unit,
navProfil:(Int) -> Unit,
navQuiz: (Int) -> Unit,
navControllerQuizEnd: (Int, Int) -> Unit,
@ -42,7 +43,7 @@ fun QuizPage(
var pts by remember { mutableIntStateOf(0) }
val gradient = Brush.linearGradient(
colors = listOf(MaterialTheme.colorScheme.onPrimary, MaterialTheme.colorScheme.onPrimary),
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)),
start = Offset(0f, 1000f),
end = Offset(1000f, 0f)
)
@ -60,14 +61,12 @@ fun QuizPage(
if (idCurrentQuestion < questions.size - 1) idCurrentQuestion++
else navControllerQuizEnd(idQuiz, pts) // Retour menu
}
NavBar(
currentUserVM = currentUserVM,
currentUserState = currentUserState,
NavBar(onQuiz = true,
index = index,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
navControllerQuiz = navQuiz
){
Column (
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
@ -99,17 +98,14 @@ fun QuizPage(
Spacer(Modifier.height(20.dp))
Column(
modifier = Modifier
.background(brush = gradient, shape = RoundedCornerShape(20.dp))
.height(800.dp),
.background(brush = gradient, shape = RoundedCornerShape(20.dp)),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"Question ${idCurrentQuestion + 1}",
color = Color.White,
fontSize = 18.sp,
modifier = Modifier
.padding(top = 20.dp)
.weight(0.1f),
modifier = Modifier.padding(top = 20.dp),
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
@ -119,19 +115,12 @@ fun QuizPage(
Text(
question.question,
color = Color.White,
fontSize = 15.sp,
modifier = Modifier
.padding(horizontal = 25.dp)
.weight(0.1f),
textAlign = TextAlign.Center
fontSize = 22.sp,
modifier = Modifier.padding(40.dp)
)
Column(
modifier = Modifier
.weight(0.7f)
.fillMaxHeight()
.padding(vertical = 30.dp),
verticalArrangement = Arrangement.SpaceBetween
.padding(top = 30.dp)
) {
listOf(
question.ansA,
@ -150,6 +139,7 @@ fun QuizPage(
) {
Text(answer, color = Color.Black, fontSize = 18.sp)
}
Spacer(modifier = Modifier.height(60.dp))
}
}
}

@ -1,165 +0,0 @@
package com.example.what_the_fantasy.ui.screens
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.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.data.local.QuestionStub
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
@Composable
fun QuizRandom(
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navQuiz: () -> Unit,
navSearch: () -> Unit,
navControllerQuizEnd: (Int, Int) -> Unit,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
) {
val questions = QuestionStub.shuffleRandomQuestions
var idCurrentQuestion by remember { mutableIntStateOf(0) }
var pts by remember { mutableIntStateOf(0) }
var lifes by remember { mutableIntStateOf(3) }
val gradient = Brush.linearGradient(
colors = listOf(MaterialTheme.colorScheme.onPrimary, MaterialTheme.colorScheme.onPrimary),
start = Offset(0f, 1000f),
end = Offset(1000f, 0f)
)
fun onAnswerSelected(answer: String) {
val currentQuestion = questions[idCurrentQuestion]
val correctAnswer = mapOf(
"A" to currentQuestion.ansA,
"B" to currentQuestion.ansB,
"C" to currentQuestion.ansC,
"D" to currentQuestion.ansD
)[currentQuestion.correctAns]
if (answer == correctAnswer) pts++
else {
lifes -= 1
Log.d("Quiz Debug", "Lifes -1 :, $lifes")
}
if (idCurrentQuestion < questions.size - 1 && lifes > 0) idCurrentQuestion++
else {
navControllerQuizEnd(-1, pts)
Log.d("Quiz Debug", "Game over lifes : $lifes")
} // Retour menu
}
NavBar(
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
){
Column (
modifier = Modifier.fillMaxSize().background(Color(0xFF100C1B))
) {
// Contenu princiapl
Column(
modifier = Modifier
.weight(0.8f)
.fillMaxWidth()
.padding(horizontal = 50.dp, vertical = 20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
val question = questions[idCurrentQuestion]
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
if (questions != null) {
Text(
text = "▶ Random Quiz ◀",
color = Color.White,
style = TextStyle(
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
}
Spacer(Modifier.height(20.dp))
Column(
modifier = Modifier
.background(brush = gradient, shape = RoundedCornerShape(20.dp))
.height(800.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"Question ${idCurrentQuestion + 1}",
color = Color.White,
fontSize = 18.sp,
modifier = Modifier
.padding(top = 20.dp)
.weight(0.1f),
style = TextStyle(
fontSize = 25.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
)
Text(
question.question,
color = Color.White,
fontSize = 15.sp,
modifier = Modifier
.padding(horizontal = 25.dp)
.weight(0.1f),
textAlign = TextAlign.Center
)
Column(
modifier = Modifier
.weight(0.7f)
.fillMaxHeight()
.padding(vertical = 30.dp),
verticalArrangement = Arrangement.SpaceBetween
) {
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)
}
}
}
}
}
}
}
}
}

@ -1,447 +1,8 @@
package com.example.what_the_fantasy.ui.screens
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.R
import coil.compose.AsyncImage
import com.example.what_the_fantasy.data.model.Comment
import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.data.services.IServices
import com.example.what_the_fantasy.logs.LogsUsers
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.states.QuoteInformationUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.viewModels.QuoteInformationUserViewModel
var isCommentVisible by mutableStateOf(false)
@Composable
fun QuotePage(
quoteId : Int,
service : IServices,
navAccueil: () -> Unit,
navFavorite:() -> Unit,
navQuiz: () -> Unit,
navProfil:() -> Unit,
navSearch: () -> Unit,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
quoteInformationUserVM : QuoteInformationUserViewModel,
quoteInformationUserState : QuoteInformationUserState
)
{
// utiliser ViewModel
val quote = service.getQuote(quoteId) ?: return
val context = LocalContext.current
val favorite by remember { mutableStateOf(service.isFavorite(
idQuote = quoteId,
iduser = currentUserState.id)) }
NavBar(
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState()),
contentAlignment = Alignment.Center
) {
Column(modifier = Modifier
.padding(15.dp)
.background(
color = MaterialTheme.colorScheme.primary,
shape = RoundedCornerShape(15.dp)
)
) {
Row(modifier = Modifier.padding(15.dp)) {
ImageQuote(
imageUrl = quote.imgUrl
)
Column {
FunctionalIcon(
isFavorite = favorite,
userId = currentUserState.id,
quoteId = quoteId,
context = context,
quoteInformationUserVM = quoteInformationUserVM,
quoteInformationUserState = quoteInformationUserState,
quote = quote
)
QuoteText(
text = '"' + quote.content + '"'
)
}
}
Column(modifier = Modifier
.padding(15.dp)
.fillMaxWidth()
) {
InfoQuoteText(
nameId = R.string.source,
text = quote.source
)
InfoQuoteText(
nameId = R.string.charac,
text = quote.character
)
InfoQuoteText(
nameId = R.string.date,
text = quote.date.toString()
)
InfoQuoteText(
nameId = R.string.type,
text = quote.type.toString()
)
Row(
modifier = Modifier
.padding(top = 10.dp)
.align(alignment = Alignment.End)
) {
LikeInfo(
likes = quote.likes,
quoteInformationUserVM
)
}
}
}
}
AnimatedVisibility(
visible = isCommentVisible,
enter = expandVertically(
expandFrom = Alignment.CenterVertically
) + fadeIn(
initialAlpha = 0.3f
) + slideInVertically(
initialOffsetY = { -40 }
),
exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
Box(modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primary)
.fillMaxSize()){
Column {
AddComment(currentUserState.id, service, quoteInformationUserState, quoteInformationUserVM)
LstComment(service.getComment(quoteId))
}
}
}
}
}
// ------------------ Composants non partager de la page --------------------------------------
@Composable
fun QuoteText(text: String ){
Text(
text = text,
modifier = Modifier.padding(start = 10.dp, top = 15.dp),
fontWeight = FontWeight(1000),
fontSize = 20.sp,
color = MaterialTheme.colorScheme.onPrimary
)
}
@Composable
fun ImageQuote(imageUrl : String){
AsyncImage(
model = imageUrl,
contentDescription = stringResource(R.string.profilePict),
modifier = Modifier
.size(150.dp)
.clip(RoundedCornerShape(15.dp))
)
}
@Composable
fun FunctionalIcon(isFavorite: Boolean,
userId : Int,
quoteId : Int,
context : Context,
quoteInformationUserVM : QuoteInformationUserViewModel,
quoteInformationUserState : QuoteInformationUserState,
quote : Quote
){
val logsUsers = LogsUsers()
Row(modifier = Modifier
.fillMaxWidth()
) {
IconButton(
onClick = {
val sendIntent = Intent().apply {
action = Intent.ACTION_SEND
// lien a changer quand le site sra deployer
putExtra(Intent.EXTRA_TEXT, "http://wfWebsite/quote/$quoteId")
type = "text/plain"
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
logsUsers.shareInformationUser("ShareQuote", quoteId, userId)
}
val shareIntent = Intent.createChooser(sendIntent, null)
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(shareIntent)
},
modifier = Modifier.padding(start = 15.dp)
) {
Icon(
Icons.Default.Share,
contentDescription = stringResource(R.string.share),
tint = MaterialTheme.colorScheme.onPrimary,
)
}
IconButton(
onClick = {
isCommentVisible = !isCommentVisible
},
modifier = Modifier.padding(start = 20.dp)
){
Image(
painter = painterResource(id = R.drawable.message),
contentDescription ="message",
modifier = Modifier.size(30.dp),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimary)
)
}
if(isFavorite){
IconButton(
onClick = {
quoteInformationUserVM.supFav(userId = userId, idQuote = quoteId)
quote.likes = quoteInformationUserState.like
//Log.e("Like", "Coeur ${quote.likes} ${quoteInformationUserState.like}")
logsUsers.favoriteInformationUserFalse("Favorite", quoteId, userId)
}, //sup fav
modifier = Modifier.padding(start = 20.dp)
){
Icon(
Icons.Default.Favorite,
contentDescription = stringResource(R.string.favorite),
tint = MaterialTheme.colorScheme.onPrimary,
)
}
}
else{
IconButton(
onClick = {
quoteInformationUserVM.addFav(userId = userId, idQuote = quoteId)
quote.likes = quoteInformationUserState.like
logsUsers.favoriteInformationUserTrue("Favorite", quoteId, userId)
}, //add fav
modifier = Modifier.padding(start = 50.dp)
){
Icon(
Icons.Default.FavoriteBorder,
contentDescription = stringResource(R.string.favorite),
tint = MaterialTheme.colorScheme.onPrimary
)
}
}
}
}
@Composable
fun InfoQuoteText(nameId : Int, text : String){
Column(modifier = Modifier.padding(bottom = 20.dp)){
Text(
text = stringResource(id = nameId),
fontSize = 18.sp,
fontWeight = FontWeight(500),
color = MaterialTheme.colorScheme.onPrimary
)
Text(
text = text,
color = MaterialTheme.colorScheme.onBackground,
fontSize = 16.sp,
fontWeight = FontWeight(400),
modifier = Modifier
.background(
color = MaterialTheme.colorScheme.background,
shape = RoundedCornerShape(15.dp)
)
.padding(5.dp)
)
}
}
@Composable
fun LikeInfo(likes : Int,
quoteInformationUserVM : QuoteInformationUserViewModel){
quoteInformationUserVM.setLike(likes)
//Log.e("Like", "LikeInfo => Nb Like : ${likes}")
Text(
text = likes.toString(),
color = MaterialTheme.colorScheme.onPrimary
)
Icon(
Icons.Default.Favorite,
contentDescription = stringResource(R.string.favorite),
tint = MaterialTheme.colorScheme.onPrimary,
)
}
@Composable
fun AddComment(userId: Int,
service: IServices,
quoteInformationUserState: QuoteInformationUserState,
quoteInformationUserVM: QuoteInformationUserViewModel) {
// var text by remember { mutableStateOf(quoteInformationUserState.comment) }
Row(
modifier = Modifier
.padding(15.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(
onClick = { isCommentVisible = !isCommentVisible }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.send),
tint = MaterialTheme.colorScheme.onPrimary
)
}
TextField(
value = quoteInformationUserState.comment,
onValueChange = { quoteInformationUserVM.setComment(it) },
label = { Text(stringResource(R.string.comment)) },
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp),
shape = RoundedCornerShape(20.dp),
colors = TextFieldDefaults.colors(
focusedContainerColor = MaterialTheme.colorScheme.onPrimary,
unfocusedContainerColor = MaterialTheme.colorScheme.onPrimary,
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.primary
),
trailingIcon = {
IconButton(
onClick = { isCommentVisible = !isCommentVisible }
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.Send,
contentDescription = "Retour",
tint = MaterialTheme.colorScheme.primary
)
}
}
)
}
}
@Composable
fun LstComment(lst: List<Comment>) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(10.dp)
) {
items(lst) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(
color = MaterialTheme.colorScheme.onPrimary,
shape = RoundedCornerShape(15.dp)
)
.padding(12.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = it.img,
contentDescription = stringResource(R.string.profilePict),
modifier = Modifier
.size(50.dp)
.clip(RoundedCornerShape(50))
)
Text(
text = "${it.user}${it.date}",
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.padding(start = 12.dp),
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
}
Text(
text = it.content,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.padding(top = 10.dp, start = 8.dp, end = 8.dp),
fontSize = 14.sp
)
}
}
}
}
fun QuotePage() {
}

@ -1,170 +0,0 @@
package com.example.what_the_fantasy.ui.screens
import androidx.compose.foundation.background
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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.what_the_fantasy.R
import coil.compose.AsyncImage
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.theme.gradienBox
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
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.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import com.example.what_the_fantasy.data.model.Character
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
@Composable
fun RecapSubmitPage(
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navSearch: () -> Unit,
navQuiz : () -> Unit,
quoteContent : String,
character: String,
source: String,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
) {
NavBar(onQuiz = true,
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = navSearch
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) {
// Contenu princiapl
Column(
modifier = Modifier
.weight(0.9f)
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "▶ Recap de la citation ◀",
color = MaterialTheme.colorScheme.onBackground,
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
) {
Column(modifier = Modifier
.padding(15.dp)
.drawBehind {
drawRoundRect(
gradienBox,
cornerRadius = CornerRadius(15.dp.toPx()),
)
}
) {
Row(modifier = Modifier.padding(15.dp)) {
ImageQuote(
imageUrl = "https://img.freepik.com/vecteurs-libre/personnage-guerrier-fantaisie_1045-185.jpg?size=338&ext=jpg"
)
Column {
QuoteText(
text = '"' + quoteContent + '"'
)
}
}
Column(modifier = Modifier
.padding(15.dp)
.fillMaxWidth()
) {
InfoQuoteText(
nameId = R.string.source,
text = source
)
Text(
text = "Character : $character"
)
}
}
}
}
}
}
}
@Composable
fun QuoteText2(text: String ){
Text(
text = text,
modifier = Modifier.padding(start = 10.dp, top = 15.dp),
fontWeight = FontWeight(1000),
fontSize = 20.sp,
color = MaterialTheme.colorScheme.background
)
}
@Composable
fun ImageQuote2(imageUrl : String){
AsyncImage(
model = imageUrl,
contentDescription = "exemple",
modifier = Modifier
.size(150.dp)
.clip(RoundedCornerShape(15.dp))
)
}
@Composable
fun InfoQuoteText2(nameId : Int, text : String){
Column(modifier = Modifier.padding(bottom = 20.dp)){
Text(
text = text,
fontSize = 16.sp,
fontWeight = FontWeight(400),
modifier = Modifier
.drawBehind {
drawRoundRect(
Color(255,255,255),
cornerRadius = CornerRadius(15.dp.toPx())
)
}
.padding(5.dp),
)
}
}

@ -1,203 +1,8 @@
package com.example.what_the_fantasy.ui.screens
import android.util.Log
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.data.services.IServices
import androidx.compose.runtime.Composable
import com.example.what_the_fantasy.ui.components.NavBar
import com.example.what_the_fantasy.ui.components.QuoteLittle
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.states.SearchState
import com.example.what_the_fantasy.ui.viewModels.AuthUserViewModel
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
import com.example.what_the_fantasy.ui.viewModels.SearchViewModel
import kotlinx.coroutines.delay
@Composable
fun SearchPage(
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil: () -> Unit,
navQuiz: () -> Unit,
navQuote: (Int) -> Unit,
navSearch: (String, String) -> Unit,
type: String,
search: String,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
searchVM : SearchViewModel,
searchState : SearchState,
) {
val textQuoteSearch = stringResource(id = R.string.QuoteSearch)
val textTitleSearch = stringResource(id = R.string.TitleQuoteSearch)
val textCharacterSearch = stringResource(id = R.string.character)
val textSearch = stringResource(id = R.string.Search)
val filtre = listOf("contenu", "personnage", "titre")
//val filtre = listOf(textQuoteSearch, textCharacterSearch, textTitleSearch)
val (newFiltre, onFiltreSelected) = remember { mutableStateOf(type) }
val page = remember { mutableIntStateOf(1) }
val quotes = remember { mutableStateListOf<Quote>() }
val isLoading = remember { mutableStateOf(false) }
val state = rememberLazyListState()
LaunchedEffect(page.intValue, type, search) {
if (!isLoading.value) {
isLoading.value = true
delay(500)
val newQuotes = searchVM.search(type, search, page.intValue * 15)
val uniqueQuotes = newQuotes.filterNot { new -> quotes.any { it.id == new.id } }
if (uniqueQuotes.isNotEmpty()) {
quotes.addAll(uniqueQuotes)
}
isLoading.value = false
}
}
NavBar(
onAccueil = true,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz,
navControllerSearch = { navSearch("contenu", "") },
currentUserVM = currentUserVM,
currentUserState = currentUserState,
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
) {
Text(
text = "" + stringResource(R.string.TitleSearch) + "",
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
textAlign = TextAlign.Center
)
Column(horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedTextField(
value = searchState.search,
onValueChange = {
searchVM.setSearch(it)
},
textStyle = TextStyle(color = MaterialTheme.colorScheme.onBackground),
label = { Text(textSearch) },
modifier = Modifier
.padding(top = 2.dp)
.fillMaxWidth()
.height(70.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
maxLines = 1,
shape = CircleShape,
trailingIcon = {
IconButton(
onClick = { navSearch(newFiltre, searchState.search) },
modifier = Modifier
.size(50.dp)
.clip(CircleShape)
) {
Image(
painter = painterResource(id = R.drawable.search),
contentDescription = "search",
modifier = Modifier
.size(30.dp),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary)
)
}
}
)
Row(horizontalArrangement = Arrangement.SpaceAround) {
filtre.forEach { typeItem ->
Row(
Modifier
.height(56.dp)
.selectable(
selected = (typeItem == newFiltre),
onClick = { onFiltreSelected(typeItem) },
role = Role.RadioButton
)
.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = (typeItem == newFiltre),
onClick = null
)
Text(
text = typeItem,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp),
color = MaterialTheme.colorScheme.onBackground
)
}
}
}
}
LazyColumn(
modifier = Modifier.weight(1f),
state = state
) {
items(quotes) { quote ->
Column(Modifier.clickable { navQuote(quote.id) }) {
if(quote.language == currentUserState.langage) { // affiche les suggestions de citation dans la bonne langue
QuoteLittle(quote)
}
}
}
item {
if (state.layoutInfo.visibleItemsInfo.lastOrNull()?.index == quotes.size - 1 && !isLoading.value) {
LaunchedEffect(Unit) {
page.intValue++
}
Box(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
}
}
}
}
}
fun SearchPage() {
}

@ -1,28 +1,29 @@
package com.example.what_the_fantasy.ui.screens
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
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.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -30,33 +31,40 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.example.what_the_fantasy.R
import com.example.what_the_fantasy.data.model.Image
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.VisibleIconPasswordComponent
import com.example.what_the_fantasy.ui.states.SignInUserState
import com.example.what_the_fantasy.ui.viewModels.SignInUserViewModel
import com.example.what_the_fantasy.ui.components.hashPassword
@Composable
fun SignUpPage(navControllerLogin: () -> Unit, signInUserVM :SignInUserViewModel,signInState : SignInUserState) {
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
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState()),
.background(colorBackground),
contentAlignment = Alignment.Center
){
Column(
@ -64,33 +72,19 @@ fun SignUpPage(navControllerLogin: () -> Unit, signInUserVM :SignInUserViewModel
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.onPrimary)
.background(gradienBox)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
TitlePageComponent(R.string.titleSignUp,MaterialTheme.colorScheme.onBackground) // Page Title
IdentifiantTextFieldSign(R.string.IdentifiantLogin,signInState.username){ // Username
signInUserVM.setUsername(it)
}
EmailTextFieldSign(R.string.EmailSignUp, signInState.email){ // Email
signInUserVM.setEmail(it)
}
PassWdTextFieldSign(R.string.PasswdLogin,signInState.password){ // Password
signInUserVM.setPassword(it)
}
PassWdConfirmTextFieldSign(R.string.ConfirmPassWdSignUp,signInState.confirmPassword){ // confirm Password
signInUserVM.setConfirmPassword(it)
}
TitlePageComponent(R.string.titleSignUp, 20,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, signInState.username, signInState.email, signInState.password, signInState.confirmPassword, signInUserVM, navControllerLogin)
ConnexionButtonSign(R.string.ButtonSignUp,18, Color.White, Color.Black, username, email, password, confirmPassword, services, navControllerLogin)
SpaceHeightComponent(16)
ReturnLogin(R.string.ButtonLogin,12, Color.White, navController = navControllerLogin)
}
@ -98,6 +92,8 @@ fun SignUpPage(navControllerLogin: () -> Unit, signInUserVM :SignInUserViewModel
}
@Composable
fun IdentifiantTextFieldSign(textIdentifiantResId : Int, identifiant: String, onValueChange: (String) -> Unit){
val textIdentifiant = stringResource(id = textIdentifiantResId)
@ -134,10 +130,8 @@ fun EmailTextFieldSign(textIdentifiantResId: Int, email: String, onValueChange:
}
@Composable
fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (String) -> Unit){
fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){
val textpasswd = stringResource(id = textpasswdResId)
var passwordVisible by remember { mutableStateOf(false) }
Column(modifier = Modifier.padding(top = 10.dp)) {
OutlinedTextField(
value = passwd,
@ -149,10 +143,8 @@ fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (S
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = {
passwordVisible = !passwordVisible
}) {
VisibleIconPasswordComponent(passwordVisible)
IconButton(onClick = onPasswordVisibilityChange) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider")
}
},
shape = RoundedCornerShape(16.dp)
@ -161,10 +153,8 @@ fun PassWdTextFieldSign(textpasswdResId : Int, passwd: String, onValueChange: (S
}
@Composable
fun PassWdConfirmTextFieldSign(textpasswdResId : Int,confirmPassword: String, onValueChange: (String) -> Unit){
fun PassWdConfirmTextFieldSign(textpasswdResId : Int,confirmPassword: String, onValueChange: (String) -> Unit, passwordVisible: Boolean, onPasswordVisibilityChange: () -> Unit){
val textpasswd = stringResource(id = textpasswdResId)
var passwordVisible by remember { mutableStateOf(false) }
Column(modifier = Modifier.padding(top = 10.dp)) {
OutlinedTextField(
value = confirmPassword,
@ -176,8 +166,8 @@ fun PassWdConfirmTextFieldSign(textpasswdResId : Int,confirmPassword: String, on
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
IconButton(onClick = {passwordVisible = !passwordVisible}) {
VisibleIconPasswordComponent(passwordVisible)
IconButton(onClick = onPasswordVisibilityChange) {
Icon(imageVector = Icons.Default.Check, contentDescription = "Valider")
}
},
shape = RoundedCornerShape(16.dp)
@ -207,27 +197,25 @@ fun ConnexionButtonSign(
email: String,
password: String,
confirmPassword: String,
viewModel: SignInUserViewModel,
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 usernameError by remember { mutableStateOf(false) }
var usernameErrorEmpty by remember { mutableStateOf(false) }
var usernameErrorExist by remember { mutableStateOf(false) }
val invalidRegex = """^[a-zA-Z0-9]*$""".toRegex()
Button(
onClick = {
emailError = !isValidEmail(email)
passwordError = !arePasswordsMatching(password, confirmPassword)
usernameError = username.isBlank() && !username.matches(invalidRegex)
usernameErrorEmpty = username.isBlank()
passwordErrorEmpty = password.isBlank() || confirmPassword.isBlank()
if (!emailError && !passwordError && !usernameError && !passwordErrorEmpty) {
usernameErrorExist = !viewModel.createUser(username, email, password)
if (!emailError && !passwordError && !usernameErrorEmpty && !passwordErrorEmpty) {
usernameErrorExist = !service.CreateUser(username, email, password, service)
if(!usernameErrorExist){
navController() // retour à la page login
}
@ -240,8 +228,8 @@ fun ConnexionButtonSign(
}
// Afficher erreurs
if (usernameError) {
ErrorMessageProfileComponent(R.string.ErrorUserSignUp)
if (usernameErrorEmpty) {
ErrorMessageProfileComponent(R.string.ErrorUserEmptySignUp)
}
if (usernameErrorExist) {

@ -1,267 +1,8 @@
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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
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.ui.components.ErrorMessageSubmitQuoteComponent
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.states.CurrentUserState
import com.example.what_the_fantasy.ui.theme.colorBackground
import com.example.what_the_fantasy.ui.theme.gradienBox
import com.example.what_the_fantasy.ui.viewModels.CurrentUserViewModel
@Composable
fun SubmitQuotePage(
navFavorite: () -> Unit,
navAccueil: () -> Unit,
navProfil:() -> Unit,
navQuiz: () -> Unit,
navRecap: (String, String, String) -> Unit,
currentUserVM : CurrentUserViewModel,
currentUserState : CurrentUserState,
) {
NavBar(
currentUserVM = currentUserVM,
currentUserState = currentUserState,
navControllerFavorite = navFavorite,
navControllerAccueil = navAccueil,
navControllerProfil = navProfil,
navControllerQuiz = navQuiz
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState()),
contentAlignment = Alignment.Center
){
Column(
modifier = Modifier
.fillMaxWidth(0.9f)
.padding(20.dp)
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.onPrimary)
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
TitlePageComponent(R.string.titleSubmitQuote, MaterialTheme.colorScheme.onBackground)
SpaceHeightComponent(20)
SubmitQuoteButton(
quoteTextField(R.string.quote),
characterTextField(R.string.character),
sourceTextField(R.string.source),
timeCodeTextField(R.string.timeCode),
yearTextField(R.string.year),
R.string.titleButtonSubmit,
18,
MaterialTheme.colorScheme.background,
MaterialTheme.colorScheme.onBackground,
navRecap
)
SpaceHeightComponent(20)
BackButton(R.string.titleButtonBack, 12, Color.White,navProfil)
}
}
}
}
@Composable
fun quoteTextField(textQuoteResId : Int) : String{
val textQuote = stringResource(id = textQuoteResId)
var quote by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField(
value = quote,
onValueChange = { quote = it },
label = { Text(textQuote, color = MaterialTheme.colorScheme.onBackground) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp)
)
}
return quote;
}
@Composable
fun characterTextField(textCharacterResId : Int) : String{
val textCharacter = stringResource(id = textCharacterResId)
var character by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField(
value = character,
onValueChange = { character = it },
label = { Text(textCharacter, color = MaterialTheme.colorScheme.onBackground) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp)
)
}
return character;
}
@Composable
fun sourceTextField(textSourceResId : Int) : String{
val textSource = stringResource(id = textSourceResId)
var source by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField(
value = source,
onValueChange = { source = it },
label = { Text(textSource, color = MaterialTheme.colorScheme.onBackground) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp)
)
}
return source;
}
@Composable
fun timeCodeTextField(textTimeCodeResId : Int) : String{
val textTimeCode = stringResource(id = textTimeCodeResId)
var timeCode by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(top = 16.dp)) {
OutlinedTextField(
value = timeCode,
onValueChange = { timeCode = it },
label = { Text(textTimeCode, color = MaterialTheme.colorScheme.onBackground) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp)
)
}
return timeCode;
}
@Composable
fun yearTextField(textYearResId : Int) : String{
val textYear = stringResource(id = textYearResId)
var year by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(top = 16.dp, bottom = 30.dp)) {
OutlinedTextField(
value = year,
onValueChange = { year = it },
label = { Text(textYear, color = MaterialTheme.colorScheme.onBackground) },
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
shape = RoundedCornerShape(16.dp)
)
}
return year;
}
@Composable
fun SubmitQuoteButton(
quote: String,
character: String,
source: String,
timeCode: String,
year: String,
titleResId: Int,
size: Int,
colorButton: Color,
colorText: Color,
navRecap : (String, String, String) -> Unit
) {
val title = stringResource(id = titleResId)
var showError by remember { mutableStateOf(false) }
Button(
onClick = { showError = !goToRecap(quote, character, source, timeCode, year, navRecap) },
colors = ButtonDefaults.buttonColors(containerColor = colorButton),
modifier = Modifier.fillMaxWidth(),
) {
Text(title, fontSize = size.sp, color = colorText)
}
if (showError) {
ErrorMessageSubmitQuoteComponent(R.string.ErrorSubmitQuote)
}
}
fun goToRecap(quote: String,
character: String,
source: String,
timeCode: String,
year: String,
navRecap : (String, String, String) -> Unit): Boolean {
if (validSubmitQuote(quote, character, source, timeCode, year)) {
navRecap(quote, character, source)
return true
}
return false
}
fun validSubmitQuote(quote : String, character : String, source: String, timeCode: String, year: String): Boolean{
val quoteRegex = """^[A-Za-zÀ-ÿ0-9\s\-\.,!?'"()]+$""".toRegex()
val timeCodeRegex = """^\d{1}:\d{2}:\d{2}$""".toRegex()
val movieTitleRegex = """^[A-Za-z0-9\s\-\(\):]+$""".toRegex()
val characterRegex = """^[A-Za-zÀ-ÿ\s\-']+$""".toRegex()
val invalidRegex = """^[a-zA-Z0-9]*$""".toRegex()
val isNotBlank = quote.isNotBlank() && quote.matches(quoteRegex) && !quote.matches(invalidRegex) && quote.length in 3..100 &&
character.isNotBlank() && character.matches(characterRegex) && character.length in 3..50 && /*!character.matches(invalidRegex) &&*/
source.isNotBlank() && source.matches(movieTitleRegex) && source.length in 3..50 && /*!source.matches(invalidRegex) &&*/
timeCode.isNotBlank() && timeCode.matches(timeCodeRegex) &&
year.isNotBlank() && year.all { it.isDigit() } && year.length == 4 && year.toInt() in 1900..2025
return isNotBlank
}
@Composable
fun BackButton(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()
}
)
}
fun SubmitQuotePage() {
}

@ -1,9 +0,0 @@
package com.example.what_the_fantasy.ui.states
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.data.model.User
data class AuthUserState (
val username : String = "",
val password: String = "",
)

@ -1,13 +0,0 @@
package com.example.what_the_fantasy.ui.states
import com.example.what_the_fantasy.data.model.SrcLanguage
data class CurrentUserState (
var id : Int = -1,
val imagePath : String ="",
var username :String="",
var email : String="",
var password : String="",
var confirmPassword : String="",
val langage : SrcLanguage = SrcLanguage.vo
)

@ -1,7 +0,0 @@
package com.example.what_the_fantasy.ui.states
data class QuoteInformationUserState (
val comment : String ="",
val isFavorite : Boolean = false,
val like : Int = 0
)

@ -1,5 +0,0 @@
package com.example.what_the_fantasy.ui.states
data class SearchState (
var search : String = ""
)

@ -1,8 +0,0 @@
package com.example.what_the_fantasy.ui.states
data class SignInUserState (
val username : String ="",
val email : String ="",
val password : String ="",
val confirmPassword : String ="",
)

@ -1,14 +1,9 @@
package com.example.what_the_fantasy.ui.theme
import android.content.Context
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.core.content.ContextCompat
fun Context.getColorFromRes(resId: Int): Color {
return Color(ContextCompat.getColor(this, resId))
}
import com.example.what_the_fantasy.R
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
@ -17,9 +12,7 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Pink40 = Color(0xFF7D5260)
val likeIcon = Color.Red
val whiteBackcgroundText = Color.Black
val iconText = Color.White
val gradienBox = Brush.linearGradient(
colors = listOf(Color(0xFF7B1FA2), Color(0xFF311B92)), // Violet clair → Violet foncé
start = Offset(0f, 1000f), // Départ en bas à gauche
@ -27,7 +20,6 @@ val gradienBox = Brush.linearGradient(
)
val colorBackground = Color(0xFF100C1B)
val colorNavBar = Color.Black
val colorButtonNavSelected= Color(0xFFC8C8C8)

@ -1,30 +0,0 @@
package com.example.what_the_fantasy.ui.viewModels
import android.util.Log
import androidx.lifecycle.ViewModel
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.states.AuthUserState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
class AuthUserViewModel : ViewModel(){
private val services = ServicesStub() // faire repository qui gère les services Stub et API
private val _userState = MutableStateFlow(AuthUserState())
val userState : StateFlow<AuthUserState> = _userState.asStateFlow()
fun setUsername(username : String){
_userState.update { it.copy(username=username) }
}
fun setPassword(password : String){
_userState.update { it.copy(password=password) }
}
fun validLogin(username : String, passwd : String, navController: (Int) -> Unit, initialierCurrentUser : (Int) -> Unit) : Boolean{
return services.validLogin(username,passwd, navController, initialierCurrentUser)
}
}

@ -1,94 +0,0 @@
package com.example.what_the_fantasy.ui.viewModels
import android.util.Log
import androidx.lifecycle.ViewModel
import com.example.what_the_fantasy.data.model.SrcLanguage
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.states.CurrentUserState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
class CurrentUserViewModel : ViewModel(){
private val services = ServicesStub() // faire repository qui gère les services Stub et API
private val _currentUserState = MutableStateFlow(CurrentUserState())
var currentUserState : StateFlow<CurrentUserState> = _currentUserState.asStateFlow()
fun initialiseCurrentUser(index : Int){
services.getUserById(index)?.let {
setId(it.id)
setUsername(it.username)
setEmail(it.email)
setPassword(it.password)
setLangue(it.langage)
setImage(it.imgUrl)
}
}
fun clearCurrentUser(){
_currentUserState.value = CurrentUserState()
}
fun setId(id : Int){
_currentUserState.update {it.copy(id = id)}
}
fun setUsername(username : String){
_currentUserState.update {it.copy(username = username)}
}
fun setEmail(email : String){
_currentUserState.update {it.copy(email = email)}
}
fun setPassword(password : String){
_currentUserState.update {it.copy(password = password)}
}
fun setLangue(langue : SrcLanguage){
_currentUserState.update {it.copy(langage = langue)}
}
fun setImage(imagePath : String){
_currentUserState.update {it.copy(imagePath = imagePath)}
}
fun editUsername(username : String, index : Int) : Boolean{
_currentUserState.update {it.copy(username = username)}
return services.EditUsername(username, index)
}
fun editEmail(email : String, index : Int) : Boolean{
_currentUserState.update {
it.copy(email = email)
}
return services.EditEmail(email, index)
}
fun editPassword(password : String, index : Int){
services.EditPasswd(password, index)
}
fun editLangue(index : Int){
val langage = services.ChangeLangage(index)
_currentUserState.update {
it.copy(langage = langage)
}
}
fun editImage(index : Int){
val image = services.EditImage(index)
_currentUserState.update {
it.copy(imagePath = image)
}
}
}

@ -1,43 +0,0 @@
package com.example.what_the_fantasy.ui.viewModels
import android.util.Log
import androidx.lifecycle.ViewModel
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.states.QuoteInformationUserState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
class QuoteInformationUserViewModel: ViewModel() {
private val services = ServicesStub() // faire repository qui gère les services Stub et API
private val _quoteState = MutableStateFlow(QuoteInformationUserState())
val quoteState : StateFlow<QuoteInformationUserState> = _quoteState.asStateFlow()
fun setComment(comment : String){
_quoteState.update { it.copy(comment=comment) }
}
fun setFavorite(isFavorite : Boolean){
_quoteState.update { it.copy(isFavorite=isFavorite) }
}
fun setLike(like : Int){
if(like >= 0) {
_quoteState.update { it.copy(like=like) }
}
}
fun addFav(userId: Int, idQuote: Int) {
services.AddFav(userId, idQuote)
setLike(quoteState.value.like + 1)
setFavorite(true)
}
fun supFav(userId: Int, idQuote: Int) {
services.SupFav(userId, idQuote)
setLike(quoteState.value.like - 1)
setFavorite(false)
//Log.e("Like", "Service ${quoteState.value.like}")
}
}

@ -1,27 +0,0 @@
package com.example.what_the_fantasy.ui.viewModels
import androidx.lifecycle.ViewModel
import com.example.what_the_fantasy.data.model.Quote
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.states.CurrentUserState
import com.example.what_the_fantasy.ui.states.SearchState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
class SearchViewModel : ViewModel() {
private val services = ServicesStub() // faire repository qui gère les services Stub et API
private val _searchState = MutableStateFlow(SearchState())
var searchState : StateFlow<SearchState> = _searchState.asStateFlow()
fun setSearch(search : String){
_searchState.update {it.copy(search = search)}
}
fun search(type : String ,search:String ,indexCount: Int): List<Quote>{
return services.search(type,search,indexCount)
}
}

@ -1,35 +0,0 @@
package com.example.what_the_fantasy.ui.viewModels
import androidx.lifecycle.ViewModel
import com.example.what_the_fantasy.data.services.ServicesStub
import com.example.what_the_fantasy.ui.states.SignInUserState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
class SignInUserViewModel: ViewModel() {
private val services = ServicesStub() // faire repository qui gère les services Stub et API
private val _userState = MutableStateFlow(SignInUserState())
val userState : StateFlow<SignInUserState> = _userState.asStateFlow()
fun createUser(username: String, email: String, passwd: String) : Boolean{
return services.CreateUser(username, email, passwd)
}
fun setUsername(username : String){
_userState.update { it.copy(username=username) }
}
fun setEmail(email : String){
_userState.update { it.copy(email=email) }
}
fun setPassword(password : String){
_userState.update { it.copy(password=password) }
}
fun setConfirmPassword(confirmPassword : String){
_userState.update { it.copy(confirmPassword=confirmPassword) }
}
}

@ -4,10 +4,10 @@
android:height="108dp"
android:viewportWidth="202"
android:viewportHeight="202">
<group android:scaleX="1.2"
android:scaleY="1.2"
android:translateX="-20.2"
android:translateY="-20.2">
<group android:scaleX="1.16"
android:scaleY="1.16"
android:translateX="-16.16"
android:translateY="-16.16">
<path
android:pathData="M30,0L172,0A26,26 0,0 1,198 26L198,168A26,26 0,0 1,172 194L30,194A26,26 0,0 1,4 168L4,26A26,26 0,0 1,30 0z">
<aapt:attr name="android:fillColor">

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

@ -1,21 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="202dp"
android:height="202dp"
android:viewportWidth="202"
android:viewportHeight="202">
<path
android:pathData="M30,0L172,0A26,26 0,0 1,198 26L198,168A26,26 0,0 1,172 194L30,194A26,26 0,0 1,4 168L4,26A26,26 0,0 1,30 0z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="198"
android:startY="194"
android:endX="-6.98"
android:endY="181.61"
android:type="linear">
<item android:offset="0" android:color="#FF4A148C"/>
<item android:offset="1" android:color="#FF7B1FA2"/>
</gradient>
</aapt:attr>
</path>
</vector>

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

File diff suppressed because one or more lines are too long

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
</selector>

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

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M115.8,18C90.7,20.2 67,29.2 47.6,43.8c-4.7,3.6 -13.8,12.4 -17.5,17C7.9,88.2 3.8,123.2 19.2,154c4.9,9.8 9.9,16.6 19,26c9.9,10.3 9.8,9.8 10.1,32.1l0.2,17.3l1.2,2.1c2.8,4.7 6.9,7.1 12.1,7.1c2.3,0 3.9,-0.3 5.3,-1c1.2,-0.5 9.1,-5.4 17.7,-10.9c8.6,-5.5 16.7,-10.4 18.2,-10.9c5.1,-1.9 8.2,-2.2 20.1,-2c12.5,0.3 20,-0.2 29.8,-2c12.8,-2.3 24,-6 35.5,-11.8c42.5,-21.2 64.2,-60.6 55.8,-101.5c-6,-29.3 -29.2,-55.7 -61.4,-69.7C162.2,19.8 138.5,16 115.8,18zM145.3,32.4c14.3,1.9 25.6,5.2 37.8,11.1c28.9,14 46.2,37.4 48.7,66.1c1.5,16.2 -2.8,33.1 -11.9,47.1c-13.1,20.1 -36.5,35 -63.8,40.6c-10.9,2.3 -13.4,2.5 -30.3,2.6c-17,0.1 -19.2,0.3 -25.8,2.4c-5.3,1.7 -7.1,2.7 -23.3,13l-14.5,9.3l-0.2,-15.6l-0.2,-15.5l-1.7,-4.8c-2.5,-7.1 -5.3,-11.3 -11.9,-18c-13.7,-13.9 -20.1,-25.2 -23.2,-41.2c-1.3,-6.8 -1.4,-19.4 -0.2,-26.4c4.6,-25.5 21.7,-46.8 48,-59.5c12.7,-6.1 25.8,-9.8 39.7,-11.2c2.8,-0.3 5.8,-0.6 6.7,-0.7C122.5,31.2 140.4,31.8 145.3,32.4z"
android:fillColor="#000000"/>
</vector>

@ -1,18 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportWidth="96"
android:viewportHeight="96">
<path
android:pathData="M45.6,45.8c-38,38.1 -40.4,41 -35.2,42 1.3,0.3 5,-2.8 12.1,-9.8l10.2,-10.2 4.3,2.8c3.7,2.5 5.4,2.9 11,2.9 5.5,-0 7.3,-0.4 10.7,-2.7 6.3,-4.1 8.8,-9 8.8,-16.9 0,-5.5 -0.4,-7.2 -2.9,-10.9l-2.8,-4.3 4.4,-4.3 4.3,-4.4 4.6,3.8c6.1,5 10.6,10.9 13.5,17.9 1.9,4.7 2.7,5.8 4.6,5.8 2,-0 2.3,-0.5 2.1,-3.3 -0.2,-5.8 -5.2,-14.3 -12.8,-21.8l-7.3,-7.2 6.5,-6.3c4.3,-4.3 6.3,-7.1 6.1,-8.4 -0.8,-5.5 -4,-2.9 -42.2,35.3zM60,47.2c7.6,12.4 -9,27.1 -20.1,17.9l-2.4,-2 2.6,-2.6c2.3,-2.3 2.8,-2.5 5.2,-1.4 5.4,2.5 10.5,-2.9 7.7,-8.1 -1,-1.8 -0.8,-2.6 1.1,-4.6 2.9,-3.1 3.5,-3 5.9,0.8z"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
<path
android:pathData="M36,19.6c-9.3,2.5 -16.2,6.4 -23.1,13.3 -10.1,10.2 -15.8,24.1 -10.1,24.9 1.4,0.2 2.4,-0.3 2.8,-1.5 7.1,-21 25.4,-33.7 46,-31.9 6.6,0.5 7.3,0.4 9.3,-1.8l2.3,-2.4 -5.2,-1.1c-6.8,-1.5 -15.3,-1.3 -22,0.5z"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
<path
android:pathData="M41.2,35.1c-6.6,1.9 -14.3,12.8 -13,18.4 0.2,0.7 4.9,-3.3 10.7,-9.1 10.8,-10.9 11,-11.8 2.3,-9.3z"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
</vector>

@ -1,14 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportWidth="96"
android:viewportHeight="96">
<path
android:pathData="M36,19.6c-9.3,2.5 -16.2,6.4 -23.1,13.3 -10.1,10.2 -15.8,24.1 -10.1,24.9 1.4,0.2 2.4,-0.3 2.8,-1.5 2.4,-7.2 6.8,-14.6 11.2,-19 22.4,-22.4 59.9,-14.8 71.8,14.6 1.9,4.5 2.7,5.6 4.6,5.6 5.9,-0 -0.1,-14.5 -10.1,-24.5 -12.9,-12.7 -30.6,-17.8 -47.1,-13.4z"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
<path
android:pathData="M40.5,35.9c-12.5,5.8 -15.5,20.7 -6.1,30.9 11.1,12.2 32.6,3.5 32.6,-13.2 0,-2.5 -0.5,-5.7 -1.1,-7.3 -2.4,-6.4 -10.9,-12.3 -17.9,-12.3 -1.9,-0 -5.3,0.9 -7.5,1.9zM53.5,41.4c10.4,4.4 9.8,20 -1,24.1 -4.5,1.8 -8.8,1.2 -12.5,-1.8 -7.5,-5.8 -6.2,-18.6 2.3,-22.2 4.1,-1.8 6.9,-1.8 11.2,-0.1z"
android:fillColor="#000000"
android:strokeColor="#00000000"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="256"
android:viewportHeight="256">
<path
android:pathData="M96.1,10.5c-18.4,1.9 -36,9.2 -50.7,21.1c-4.1,3.3 -12.3,11.7 -15.2,15.5c-3.9,5 -7.8,11.4 -10.4,16.6C3.7,96.9 7.6,135 30.2,164.6c2.9,3.9 11.2,12.3 15.2,15.5c34.5,27.8 82.4,28.8 117.6,2.4l5.2,-3.9l33.4,33.4c36.3,36.2 34.3,34.5 38.6,33.7c2.2,-0.4 5.1,-3.4 5.5,-5.5c0.8,-4.2 2.4,-2.3 -33.7,-38.6l-33.4,-33.4l3.9,-5.2c26.4,-35.2 25.4,-83.2 -2.4,-117.6c-3.3,-4.1 -11.7,-12.3 -15.5,-15.2C144.7,15 120.4,8 96.1,10.5zM116,25.4c9.6,1.2 17.5,3.6 25.9,7.9c40,20 56.4,68.8 36.5,108.5c-14,27.7 -42,45.1 -72.6,45.1c-27,0 -52.4,-13.7 -67.6,-36.5C18.7,121.3 20.7,82 42.9,54.7c2.7,-3.3 9.4,-9.9 12.7,-12.5C72.2,28.9 95,22.6 116,25.4z"
android:fillColor="#000000"/>
</vector>

File diff suppressed because one or more lines are too long

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save