Replacesd magic numbers with constants
This commit is contained in:
@@ -19,6 +19,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.aldo.apps.ochecompanion.database.AppDatabase;
|
||||
import com.aldo.apps.ochecompanion.database.objects.Player;
|
||||
import com.aldo.apps.ochecompanion.ui.CropOverlayView;
|
||||
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.imageview.ShapeableImageView;
|
||||
|
||||
@@ -130,7 +131,7 @@ public class AddPlayerActivity extends AppCompatActivity {
|
||||
/**
|
||||
* Current scale factor applied to the crop preview image (1.0 default, clamped 0.1 to 10.0).
|
||||
*/
|
||||
private float mScaleFactor = 1.0f;
|
||||
private float mScaleFactor = UIConstants.SCALE_NORMAL;
|
||||
|
||||
/**
|
||||
* ActivityResultLauncher for selecting images from the device gallery.
|
||||
@@ -207,7 +208,7 @@ public class AddPlayerActivity extends AppCompatActivity {
|
||||
|
||||
// Prevent the image from becoming too small or impossibly large
|
||||
// Clamp between 0.1× (10% size) and 10.0× (1000% size)
|
||||
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
|
||||
mScaleFactor = Math.max(UIConstants.SCALE_MIN_ZOOM, Math.min(mScaleFactor, UIConstants.SCALE_MAX_ZOOM));
|
||||
|
||||
// Apply the scale to both X and Y axes for uniform scaling
|
||||
mIvCropPreview.setScaleX(mScaleFactor);
|
||||
@@ -259,9 +260,9 @@ public class AddPlayerActivity extends AppCompatActivity {
|
||||
mLayoutCropper.setVisibility(View.VISIBLE);
|
||||
|
||||
// Reset transformation state for a fresh start
|
||||
mScaleFactor = 1.0f; // Reset zoom to 100%
|
||||
mIvCropPreview.setScaleX(1.0f);
|
||||
mIvCropPreview.setScaleY(1.0f);
|
||||
mScaleFactor = UIConstants.SCALE_NORMAL; // Reset zoom to 100%
|
||||
mIvCropPreview.setScaleX(UIConstants.SCALE_NORMAL);
|
||||
mIvCropPreview.setScaleY(UIConstants.SCALE_NORMAL);
|
||||
mIvCropPreview.setTranslationX(0); // Reset horizontal position
|
||||
mIvCropPreview.setTranslationY(0); // Reset vertical position
|
||||
|
||||
@@ -371,7 +372,7 @@ public class AddPlayerActivity extends AppCompatActivity {
|
||||
|
||||
// Write bitmap to file as JPEG with 90% quality (good balance of quality/size)
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
bmp.compress(Bitmap.CompressFormat.JPEG, 90, fos);
|
||||
bmp.compress(Bitmap.CompressFormat.JPEG, UIConstants.JPEG_QUALITY, fos);
|
||||
}
|
||||
|
||||
// Return the absolute path for database storage
|
||||
|
||||
@@ -15,6 +15,9 @@ import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.aldo.apps.ochecompanion.database.objects.Player;
|
||||
import com.aldo.apps.ochecompanion.utils.CheckoutConstants;
|
||||
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
||||
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -57,7 +60,7 @@ public class GameActivity extends AppCompatActivity {
|
||||
/**
|
||||
* Starting score for this X01 game (typically 501, 301, or 701).
|
||||
*/
|
||||
private int mStartingScore = 501;
|
||||
private int mStartingScore = DartsConstants.DEFAULT_GAME_SCORE;
|
||||
|
||||
/**
|
||||
* List of player game states, one per participant.
|
||||
@@ -162,7 +165,7 @@ public class GameActivity extends AppCompatActivity {
|
||||
setContentView(R.layout.activity_game);
|
||||
|
||||
// Extract game parameters from intent
|
||||
mStartingScore = getIntent().getIntExtra(EXTRA_START_SCORE, 501);
|
||||
mStartingScore = getIntent().getIntExtra(EXTRA_START_SCORE, DartsConstants.DEFAULT_GAME_SCORE);
|
||||
ArrayList<Player> participants = getIntent().getParcelableArrayListExtra(EXTRA_PLAYERS);
|
||||
|
||||
// Initialize activity components in order
|
||||
@@ -237,7 +240,7 @@ public class GameActivity extends AppCompatActivity {
|
||||
mPlayerStates.add(new X01State("GUEST 1", mStartingScore));
|
||||
}
|
||||
updateUI();
|
||||
setMultiplier(1);
|
||||
setMultiplier(DartsConstants.MULTIPLIER_SINGLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,17 +253,19 @@ public class GameActivity extends AppCompatActivity {
|
||||
if (mCurrentTurnDarts.size() >= 3 || mIsTurnOver) return;
|
||||
|
||||
int points = baseValue * mMultiplier;
|
||||
if (baseValue == 25 && mMultiplier == 3) points = 50; // Triple Bull is Double Bull
|
||||
if (baseValue == DartsConstants.BULL_VALUE && mMultiplier == DartsConstants.MULTIPLIER_TRIPLE) {
|
||||
points = DartsConstants.DOUBLE_BULL_VALUE; // Triple Bull is Double Bull
|
||||
}
|
||||
|
||||
X01State active = mPlayerStates.get(mActivePlayerIndex);
|
||||
int scoreBeforeDart = active.remainingScore;
|
||||
for (int d : mCurrentTurnDarts) scoreBeforeDart -= d;
|
||||
|
||||
int scoreAfterDart = scoreBeforeDart - points;
|
||||
boolean isDouble = (mMultiplier == 2) || (points == 50);
|
||||
boolean isDouble = (mMultiplier == DartsConstants.MULTIPLIER_DOUBLE) || (points == DartsConstants.DOUBLE_BULL_VALUE);
|
||||
|
||||
// --- DOUBLE OUT LOGIC CHECK ---
|
||||
if (scoreAfterDart < 0 || scoreAfterDart == 1 || (scoreAfterDart == 0 && !isDouble)) {
|
||||
if (scoreAfterDart < 0 || scoreAfterDart == DartsConstants.BUST_SCORE || (scoreAfterDart == 0 && !isDouble)) {
|
||||
// BUST CONDITION: Score < 0, Score == 1, or Score == 0 on a non-double
|
||||
mCurrentTurnDarts.add(points);
|
||||
updateTurnIndicators();
|
||||
@@ -279,12 +284,12 @@ public class GameActivity extends AppCompatActivity {
|
||||
updateTurnIndicators();
|
||||
updateUI();
|
||||
|
||||
if (mCurrentTurnDarts.size() == 3) {
|
||||
if (mCurrentTurnDarts.size() == DartsConstants.MAX_DARTS_PER_TURN) {
|
||||
mIsTurnOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
setMultiplier(1);
|
||||
setMultiplier(DartsConstants.MULTIPLIER_SINGLE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,7 +298,7 @@ public class GameActivity extends AppCompatActivity {
|
||||
* @param v The clicked View (Bull button)
|
||||
*/
|
||||
public void onBullTap(final View v) {
|
||||
onNumberTap(25);
|
||||
onNumberTap(DartsConstants.BULL_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,21 +308,21 @@ public class GameActivity extends AppCompatActivity {
|
||||
*/
|
||||
private void setMultiplier(final int m) {
|
||||
mMultiplier = m;
|
||||
btnSingle.setAlpha(m == 1 ? 1.0f : 0.4f);
|
||||
btnDouble.setAlpha(m == 2 ? 1.0f : 0.4f);
|
||||
btnTriple.setAlpha(m == 3 ? 1.0f : 0.4f);
|
||||
btnSingle.setAlpha(m == DartsConstants.MULTIPLIER_SINGLE ? UIConstants.ALPHA_FULL : UIConstants.ALPHA_INACTIVE);
|
||||
btnDouble.setAlpha(m == DartsConstants.MULTIPLIER_DOUBLE ? UIConstants.ALPHA_FULL : UIConstants.ALPHA_INACTIVE);
|
||||
btnTriple.setAlpha(m == DartsConstants.MULTIPLIER_TRIPLE ? UIConstants.ALPHA_FULL : UIConstants.ALPHA_INACTIVE);
|
||||
|
||||
btnSingle.setBackgroundResource(m == 1 ? R.drawable.shape_multiplier_active : 0);
|
||||
btnDouble.setBackgroundResource(m == 2 ? R.drawable.shape_multiplier_red : 0);
|
||||
btnTriple.setBackgroundResource(m == 3 ? R.drawable.shape_multiplier_blue : 0);
|
||||
btnSingle.setBackgroundResource(m == DartsConstants.MULTIPLIER_SINGLE ? R.drawable.shape_multiplier_active : 0);
|
||||
btnDouble.setBackgroundResource(m == DartsConstants.MULTIPLIER_DOUBLE ? R.drawable.shape_multiplier_red : 0);
|
||||
btnTriple.setBackgroundResource(m == DartsConstants.MULTIPLIER_TRIPLE ? R.drawable.shape_multiplier_blue : 0);
|
||||
|
||||
int bgColor, textColor, strokeColor;
|
||||
if (m == 3) {
|
||||
bgColor = Color.parseColor("#1A007AFF");
|
||||
if (m == DartsConstants.MULTIPLIER_TRIPLE) {
|
||||
bgColor = Color.parseColor(UIConstants.COLOR_BG_VALID);
|
||||
textColor = ContextCompat.getColor(this, R.color.triple_blue);
|
||||
strokeColor = textColor;
|
||||
} else if (m == 2) {
|
||||
bgColor = Color.parseColor("#1AFF3B30");
|
||||
} else if (m == DartsConstants.MULTIPLIER_DOUBLE) {
|
||||
bgColor = Color.parseColor(UIConstants.COLOR_BG_BUST);
|
||||
textColor = ContextCompat.getColor(this, R.color.double_red);
|
||||
strokeColor = textColor;
|
||||
} else {
|
||||
@@ -441,15 +446,15 @@ public class GameActivity extends AppCompatActivity {
|
||||
* @param dartsLeft Number of darts remaining (0-3)
|
||||
*/
|
||||
private void updateCheckoutSuggestion(final int score, final int dartsLeft) {
|
||||
if (score <= 170 && score > 1 && dartsLeft > 0) {
|
||||
if (score <= DartsConstants.MAX_CHECKOUT_SCORE && score > DartsConstants.BUST_SCORE && dartsLeft > 0) {
|
||||
String route = CheckoutEngine.getRoute(score, dartsLeft);
|
||||
|
||||
if (route != null) {
|
||||
layoutCheckoutSuggestion.setVisibility(View.VISIBLE);
|
||||
tvCheckout.setText(route);
|
||||
|
||||
Animation pulse = new AlphaAnimation(0.5f, 1.0f);
|
||||
pulse.setDuration(1000);
|
||||
Animation pulse = new AlphaAnimation(UIConstants.ALPHA_PULSE_MIN, UIConstants.ALPHA_PULSE_MAX);
|
||||
pulse.setDuration(UIConstants.ANIMATION_PULSE_DURATION);
|
||||
pulse.setRepeatMode(Animation.REVERSE);
|
||||
pulse.setRepeatCount(Animation.INFINITE);
|
||||
layoutCheckoutSuggestion.startAnimation(pulse);
|
||||
@@ -486,8 +491,8 @@ public class GameActivity extends AppCompatActivity {
|
||||
* @return Display label for UI
|
||||
*/
|
||||
private String getDartLabel(final int score) {
|
||||
if (score == 50) return "DB"; // Double Bull / Bullseye
|
||||
if (score == 25) return "B"; // Single Bull
|
||||
if (score == DartsConstants.DOUBLE_BULL_VALUE) return DartsConstants.LABEL_DOUBLE_BULL; // Double Bull / Bullseye
|
||||
if (score == DartsConstants.BULL_VALUE) return DartsConstants.LABEL_BULL; // Single Bull
|
||||
// Return numeric value for all other scores
|
||||
return String.valueOf(score);
|
||||
}
|
||||
@@ -585,21 +590,6 @@ public class GameActivity extends AppCompatActivity {
|
||||
* @see #getRoute(int, int)
|
||||
*/
|
||||
private static class CheckoutEngine {
|
||||
/**
|
||||
* Pre-calculated checkout routes for classic finishes.
|
||||
*/
|
||||
private static final Map<Integer, String[]> checkoutMap = new HashMap<>();
|
||||
|
||||
// Initialize pre-calculated checkout routes
|
||||
static {
|
||||
checkoutMap.put(170, new String[]{"T20", "T20", "BULL"}); // Max 3-dart checkout
|
||||
checkoutMap.put(141, new String[]{"T20", "T19", "D12"}); // Common high finish
|
||||
// ... add more fixed routes as needed
|
||||
// Examples to add:
|
||||
// checkoutMap.put(167, new String[]{"T20", "T19", "BULL"});
|
||||
// checkoutMap.put(164, new String[]{"T20", "T18", "BULL"});
|
||||
// checkoutMap.put(160, new String[]{"T20", "T20", "D20"});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns optimal checkout route for given score and darts remaining.
|
||||
@@ -611,8 +601,10 @@ public class GameActivity extends AppCompatActivity {
|
||||
*/
|
||||
public static String getRoute(final int score, final int dartsLeft) {
|
||||
// 1. Direct Out check (highest priority)
|
||||
if (score <= 40 && score % 2 == 0) return "D" + (score / 2);
|
||||
if (score == 50) return "BULL";
|
||||
if (score <= DartsConstants.MAX_DIRECT_DOUBLE && score % 2 == 0) {
|
||||
return DartsConstants.PREFIX_DOUBLE + (score / 2);
|
||||
}
|
||||
if (score == DartsConstants.DOUBLE_BULL_VALUE) return DartsConstants.LABEL_BULLSEYE;
|
||||
|
||||
// 2. Logic for Setup Darts (preventing score of 1)
|
||||
if (dartsLeft >= 2) {
|
||||
@@ -620,24 +612,30 @@ public class GameActivity extends AppCompatActivity {
|
||||
// Suggesting 1 leaves 6 (D3). Correct.
|
||||
if (score <= 41 && score % 2 != 0) {
|
||||
// Try to leave a common double (32, 40, 16)
|
||||
if (score - 32 > 0 && score - 32 <= 20) return (score - 32) + " • D16";
|
||||
if (score - 40 > 0 && score - 40 <= 20) return (score - 40) + " • D20";
|
||||
return "1 • D" + ((score - 1) / 2); // Default setup
|
||||
if (score - DartsConstants.SETUP_DOUBLE_32 > 0 && score - DartsConstants.SETUP_DOUBLE_32 <= DartsConstants.MAX_DARTBOARD_NUMBER) {
|
||||
return (score - DartsConstants.SETUP_DOUBLE_32) + DartsConstants.CHECKOUT_SEPARATOR + DartsConstants.PREFIX_DOUBLE + "16";
|
||||
}
|
||||
if (score - DartsConstants.SETUP_DOUBLE_40 > 0 && score - DartsConstants.SETUP_DOUBLE_40 <= DartsConstants.MAX_DARTBOARD_NUMBER) {
|
||||
return (score - DartsConstants.SETUP_DOUBLE_40) + DartsConstants.CHECKOUT_SEPARATOR + DartsConstants.PREFIX_DOUBLE + "20";
|
||||
}
|
||||
return "1" + DartsConstants.CHECKOUT_SEPARATOR + DartsConstants.PREFIX_DOUBLE + ((score - 1) / 2); // Default setup
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback to Map or High Scoring Route
|
||||
if (checkoutMap.containsKey(score) && checkoutMap.get(score).length <= dartsLeft) {
|
||||
String[] parts = checkoutMap.get(score);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
sb.append(parts[i]);
|
||||
if (i < parts.length - 1) sb.append(" • ");
|
||||
if (CheckoutConstants.hasCheckoutRoute(score)) {
|
||||
String[] parts = CheckoutConstants.getCheckoutRoute(score);
|
||||
if (parts != null && parts.length <= dartsLeft) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
sb.append(parts[i]);
|
||||
if (i < parts.length - 1) sb.append(DartsConstants.CHECKOUT_SEPARATOR);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
if (score > 60) return "T20 Route";
|
||||
if (score > DartsConstants.HIGH_SCORE_THRESHOLD) return DartsConstants.LABEL_T20_ROUTE;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import com.aldo.apps.ochecompanion.database.objects.Player;
|
||||
import com.aldo.apps.ochecompanion.models.Match;
|
||||
import com.aldo.apps.ochecompanion.ui.MatchRecapView;
|
||||
import com.aldo.apps.ochecompanion.ui.adapter.MainMenuPlayerAdapter;
|
||||
import com.aldo.apps.ochecompanion.utils.DartsConstants;
|
||||
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -97,13 +99,13 @@ public class MainMenuActivity extends AppCompatActivity {
|
||||
* Test players are not persisted to the database.
|
||||
*/
|
||||
private void quickStart() {
|
||||
final Player playerOne = new Player("Test1", null);
|
||||
final Player playerTwo = new Player("Test2", null);
|
||||
final Player playerOne = new Player(DartsConstants.TEST_PLAYER_1, null);
|
||||
final Player playerTwo = new Player(DartsConstants.TEST_PLAYER_2, null);
|
||||
final ArrayList<Player> players = new ArrayList<>();
|
||||
players.add(playerOne);
|
||||
players.add(playerTwo);
|
||||
|
||||
GameActivity.start(MainMenuActivity.this, players, 501);
|
||||
GameActivity.start(MainMenuActivity.this, players, DartsConstants.DEFAULT_GAME_SCORE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,20 +155,20 @@ public class MainMenuActivity extends AppCompatActivity {
|
||||
*/
|
||||
private void applyTestData(final int counter) {
|
||||
// Create test player objects
|
||||
final Player playerOne = new Player("Test1", null);
|
||||
final Player playerTwo = new Player("Test2", null);
|
||||
final Player playerThree = new Player("Test3", null);
|
||||
final Player playerFour = new Player("Test4", null);
|
||||
final Player playerOne = new Player(DartsConstants.TEST_PLAYER_1, null);
|
||||
final Player playerTwo = new Player(DartsConstants.TEST_PLAYER_2, null);
|
||||
final Player playerThree = new Player(DartsConstants.TEST_PLAYER_3, null);
|
||||
final Player playerFour = new Player(DartsConstants.TEST_PLAYER_4, null);
|
||||
|
||||
// Create test match objects with different player configurations
|
||||
final Match match1on1 = new Match(playerOne, playerTwo);
|
||||
final Match matchGroup = new Match(playerOne, playerTwo, playerThree, playerFour);
|
||||
|
||||
// Cycle through different test scenarios based on counter value
|
||||
if (counter % 3 == 0) {
|
||||
if (counter % UIConstants.TEST_CYCLE_MODULO == 0) {
|
||||
// Scenario 1: No match (null state)
|
||||
mMatchRecap.setMatch(null);
|
||||
} else if (counter % 3 == 1) {
|
||||
} else if (counter % UIConstants.TEST_CYCLE_MODULO == 1) {
|
||||
// Scenario 2: 1v1 match (two players)
|
||||
mMatchRecap.setMatch(match1on1);
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.aldo.apps.ochecompanion.utils.UIConstants;
|
||||
|
||||
/**
|
||||
* Visual cropping guide overlay with semi-transparent mask and center crop window.
|
||||
@@ -48,7 +49,7 @@ public class CropOverlayView extends View {
|
||||
|
||||
/** Initializes paint with Midnight Black at 85% opacity. */
|
||||
private void init() {
|
||||
mMaskPaint.setColor(Color.parseColor("#D90A0A0A"));
|
||||
mMaskPaint.setColor(Color.parseColor(UIConstants.COLOR_MASK_OVERLAY));
|
||||
mMaskPaint.setStyle(Paint.Style.FILL);
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ public class CropOverlayView extends View {
|
||||
protected void onLayout(final boolean changed, final int left, final int top, final int right, final int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
mBoxSize = getWidth() * 0.8f;
|
||||
mBoxSize = getWidth() * UIConstants.CROP_BOX_SIZE_RATIO;
|
||||
final float l = (getWidth() - mBoxSize) / 2;
|
||||
final float t = (getHeight() - mBoxSize) / 2;
|
||||
mCropRect.set(l, t, l + mBoxSize, t + mBoxSize);
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.aldo.apps.ochecompanion.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Pre-calculated checkout routes for classic darts finishes.
|
||||
* Contains standard 3-dart checkout combinations for common scores.
|
||||
*/
|
||||
public final class CheckoutConstants {
|
||||
|
||||
// Prevent instantiation
|
||||
private CheckoutConstants() {
|
||||
throw new UnsupportedOperationException("Constants class cannot be instantiated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of pre-calculated checkout routes.
|
||||
* Key: Target score, Value: Array of dart notations to achieve the checkout
|
||||
*/
|
||||
private static final Map<Integer, String[]> CHECKOUT_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
// Maximum 3-dart checkouts
|
||||
CHECKOUT_MAP.put(170, new String[]{"T20", "T20", "BULL"});
|
||||
CHECKOUT_MAP.put(167, new String[]{"T20", "T19", "BULL"});
|
||||
CHECKOUT_MAP.put(164, new String[]{"T20", "T18", "BULL"});
|
||||
CHECKOUT_MAP.put(161, new String[]{"T20", "T17", "BULL"});
|
||||
CHECKOUT_MAP.put(160, new String[]{"T20", "T20", "D20"});
|
||||
|
||||
// Common high finishes
|
||||
CHECKOUT_MAP.put(141, new String[]{"T20", "T19", "D12"});
|
||||
CHECKOUT_MAP.put(140, new String[]{"T20", "T20", "D10"});
|
||||
CHECKOUT_MAP.put(139, new String[]{"T20", "T19", "D11"});
|
||||
CHECKOUT_MAP.put(138, new String[]{"T20", "T18", "D12"});
|
||||
CHECKOUT_MAP.put(137, new String[]{"T20", "T19", "D10"});
|
||||
CHECKOUT_MAP.put(136, new String[]{"T20", "T20", "D8"});
|
||||
CHECKOUT_MAP.put(135, new String[]{"T20", "T17", "D12"});
|
||||
CHECKOUT_MAP.put(134, new String[]{"T20", "T14", "D16"});
|
||||
CHECKOUT_MAP.put(133, new String[]{"T20", "T19", "D8"});
|
||||
CHECKOUT_MAP.put(132, new String[]{"T20", "T16", "D12"});
|
||||
CHECKOUT_MAP.put(131, new String[]{"T20", "T13", "D16"});
|
||||
CHECKOUT_MAP.put(130, new String[]{"T20", "T20", "D5"});
|
||||
|
||||
// Mid-range finishes
|
||||
CHECKOUT_MAP.put(121, new String[]{"T17", "T18", "D10"});
|
||||
CHECKOUT_MAP.put(120, new String[]{"T20", "20", "D20"});
|
||||
CHECKOUT_MAP.put(119, new String[]{"T19", "T12", "D13"});
|
||||
CHECKOUT_MAP.put(118, new String[]{"T18", "T14", "D14"});
|
||||
CHECKOUT_MAP.put(117, new String[]{"T20", "17", "D20"});
|
||||
CHECKOUT_MAP.put(116, new String[]{"T19", "19", "D20"});
|
||||
CHECKOUT_MAP.put(115, new String[]{"T19", "18", "D20"});
|
||||
CHECKOUT_MAP.put(114, new String[]{"T18", "18", "D20"});
|
||||
CHECKOUT_MAP.put(113, new String[]{"T19", "16", "D20"});
|
||||
CHECKOUT_MAP.put(112, new String[]{"T20", "12", "D20"});
|
||||
CHECKOUT_MAP.put(111, new String[]{"T20", "11", "D20"});
|
||||
CHECKOUT_MAP.put(110, new String[]{"T20", "10", "D20"});
|
||||
|
||||
// Lower finishes
|
||||
CHECKOUT_MAP.put(107, new String[]{"T19", "10", "D20"});
|
||||
CHECKOUT_MAP.put(106, new String[]{"T20", "10", "D18"});
|
||||
CHECKOUT_MAP.put(105, new String[]{"T20", "13", "D16"});
|
||||
CHECKOUT_MAP.put(104, new String[]{"T18", "18", "D16"});
|
||||
CHECKOUT_MAP.put(103, new String[]{"T17", "12", "D20"});
|
||||
CHECKOUT_MAP.put(102, new String[]{"T20", "10", "D16"});
|
||||
CHECKOUT_MAP.put(101, new String[]{"T17", "10", "D20"});
|
||||
CHECKOUT_MAP.put(100, new String[]{"T20", "D20"});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pre-calculated checkout route for a given score.
|
||||
*
|
||||
* @param score The target score to checkout
|
||||
* @return Array of dart notations, or null if no route exists
|
||||
*/
|
||||
public static String[] getCheckoutRoute(final int score) {
|
||||
return CHECKOUT_MAP.get(score);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a pre-calculated checkout route exists for the given score.
|
||||
*
|
||||
* @param score The target score
|
||||
* @return true if a route exists, false otherwise
|
||||
*/
|
||||
public static boolean hasCheckoutRoute(final int score) {
|
||||
return CHECKOUT_MAP.containsKey(score);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all available pre-calculated checkout scores.
|
||||
*
|
||||
* @return Set of scores with pre-calculated routes
|
||||
*/
|
||||
public static java.util.Set<Integer> getAvailableCheckouts() {
|
||||
return CHECKOUT_MAP.keySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.aldo.apps.ochecompanion.utils;
|
||||
|
||||
/**
|
||||
* Central constants for darts game logic and scoring.
|
||||
* Contains standard X01 game values, dart scores, and checkout limits.
|
||||
*/
|
||||
public final class DartsConstants {
|
||||
|
||||
// Prevent instantiation
|
||||
private DartsConstants() {
|
||||
throw new UnsupportedOperationException("Constants class cannot be instantiated");
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
// X01 Game Scores
|
||||
// ========================================================================================
|
||||
|
||||
/** Standard 501 game starting score */
|
||||
public static final int GAME_SCORE_501 = 501;
|
||||
|
||||
/** Standard 301 game starting score */
|
||||
public static final int GAME_SCORE_301 = 301;
|
||||
|
||||
/** Standard 701 game starting score */
|
||||
public static final int GAME_SCORE_701 = 701;
|
||||
|
||||
/** Default game score when not specified */
|
||||
public static final int DEFAULT_GAME_SCORE = GAME_SCORE_501;
|
||||
|
||||
// ========================================================================================
|
||||
// Dart Values
|
||||
// ========================================================================================
|
||||
|
||||
/** Bull/Single bull value */
|
||||
public static final int BULL_VALUE = 25;
|
||||
|
||||
/** Double bull/Bullseye value */
|
||||
public static final int DOUBLE_BULL_VALUE = 50;
|
||||
|
||||
/** Maximum number on dartboard */
|
||||
public static final int MAX_DARTBOARD_NUMBER = 20;
|
||||
|
||||
/** Minimum dartboard number */
|
||||
public static final int MIN_DARTBOARD_NUMBER = 1;
|
||||
|
||||
// ========================================================================================
|
||||
// Multipliers
|
||||
// ========================================================================================
|
||||
|
||||
/** Single multiplier */
|
||||
public static final int MULTIPLIER_SINGLE = 1;
|
||||
|
||||
/** Double multiplier */
|
||||
public static final int MULTIPLIER_DOUBLE = 2;
|
||||
|
||||
/** Triple multiplier */
|
||||
public static final int MULTIPLIER_TRIPLE = 3;
|
||||
|
||||
// ========================================================================================
|
||||
// Checkout Constants
|
||||
// ========================================================================================
|
||||
|
||||
/** Maximum possible checkout score in darts */
|
||||
public static final int MAX_CHECKOUT_SCORE = 170;
|
||||
|
||||
/** Minimum valid checkout score */
|
||||
public static final int MIN_CHECKOUT_SCORE = 2;
|
||||
|
||||
/** Score that results in bust (impossible to finish) */
|
||||
public static final int BUST_SCORE = 1;
|
||||
|
||||
// ========================================================================================
|
||||
// Game Limits
|
||||
// ========================================================================================
|
||||
|
||||
/** Maximum darts per turn */
|
||||
public static final int MAX_DARTS_PER_TURN = 3;
|
||||
|
||||
/** Maximum common double value (D20 = 40) */
|
||||
public static final int MAX_DIRECT_DOUBLE = 40;
|
||||
|
||||
/** Common setup double target (D16 = 32) */
|
||||
public static final int SETUP_DOUBLE_32 = 32;
|
||||
|
||||
/** Common setup double target (D20 = 40) */
|
||||
public static final int SETUP_DOUBLE_40 = 40;
|
||||
|
||||
/** High score threshold for "T20 Route" suggestion */
|
||||
public static final int HIGH_SCORE_THRESHOLD = 60;
|
||||
|
||||
// ========================================================================================
|
||||
// Display Labels
|
||||
// ========================================================================================
|
||||
|
||||
/** Label for double bull/bullseye */
|
||||
public static final String LABEL_DOUBLE_BULL = "DB";
|
||||
|
||||
/** Label for single bull */
|
||||
public static final String LABEL_BULL = "B";
|
||||
|
||||
/** Label for bullseye finish */
|
||||
public static final String LABEL_BULLSEYE = "BULL";
|
||||
|
||||
/** Separator for checkout route steps */
|
||||
public static final String CHECKOUT_SEPARATOR = " • ";
|
||||
|
||||
/** Generic high score route label */
|
||||
public static final String LABEL_T20_ROUTE = "T20 Route";
|
||||
|
||||
/** Prefix for double notation */
|
||||
public static final String PREFIX_DOUBLE = "D";
|
||||
|
||||
/** Prefix for triple notation */
|
||||
public static final String PREFIX_TRIPLE = "T";
|
||||
|
||||
// ========================================================================================
|
||||
// Test/Debug Values
|
||||
// ========================================================================================
|
||||
|
||||
/** Test player 1 name */
|
||||
public static final String TEST_PLAYER_1 = "Test1";
|
||||
|
||||
/** Test player 2 name */
|
||||
public static final String TEST_PLAYER_2 = "Test2";
|
||||
|
||||
/** Test player 3 name */
|
||||
public static final String TEST_PLAYER_3 = "Test3";
|
||||
|
||||
/** Test player 4 name */
|
||||
public static final String TEST_PLAYER_4 = "Test4";
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.aldo.apps.ochecompanion.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
/**
|
||||
* Helper class for accessing Android resources (colors, drawables, strings).
|
||||
* Provides convenient methods to extract resources with proper context handling.
|
||||
*/
|
||||
public final class ResourceHelper {
|
||||
|
||||
// Prevent instantiation
|
||||
private ResourceHelper() {
|
||||
throw new UnsupportedOperationException("Utility class cannot be instantiated");
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
// Color Resources
|
||||
// ========================================================================================
|
||||
|
||||
/**
|
||||
* Gets a color value from resources.
|
||||
*
|
||||
* @param context Application or activity context
|
||||
* @param colorResId Color resource ID (e.g., R.color.volt_green)
|
||||
* @return Resolved color integer value
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getColor(final Context context, @ColorRes final int colorResId) {
|
||||
return ContextCompat.getColor(context, colorResId);
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
// Drawable Resources
|
||||
// ========================================================================================
|
||||
|
||||
/**
|
||||
* Gets a drawable from resources.
|
||||
*
|
||||
* @param context Application or activity context
|
||||
* @param drawableResId Drawable resource ID (e.g., R.drawable.ic_users)
|
||||
* @return Drawable object or null if not found
|
||||
*/
|
||||
public static Drawable getDrawable(final Context context, @DrawableRes final int drawableResId) {
|
||||
return ContextCompat.getDrawable(context, drawableResId);
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
// String Resources
|
||||
// ========================================================================================
|
||||
|
||||
/**
|
||||
* Gets a string from resources.
|
||||
*
|
||||
* @param context Application or activity context
|
||||
* @param stringResId String resource ID (e.g., R.string.app_name)
|
||||
* @return String value
|
||||
*/
|
||||
public static String getString(final Context context, @StringRes final int stringResId) {
|
||||
return context.getString(stringResId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatted string from resources with arguments.
|
||||
*
|
||||
* @param context Application or activity context
|
||||
* @param stringResId String resource ID with format specifiers
|
||||
* @param formatArgs Arguments to format into the string
|
||||
* @return Formatted string value
|
||||
*/
|
||||
public static String getString(final Context context, @StringRes final int stringResId,
|
||||
final Object... formatArgs) {
|
||||
return context.getString(stringResId, formatArgs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.aldo.apps.ochecompanion.utils;
|
||||
|
||||
/**
|
||||
* UI-related constants for animations, opacity, scaling, and durations.
|
||||
*/
|
||||
public final class UIConstants {
|
||||
|
||||
// Prevent instantiation
|
||||
private UIConstants() {
|
||||
throw new UnsupportedOperationException("Constants class cannot be instantiated");
|
||||
}
|
||||
|
||||
// ========================================================================================
|
||||
// Alpha/Opacity Values
|
||||
// ========================================================================================
|
||||
|
||||
/** Full opacity */
|
||||
public static final float ALPHA_FULL = 1.0f;
|
||||
|
||||
/** Inactive/dimmed opacity */
|
||||
public static final float ALPHA_INACTIVE = 0.4f;
|
||||
|
||||
/** Pulse animation minimum alpha */
|
||||
public static final float ALPHA_PULSE_MIN = 0.5f;
|
||||
|
||||
/** Pulse animation maximum alpha */
|
||||
public static final float ALPHA_PULSE_MAX = 1.0f;
|
||||
|
||||
// ========================================================================================
|
||||
// Scale/Zoom Values
|
||||
// ========================================================================================
|
||||
|
||||
/** Normal scale (100%) */
|
||||
public static final float SCALE_NORMAL = 1.0f;
|
||||
|
||||
/** Minimum zoom scale for image cropping (10%) */
|
||||
public static final float SCALE_MIN_ZOOM = 0.1f;
|
||||
|
||||
/** Maximum zoom scale for image cropping (1000%) */
|
||||
public static final float SCALE_MAX_ZOOM = 10.0f;
|
||||
|
||||
/** Crop box size as percentage of view width */
|
||||
public static final float CROP_BOX_SIZE_RATIO = 0.8f;
|
||||
|
||||
// ========================================================================================
|
||||
// Animation Durations
|
||||
// ========================================================================================
|
||||
|
||||
/** Pulse animation duration in milliseconds */
|
||||
public static final int ANIMATION_PULSE_DURATION = 1000;
|
||||
|
||||
// ========================================================================================
|
||||
// Modulo Values for Cycling
|
||||
// ========================================================================================
|
||||
|
||||
/** Modulo for test data cycling (3 states: null, 1v1, group) */
|
||||
public static final int TEST_CYCLE_MODULO = 3;
|
||||
|
||||
// ========================================================================================
|
||||
// Color Values (Hex Codes)
|
||||
// ========================================================================================
|
||||
|
||||
/** Semi-transparent Midnight Black (85% opacity) for crop overlay mask */
|
||||
public static final String COLOR_MASK_OVERLAY = "#D90A0A0A";
|
||||
|
||||
/** Light Blue background tint (10% opacity) for valid/success state */
|
||||
public static final String COLOR_BG_VALID = "#1A007AFF";
|
||||
|
||||
/** Light Red background tint (10% opacity) for bust/error state */
|
||||
public static final String COLOR_BG_BUST = "#1AFF3B30";
|
||||
|
||||
// ========================================================================================
|
||||
// Quality/Compression Values
|
||||
// ========================================================================================
|
||||
|
||||
/** JPEG compression quality (0-100) for profile images */
|
||||
public static final int JPEG_QUALITY = 90;
|
||||
}
|
||||
Reference in New Issue
Block a user