diff --git a/app/src/main/java/legion/muyue/best2048/MainActivity.java b/app/src/main/java/legion/muyue/best2048/MainActivity.java
index e73060a..d9781f5 100644
--- a/app/src/main/java/legion/muyue/best2048/MainActivity.java
+++ b/app/src/main/java/legion/muyue/best2048/MainActivity.java
@@ -45,6 +45,8 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.view.ViewTreeObserver;
+import android.media.AudioAttributes; // Pour SoundPool
+import android.media.SoundPool; // Pour SoundPool
import java.util.ArrayList;
import java.util.List;
@@ -68,7 +70,7 @@ public class MainActivity extends AppCompatActivity {
private GameStats gameStats;
private static final int BOARD_SIZE = 4;
private static final String NOTIFICATION_CHANNEL_ID = "BEST_2048_CHANNEL";
- private boolean notificationsEnabled = true;
+ private boolean notificationsEnabled = false;
private static final String LAST_PLAYED_TIME_KEY = "last_played_time";
// --- State Management ---
@@ -85,6 +87,15 @@ public class MainActivity extends AppCompatActivity {
private static final String HIGH_SCORE_KEY = "high_score";
private static final String GAME_STATE_KEY = "game_state";
+ // --- Champs Son ---
+ private SoundPool soundPool;
+ private int soundMoveId = -1; // Initialise à -1 pour savoir s'ils sont chargés
+ private int soundMergeId = -1;
+ private int soundWinId = -1;
+ private int soundGameOverId = -1;
+ private boolean soundPoolLoaded = false; // Flag pour savoir si les sons sont prêts
+ private boolean soundEnabled = true; // Son activé par défaut
+
// --- Activity Lifecycle ---
private final ActivityResultLauncher requestPermissionLauncher =
@@ -115,6 +126,7 @@ public class MainActivity extends AppCompatActivity {
NotificationHelper.createNotificationChannel(this);
createNotificationChannel();
findViews();
+ initializeSoundPool();
initializeGameAndStats();
setupListeners();
if (notificationsEnabled) {
@@ -231,6 +243,15 @@ public class MainActivity extends AppCompatActivity {
}
}
+ @Override
+ protected void onDestroy() { // Important de libérer SoundPool
+ super.onDestroy();
+ if (soundPool != null) {
+ soundPool.release();
+ soundPool = null;
+ }
+ }
+
// --- Initialisation ---
/**
@@ -256,6 +277,7 @@ public class MainActivity extends AppCompatActivity {
preferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
gameStats = new GameStats(this);
loadNotificationPreference();
+ loadSoundPreference();
loadGame(); // Charge jeu et met à jour high score
updateUI();
if (game == null) {
@@ -265,6 +287,73 @@ public class MainActivity extends AppCompatActivity {
// L'état (currentGameState) est défini dans loadGame ou startNewGame
}
+ /** Initialise le SoundPool et charge les effets sonores. */
+ private void initializeSoundPool() {
+ // Configuration pour les effets sonores de jeu
+ AudioAttributes attributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_GAME)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+
+ // Crée le SoundPool
+ soundPool = new SoundPool.Builder()
+ .setMaxStreams(3) // Nombre max de sons joués simultanément
+ .setAudioAttributes(attributes)
+ .build();
+
+ // Listener pour savoir quand les sons sont chargés
+ soundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> {
+ if (status == 0) {
+ // Vérifie si TOUS les sons sont chargés (ou gère individuellement)
+ // Ici, on met juste un flag général pour simplifier
+ soundPoolLoaded = true;
+ }
+ });
+
+ // Charge les sons depuis res/raw
+ // Le 3ème argument (priority) est 1 (priorité normale)
+ try {
+ soundMoveId = soundPool.load(this, R.raw.move, 1);
+ soundMergeId = soundPool.load(this, R.raw.merge, 1);
+ soundWinId = soundPool.load(this, R.raw.win, 1);
+ soundGameOverId = soundPool.load(this, R.raw.game_over, 1);
+ } catch (Exception e) {
+ // Gérer l'erreur, peut-être désactiver le son
+ soundEnabled = false;
+ }
+ }
+
+ // --- Préférences Son ---
+
+ /** Sauvegarde la préférence d'activation du son. */
+ private void saveSoundPreference(boolean enabled) {
+ if (preferences != null) {
+ preferences.edit().putBoolean("sound_enabled", enabled).apply();
+ }
+ }
+
+ /** Charge la préférence d'activation du son. */
+ private void loadSoundPreference() {
+ if (preferences != null) {
+ soundEnabled = preferences.getBoolean("sound_enabled", true); // Son activé par défaut
+ } else {
+ soundEnabled = true;
+ }
+ }
+
+ // --- Lecture Son ---
+
+ /**
+ * Joue un effet sonore si le SoundPool est chargé et si le son est activé.
+ * @param soundId L'ID du son retourné par soundPool.load().
+ */
+ private void playSound(int soundId) {
+ if (soundPoolLoaded && soundEnabled && soundPool != null && soundId > 0) {
+ // Arguments: soundID, leftVolume, rightVolume, priority, loop, rate
+ soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1.0f);
+ }
+ }
+
/** Crée le canal de notification nécessaire pour Android 8.0+. */
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -419,6 +508,7 @@ public class MainActivity extends AppCompatActivity {
}
if (boardChanged) {
+ playSound(soundMoveId);
// Capture l'état APRÈS le push mais AVANT l'ajout de la nouvelle tuile
int[][] boardAfterPush = game.getBoard();
@@ -426,6 +516,7 @@ public class MainActivity extends AppCompatActivity {
gameStats.recordMove();
int scoreAfter = game.getCurrentScore();
if (scoreAfter > scoreBefore) {
+ playSound(soundMergeId);
gameStats.recordMerge(1); // Simplifié
if (scoreAfter > game.getHighestScore()) {
game.setHighestScore(scoreAfter);
@@ -608,6 +699,7 @@ public class MainActivity extends AppCompatActivity {
* Propose de continuer à jouer ou de commencer une nouvelle partie.
*/
private void showGameWonKeepPlayingDialog() {
+ playSound(soundWinId);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_game_won, null);
@@ -634,6 +726,7 @@ public class MainActivity extends AppCompatActivity {
* Propose Nouvelle Partie ou Quitter.
*/
private void showGameOverDialog() {
+ playSound(soundGameOverId);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_game_over, null);
@@ -749,10 +842,16 @@ public class MainActivity extends AppCompatActivity {
final AlertDialog dialog = builder.create();
- // Config Son (Placeholder)
- switchSound.setEnabled(false);
- switchSound.setChecked(false);
- switchSound.setOnCheckedChangeListener((v, i) -> Toast.makeText(this, "Gestion du son à venir.", Toast.LENGTH_SHORT).show());
+ // Config Son (MAINTENANT ACTIF)
+ switchSound.setEnabled(true); // Activé
+ switchSound.setChecked(soundEnabled); // État actuel chargé
+ switchSound.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ soundEnabled = isChecked; // Met à jour l'état
+ saveSoundPreference(isChecked); // Sauvegarde la préférence
+ Toast.makeText(this,
+ isChecked ? R.string.sound_enabled : R.string.sound_disabled,
+ Toast.LENGTH_SHORT).show();
+ });
// Config Notifications (Activé + Gestion Permission)
switchNotifications.setEnabled(true); // Activé
@@ -803,7 +902,10 @@ public class MainActivity extends AppCompatActivity {
/** Charge la préférence d'activation des notifications. */
private void loadNotificationPreference() {
if (preferences != null) {
- notificationsEnabled = preferences.getBoolean("notifications_enabled", true); // Activé par défaut
+ // Change le défaut de true à false
+ notificationsEnabled = preferences.getBoolean("notifications_enabled", false);
+ } else {
+ notificationsEnabled = false; // Assure une valeur par défaut si prefs est null
}
}
diff --git a/app/src/main/res/layout/dialog_settings.xml b/app/src/main/res/layout/dialog_settings.xml
index 5eb4930..e1e7200 100644
--- a/app/src/main/res/layout/dialog_settings.xml
+++ b/app/src/main/res/layout/dialog_settings.xml
@@ -30,7 +30,7 @@
android:textSize="16sp"
android:fontFamily="@font/nunito_family"
android:textColor="@color/text_tile_low"
- android:enabled="false" />
+ android:enabled="true" />
https://legion-muyue.fr
OK
Settings
- Sound (coming soon)
- Notifications (coming soon)
+ Sound
+ Notifications
Manage Permissions
Share my Statistics
Reset Statistics
@@ -91,4 +91,6 @@
Notifications disabled.
Test High Score Notif
Test Inactivity Notif
+ Sound effects enabled.
+ Sound effects disabled.
\ No newline at end of file