Merge pull request #65 from flixcoo/feature/61-implement-graph-for-player-scores

Implement graph for player scores
This commit is contained in:
2025-06-27 19:35:49 +02:00
committed by GitHub
8 changed files with 228 additions and 5 deletions

View File

@@ -14,6 +14,7 @@
"player": "Spieler:in",
"players": "Spieler:innen",
"name": "Name",
"back": "Zurück",
"home": "Home",
"about": "Über",
@@ -63,6 +64,13 @@
"done": "Fertig",
"next_round": "Nächste Runde",
"statistics": "Statistiken",
"delete_game": "Spiel löschen",
"new_game_same_settings": "Neues Spiel mit gleichen Einstellungen",
"export_game": "Spiel exportieren",
"game_process": "Spielverlauf",
"settings": "Einstellungen",
"cabo_penalty": "Cabo-Strafe",
"cabo_penalty_subtitle": "... für falsches Cabo sagen",

View File

@@ -14,6 +14,7 @@
"player": "Player",
"players": "Players",
"name": "Name",
"back": "Back",
"home": "Home",
"about": "About",
@@ -63,6 +64,13 @@
"done": "Done",
"next_round": "Next Round",
"statistics": "Statistics",
"delete_game": "Delete Game",
"new_game_same_settings": "New Game with same Settings",
"export_game": "Export Game",
"game_process": "Spielverlauf",
"settings": "Settings",
"cabo_penalty": "Cabo Penalty",
"cabo_penalty_subtitle": "... for falsely calling Cabo.",
@@ -80,5 +88,6 @@
"app_version": "App Version",
"load_version": "Loading version...",
"build": "Build",
"about_text": "Hey :) Thanks for being one of the first users of my app! Ive put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!"
}

View File

@@ -176,6 +176,12 @@ abstract class AppLocalizations {
/// **'Name'**
String get name;
/// No description provided for @back.
///
/// In de, this message translates to:
/// **'Zurück'**
String get back;
/// No description provided for @home.
///
/// In de, this message translates to:
@@ -356,6 +362,36 @@ abstract class AppLocalizations {
/// **'Nächste Runde'**
String get next_round;
/// No description provided for @statistics.
///
/// In de, this message translates to:
/// **'Statistiken'**
String get statistics;
/// No description provided for @delete_game.
///
/// In de, this message translates to:
/// **'Spiel löschen'**
String get delete_game;
/// No description provided for @new_game_same_settings.
///
/// In de, this message translates to:
/// **'Neues Spiel mit gleichen Einstellungen'**
String get new_game_same_settings;
/// No description provided for @export_game.
///
/// In de, this message translates to:
/// **'Spiel exportieren'**
String get export_game;
/// No description provided for @game_process.
///
/// In de, this message translates to:
/// **'Spielverlauf'**
String get game_process;
/// No description provided for @settings.
///
/// In de, this message translates to:

View File

@@ -47,6 +47,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get name => 'Name';
@override
String get back => 'Zurück';
@override
String get home => 'Home';
@@ -146,6 +149,21 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get next_round => 'Nächste Runde';
@override
String get statistics => 'Statistiken';
@override
String get delete_game => 'Spiel löschen';
@override
String get new_game_same_settings => 'Neues Spiel mit gleichen Einstellungen';
@override
String get export_game => 'Spiel exportieren';
@override
String get game_process => 'Spielverlauf';
@override
String get settings => 'Einstellungen';

View File

@@ -47,6 +47,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get name => 'Name';
@override
String get back => 'Back';
@override
String get home => 'Home';
@@ -58,7 +61,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get empty_text_2 =>
'Add a new round using the button in the top right corner';
'Add a new round using the button in the top right corner.';
@override
String get delete_game_title => 'Delete game?';
@@ -143,6 +146,21 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get next_round => 'Next Round';
@override
String get statistics => 'Statistics';
@override
String get delete_game => 'Delete Game';
@override
String get new_game_same_settings => 'New Game with same Settings';
@override
String get export_game => 'Export Game';
@override
String get game_process => 'Spielverlauf';
@override
String get settings => 'Settings';
@@ -150,13 +168,13 @@ class AppLocalizationsEn extends AppLocalizations {
String get cabo_penalty => 'Cabo Penalty';
@override
String get cabo_penalty_subtitle => '... for falsely calling Cabo';
String get cabo_penalty_subtitle => '... for falsely calling Cabo.';
@override
String get point_limit => 'Point Limit';
@override
String get point_limit_subtitle => '... the game ends here';
String get point_limit_subtitle => '... the game ends here.';
@override
String get reset_to_default => 'Reset to Default';
@@ -196,5 +214,5 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get about_text =>
'Hey :) Thanks for being one of the first users of my first app! Ive put a lot of work into this project, and even though I (hopefully) thought of a lot, not everything will work 100% yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the Testflight app or a message / email. Thank you very much!';
'Hey :) Thanks for being one of the first users of my app! Ive put a lot of work into this project, and even though I tried to think of everything, it might not work perfectly just yet. So if you discover any bugs or have feedback on the design or usability, please let me know via the TestFlight app or by sending me a message or email. Thank you very much!';
}

View File

@@ -1,8 +1,10 @@
import 'package:cabo_counter/data/game_session.dart';
import 'package:cabo_counter/l10n/app_localizations.dart';
import 'package:cabo_counter/utility/custom_theme.dart';
import 'package:cabo_counter/views/graph_view.dart';
import 'package:cabo_counter/views/round_view.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class ActiveGameView extends StatefulWidget {
final GameSession gameSession;
@@ -80,6 +82,8 @@ class _ActiveGameViewState extends State<ActiveGameView> {
return Padding(
padding: const EdgeInsets.all(1),
child: CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(
'${AppLocalizations.of(context).round} ${index + 1}',
),
@@ -107,6 +111,51 @@ class _ActiveGameViewState extends State<ActiveGameView> {
));
},
),
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 0),
child: Text(
AppLocalizations.of(context).game,
style: CustomTheme.rowTitle,
),
),
Column(
children: [
CupertinoListTile(
backgroundColorActivated:
CustomTheme.backgroundColor,
title: Text(
AppLocalizations.of(context).statistics,
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => GraphView(
gameSession: widget.gameSession,
)))),
CupertinoListTile(
title:
Text(AppLocalizations.of(context).delete_game,
style: const TextStyle(
color: Colors.white30,
)),
onTap: () {},
),
CupertinoListTile(
title: Text(
AppLocalizations.of(context)
.new_game_same_settings,
style: const TextStyle(
color: Colors.white30,
))),
CupertinoListTile(
title:
Text(AppLocalizations.of(context).export_game,
style: const TextStyle(
color: Colors.white30,
)),
),
],
)
],
),
),

