Fixed animation, fixed UI
This commit is contained in:
@@ -6,8 +6,11 @@
|
|||||||
that other apps created.
|
that other apps created.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
<attribution android:tag="oche_gameplay" android:label="@string/attribution_label" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.aldo.apps.ochecompanion;
|
package com.aldo.apps.ochecompanion;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -16,7 +19,9 @@ import android.widget.Toast;
|
|||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
@@ -157,6 +162,15 @@ public class AddPlayerActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||||
|
if (isGranted) {
|
||||||
|
mGetContent.launch("image/*");
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "Permission denied to read images", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the activity is first created. Initializes UI and loads existing player if present.
|
* Called when the activity is first created. Initializes UI and loads existing player if present.
|
||||||
*
|
*
|
||||||
@@ -207,7 +221,7 @@ public class AddPlayerActivity extends AppCompatActivity {
|
|||||||
mCropOverlay = findViewById(R.id.cropOverlay);
|
mCropOverlay = findViewById(R.id.cropOverlay);
|
||||||
|
|
||||||
// Set up click listeners
|
// Set up click listeners
|
||||||
mProfilePictureView.setOnClickListener(v -> mGetContent.launch("image/*"));
|
mProfilePictureView.setOnClickListener(v -> checkForPermissionAndLaunchImagePicker());
|
||||||
mSaveButton.setOnClickListener(v -> savePlayer());
|
mSaveButton.setOnClickListener(v -> savePlayer());
|
||||||
if (mBtnDelete != null) {
|
if (mBtnDelete != null) {
|
||||||
mBtnDelete.setOnClickListener(v -> deletePlayer());
|
mBtnDelete.setOnClickListener(v -> deletePlayer());
|
||||||
@@ -216,6 +230,32 @@ public class AddPlayerActivity extends AppCompatActivity {
|
|||||||
findViewById(R.id.btnCancelCrop).setOnClickListener(v -> exitCropMode());
|
findViewById(R.id.btnCancelCrop).setOnClickListener(v -> exitCropMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkForPermissionAndLaunchImagePicker() {
|
||||||
|
final String permission = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
||||||
|
? Manifest.permission.READ_MEDIA_IMAGES
|
||||||
|
: Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||||
|
|
||||||
|
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// Already have permission
|
||||||
|
mGetContent.launch("image/*");
|
||||||
|
} else if (shouldShowRequestPermissionRationale(permission)) {
|
||||||
|
// Explain to the user why the permission is needed before requesting
|
||||||
|
showRationaleDialog(permission);
|
||||||
|
} else {
|
||||||
|
// Directly request the permission
|
||||||
|
requestPermissionLauncher.launch(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showRationaleDialog(final String permission) {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.txt_permission_hint_title)
|
||||||
|
.setMessage(R.string.txt_permission_hint_description)
|
||||||
|
.setPositiveButton(R.string.txt_permission_hint_button_ok, (d, w) -> requestPermissionLauncher.launch(permission))
|
||||||
|
.setNegativeButton(R.string.txt_permission_hint_button_cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes gesture detectors to handle pinch-to-zoom and pan gestures.
|
* Initializes gesture detectors to handle pinch-to-zoom and pan gestures.
|
||||||
*/
|
*/
|
||||||
@@ -436,7 +476,9 @@ public class AddPlayerActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the selected player from the database.
|
* Deletes the currently loaded player from the database.
|
||||||
|
* Shows confirmation toast and closes the activity upon successful deletion.
|
||||||
|
* Runs database operation on background thread. Does nothing if no player is loaded.
|
||||||
*/
|
*/
|
||||||
private void deletePlayer() {
|
private void deletePlayer() {
|
||||||
if (mExistingPlayer == null) return;
|
if (mExistingPlayer == null) return;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.media.SoundPool;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.VibrationEffect;
|
import android.os.VibrationEffect;
|
||||||
@@ -26,10 +25,8 @@ import androidx.core.view.ViewCompat;
|
|||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
|
||||||
import com.aldo.apps.ochecompanion.database.AppDatabase;
|
import com.aldo.apps.ochecompanion.database.AppDatabase;
|
||||||
import com.aldo.apps.ochecompanion.database.objects.Match;
|
|
||||||
import com.aldo.apps.ochecompanion.database.objects.Player;
|
import com.aldo.apps.ochecompanion.database.objects.Player;
|
||||||
import com.aldo.apps.ochecompanion.database.objects.Statistics;
|
import com.aldo.apps.ochecompanion.database.objects.Statistics;
|
||||||
import com.aldo.apps.ochecompanion.utils.CheckoutConstants;
|
|
||||||
import com.aldo.apps.ochecompanion.utils.CheckoutEngine;
|
import com.aldo.apps.ochecompanion.utils.CheckoutEngine;
|
||||||
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
||||||
import com.aldo.apps.ochecompanion.utils.SoundEngine;
|
import com.aldo.apps.ochecompanion.utils.SoundEngine;
|
||||||
@@ -169,7 +166,7 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
/**
|
/**
|
||||||
* Array of three TextViews showing darts thrown in current turn.
|
* Array of three TextViews showing darts thrown in current turn.
|
||||||
*/
|
*/
|
||||||
private TextView[] tvDartPills = new TextView[3];
|
private final TextView[] tvDartPills = new TextView[3];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GridLayout container holding numeric keyboard buttons (1-20).
|
* GridLayout container holding numeric keyboard buttons (1-20).
|
||||||
@@ -220,9 +217,7 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
final List<Player> allAvailablePlayers = AppDatabase.getDatabase(GameActivity.this).playerDao().getAllPlayers();
|
final List<Player> allAvailablePlayers = AppDatabase.getDatabase(GameActivity.this).playerDao().getAllPlayers();
|
||||||
Log.d(TAG, "onCreate: allAvailablePlayers = [" + allAvailablePlayers + "]");
|
Log.d(TAG, "onCreate: allAvailablePlayers = [" + allAvailablePlayers + "]");
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> setupGame(allAvailablePlayers));
|
||||||
setupGame(allAvailablePlayers);
|
|
||||||
});
|
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +390,16 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates player statistics in the database after a turn.
|
||||||
|
* Tracks darts thrown, points made, missed darts, and updates career average.
|
||||||
|
* Runs on background thread to avoid blocking UI.
|
||||||
|
*
|
||||||
|
* @param active Current player's game state
|
||||||
|
* @param dartsThrown Number of darts thrown this turn
|
||||||
|
* @param pointsMade Total points scored this turn
|
||||||
|
* @param wasBust Whether the turn resulted in a bust
|
||||||
|
*/
|
||||||
private void updatePlayerStats(GameActivity.X01State active, int dartsThrown, int pointsMade, boolean wasBust) {
|
private void updatePlayerStats(GameActivity.X01State active, int dartsThrown, int pointsMade, boolean wasBust) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
final Player player = active.player;
|
final Player player = active.player;
|
||||||
@@ -411,7 +416,7 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
// Calculate career average: total points / total darts thrown
|
// Calculate career average: total points / total darts thrown
|
||||||
final long totalDarts = playerStats.getDartsThrown();
|
final long totalDarts = playerStats.getDartsThrown();
|
||||||
if (totalDarts > 0) {
|
if (totalDarts > 0) {
|
||||||
player.careerAverage = (double) playerStats.getOverallPointsMade() / totalDarts;
|
player.careerAverage = (double) playerStats.getOverallPointsMade() / totalDarts * 3;
|
||||||
} else {
|
} else {
|
||||||
player.careerAverage = 0.0;
|
player.careerAverage = 0.0;
|
||||||
}
|
}
|
||||||
@@ -443,7 +448,15 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
final Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
final Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||||
if (vibrator != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (vibrator != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
vibrator.vibrate(VibrationEffect.createOneShot(300, VibrationEffect.DEFAULT_AMPLITUDE));
|
Log.d(TAG, "submitTurn: Pattern vibration");
|
||||||
|
// Pattern that should match the 180 shout.
|
||||||
|
long[] pattern = {0, 150, 100, 1650, 50, 150, 10, 500, 300, 200};
|
||||||
|
vibrator.vibrate(VibrationEffect.createWaveform(pattern, -1));
|
||||||
|
} else if (vibrator != null) {
|
||||||
|
Log.d(TAG, "submitTurn: Vibrating legacy mode");
|
||||||
|
vibrator.vibrate(500);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "submitTurn: Vibrator not available");
|
||||||
}
|
}
|
||||||
mSoundEngine.playOneHundredAndEightySound();
|
mSoundEngine.playOneHundredAndEightySound();
|
||||||
}
|
}
|
||||||
@@ -601,9 +614,11 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles win condition when a player finishes on zero with a double.
|
* Handles win condition when a player finishes on zero with a double.
|
||||||
* Displays win toast and finishes activity.
|
* Updates statistics, displays win toast, and plays celebration animation.
|
||||||
*
|
*
|
||||||
* @param winner X01State of the winning player
|
* @param winner X01State of the winning player
|
||||||
|
* @param dartsThrown Number of darts thrown in the winning turn
|
||||||
|
* @param pointsMade Points scored in the winning turn
|
||||||
*/
|
*/
|
||||||
private void handleWin(final X01State winner, final int dartsThrown, final int pointsMade) {
|
private void handleWin(final X01State winner, final int dartsThrown, final int pointsMade) {
|
||||||
updatePlayerStats(winner, dartsThrown, pointsMade, false);
|
updatePlayerStats(winner, dartsThrown, pointsMade, false);
|
||||||
@@ -619,6 +634,12 @@ public class GameActivity extends AppCompatActivity {
|
|||||||
// - Offer rematch
|
// - Offer rematch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays confetti animation and displays winner's name overlay.
|
||||||
|
* Shows full-screen dimmer with celebratory confetti effect.
|
||||||
|
*
|
||||||
|
* @param winnerName Name of the winning player to display
|
||||||
|
*/
|
||||||
private void playWinnerAnimation(final String winnerName) {
|
private void playWinnerAnimation(final String winnerName) {
|
||||||
final KonfettiView konfettiView = findViewById(R.id.konfetti_view);
|
final KonfettiView konfettiView = findViewById(R.id.konfetti_view);
|
||||||
final View dimmerLayout = findViewById(R.id.dimmer);
|
final View dimmerLayout = findViewById(R.id.dimmer);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
@@ -20,6 +19,7 @@ import com.aldo.apps.ochecompanion.database.AppDatabase;
|
|||||||
import com.aldo.apps.ochecompanion.database.objects.Player;
|
import com.aldo.apps.ochecompanion.database.objects.Player;
|
||||||
import com.aldo.apps.ochecompanion.database.objects.Match;
|
import com.aldo.apps.ochecompanion.database.objects.Match;
|
||||||
import com.aldo.apps.ochecompanion.ui.MatchRecapView;
|
import com.aldo.apps.ochecompanion.ui.MatchRecapView;
|
||||||
|
import com.aldo.apps.ochecompanion.ui.QuickStartButton;
|
||||||
import com.aldo.apps.ochecompanion.ui.adapter.MainMenuPlayerAdapter;
|
import com.aldo.apps.ochecompanion.ui.adapter.MainMenuPlayerAdapter;
|
||||||
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
||||||
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
||||||
@@ -77,7 +77,11 @@ public class MainMenuActivity extends AppCompatActivity {
|
|||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
|
|
||||||
findViewById(R.id.quick_start_btn).setOnClickListener(v -> quickStart());
|
final QuickStartButton quickStartBtn = findViewById(R.id.quick_start_btn);
|
||||||
|
final String defaultGameMode = mSettingsPref.getString(getString(R.string.pref_desc_standard_game_mode),
|
||||||
|
getString(R.string.pref_game_mode_501_value));
|
||||||
|
quickStartBtn.setSubText(defaultGameMode);
|
||||||
|
quickStartBtn.setOnClickListener(v -> quickStart());
|
||||||
findViewById(R.id.btnSettings).setOnClickListener(v -> launchSettings());
|
findViewById(R.id.btnSettings).setOnClickListener(v -> launchSettings());
|
||||||
|
|
||||||
// Set up match recap view with test data functionality
|
// Set up match recap view with test data functionality
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
package com.aldo.apps.ochecompanion.utils;
|
package com.aldo.apps.ochecompanion.utils;
|
||||||
|
|
||||||
|
import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
|
||||||
|
import static android.media.AudioAttributes.USAGE_GAME;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.AudioAttributes;
|
||||||
import android.media.SoundPool;
|
import android.media.SoundPool;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.aldo.apps.ochecompanion.R;
|
import com.aldo.apps.ochecompanion.R;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
/**
|
||||||
import java.util.SimpleTimeZone;
|
* Singleton sound engine for managing game audio effects.
|
||||||
|
* Uses Android SoundPool API for low-latency sound playback during gameplay.
|
||||||
|
* Supports winner celebration, bust notifications, and perfect score achievements.
|
||||||
|
*/
|
||||||
public final class SoundEngine {
|
public final class SoundEngine {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,30 +23,80 @@ public final class SoundEngine {
|
|||||||
*/
|
*/
|
||||||
private static final String TAG = "SoundEngine";
|
private static final String TAG = "SoundEngine";
|
||||||
|
|
||||||
private Context mContext;
|
/**
|
||||||
|
* Application context used for audio operations.
|
||||||
|
* On Android R+, uses attribution context for proper audio tracking.
|
||||||
|
*/
|
||||||
|
private final Context mContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton instance of the SoundEngine.
|
||||||
|
*/
|
||||||
private static SoundEngine sInstance;
|
private static SoundEngine sInstance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android SoundPool for low-latency audio playback.
|
||||||
|
* Configured with game audio attributes and max 5 concurrent streams.
|
||||||
|
*/
|
||||||
private final SoundPool mSoundPool;
|
private final SoundPool mSoundPool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating whether all sound resources have been loaded.
|
||||||
|
* Set to true by the OnLoadCompleteListener once all sounds are ready.
|
||||||
|
*/
|
||||||
private boolean mIsReady;
|
private boolean mIsReady;
|
||||||
|
|
||||||
private int mWinnerSoundId;
|
/**
|
||||||
|
* Sound ID for the winner celebration audio effect.
|
||||||
|
* Loaded from R.raw.winner resource.
|
||||||
|
*/
|
||||||
|
private final int mWinnerSoundId;
|
||||||
|
|
||||||
private int mBustedSoundId;
|
/**
|
||||||
|
* Sound ID for the bust notification audio effect.
|
||||||
|
* Loaded from R.raw.busted resource.
|
||||||
|
*/
|
||||||
|
private final int mBustedSoundId;
|
||||||
|
|
||||||
private int m180SoundId;
|
/**
|
||||||
|
* Sound ID for the perfect score (180) celebration audio effect.
|
||||||
|
* Loaded from R.raw.onehundredandeighty resource.
|
||||||
|
*/
|
||||||
|
private final int m180SoundId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor for singleton pattern.
|
||||||
|
* Initializes SoundPool with game audio attributes and preloads sound effects.
|
||||||
|
*
|
||||||
|
* @param context Application context for loading sound resources
|
||||||
|
*/
|
||||||
private SoundEngine(final Context context) {
|
private SoundEngine(final Context context) {
|
||||||
mContext = context;
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
mSoundPool = new SoundPool.Builder().setMaxStreams(5).build();
|
mContext = context.createAttributionContext("oche_gameplay");
|
||||||
|
} else {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
mSoundPool = new SoundPool.Builder()
|
||||||
|
.setMaxStreams(5)
|
||||||
|
.setAudioAttributes(new AudioAttributes.Builder()
|
||||||
|
.setUsage(USAGE_GAME)
|
||||||
|
.setContentType(CONTENT_TYPE_SONIFICATION)
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
mSoundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> mIsReady = true);
|
mSoundPool.setOnLoadCompleteListener((soundPool, sampleId, status) -> mIsReady = true);
|
||||||
mWinnerSoundId = mSoundPool.load(context, R.raw.winner, 1);
|
mWinnerSoundId = mSoundPool.load(context.getApplicationContext(), R.raw.winner, 1);
|
||||||
mBustedSoundId = mSoundPool.load(context, R.raw.busted, 1);
|
mBustedSoundId = mSoundPool.load(context.getApplicationContext(), R.raw.busted, 1);
|
||||||
m180SoundId = mSoundPool.load(context, R.raw.onehundredandeighty, 1);
|
m180SoundId = mSoundPool.load(context.getApplicationContext(), R.raw.onehundredandeighty, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the singleton SoundEngine instance.
|
||||||
|
* Creates instance on first call using the provided context.
|
||||||
|
*
|
||||||
|
* @param context Application context for initialization
|
||||||
|
* @return Singleton SoundEngine instance
|
||||||
|
*/
|
||||||
public static SoundEngine getInstance(final Context context) {
|
public static SoundEngine getInstance(final Context context) {
|
||||||
if (sInstance == null) {
|
if (sInstance == null) {
|
||||||
sInstance = new SoundEngine(context);
|
sInstance = new SoundEngine(context);
|
||||||
@@ -47,6 +104,10 @@ public final class SoundEngine {
|
|||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the winner celebration sound effect.
|
||||||
|
* Only plays if sound engine has finished loading resources.
|
||||||
|
*/
|
||||||
public void playWinnerSound() {
|
public void playWinnerSound() {
|
||||||
if (mIsReady) {
|
if (mIsReady) {
|
||||||
mSoundPool.play(mWinnerSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
mSoundPool.play(mWinnerSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
||||||
@@ -55,6 +116,10 @@ public final class SoundEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the bust notification sound effect.
|
||||||
|
* Only plays if sound engine has finished loading resources.
|
||||||
|
*/
|
||||||
public void playBustedSound() {
|
public void playBustedSound() {
|
||||||
if (mIsReady) {
|
if (mIsReady) {
|
||||||
mSoundPool.play(mBustedSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
mSoundPool.play(mBustedSoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
||||||
@@ -63,6 +128,10 @@ public final class SoundEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the 180 score notification sound effect.
|
||||||
|
* Only plays if sound engine has finished loading resources.
|
||||||
|
*/
|
||||||
public void playOneHundredAndEightySound() {
|
public void playOneHundredAndEightySound() {
|
||||||
if (mIsReady) {
|
if (mIsReady) {
|
||||||
mSoundPool.play(m180SoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
mSoundPool.play(m180SoundId, 1.0f, 1.0f, 0, 0, 1.0f);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:duration="50"
|
android:duration="80"
|
||||||
android:fromXDelta="0"
|
android:fromXDelta="-12"
|
||||||
android:toXDelta="15"
|
android:toXDelta="12"
|
||||||
android:repeatCount="8"
|
android:repeatCount="15"
|
||||||
android:repeatMode="reverse"
|
android:repeatMode="reverse"
|
||||||
android:interpolator="@android:anim/linear_interpolator" />
|
android:interpolator="@android:anim/cycle_interpolator" />
|
||||||
@@ -21,6 +21,10 @@
|
|||||||
<string name="txt_update_profile_username_save">Update Squad</string>
|
<string name="txt_update_profile_username_save">Update Squad</string>
|
||||||
<string name="txt_cancel_crop">Cancel</string>
|
<string name="txt_cancel_crop">Cancel</string>
|
||||||
<string name="txt_confirm_crop">Confirm Crop</string>
|
<string name="txt_confirm_crop">Confirm Crop</string>
|
||||||
|
<string name="txt_permission_hint_title">Image Permission required</string>
|
||||||
|
<string name="txt_permission_hint_description">This app needs access to your images to set a custom profile picture</string>
|
||||||
|
<string name="txt_permission_hint_button_ok">OK</string>
|
||||||
|
<string name="txt_permission_hint_button_cancel">Cancel</string>
|
||||||
|
|
||||||
<!-- GameActivity -->
|
<!-- GameActivity -->
|
||||||
<string name="txt_game_btn_single">Single</string>
|
<string name="txt_game_btn_single">Single</string>
|
||||||
@@ -32,9 +36,9 @@
|
|||||||
<!-- Preference Strings -->
|
<!-- Preference Strings -->
|
||||||
<string name="pref_key_day_night_mode">day_night_mode</string>
|
<string name="pref_key_day_night_mode">day_night_mode</string>
|
||||||
<string name="pref_key_standard_game_mode">standard_game_mode</string>
|
<string name="pref_key_standard_game_mode">standard_game_mode</string>
|
||||||
<string name="pref_game_mode_701_value">701</string>
|
<string name="pref_game_mode_701_value">Standard 701 - Double Out</string>
|
||||||
<string name="pref_game_mode_501_value">501</string>
|
<string name="pref_game_mode_501_value">Standard 501 - Double Out</string>
|
||||||
<string name="pref_game_mode_301_value">301</string>
|
<string name="pref_game_mode_301_value">Standard 301 - Double Out</string>
|
||||||
<string name="pref_game_mode_cricket_value">Cricket</string>
|
<string name="pref_game_mode_cricket_value">Cricket</string>
|
||||||
<string name="pref_desc_day_night_mode">Day/Night Mode</string>
|
<string name="pref_desc_day_night_mode">Day/Night Mode</string>
|
||||||
<string name="pref_title_standard_game_mode">Standard Game Mode</string>
|
<string name="pref_title_standard_game_mode">Standard Game Mode</string>
|
||||||
@@ -61,4 +65,7 @@
|
|||||||
<string name="attachment_summary_on">Automatically download attachments for incoming emails
|
<string name="attachment_summary_on">Automatically download attachments for incoming emails
|
||||||
</string>
|
</string>
|
||||||
<string name="attachment_summary_off">Only download attachments when manually requested</string>
|
<string name="attachment_summary_off">Only download attachments when manually requested</string>
|
||||||
|
|
||||||
|
<!-- Other strings -->
|
||||||
|
<string name="attribution_label">"Oche Game Effects"</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user