diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7e97d2a..178f664 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { implementation(libs.androidx.navigation.compose) implementation(libs.retrofit) implementation(libs.converter.gson) + implementation("io.coil-kt:coil-compose:2.4.0") testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/fr/univpau/queezer/Fetcher.kt b/app/src/main/java/fr/univpau/queezer/Fetcher.kt deleted file mode 100644 index 6d90f6f..0000000 --- a/app/src/main/java/fr/univpau/queezer/Fetcher.kt +++ /dev/null @@ -1,61 +0,0 @@ -package fr.univpau.queezer - -import android.util.Log -import androidx.compose.runtime.MutableState -import com.google.gson.Gson -import com.google.gson.JsonObject -import com.google.gson.reflect.TypeToken -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import java.net.HttpURLConnection -import java.net.URL - -data class Track( - val title: String, - val artist: Artist, - val preview: String, - val album: Album -) - -data class Artist( - val name: String -) - -data class Album( - val cover: String -) - - -suspend fun fetchTracks(apiUrl: String): List { - return withContext(Dispatchers.IO) { - try { - val url = URL(apiUrl) - val connection = url.openConnection() as HttpURLConnection - connection.requestMethod = "GET" - - if (connection.responseCode == HttpURLConnection.HTTP_OK) { - val response = connection.inputStream.bufferedReader().use { it.readText() } - val json = Gson().fromJson(response, JsonObject::class.java) - val tracksJson = json["tracks"].asJsonObject["data"].toString() - val trackListType = object : TypeToken>() {}.type - Gson().fromJson>(tracksJson, trackListType) - } else { - emptyList() - } - } catch (e: Exception) { - e.printStackTrace() - emptyList() - } - } -} - -suspend fun displayTracks(apiUrl: String) { - val tracks = fetchTracks(apiUrl) - - tracks?.forEach { track -> - Log.d("Track", track.title) - Log.d("Artist", track.artist.name) - Log.d("Preview", track.preview) - Log.d("Album", track.album.cover) - } -} diff --git a/app/src/main/java/fr/univpau/queezer/GameScreen.kt b/app/src/main/java/fr/univpau/queezer/GameScreen.kt deleted file mode 100644 index 094f7bc..0000000 --- a/app/src/main/java/fr/univpau/queezer/GameScreen.kt +++ /dev/null @@ -1,151 +0,0 @@ -package fr.univpau.queezer - -import android.os.CountDownTimer -import android.util.Log -import android.widget.Toast -import androidx.compose.foundation.layout.Arrangement -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.text.KeyboardOptions -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -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.platform.LocalContext -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.navigation.NavHostController - -@Composable -fun GameScreen(navController: NavHostController) { - val context = LocalContext.current - val loadedSettings = loadSettings(context) - - var selectedGameMode by remember { mutableStateOf(loadedSettings.gameMode) } - val numberOfTitles by remember { mutableIntStateOf(loadedSettings.numberOfTitles.toInt()) } - val playlistUrl by remember { mutableStateOf(loadedSettings.playlistUrl) } - var tracks by remember { mutableStateOf(emptyList()) } - - LaunchedEffect(playlistUrl) { - tracks = fetchTracks(playlistUrl) - if (tracks.isEmpty()) { - // Affiche un message d'erreur en toast - Toast.makeText(context, "Impossible de charger les titres, veuillez vérifier la validité de l'URL.", Toast.LENGTH_SHORT).show() - - // Retourn à l'écran d'accueil - navController.popBackStack() - } - - tracks = tracks.shuffled() // On mélange les titres - Log.i("Tracks", tracks.toString()) - } - - val score = remember { mutableIntStateOf(0) } - val remainingTitles = remember { mutableIntStateOf(numberOfTitles) } // Exemple avec 5 titres restants - val userInput = remember { mutableStateOf("") } - // val albumCover: Painter = painterResource(id = R.drawable.album_cover) // Remplacez par une ressource valide d'album - val isCoverVisible = remember { mutableStateOf(false) } - val totalTime = 30000L // 30 secondes - var timeLeft by remember { mutableStateOf(totalTime / 1000) } - - var currentTrackIndex by remember { mutableIntStateOf(0) } - - // Timer de 30 secondes - LaunchedEffect(Unit) { - object : CountDownTimer(totalTime, 1000) { // Tick toutes les secondes - override fun onTick(millisUntilFinished: Long) { - timeLeft = millisUntilFinished / 1000 // Mettre à jour en secondes - } - - override fun onFinish() { - timeLeft = 0 // Compte à rebours terminé - currentTrackIndex += 1 // Passer à la chanson suivante - } - }.start() - } - - - Column( - modifier = Modifier - .fillMaxSize() - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - // Score - Text("Score : ${score.intValue}", fontSize = 24.sp) - - // Nombre de titres restants - Text("Titres restants : ${remainingTitles.intValue}", fontSize = 20.sp) - - // Timer - Text("Temps restant : $timeLeft s", fontSize = 20.sp) - - // Affichage de la couverture de l'album - if (isCoverVisible.value) { - // Image(painter = albumCover, contentDescription = "Cover", modifier = Modifier.fillMaxWidth()) - } else { - Text("Couverture cachée", fontSize = 18.sp) - } - - // Champ de texte pour entrer la proposition - TextField( - value = userInput.value, - onValueChange = { userInput.value = it }, - label = { Text("Titre / Artiste") }, - keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text), - modifier = Modifier.fillMaxWidth() - ) - - // Bouton Valider la réponse - Button( - onClick = { - // Logique pour valider la réponse, en vérifiant la casse et en ajustant le score - val correctAnswer = "Titre Correct" // Exemple, il faut remplacer par la bonne réponse - if (userInput.value.trim().equals(correctAnswer, ignoreCase = true)) { - score.value += 1 // Ajouter 10 points pour une bonne réponse - } - remainingTitles.value -= 1 - userInput.value = "" // Réinitialiser le champ de texte - // Réinitialiser ou ajuster le timer si nécessaire - } - ) { - Text("Valider") - } - - // Bouton Passer - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { - Button( - onClick = { - // Logique pour passer la chanson - remainingTitles.value -= 1 - // Vous pouvez réinitialiser le timer, ou passer à la chanson suivante - }, - ) { - Text("Passer") - } - - // Bouton Abandonner - Button( - onClick = { - // Logique pour abandonner, peut-être retour à l'écran d'accueil - navController.popBackStack() - }, - ) { - Text("Abandonner") - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/MainActivity.kt b/app/src/main/java/fr/univpau/queezer/MainActivity.kt index 034d5b7..65ac09f 100644 --- a/app/src/main/java/fr/univpau/queezer/MainActivity.kt +++ b/app/src/main/java/fr/univpau/queezer/MainActivity.kt @@ -4,13 +4,12 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.platform.LocalContext import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import androidx.lifecycle.lifecycleScope -import kotlinx.coroutines.launch +import fr.univpau.queezer.screen.GameScreen +import fr.univpau.queezer.screen.HomeScreen +import fr.univpau.queezer.screen.SettingsScreen class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -27,14 +26,8 @@ fun QueezerApp() { val navController = rememberNavController() NavHost(navController = navController, startDestination = "home") { - composable("home") { - HomeScreen(navController) - } - composable("game") { - GameScreen(navController) - } - composable("settings") { - SettingsScreen(navController) - } + composable("home") { HomeScreen(navController) } + composable("game") { GameScreen(navController) } + composable("settings") { SettingsScreen(navController) } } } \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/SharedPreferences.kt b/app/src/main/java/fr/univpau/queezer/SharedPreferences.kt deleted file mode 100644 index 80b46ed..0000000 --- a/app/src/main/java/fr/univpau/queezer/SharedPreferences.kt +++ /dev/null @@ -1,28 +0,0 @@ -package fr.univpau.queezer - -import android.content.Context -import android.content.SharedPreferences - -val gameModes = listOf("Titre Uniquement", "Artiste Uniquement", "Titre et Artiste") - -fun saveSettings(context: Context, gameMode: String, numberOfTitles: String, playlistUrl: String) { - val sharedPreferences: SharedPreferences = - context.getSharedPreferences("AppSettings", Context.MODE_PRIVATE) - with(sharedPreferences.edit()) { - putString("gameMode", gameMode) - putString("numberOfTitles", numberOfTitles) - putString("playlistUrl", playlistUrl) - apply() - } -} - -fun loadSettings(context: Context): Settings { - val sharedPreferences: SharedPreferences = - context.getSharedPreferences("AppSettings", Context.MODE_PRIVATE) - val gameMode = sharedPreferences.getString("gameMode", gameModes[0]) ?: gameModes[0] - val numberOfTitles = sharedPreferences.getString("numberOfTitles", "30") ?: "30" - val playlistUrl = sharedPreferences.getString("playlistUrl", "") ?: "" - return Settings(gameMode, numberOfTitles, playlistUrl) -} - -data class Settings(val gameMode: String, val numberOfTitles: String, val playlistUrl: String) diff --git a/app/src/main/java/fr/univpau/queezer/data/Album.kt b/app/src/main/java/fr/univpau/queezer/data/Album.kt new file mode 100644 index 0000000..1069977 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/Album.kt @@ -0,0 +1,5 @@ +package fr.univpau.queezer.data + +data class Album( + val cover: String +) diff --git a/app/src/main/java/fr/univpau/queezer/data/Artist.kt b/app/src/main/java/fr/univpau/queezer/data/Artist.kt new file mode 100644 index 0000000..a945ba6 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/Artist.kt @@ -0,0 +1,5 @@ +package fr.univpau.queezer.data + +data class Artist( + val name: String +) diff --git a/app/src/main/java/fr/univpau/queezer/data/Game.kt b/app/src/main/java/fr/univpau/queezer/data/Game.kt new file mode 100644 index 0000000..847cdc0 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/Game.kt @@ -0,0 +1,10 @@ +package fr.univpau.queezer.data + +import java.sql.Date + +data class Game( + val settings: Settings, + val tracks: List, + val score: Int, + val date: Date +) diff --git a/app/src/main/java/fr/univpau/queezer/data/GameMode.kt b/app/src/main/java/fr/univpau/queezer/data/GameMode.kt new file mode 100644 index 0000000..d87e6c3 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/GameMode.kt @@ -0,0 +1,7 @@ +package fr.univpau.queezer.data + +enum class GameMode { + TITLE, + ARTIST, + ALL +} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/data/Settings.kt b/app/src/main/java/fr/univpau/queezer/data/Settings.kt new file mode 100644 index 0000000..a28fc46 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/Settings.kt @@ -0,0 +1,27 @@ +package fr.univpau.queezer.data + +import fr.univpau.queezer.R + +data class Settings( + var gameMode: GameMode = GameMode.TITLE, + var numberOfTitles: Int? = 5, + var playlistUrl: String = "https://api.deezer.com/playlist/13279914183", +) { + fun validate(context: android.content.Context) { + if (playlistUrl.isEmpty()) { + throw IllegalArgumentException(context.resources.getString(R.string.error_playlist_url_empty)) + } + + if (!playlistUrl.startsWith("https://api.deezer.com/playlist/")) { + throw IllegalArgumentException(context.resources.getString(R.string.error_playlist_url_invalid)) + } + + if (numberOfTitles == null) { + throw IllegalArgumentException(context.resources.getString(R.string.error_tracks_count_empty)) + } + + if (numberOfTitles!! <= 0) { + throw IllegalArgumentException(context.resources.getString(R.string.error_tracks_count_negative)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/data/Track.kt b/app/src/main/java/fr/univpau/queezer/data/Track.kt new file mode 100644 index 0000000..8a5a1e0 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/data/Track.kt @@ -0,0 +1,8 @@ +package fr.univpau.queezer.data + +data class Track( + val title: String, + val artist: Artist, + val preview: String, + val album: Album +) diff --git a/app/src/main/java/fr/univpau/queezer/manager/AudioManager.kt b/app/src/main/java/fr/univpau/queezer/manager/AudioManager.kt new file mode 100644 index 0000000..44e1316 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/manager/AudioManager.kt @@ -0,0 +1,31 @@ +package fr.univpau.queezer.manager + +import android.media.MediaPlayer + +class AudioManager { + private var mediaPlayer: MediaPlayer = MediaPlayer() + + fun play(url: String) { + mediaPlayer.apply { + setDataSource(url) + prepare() + start() + } + } + + fun stop() { + mediaPlayer.release() + } + + fun pause() { + mediaPlayer.pause() + } + + fun resume() { + mediaPlayer.start() + } + + fun isPlaying(): Boolean { + return mediaPlayer.isPlaying + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/manager/CountdownManager.kt b/app/src/main/java/fr/univpau/queezer/manager/CountdownManager.kt new file mode 100644 index 0000000..60a2faf --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/manager/CountdownManager.kt @@ -0,0 +1,34 @@ +package fr.univpau.queezer.manager + +import android.os.CountDownTimer + +class CountdownManager (val duration: Long, val onFinish: () -> Unit) { + + var timeLeft = duration; + var interval = 1000L; + var timer: CountDownTimer? = null + + private fun create() { + timer = object : CountDownTimer(duration, interval) { + override fun onTick(millisUntilFinished: Long) { + timeLeft = millisUntilFinished / 1000; + } + override fun onFinish() { onFinish() } + } + } + + fun start() { + create() + timer?.start() + } + + fun stop() { + timer?.cancel() + timer = null + } + + fun restart() { + stop() + start() + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/manager/GameManager.kt b/app/src/main/java/fr/univpau/queezer/manager/GameManager.kt new file mode 100644 index 0000000..20a1b50 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/manager/GameManager.kt @@ -0,0 +1,71 @@ +package fr.univpau.queezer.manager + +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.reflect.TypeToken +import fr.univpau.queezer.data.Settings +import fr.univpau.queezer.data.Track +import java.net.HttpURLConnection +import java.net.URL + +class GameManager(var settings: Settings) { + + val audioManager = AudioManager() + val countDownManager = CountdownManager(30000L, onFinish = ::nextTrack) + + var tracks: List = mutableListOf() + + var currentTrackIndex: Int = 0; + var score = 0 + + suspend fun loadTracks() { + val url = URL(settings.playlistUrl) + val connection = url.openConnection() as HttpURLConnection + connection.requestMethod = "GET" + + if (connection.responseCode != HttpURLConnection.HTTP_OK) { + throw Exception("Failed to load tracks") + } + + val response = connection.inputStream.bufferedReader().use { it.readText() } + val json = Gson().fromJson(response, JsonObject::class.java) + val tracksJson = json["tracks"].asJsonObject["data"].toString() + + // Assurez-vous d'utiliser un TypeToken explicite pour une liste de Track + tracks = Gson().fromJson(tracksJson, object : TypeToken>() {}.type) + } + + + fun nextTrack() { + // Stop the current track + audioManager.stop() + + // Play the next track + if (currentTrackIndex >= tracks.size - 1) { + return + } + + currentTrackIndex++ + audioManager.play(getCurrentTrack().preview) + + // Restart the countdown + countDownManager.restart() + } + + fun getCurrentTrack(): Track { + if (tracks.isEmpty()) { + throw IllegalStateException("La liste des pistes est vide") + } + return tracks[currentTrackIndex] + } + + + fun start() { + if (tracks.isEmpty()) { + throw IllegalStateException("Aucune piste n'a été trouvée dans la playlist") + } + countDownManager.start() + audioManager.play(tracks[currentTrackIndex].preview) + + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/univpau/queezer/manager/SettingsManager.kt b/app/src/main/java/fr/univpau/queezer/manager/SettingsManager.kt new file mode 100644 index 0000000..c1682e7 --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/manager/SettingsManager.kt @@ -0,0 +1,32 @@ +package fr.univpau.queezer.manager + +import android.content.Context +import com.google.gson.Gson +import fr.univpau.queezer.data.Settings + +fun saveSettings(context: Context, settings: Settings) { + + val sharedPreferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) + val editor = sharedPreferences.edit() + + // Sérialiser l'objet Settings en JSON + val json = Gson().toJson(settings) + + // Sauvegarder le JSON dans les SharedPreferences + editor.putString("settings", json) + editor.apply() +} + +fun loadSettings(context: Context): Settings { + val sharedPreferences = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) + + // Récupérer le JSON depuis SharedPreferences + val json = sharedPreferences.getString("settings", null) + + // Si le JSON n'est pas null, le convertir en objet Settings + return if (json != null) { + Gson().fromJson(json, Settings::class.java) + } else { + Settings() + } +} diff --git a/app/src/main/java/fr/univpau/queezer/screen/GameScreen.kt b/app/src/main/java/fr/univpau/queezer/screen/GameScreen.kt new file mode 100644 index 0000000..19e1aec --- /dev/null +++ b/app/src/main/java/fr/univpau/queezer/screen/GameScreen.kt @@ -0,0 +1,104 @@ +package fr.univpau.queezer.screen + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio +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.text.KeyboardOptions +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.blur +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import fr.univpau.queezer.R +import fr.univpau.queezer.data.Settings +import fr.univpau.queezer.manager.loadSettings +import coil.compose.AsyncImage + +@Composable +fun GameScreen(navController: NavHostController) { + val context = LocalContext.current + val settings: Settings = loadSettings(context) + + // val gameManager: GameManager = remember { GameManager(settings) } + + // LaunchedEffect(gameManager) { + // gameManager.loadTracks() + // gameManager.start() + // } + + // État de l'utilisateur et des éléments du jeu + val userInput = remember { mutableStateOf("") } + + // Affichage de l'interface + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + + Text("Score : 0", fontSize = 24.sp) + + Text("Temps restant : 30sec", fontSize = 20.sp) + + // Affiche une image a partir d'une url + AsyncImage( + model = "https://api.deezer.com/album/382921287/image", + contentDescription = "Image from URL", + modifier = Modifier + .width(200.dp) + .height(200.dp) + .blur(30.dp) + , + contentScale = ContentScale.Crop + ) + + Text("Titre : Légende Vivante", fontSize = 20.sp) + Text("Artiste : Lorenzo", fontSize = 20.sp) + + // Champ de texte pour entrer la proposition + TextField( + value = userInput.value, + onValueChange = { userInput.value = it }, + label = { Text("Titre / Artiste") }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text), + modifier = Modifier.fillMaxWidth() + ) + + // Bouton Valider la réponse + Button( + onClick = { + userInput.value = "" // Réinitialiser le champ de texte + } + ) { Text(context.resources.getString(R.string.submit)) } + + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { + Button( + onClick = { + userInput.value = "" // Réinitialiser le champ de texte + }, + ) { Text(context.resources.getString(R.string.skip)) } + + Button(onClick = { navController.popBackStack() }) + { Text(context.resources.getString(R.string.give_up)) } + } + } +} diff --git a/app/src/main/java/fr/univpau/queezer/HomeScreen.kt b/app/src/main/java/fr/univpau/queezer/screen/HomeScreen.kt similarity index 98% rename from app/src/main/java/fr/univpau/queezer/HomeScreen.kt rename to app/src/main/java/fr/univpau/queezer/screen/HomeScreen.kt index a518b12..86ab407 100644 --- a/app/src/main/java/fr/univpau/queezer/HomeScreen.kt +++ b/app/src/main/java/fr/univpau/queezer/screen/HomeScreen.kt @@ -1,4 +1,4 @@ -package fr.univpau.queezer +package fr.univpau.queezer.screen import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/app/src/main/java/fr/univpau/queezer/SettingsScreen.kt b/app/src/main/java/fr/univpau/queezer/screen/SettingsScreen.kt similarity index 57% rename from app/src/main/java/fr/univpau/queezer/SettingsScreen.kt rename to app/src/main/java/fr/univpau/queezer/screen/SettingsScreen.kt index fb1ee36..4150653 100644 --- a/app/src/main/java/fr/univpau/queezer/SettingsScreen.kt +++ b/app/src/main/java/fr/univpau/queezer/screen/SettingsScreen.kt @@ -1,5 +1,6 @@ -package fr.univpau.queezer +package fr.univpau.queezer.screen +import android.widget.Toast import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -13,10 +14,8 @@ import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.material3.TextField 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.platform.LocalContext @@ -24,15 +23,16 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavHostController +import fr.univpau.queezer.R +import fr.univpau.queezer.data.GameMode +import fr.univpau.queezer.manager.loadSettings +import fr.univpau.queezer.manager.saveSettings +import java.net.URL @Composable fun SettingsScreen(navController: NavHostController) { val context = LocalContext.current - val loadedSettings = loadSettings(context) - - var selectedGameMode by remember { mutableStateOf(loadedSettings.gameMode) } - var numberOfTitles by remember { mutableStateOf(loadedSettings.numberOfTitles) } - var playlistUrl by remember { mutableStateOf(loadedSettings.playlistUrl) } + val settings = remember { mutableStateOf(loadSettings(context)) } Column( modifier = Modifier @@ -43,7 +43,7 @@ fun SettingsScreen(navController: NavHostController) { ) { // Titre des paramètres Text( - text = "Paramètres", + text = context.resources.getString(R.string.settings), fontSize = 32.sp, modifier = Modifier.padding(bottom = 32.dp) ) @@ -54,10 +54,12 @@ fun SettingsScreen(navController: NavHostController) { horizontalArrangement = Arrangement.SpaceBetween ) { TextField( - value = playlistUrl, - onValueChange = { playlistUrl = it }, - label = { Text("URL de la playlist") }, - modifier = Modifier.fillMaxWidth() + label = { Text(context.resources.getString(R.string.playlist_url_label)) }, + placeholder = { Text(context.resources.getString(R.string.playlist_url_hint)) }, + modifier = Modifier.fillMaxWidth(), + value = settings.value.playlistUrl, + onValueChange = { settings.value = settings.value.copy(playlistUrl = it) }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Uri), ) } @@ -67,11 +69,13 @@ fun SettingsScreen(navController: NavHostController) { horizontalArrangement = Arrangement.SpaceBetween ) { TextField( - value = numberOfTitles, - onValueChange = { numberOfTitles = it }, - label = { Text("Nombre de titres dans une partie") }, + label = { Text(context.resources.getString(R.string.tracks_count_label)) }, + modifier = Modifier.fillMaxWidth(1f), + value = settings.value.numberOfTitles?.toString() ?: "", + onValueChange = { + settings.value = settings.value.copy(numberOfTitles = it.toIntOrNull()) + }, keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), - modifier = Modifier.fillMaxWidth(1f) ) } @@ -82,16 +86,20 @@ fun SettingsScreen(navController: NavHostController) { ) { Column { Text(text = "Mode de jeu", fontSize = 18.sp) - gameModes.forEach { option -> + val gameModes = context.resources.getStringArray(R.array.game_modes) + gameModes.forEachIndexed { index, label -> Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(end = 16.dp) ) { RadioButton( - selected = selectedGameMode == option, - onClick = { selectedGameMode = option } + selected = settings.value.gameMode.ordinal == index, + onClick = { + settings.value = + settings.value.copy(gameMode = GameMode.entries[index]) + } ) - Text(text = option) + Text(text = label) } } } @@ -104,18 +112,21 @@ fun SettingsScreen(navController: NavHostController) { ) { OutlinedButton( onClick = { navController.popBackStack() }, - ) { - Text("Retour") - } + ) { Text(context.resources.getString(R.string.back)) } Button( onClick = { - saveSettings(context, selectedGameMode, numberOfTitles, playlistUrl) - navController.popBackStack() + try { + settings.value.validate(context) + saveSettings(context, settings.value) + navController.popBackStack() + } catch (e: Exception) { + Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() + } }, ) { - Text("Valider") + Text(context.resources.getString(R.string.submit)) } } } -} \ No newline at end of file +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61e9015..b9cc33a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,32 @@ Queezer + + Partie rapide + Partie personnalisée + Paramètre + Score + + + URL de la playlist + https://api.deezer.com/playlist/... + L\'URL de la playlist ne peut pas être vide + L\'URL de la playlist est invalide + + Nombre de titres dans une partie + 10 + Le nombre de titres ne peut pas être vide + Le nombre de titres doit être supérieur à 0 + + Mode de jeu + + Titres + Artistes + Tout + + + Retour + Passer + Abandonner + Valider + \ No newline at end of file