84
lib/views/graph_view.dart Normal file
View File

@@ -0,0 +1,84 @@
import 'package:cabo_counter/data/game_session.dart';
import 'package:cabo_counter/l10n/app_localizations.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class GraphView extends StatefulWidget {
final GameSession gameSession;
const GraphView({super.key, required this.gameSession});
@override
State<GraphView> createState() => _GraphViewState();
}
class _GraphViewState extends State<GraphView> {
/// List of colors for the graph lines.
List<Color> lineColors = [
Colors.red,
Colors.blue,
Colors.orange.shade400,
Colors.purple,
Colors.green,
];
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text(AppLocalizations.of(context).game_process),
previousPageTitle: AppLocalizations.of(context).back,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0),
child: SfCartesianChart(
legend:
const Legend(isVisible: true, position: LegendPosition.bottom),
primaryXAxis: const NumericAxis(),
primaryYAxis: const NumericAxis(),
series: getCumulativeScores(),
),
),
);
}
/// Returns a list of LineSeries representing the cumulative scores of each player.
/// Each series contains data points for each round, showing the cumulative score up to that round.
/// The x-axis represents the round number, and the y-axis represents the cumulative score.
List<LineSeries<(int, int), int>> getCumulativeScores() {
final rounds = widget.gameSession.roundList;
final playerCount = widget.gameSession.players.length;
final playerNames = widget.gameSession.players;
List<List<int>> cumulativeScores = List.generate(playerCount, (_) => []);
List<int> runningTotals = List.filled(playerCount, 0);
for (var round in rounds) {
for (int i = 0; i < playerCount; i++) {
runningTotals[i] += round.scores[i];
cumulativeScores[i].add(runningTotals[i]);
}
}
/// Create a list of LineSeries for each player
/// Each series contains data points for each round
return List.generate(playerCount, (i) {
final data = List.generate(
cumulativeScores[i].length,
(j) => (j + 1, cumulativeScores[i][j]), // (round, score)
);
/// Create a LineSeries for the player
/// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score.
return LineSeries<(int, int), int>(
name: playerNames[i],
dataSource: data,
xValueMapper: (record, _) => record.$1, // Runde
yValueMapper: (record, _) => record.$2, // Punktestand
markerSettings: const MarkerSettings(isVisible: true),
color: lineColors[i],
);
});
}
}

View File

@@ -2,7 +2,7 @@ name: cabo_counter
description: "Mobile app for the card game Cabo"
publish_to: 'none'
version: 0.3.1+237
version: 0.3.2+244
environment:
sdk: ^3.5.4
@@ -25,6 +25,7 @@ dependencies:
flutter_localizations:
sdk: flutter
intl: any
syncfusion_flutter_charts: ^30.1.37
dev_dependencies:
flutter_test: