Merge pull request #96 from flixcoo/enhance/94-restrict-graph-view

Restrict graph view
This commit is contained in:
2025-07-11 10:53:00 +02:00
committed by GitHub
9 changed files with 87 additions and 35 deletions

View File

@@ -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,

View File

@@ -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",

View File

@@ -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.",

View File

@@ -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:

View File

@@ -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';

View File

@@ -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';

View File

@@ -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<GraphView> {
/// List of colors for the graph lines.
List<Color> lineColors = [
Colors.red,
Colors.blue,
Colors.orange.shade400,
Colors.purple,
Colors.green,
final List<Color> 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<LineSeries<(int, int), int>> getCumulativeScores() {
List<LineSeries<(int, num), int>> 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<GraphView> {
}
}
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],
);

View File

@@ -88,10 +88,9 @@ class _MainMenuViewState extends State<MainMenuView> {
? 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<MainMenuView> {
color: CustomTheme.primaryColor,
),
)),
const SizedBox(height: 10), // Abstand von oben
const SizedBox(height: 10),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 70),

View File

@@ -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