Files
cabo-counter/lib/presentation/views/graph_view.dart
Felix Kirchner 8565382fab Beta-Version 0.4.4 (#105)
* Update README.md

* Tried new design for im- and export-button

* Moved views to presentation folder

* Moved widgets to presentation folder

* Implemented CustomRowForm Widget

* Used new custom form row

* Removed double information

* Refactored methods to private

* Changed label

* Modified paddings and text color

* Changed string

* Updated CustomFormRow padding and pressed handler

* Implemented various new forms of CustomFormRow into SettingsView

* Implemented VersionService

* Updated strings, added wiki button

* Corrected replaced string

* Added import dialog feedback (got lost in refactoring)

* Corrected function duplication

* changed suffixWidget assignment and moved stepperKeys

* Changed icons

* Added rate_my_app package

* Renamed folder

* Implement native rating dialog

* Implemented logic for pre rating and refactored rating dialog

* updated launch mode

* Small changes

* Updated launch mode

* Updated linting rules

* Renamed folders

* Changed l10n files location

* Implemented new link constants

* Changed privacy policy link

* Corrected wiki link

* Removed import

* Updated links

* Updated links to subdomains

* Updated file paths

* Updated strings

* Updated identifiers

* Added break in switch case

* Updated strings

* Implemented new popup

* Corrected links

* Changed color

* Ensured rating dialog wont show in Beta

* Refactoring

* Adding const

* Renamed variables

* Corrected links

* updated Dialog function

* Added version number in about view

* Changed order and corrected return

* Changed translation

* Changed popups because of unmounted context errors

* corrected string typo

* Replaced int constants with enums

* Renamed Stepper to CustomStepper

* Changed argument order

* Reordered properties

* Implemented empty builder for GraphView

* Added jitterStip to prevent the graphs overlaying each other

* Removed german comments

* Added comment to jitter calculation

* Overhauled comments in CustomTheme

* Updated version

* Added Delete all games button to Settings

* Updated version

* Updated en string

* Updated RoundView buttons when game is finished

* Changed lock emoji to CuperinoIcons.lock and placed it in trailing of app bar

* Simplified comparison

* Updated version

* Corrected scaling

* Updates constant names and lint rule

* HOTFIX: Graph showed wrong data

* Graph starts at round 0 now where all players have 0 points

* Adjusted jitterStep

* Removed dead code

* Updated Y-Axis and removed values under y = 0

* Changed overflow mode

* Replaced string & if statement with visibility widget

* updated accessability of graph view

* Changed string for GraphView title

* Updated comment

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Updated generated files

* Updated version in README

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-13 12:48:24 +02:00

121 lines
4.5 KiB
Dart

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: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.
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: widget.gameSession.roundNumber > 1
? Padding(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0),
child: SfCartesianChart(
legend: const Legend(
overflowMode: LegendItemOverflowMode.wrap,
isVisible: true,
position: LegendPosition.bottom),
primaryXAxis: const NumericAxis(
interval: 1,
decimalPlaces: 0,
),
primaryYAxis: const NumericAxis(
interval: 1,
decimalPlaces: 0,
),
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, num), 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.scoreUpdates[i];
cumulativeScores[i].add(runningTotals[i]);
}
}
const double jitterStep = 0.03;
/// 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 + 1,
(j) => (
j,
j == 0 || cumulativeScores[i][j - 1] == 0
? 0 // 0 points at the start of the game or when the value is 0 (don't subtract jitter step)
// Adds 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 - 1] + (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, num), int>(
name: playerNames[i],
dataSource: data,
xValueMapper: (record, _) => record.$1,
yValueMapper: (record, _) => record.$2,
markerSettings: const MarkerSettings(isVisible: true),
color: lineColors[i],
);
});
}
}