diff --git a/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java b/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java index e0eab33..ee37acb 100644 --- a/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java +++ b/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java @@ -29,6 +29,7 @@ import androidx.preference.PreferenceManager; import com.aldo.apps.ochecompanion.database.AppDatabase; import com.aldo.apps.ochecompanion.database.objects.Player; import com.aldo.apps.ochecompanion.database.objects.Statistics; +import com.aldo.apps.ochecompanion.ui.PlayerStatsView; import com.aldo.apps.ochecompanion.utils.CheckoutEngine; import com.aldo.apps.ochecompanion.utils.DartsConstants; import com.aldo.apps.ochecompanion.utils.SoundEngine; @@ -197,6 +198,16 @@ public class GameActivity extends AppCompatActivity { * Button for selecting triple (3×) multiplier. */ private View btnTriple; + + /** + * The Button to open the stats view. + */ + private MaterialButton mShowStatsBtn; + + /** + * The {@link PlayerStatsView} to display player statistics. + */ + private PlayerStatsView mStatsView; /** * Array of three TextViews showing darts thrown in current turn. @@ -316,6 +327,14 @@ public class GameActivity extends AppCompatActivity { btnDouble.setOnClickListener(v -> setMultiplier(2)); btnTriple.setOnClickListener(v -> setMultiplier(3)); + mShowStatsBtn = findViewById(R.id.show_stats_btn); + mStatsView = findViewById(R.id.player_stats_view); + mShowStatsBtn.setOnClickListener(v -> { + mStatsView.setVisibility(View.VISIBLE); + mShowStatsBtn.setVisibility(View.GONE); + }); + + findViewById(R.id.btnSubmitTurn).setOnClickListener(v -> submitTurn()); findViewById(R.id.btnUndoDart).setOnClickListener(v -> undoLastDart()); } @@ -875,13 +894,28 @@ public class GameActivity extends AppCompatActivity { if (mIsAudioEnabled) { mSoundEngine.playWinnerSound(); } - + + mShowStatsBtn.setVisibility(View.VISIBLE); + attachPlayerStats(); // TODO: Consider adding: - // - Statistics display // - Save match to database // - Offer rematch } + private void attachPlayerStats() { + new Thread(() -> { + try { + final Player player = mPlayerStates.get(mActivePlayerIndex).player; + final Statistics statistics = AppDatabase.getDatabase(GameActivity.this).statisticsDao().getStatisticsForPlayer(player.id); + runOnUiThread(() -> { + mStatsView.bind(player, statistics); + }); + } catch (Exception e) { + Log.e(TAG, "attachPlayerStats: Failed to increment matches", e); + } + }).start(); + } + /** * Plays confetti animation and displays winner's name overlay. * Shows full-screen dimmer with celebratory confetti effect. diff --git a/app/src/main/java/com/aldo/apps/ochecompanion/ui/PlayerStatsView.java b/app/src/main/java/com/aldo/apps/ochecompanion/ui/PlayerStatsView.java new file mode 100644 index 0000000..687692b --- /dev/null +++ b/app/src/main/java/com/aldo/apps/ochecompanion/ui/PlayerStatsView.java @@ -0,0 +1,81 @@ +package com.aldo.apps.ochecompanion.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.widget.ScrollView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.aldo.apps.ochecompanion.R; +import com.aldo.apps.ochecompanion.database.objects.Player; +import com.aldo.apps.ochecompanion.database.objects.Statistics; +import com.bumptech.glide.Glide; +import com.google.android.material.imageview.ShapeableImageView; + +/** + * PlayerStatsView: A complete dashboard component that visualizes a player's + * career performance, including a heatmap and detailed metrics. + */ +public class PlayerStatsView extends ScrollView { + + // UI References + private HeatmapView mHeatmap; + private ShapeableImageView mIvAvatar; + private TextView mTvUsername, mTvCareerAvg, mTvFirst9, mTvCheckoutPct, mTvBestFinish; + private TextView mTvCount60, mTvCount100, mTvCount140, mTvCount180; + + public PlayerStatsView(@NonNull final Context context) { + this(context, null); + } + + public PlayerStatsView(@NonNull final Context context, @Nullable final AttributeSet attrs) { + super(context, attrs); + LayoutInflater.from(context).inflate(R.layout.player_stats_layout, this, true); + initViews(); + } + + private void initViews() { + mHeatmap = findViewById(R.id.statsHeatmap); + mIvAvatar = findViewById(R.id.ivPlayerAvatar); + mTvUsername = findViewById(R.id.tvUsername); + mTvCareerAvg = findViewById(R.id.tvCareerAvgValue); + mTvFirst9 = findViewById(R.id.tvFirst9Value); + mTvCheckoutPct = findViewById(R.id.tvCheckoutPctValue); + mTvBestFinish = findViewById(R.id.tvBestFinishValue); + + // Threshold counters + mTvCount60 = findViewById(R.id.tvCount60); + mTvCount100 = findViewById(R.id.tvCount100); + mTvCount140 = findViewById(R.id.tvCount140); + mTvCount180 = findViewById(R.id.tvCount180); + } + + /** + * Binds both the player identity and their accumulated stats to the UI. + */ + public void bind(@NonNull final Player player, final @NonNull Statistics stats) { + // 1. Identity + mTvUsername.setText(player.username.toUpperCase()); + if (player.profilePictureUri != null) { + Glide.with(getContext()).load(player.profilePictureUri).into(mIvAvatar); + } else { + mIvAvatar.setImageResource(R.drawable.ic_users); + } + + // 2. High-Level Metrics + mTvCareerAvg.setText(String.format("%.1f", stats.getAverage())); + mTvFirst9.setText(String.format("%.1f", stats.getFirst9Average())); + mTvCheckoutPct.setText(String.format("%.1f%%", stats.getCheckoutPercentage())); + mTvBestFinish.setText(String.valueOf(stats.getHighestCheckout())); + + // 3. Threshold Totals + mTvCount60.setText(String.valueOf(stats.getCount60Plus())); + mTvCount100.setText(String.valueOf(stats.getCount100Plus())); + mTvCount140.setText(String.valueOf(stats.getCount140Plus())); + mTvCount180.setText(String.valueOf(stats.getCount180())); + + // 4. Heatmap Rendering + mHeatmap.setStats(stats); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_game.xml b/app/src/main/res/layout/activity_game.xml index 0a23158..b7b1dbc 100644 --- a/app/src/main/res/layout/activity_game.xml +++ b/app/src/main/res/layout/activity_game.xml @@ -177,10 +177,28 @@ android:visibility="gone" tools:text="Zander"/> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/player_stats_layout.xml b/app/src/main/res/layout/player_stats_layout.xml new file mode 100644 index 0000000..2331e60 --- /dev/null +++ b/app/src/main/res/layout/player_stats_layout.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 547cd54..a0a2ef1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,6 +32,7 @@ Triple Bull Submit Turn + Show Stats day_night_mode_auto diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7275ee8..47add06 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -87,4 +87,46 @@ 12dp + + + + + + + + + + + +