diff --git a/app/src/main/java/legion/muyue/best2048/MainActivity.java b/app/src/main/java/legion/muyue/best2048/MainActivity.java index d9781f5..2f9915d 100644 --- a/app/src/main/java/legion/muyue/best2048/MainActivity.java +++ b/app/src/main/java/legion/muyue/best2048/MainActivity.java @@ -124,7 +124,6 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); NotificationHelper.createNotificationChannel(this); - createNotificationChannel(); findViews(); initializeSoundPool(); initializeGameAndStats(); @@ -132,52 +131,98 @@ public class MainActivity extends AppCompatActivity { if (notificationsEnabled) { startNotificationService(); } - syncBoardView(); } /** * Synchronise COMPLETEMENT le GridLayout avec l'état actuel de 'game.board'. - * Crée/Met à jour/Supprime les TextViews nécessaires et les stocke dans tileViews. - * C'est la méthode qui assure que l'affichage correspond à la logique à un instant T. + * Étape 1: Ajoute 16 vues de fond pour "fixer" la structure de la grille. + * Étape 2: Ajoute les TextViews des tuiles réelles (valeur > 0) par-dessus. + * Stocke les références des tuiles réelles dans tileViews. */ private void syncBoardView() { - if (game == null) return; - // Log.d("SyncDebug", "Syncing board view..."); + // Vérifications de sécurité + if (game == null || boardGridLayout == null) { + System.err.println("syncBoardView: Game ou GridLayout est null !"); + return; + } + // Log.d("SyncDebug", "Syncing board view (Background + Tiles)..."); - // Pas besoin de removeAllViews si on gère correctement add/remove/update + // --- Réinitialisation --- + boardGridLayout.removeAllViews(); // Vide complètement le GridLayout visuel + // Réinitialise le tableau qui stocke les références aux *vraies* tuiles (pas les fonds) for (int r = 0; r < BOARD_SIZE; r++) { for (int c = 0; c < BOARD_SIZE; c++) { - int value = game.getCellValue(r, c); - TextView currentView = tileViews[r][c]; + tileViews[r][c] = null; + } + } - if (currentView == null && value > 0) { - // Une nouvelle tuile doit apparaître là où il n'y en avait pas - currentView = createTileTextView(value, r, c); - tileViews[r][c] = currentView; - boardGridLayout.addView(currentView); - // Log.d("SyncDebug", "Added view at ["+r+","+c+"]"); - } else if (currentView != null && value == 0) { - // Une tuile doit disparaître - boardGridLayout.removeView(currentView); - tileViews[r][c] = null; - // Log.d("SyncDebug", "Removed view at ["+r+","+c+"]"); - } else if (currentView != null && value > 0) { - // Une tuile existe déjà, on met juste à jour son style/texte - // Vérifie si la valeur a changé (fusion) pour potentielle animation future - // if (!currentView.getText().toString().equals(String.valueOf(value))) { - // Log.d("SyncDebug", "Updating view at ["+r+","+c+"] to "+value); - // } - setTileStyle(currentView, value); // Applique toujours le style correct + // Récupère la marge une seule fois + int gridMargin = (int) getResources().getDimension(R.dimen.tile_margin); + + // --- Étape 1: Ajouter les 16 vues de fond pour définir la grille --- + for (int r = 0; r < BOARD_SIZE; r++) { + for (int c = 0; c < BOARD_SIZE; c++) { + // Utiliser un simple View pour le fond est suffisant + View backgroundCell = new View(this); + + // Appliquer le style d'une cellule vide + // Utilise le même drawable que les tuiles pour les coins arrondis, mais avec la couleur de fond vide + backgroundCell.setBackgroundResource(R.drawable.tile_background); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + // Utiliser setTintList pour la compatibilité et éviter de recréer des drawables + backgroundCell.getBackground().setTintList(ContextCompat.getColorStateList(this, R.color.tile_empty)); + } else { + // Pour les versions plus anciennes, une approche différente pourrait être nécessaire si setTintList n'est pas dispo + // ou utiliser un drawable spécifique pour le fond. Ici on suppose API 21+ pour setTintList. + // Alternative simple mais moins propre : backgroundCell.setBackgroundColor(ContextCompat.getColor(this, R.color.tile_empty)); (perd les coins arrondis) + } + + + // Définir les LayoutParams pour positionner cette vue de fond dans la grille + GridLayout.LayoutParams params = new GridLayout.LayoutParams(); + params.width = 0; + params.height = 0; + // Spécifier ligne, colonne, span=1, et poids=1 pour occuper la cellule + params.rowSpec = GridLayout.spec(r, 1, 1f); + params.columnSpec = GridLayout.spec(c, 1, 1f); + params.setMargins(gridMargin, gridMargin, gridMargin, gridMargin); + backgroundCell.setLayoutParams(params); + + // Ajouter cette vue de fond au GridLayout + boardGridLayout.addView(backgroundCell); + } + } + + // --- Étape 2: Ajouter les TextViews des tuiles réelles (par-dessus les fonds) --- + for (int r = 0; r < BOARD_SIZE; r++) { + for (int c = 0; c < BOARD_SIZE; c++) { + int value = game.getCellValue(r, c); // Récupère la valeur logique + + // Si la case logique contient une tuile réelle + if (value > 0) { + // Crée la TextView stylisée pour cette tuile via notre méthode helper + // createTileTextView utilise les mêmes LayoutParams (row, col, span 1, weight 1, margins) + TextView tileTextView = createTileTextView(value, r, c); + + // Stocke la référence à cette TextView de tuile (pas la vue de fond) + tileViews[r][c] = tileTextView; + + // Ajoute la TextView de la tuile au GridLayout. + // Comme elle est ajoutée après la vue de fond pour la même cellule (r,c) + // et utilise les mêmes paramètres de positionnement, elle s'affichera par-dessus. + boardGridLayout.addView(tileTextView); + // Log.d("SyncDebug", "Added TILE view at ["+r+","+c+"] with value "+value); } - // Si currentView == null && value == 0 -> rien à faire } } // Log.d("SyncDebug", "Board sync finished."); - updateScores(); // Assure que les scores sont aussi à jour + + // Met à jour l'affichage textuel des scores + updateScores(); } /** - * Crée et configure une TextView pour une tuile. (Peut être simplifié) + * Crée et configure une TextView pour une tuile. * @param value Valeur de la tuile. * @param row Ligne. * @param col Colonne. @@ -187,14 +232,16 @@ public class MainActivity extends AppCompatActivity { TextView tileTextView = new TextView(this); setTileStyle(tileTextView, value); // Applique le style visuel - // Les LayoutParams sont nécessaires pour GridLayout GridLayout.LayoutParams params = new GridLayout.LayoutParams(); - // Taille à 0dp pour que le poids (spec) fonctionne - params.width = 0; - params.height = 0; - // Position initiale basée sur row/col, poids pour remplir la cellule - params.rowSpec = GridLayout.spec(row, 1f); - params.columnSpec = GridLayout.spec(col, 1f); + params.width = 0; // Largeur gérée par GridLayout basé sur la colonne/poids + params.height = 0; // Hauteur gérée par GridLayout basé sur la ligne/poids + + // --- Modification : Spécifier explicitement le span (taille) à 1 --- + // Utilisation de spec(start, size, weight) + params.rowSpec = GridLayout.spec(row, 1, 1f); // Commence à 'row', occupe 1 ligne, poids 1 + params.columnSpec = GridLayout.spec(col, 1, 1f); // Commence à 'col', occupe 1 colonne, poids 1 + // --- Fin Modification --- + int margin = (int) getResources().getDimension(R.dimen.tile_margin); params.setMargins(margin, margin, margin, margin); tileTextView.setLayoutParams(params); @@ -687,8 +734,8 @@ public class MainActivity extends AppCompatActivity { if (statisticsVisible) { toggleStatistics(); // Utilise la méthode existante pour masquer proprement } - // Assure que le bouton multijoueur est visible (pourrait être masqué par les stats) - multiplayerButton.setVisibility(View.VISIBLE); + + syncBoardView(); updateUI(); // Met à jour l'affichage (plateau, scores) }