Feat: Notifications OFF par défaut et Implémentation Sonore
- 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.
This commit is contained in:
parent
470649ad36
commit
c4f960f332
@ -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<String> 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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
android:textSize="16sp"
|
||||
android:fontFamily="@font/nunito_family"
|
||||
android:textColor="@color/text_tile_low"
|
||||
android:enabled="false" /> <com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:enabled="true" /> <com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switchNotifications"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -39,7 +39,7 @@
|
||||
android:textSize="16sp"
|
||||
android:fontFamily="@font/nunito_family"
|
||||
android:textColor="@color/text_tile_low"
|
||||
android:enabled="false" /> </LinearLayout>
|
||||
android:enabled="true" /> </LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonManagePermissions"
|
||||
|
BIN
app/src/main/res/raw/game_over.mp3
Normal file
BIN
app/src/main/res/raw/game_over.mp3
Normal file
Binary file not shown.
BIN
app/src/main/res/raw/merge.mp3
Normal file
BIN
app/src/main/res/raw/merge.mp3
Normal file
Binary file not shown.
BIN
app/src/main/res/raw/move.mp3
Normal file
BIN
app/src/main/res/raw/move.mp3
Normal file
Binary file not shown.
BIN
app/src/main/res/raw/win.mp3
Normal file
BIN
app/src/main/res/raw/win.mp3
Normal file
Binary file not shown.
@ -63,8 +63,8 @@
|
||||
<string name="about_website_text">Website : legion-muyue.fr</string> <string name="about_website_url">https://legion-muyue.fr</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="settings_sound_label">Sound (coming soon)</string>
|
||||
<string name="settings_notifications_label">Notifications (coming soon)</string>
|
||||
<string name="settings_sound_label">Sound</string>
|
||||
<string name="settings_notifications_label">Notifications</string>
|
||||
<string name="settings_permissions_button">Manage Permissions</string>
|
||||
<string name="settings_share_stats_button">Share my Statistics</string>
|
||||
<string name="settings_reset_stats_button">Reset Statistics</string>
|
||||
@ -91,4 +91,6 @@
|
||||
<string name="notifications_disabled">Notifications disabled.</string>
|
||||
<string name="settings_test_notif_highscore">Test High Score Notif</string>
|
||||
<string name="settings_test_notif_inactivity">Test Inactivity Notif</string>
|
||||
<string name="sound_enabled">Sound effects enabled.</string>
|
||||
<string name="sound_disabled">Sound effects disabled.</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user