diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 77a2f5b..a00340b 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -6,6 +6,13 @@ class CustomTheme { static Color backgroundColor = const Color(0xFF101010); static Color backgroundTintColor = CupertinoColors.darkBackgroundGray; + // Line Colors for GraphView + static const Color graphColor1 = Color(0xFFF44336); + static const Color graphColor2 = Color(0xFF2196F3); + static const Color graphColor3 = Color(0xFFFFA726); + static const Color graphColor4 = Color(0xFF9C27B0); + static final Color graphColor5 = primaryColor; + static TextStyle modeTitle = TextStyle( color: primaryColor, fontSize: 20, diff --git a/lib/l10n/arb/app_de.arb b/lib/l10n/arb/app_de.arb index d89399b..acff3c1 100644 --- a/lib/l10n/arb/app_de.arb +++ b/lib/l10n/arb/app_de.arb @@ -85,6 +85,7 @@ "end_game_message": "Möchtest du das Spiel beenden? Das Spiel wird als beendet markiert und kann nicht fortgeführt werden.", "game_process": "Spielverlauf", + "empty_graph_text": "Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.", "settings": "Einstellungen", "cabo_penalty": "Cabo-Strafe", diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e01e242..4a0735a 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -74,18 +74,20 @@ "done": "Done", "next_round": "Next Round", + "statistics": "Statistics", "end_game": "End Game", "delete_game": "Delete Game", "new_game_same_settings": "New Game with same Settings", "export_game": "Export Game", - - "game_process": "Spielverlauf", "id_error_title": "ID Error", "id_error_message": "The game has not yet been assigned an ID. If you want to delete the game, please do so via the main menu. All newly created games have an ID.", "end_game_title": "End the game?", "end_game_message": "Do you want to end the game? The game gets marked as finished and cannot be continued.", + "game_process": "Scoring History", + "empty_graph_text": "You must play at least two rounds for the game progress graph to be displayed.", + "settings": "Settings", "cabo_penalty": "Cabo Penalty", "cabo_penalty_subtitle": "... for falsely calling Cabo.", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index af778ae..c139891 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -476,6 +476,12 @@ abstract class AppLocalizations { /// **'Spielverlauf'** String get game_process; + /// No description provided for @empty_graph_text. + /// + /// In de, this message translates to: + /// **'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'** + String get empty_graph_text; + /// No description provided for @settings. /// /// In de, this message translates to: diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index afe558f..b61feb0 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -210,6 +210,10 @@ class AppLocalizationsDe extends AppLocalizations { @override String get game_process => 'Spielverlauf'; + @override + String get empty_graph_text => + 'Du musst mindestens zwei Runden spielen, damit der Graph des Spielverlaufes angezeigt werden kann.'; + @override String get settings => 'Einstellungen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index a986058..fcfd494 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -92,7 +92,7 @@ class AppLocalizationsEn extends AppLocalizations { 'If you are not satisfied with the app, please let me know before leaving a bad rating. I will try to fix the issue as soon as possible.'; @override - String get contact_email => 'Contac via E-Mail'; + String get contact_email => 'Contact via E-Mail'; @override String get email_subject => 'Feedback: Cabo Counter App'; @@ -205,7 +205,11 @@ class AppLocalizationsEn extends AppLocalizations { 'Do you want to end the game? The game gets marked as finished and cannot be continued.'; @override - String get game_process => 'Spielverlauf'; + String get game_process => 'Scoring History'; + + @override + String get empty_graph_text => + 'You must play at least two rounds for the game progress graph to be displayed.'; @override String get settings => 'Settings'; diff --git a/lib/presentation/views/graph_view.dart b/lib/presentation/views/graph_view.dart index 1007007..7736bb1 100644 --- a/lib/presentation/views/graph_view.dart +++ b/lib/presentation/views/graph_view.dart @@ -1,7 +1,7 @@ +import 'package:cabo_counter/core/custom_theme.dart'; import 'package:cabo_counter/data/game_session.dart'; import 'package:cabo_counter/l10n/generated/app_localizations.dart'; import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_charts/charts.dart'; class GraphView extends StatefulWidget { @@ -15,38 +15,59 @@ class GraphView extends StatefulWidget { class _GraphViewState extends State { /// List of colors for the graph lines. - List lineColors = [ - Colors.red, - Colors.blue, - Colors.orange.shade400, - Colors.purple, - Colors.green, + final List lineColors = [ + CustomTheme.graphColor1, + CustomTheme.graphColor2, + CustomTheme.graphColor3, + CustomTheme.graphColor4, + CustomTheme.graphColor5 ]; @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(), + navigationBar: CupertinoNavigationBar( + middle: Text(AppLocalizations.of(context).game_process), + previousPageTitle: AppLocalizations.of(context).back, ), - ), - ); + child: widget.gameSession.roundNumber > 2 + ? Padding( + padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), + child: SfCartesianChart( + legend: const Legend( + isVisible: true, position: LegendPosition.bottom), + primaryXAxis: const NumericAxis( + interval: 1, + decimalPlaces: 0, + ), + primaryYAxis: const NumericAxis(), + series: getCumulativeScores(), + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Center( + child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), + ), + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 40), + child: Text( + AppLocalizations.of(context).empty_graph_text, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 16), + ), + ), + ], + )); } /// 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> getCumulativeScores() { + List> getCumulativeScores() { final rounds = widget.gameSession.roundList; final playerCount = widget.gameSession.players.length; final playerNames = widget.gameSession.players; @@ -61,21 +82,29 @@ class _GraphViewState extends State { } } + const double jitterStep = 0.15; + /// 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) + (j) => ( + j + 1, + + // Add a small jitter to the cumulative scores to prevent overlapping data points in the graph. + // The jitter is centered around zero by subtracting playerCount ~/ 2 from the player index i. + cumulativeScores[i][j] + (i - playerCount ~/ 2) * jitterStep + ), ); /// Create a LineSeries for the player /// The xValueMapper maps the round number, and the yValueMapper maps the cumulative score. - return LineSeries<(int, int), int>( + return LineSeries<(int, num), int>( name: playerNames[i], dataSource: data, - xValueMapper: (record, _) => record.$1, // Runde - yValueMapper: (record, _) => record.$2, // Punktestand + xValueMapper: (record, _) => record.$1, + yValueMapper: (record, _) => record.$2, markerSettings: const MarkerSettings(isVisible: true), color: lineColors[i], ); diff --git a/lib/presentation/views/main_menu_view.dart b/lib/presentation/views/main_menu_view.dart index 1f8b5d0..fa537c6 100644 --- a/lib/presentation/views/main_menu_view.dart +++ b/lib/presentation/views/main_menu_view.dart @@ -88,10 +88,9 @@ class _MainMenuViewState extends State { ? const Center(child: CupertinoActivityIndicator()) : gameManager.gameList.isEmpty ? Column( - mainAxisAlignment: - MainAxisAlignment.center, // Oben ausrichten + mainAxisAlignment: MainAxisAlignment.center, children: [ - const SizedBox(height: 30), // Abstand von oben + const SizedBox(height: 30), Center( child: GestureDetector( onTap: () => Navigator.push( @@ -107,7 +106,7 @@ class _MainMenuViewState extends State { color: CustomTheme.primaryColor, ), )), - const SizedBox(height: 10), // Abstand von oben + const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 70), diff --git a/pubspec.yaml b/pubspec.yaml index 31146e6..fbacd1e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.4.0+467 +version: 0.4.1+470 environment: sdk: ^3.5.4