Adds a detailed README file for the Best 2048 project.
The README includes:
- Project description and context (university project).
- List of features for both single-player and multiplayer modes.
- Overview of technologies used (Android, Java, network libraries, backend).
- Simplified project structure overview.
- Basic setup instructions for development.
- Mention of the required backend server for multiplayer.
- Instructions on how to play both modes.
- Author information.
Remplace le comportement précédent à la fin d'une partie multijoueur par une boîte de dialogue claire et stylisée.
- Ajout d'une AlertDialog dans MultiplayerActivity affichée via showEndGameDialog lorsque la partie se termine (déclenché par handleMultiplayerGameOver).
- La boîte de dialogue indique si le joueur a gagné, perdu ou fait match nul.
- Inclut un bouton unique ('Menu principal') pour revenir à MainActivity, fermer l'activité multijoueur et clore la connexion WebSocket.
- Création d'un layout personnalisé (dialog_multiplayer_game_over.xml) pour cette boîte de dialogue afin qu'elle corresponde au style visuel des dialogues existants en mode solo (par exemple, dialog_game_over.xml).
- Mise à jour de showEndGameDialog pour charger et utiliser ce layout personnalisé au lieu des méthodes standard d'AlertDialog.Builder pour le titre/message/bouton.
- Ajout des ressources string nécessaires pour les titres, messages et textes des boutons de la nouvelle boîte de dialogue.
This commit incorporates significant improvements and cleaning across the Best 2048 application.
**Code Cleaning & Refactoring:**
- Removed comments, logs (Log.*, System.out), and unused imports/variables/methods from all core Java files:
- MainActivity, Game, GameStats, MultiplayerActivity, NotificationHelper,
OnSwipeTouchListener, ApiClient, ApiService, data classes.
- Removed NotificationService.java as it's replaced by WorkManager.
**Notifications:**
- Replaced the unreliable Handler-based NotificationService with a robust WorkManager implementation (NotificationWorker.java).
- MainActivity now schedules/cancels periodic work for notifications correctly based on user preference and permissions.
- Removed the <service> declaration for NotificationService from AndroidManifest.xml.
- Requires 'androidx.work:work-runtime' dependency in build.gradle.
**Multiplayer Enhancements:**
- **Stats Integration:**
- Added recordMultiplayerWin/Loss/Draw methods to GameStats.
- MultiplayerActivity now correctly calculates game duration and updates GameStats upon game completion.
- Added saveStats() call in MultiplayerActivity.onPause to persist MP stats.
- **Animations:**
- Implemented tile appearance and merge animations in MultiplayerActivity by comparing previous and current board states received via WebSocket.
- **Robustness:**
- Added automatic WebSocket reconnection attempts with UI feedback in MultiplayerActivity.
- Implemented finer-grained handling of server error messages (critical vs. info).
- Added UI feedback for opponent disconnections (inferred from final game state).
- Disabled swipe input during inappropriate times (opponent's turn, disconnected, game over).
**Layout Corrections:**
- Fixed duplicate ID 'average_time_per_game_label' in stats_layout.xml (renamed the multiplayer one to 'average_time_per_game_multi_label').
- Removed the unused 'perfect_game_label' TextView from stats_layout.xml.
- Updated MainActivity's updateStatisticsTextViews to use the corrected ID.
**Localization:**
- Translated all user-facing strings in strings.xml from French to English.
Remplace le polling REST inefficace et les tentatives d'envoi de mouvements via REST par une communication WebSocket complète dans MultiplayerActivity.
Modifications clés :
- Ajout de la dépendance OkHttp pour le support WebSocket (action manuelle).
- Utilisation de OkHttp pour établir et gérer la connexion WebSocket (, ).
- Implémentation d'un () pour gérer les événements :
- Envoi du message 'register' à l'ouverture ().
- Réception et traitement des messages 'gameStateUpdate', 'error', 'info' ().
- Gestion de la fermeture et des erreurs (, , ).
- Mise à jour de l'interface utilisateur (, ) en temps réel basée sur les messages reçus (en utilisant ).
- Modification de pour créer et envoyer les messages 'move' via WebSocket ().
- Suppression complète du mécanisme de polling basé sur .
- Gestion du cycle de vie de la connexion WebSocket dans , , .
- Ajout de classes de données internes pour parser/créer les messages WebSocket JSON (, , , etc.).
Implémente les modifications nécessaires côté client Android pour établir une connexion de base avec l'API REST du serveur multijoueur.
Changements principaux :
- Ajout de la permission INTERNET dans AndroidManifest.xml.
- Correction de l'URL de base (BASE_URL) dans ApiClient pour utiliser HTTPS.
- Déclaration de MultiplayerActivity dans AndroidManifest.xml.
- Correction de l'appel API createOrJoinGame (ApiService et MultiplayerActivity) pour envoyer le playerId dans le corps de la requête (@Body) au lieu d'un paramètre de requête (@Query).
- Utilisation d'un UUID aléatoire temporaire comme playerId côté client.
- Mise à jour de GameStateResponse.java pour inclure targetScore et corriger la logique getMyScore/getOpponentScore.
- Ajout dépendances Retrofit, OkHttp logging, Gson dans build.gradle.
- Création des modèles de données (POJO) pour l'API: GameInfo, GameStateResponse, MoveRequest.
- Création de l'interface Retrofit 'ApiService' définissant les endpoints (create/join, get state, make move).
- Création du client 'ApiClient' pour configurer et fournir l'instance Retrofit.
- Création de 'MultiplayerActivity' et 'activity_multiplayer.xml' pour l'écran de jeu multi.
- Implémentation de base dans MultiplayerActivity:
- Initialisation (findViews, ApiService).
- Tentative de création/rejoindre une partie via API.
- Récupération de l'état initial du jeu via API (fetchGameState).
- Mise à jour basique de l'UI multijoueur (scores, tour, plateau via syncBoardViewMulti).
- Gestion basique des swipes (handleMultiplayerSwipe) : vérification du tour, envoi du mouvement via API.
- Implémentation d'un polling simple et inefficace pour récupérer les coups adverses.
- Gestion basique des erreurs réseau et indicateur de chargement.
- Modification de MainActivity pour lancer MultiplayerActivity via le bouton 'Multijoueur'.
- Notifications:
- Valeur par défaut pour l'activation des notifications mise à 'false'.
- L'utilisateur doit maintenant activer explicitement les notifications via les paramètres.
- Son:
- Ajout de la structure pour les effets sonores via SoundPool.
- Création du dossier 'res/raw' (si nécessaire) pour les fichiers audio (placeholders: move, merge, win, game_over).
- Initialisation de SoundPool et chargement des sons dans MainActivity.onCreate.
- Ajout méthode playSound() pour jouer les effets (vérifie si chargé et activé).
- Déclenchement des sons 'move' et 'merge' dans handleSwipe.
- Déclenchement des sons 'win' et 'game_over' à l'affichage des dialogues correspondants.
- Activation du switch 'Son' dans les paramètres, sauvegarde/chargement de la préférence 'sound_enabled'.
- Libération de SoundPool dans MainActivity.onDestroy.
- Ajout permission POST_NOTIFICATIONS et déclaration NotificationService dans Manifest.
- Création NotificationHelper pour centraliser création canal et affichage notifications.
- Création NotificationService utilisant Handler/postDelayed pour simuler l'envoi
périodique de rappels (HighScore, Inactivité) - NOTE: WorkManager recommandé en prod.
- Modification MainActivity:
- Crée le canal via NotificationHelper.
- Gère la demande de permission POST_NOTIFICATIONS (Android 13+) via ActivityResultLauncher,
déclenchée par le switch dans les paramètres.
- Démarre/Arrête NotificationService en fonction de l'état du switch Notifications.
- Sauvegarde le timestamp de dernière partie jouée dans onPause.
- Utilise NotificationHelper pour afficher la notification d'accomplissement (2048).
- Suppression des méthodes/boutons de test de notification.
- Ajout permission POST_NOTIFICATIONS dans AndroidManifest.xml (Android 13+).
- Création d'un canal de notification ('BEST_2048_CHANNEL') dans MainActivity.onCreate.
- Ajout d'une icône de notification simple (ic_stat_notification_2048.xml).
- Ajout de strings pour les notifications et la gestion des permissions.
- Modification de MainActivity :
- Implémentation de la demande de permission POST_NOTIFICATIONS via ActivityResultLauncher,
déclenchée par l'activation du switch dans les paramètres.
- Ajout méthode utilitaire 'showNotification' utilisant NotificationCompat.Builder.
- Ajout méthodes 'showAchievementNotification', 'showHighScoreNotification' (test), 'showInactivityNotification' (test).
- Déclenchement de 'showAchievementNotification' dans handleSwipe lors de la première victoire.
- Activation du switch 'Notifications' dans le dialogue des paramètres et gestion de son état
via SharedPreferences et demande de permission.
- Ajout (commenté/optionnel) boutons de test pour notifications HighScore/Inactivité.
- NOTE: Notifications périodiques (HighScore, Inactivité) non planifiées, déclenchées
manuellement pour test dans ce commit. Nécessite WorkManager/AlarmManager pour implémentation réelle.
- Création du layout personnalisé 'dialog_settings.xml'.
- Ajout des options dans le dialogue :
- Son (placeholder désactivé).
- Notifications (placeholder désactivé).
- Bouton 'Gérer les Permissions' ouvrant les paramètres système de l'app.
- Bouton 'Partager mes Statistiques' utilisant l'Intent de partage Android.
- Bouton 'Réinitialiser les Statistiques' avec dialogue de confirmation.
- Bouton 'Quitter l'Application'.
- Bouton 'Fermer'.
- Ajout des strings correspondantes.
- Implémentation de showSettingsDialog(), shareStats(), showResetStatsConfirmationDialog(),
resetStatistics() dans MainActivity.
- Ajout de la méthode resetStats() dans GameStats.
- Remplacement de l'AlertDialog simple par un layout personnalisé (dialog_about.xml).
- Mise à jour du message 'À Propos' avec les informations du groupe et contexte projet.
- Ajout d'un TextView cliquable contenant un lien vers le site web 'legion-muyue.fr'.
- Implémentation de l'ouverture du lien dans un navigateur via Intent dans showAboutDialog().
- Intégration d'une police personnalisée (Winky Sans) via res/font et styles.xml
pour améliorer l'apparence générale du texte (scores, boutons, stats, etc.).
- Remplacement de l'AlertDialog simple pour 'Comment Jouer' par un layout
personnalisé (dialog_how_to_play.xml) utilisant un ScrollView pour une
meilleure lisibilité.
- Mise à jour de la méthode showHowToPlayDialog() dans MainActivity pour
utiliser le nouveau layout.
- Ajout des chaînes de caractères pour le menu et ses options dans strings.xml.
- Modification de MainActivity :
- Implémentation de showMenu() pour créer et afficher la liste d'options grâce à un layout personnalisé (dialog_main_menu.xml).
- Ajout de showHowToPlayDialog() affichant les règles de base.
- Ajout de showAboutDialog() affichant des informations sur l'app.
- Ajout de showSettingsDialog() comme placeholder pour les futurs paramètres.
- Suppression des logs de débogage et commentaires superflus.
- Ajout/Amélioration des commentaires JavaDoc pour les classes et méthodes principales
(Game, GameStats, MainActivity, OnSwipeTouchListener).
- Mise à jour des en-têtes de fichiers pour refléter le rôle actuel des classes.
- Revue générale pour la clarté et la cohérence du code.
- Ajout d'un enum GameFlowState (PLAYING, WON_DIALOG_SHOWN, GAME_OVER) dans MainActivity.
- handleSwipe n'accepte les mouvements que si l'état est PLAYING.
- Lors de la première victoire (>= 2048), affiche une nouvelle boîte de dialogue
proposant 'Continuer' ou 'Nouvelle Partie'.
- Si 'Continuer', l'état passe à WON_DIALOG_SHOWN, permettant au jeu de continuer
sans réafficher la dialogue de victoire.
- En cas de Game Over, l'état passe à GAME_OVER et le jeu est bloqué.
- startNewGame réinitialise l'état à PLAYING.
- loadGame détermine l'état initial basé sur le jeu chargé.
- Mise à jour des strings pour les nouvelles dialogues.
- Création de la classe GameStats pour encapsuler les données et la logique des statistiques.
- Implémentation de loadStats() et saveStats() dans GameStats utilisant SharedPreferences.
- Ajout de méthodes dans GameStats pour enregistrer les événements du jeu (startGame, recordMove, recordMerge, recordWin, recordLoss, endGame, updateHighestTile, addPlayTime, setCurrentGameStartTimeMs, setHighestScore).
- Ajout de getters dans GameStats pour l'affichage et de méthodes pour les valeurs calculées (moyennes, pourcentages).
- Déplacement de formatTime() dans GameStats.
- Refactorisation de MainActivity:
- Suppression des champs et méthodes de statistiques individuelles.
- Utilisation d'une instance de GameStats pour gérer les statistiques.
- Mise à jour de handleSwipe, startNewGame, onPause, onResume pour appeler GameStats.
- Mise à jour de updateStatisticsTextViews pour utiliser les getters de GameStats.
- MainActivity gère maintenant le chargement/sauvegarde de l'état sérialisé du jeu et du high score via SharedPreferences, en passant le high score à Game via setHighestScore.
- Refactorisation de Game:
- Suppression de la dépendance au Contexte et SharedPreferences.
- Suppression de la gestion interne du high score (reçoit via setHighestScore).
- Ajout de getBoard() et getHighestTileValue().
- Modification du constructeur et de deserialize pour être indépendants du contexte et du high score.
- Ajout/Mise à jour des commentaires JavaDoc dans les classes modifiées.
- Ajout dialog_restart_confirm.xml et dialog_background.xml pour la confirmation.
- Mise à jour strings.xml avec les textes de la boîte de dialogue.
- Modification de MainActivity:
- Implémentation de showRestartConfirmationDialog.
- Ajout logique SharedPreferences pour saveGame() dans onPause() et loadGame() dans onCreate().
- Modification de Game:
- Ajout constructeur Game(board, score, highScore).
- Ajout setter setHighScore(int).
- Implémentation de serialize() et static deserialize() pour l'état du jeu.
- updateHighScore() appelle maintenant saveHighScore() (stub).
- XML:
- Utilisation de <include> pour les boutons du bas (bottom_buttons_layout.xml).
- Extraction des dimensions dans dimens.xml.
- Définition de styles (ScoreLabelStyle, ButtonStyle, LargeButtonStyle) dans styles.xml.
- Ajout de nombreuses couleurs dans colors.xml.
- Ajout placeholders pour tile_background.xml et button_multiplayer_background.xml.
- Java:
- MainActivity: Utilisation de switch et teinte pour l'apparence des tuiles (setTileAppearance),
utilisation de getString pour les scores, ajout listeners et animations simples aux boutons,
implémentation de restartGame(), ajout stubs autres boutons, ajout enum Direction.
- Game: Ajout champ/méthodes highScore (stubs load/save), appel updateHighScore après fusion,
utilisation de List<int[]> pour emptySpaces.
- OnSwipeTouchListener: Utilisation d'une interface SwipeListener pour découplage.
- Ajout des fichiers d'animation button_press.xml et button_release.xml.
- Modification de MainActivity:
- Récupération des vues (GridLayout, TextViews).
- Implémentation de initGameBoardLayout et updateUI pour dessiner la grille
en fonction de l'état de Game.
- Création et attachement de OnSwipeTouchListener pour gérer les swipes.
- Modification de Game:
- Ajout des getters: getGameBoard, getScore, getHighScore (placeholder).
- Création de OnSwipeTouchListener.java pour la détection des gestes.
- Création de activity_main.xml avec la structure de base (labels score,
conteneur grille, boutons).
- Création de strings.xml avec les textes initiaux.
- Création de colors.xml avec les couleurs de base.
- Création des fichiers drawable tile_*.xml pour l'apparence des tuiles
(vide, 2 à 2048).
- Ajout des méthodes pushLeft et pushRight dans Game.java pour gérer
le déplacement et la fusion horizontaux.
- Logique 'alreadyCombined' adaptée pour les mouvements horizontaux.
- Ajout de logs de débogage pour pushLeft/pushRight.
- Mise à jour de MainActivity pour tester les quatre directions.
- Implémentation de la méthode pushDown dans Game.java pour le mouvement/fusion vers le bas.
- Ajout de la logique 'alreadyCombined' dans pushUp et pushDown pour empêcher
une tuile de fusionner plus d'une fois par mouvement.
- Ajout de logs de débogage pour pushUp/pushDown.
- Mise à jour de MainActivity pour tester pushDown.
- Ajout de l'attribut 'score' à Game.java.
- Implémentation de la méthode pushUp dans Game.java pour gérer:
- Le déplacement des tuiles vers le haut dans les cases vides.
- La fusion des tuiles de même valeur.
- La mise à jour du score lors d'une fusion.
- Modification de MainActivity pour tester pushUp.
- Ajout de retour à la ligne (%n) et d'une ligne vide dans printArray
pour une meilleure lisibilité dans Logcat.
- Ajout de la signature de la méthode pushUp() (vide) dans Game.java.
- Modification de MainActivity pour tester addNewNumbers/printArray 10 fois.
- Ajout d'un générateur Random dans Game.java
- Implémentation de la méthode addNewNumbers pour ajouter une tuile 2, 4 ou 8
sur une case vide aléatoire (Probabilités: 85% pour 2, 10% pour 4, 5% pour 8).
- Appel de addNewNumbers dans MainActivity avant printArray.