Merge pull request #153 from flixcoo/enhance/147-sticky-header-table

Sticky header table
This commit is contained in:
2025-08-04 19:39:29 +02:00
committed by GitHub
3 changed files with 245 additions and 132 deletions

View File

@@ -30,29 +30,28 @@ class _GraphViewState extends State<GraphView> {
middle: Text(AppLocalizations.of(context).scoring_history), middle: Text(AppLocalizations.of(context).scoring_history),
previousPageTitle: AppLocalizations.of(context).back, previousPageTitle: AppLocalizations.of(context).back,
), ),
child: Visibility( child: SafeArea(
visible: widget.gameSession.roundNumber > 1 || child: Visibility(
widget.gameSession.isGameFinished, visible: widget.gameSession.roundNumber > 1 ||
replacement: Column( widget.gameSession.isGameFinished,
mainAxisAlignment: MainAxisAlignment.center, replacement: Column(
crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ crossAxisAlignment: CrossAxisAlignment.center,
const Center( children: [
child: Icon(CupertinoIcons.chart_bar_alt_fill, size: 60), 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),
), ),
), const SizedBox(height: 10),
], Padding(
), padding: const EdgeInsets.symmetric(horizontal: 40),
child: Padding( child: Text(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), AppLocalizations.of(context).empty_graph_text,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
),
],
),
child: SfCartesianChart( child: SfCartesianChart(
enableAxisAnimation: true, enableAxisAnimation: true,
legend: const Legend( legend: const Legend(

View File

@@ -17,125 +17,239 @@ class _PointsViewState extends State<PointsView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CupertinoPageScaffold( return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar( navigationBar: CupertinoNavigationBar(
middle: Text(AppLocalizations.of(context).point_overview), middle: Text(AppLocalizations.of(context).point_overview),
previousPageTitle: AppLocalizations.of(context).back, previousPageTitle: AppLocalizations.of(context).back,
), ),
child: SingleChildScrollView( child: SafeArea(child: LayoutBuilder(builder: (context, constraints) {
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0), const double caboFieldWidthFactor = 0.2;
child: Padding( const double roundColWidth = 35;
padding: const EdgeInsets.symmetric(horizontal: 8.0), const double tablePadding = 8;
child: DataTable( final int playerCount = widget.gameSession.players.length;
dataRowMinHeight: 60, final double playerColWidth =
dataRowMaxHeight: 60, (constraints.maxWidth - roundColWidth - (tablePadding)) /
dividerThickness: 0.5, playerCount;
columnSpacing: 20,
columns: [ return Column(
const DataColumn( children: [
numeric: true, ConstrainedBox(
headingRowAlignment: MainAxisAlignment.center, constraints: BoxConstraints(maxWidth: constraints.maxWidth),
label: Text( child: Padding(
'#', padding: const EdgeInsets.symmetric(horizontal: tablePadding),
style: TextStyle(fontWeight: FontWeight.bold), child: DataTable(
), dataRowMaxHeight: 0,
columnWidth: IntrinsicColumnWidth(flex: 0.5)), dataRowMinHeight: 0,
...widget.gameSession.players.map( columnSpacing: 0,
(player) => DataColumn( horizontalMargin: 0,
label: FittedBox( columns: [
fit: BoxFit.fill, const DataColumn(
child: Text( label: SizedBox(
player, width: roundColWidth,
style: const TextStyle(fontWeight: FontWeight.bold), child: Text(
)), '#',
headingRowAlignment: MainAxisAlignment.center, style: TextStyle(fontWeight: FontWeight.bold),
columnWidth: const IntrinsicColumnWidth(flex: 1)), textAlign: TextAlign.center,
), ),
],
rows: [
...List<DataRow>.generate(
widget.gameSession.roundList.length,
(roundIndex) {
final round = widget.gameSession.roundList[roundIndex];
return DataRow(
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
'${roundIndex + 1}',
style: const TextStyle(fontSize: 20),
), ),
)), numeric: true,
...List.generate(widget.gameSession.players.length, ),
(playerIndex) { ...widget.gameSession.players.map(
final int score = round.scores[playerIndex]; (player) => DataColumn(
final int update = round.scoreUpdates[playerIndex]; label: SizedBox(
final bool saidCabo = width: playerColWidth,
round.caboPlayerIndex == playerIndex; child: Padding(
return DataCell( padding:
Center( const EdgeInsets.symmetric(horizontal: 8),
child: Column( child: Text(
mainAxisAlignment: MainAxisAlignment.center, player,
children: [ style: const TextStyle(
Container( fontWeight: FontWeight.bold),
padding: const EdgeInsets.symmetric( overflow: TextOverflow.ellipsis,
horizontal: 6, vertical: 2), softWrap: true,
decoration: BoxDecoration( maxLines: 2,
color: update <= 0 textAlign: TextAlign.center,
? CustomTheme.pointLossColor ),
: CustomTheme.pointGainColor, ),
borderRadius: BorderRadius.circular(8), ),
), ),
child: Text( ),
'${update >= 0 ? '+' : ''}$update', ],
style: const TextStyle( rows: const [],
color: CupertinoColors.white, ),
fontWeight: FontWeight.bold, ),
),
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: ConstrainedBox(
constraints:
BoxConstraints(maxWidth: constraints.maxWidth),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: tablePadding),
child: DataTable(
dataRowMaxHeight: 75,
dataRowMinHeight: 75,
columnSpacing: 0,
horizontalMargin: 0,
headingRowHeight: 0,
columns: [
const DataColumn(
label: SizedBox(
width: roundColWidth,
child: Text(
'#',
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
numeric: true,
),
...widget.gameSession.players.map(
(player) => DataColumn(
label: SizedBox(
width: playerColWidth,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8),
child: Text(
player,
style: const TextStyle(
fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
softWrap: true,
maxLines: 2,
textAlign: TextAlign.center,
), ),
), ),
), ),
const SizedBox(height: 4), ),
Text('$score', ),
style: TextStyle( ],
fontWeight: saidCabo rows: [
? FontWeight.bold ...List<DataRow>.generate(
: FontWeight.normal, widget.gameSession.roundList.length,
(roundIndex) {
final round =
widget.gameSession.roundList[roundIndex];
return DataRow(
cells: [
DataCell(Align(
alignment: Alignment.center,
child: Text(
'${roundIndex + 1}',
style: const TextStyle(fontSize: 20),
),
)), )),
...List.generate(
widget.gameSession.players.length,
(playerIndex) {
final int score =
round.scores[playerIndex];
final int update =
round.scoreUpdates[playerIndex];
final bool saidCabo =
round.caboPlayerIndex == playerIndex;
return DataCell(Center(
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 6.0),
child: Container(
width: playerColWidth *
(playerCount *
caboFieldWidthFactor), // Adjust width based on amount of players
decoration: BoxDecoration(
color: saidCabo
? CustomTheme
.buttonBackgroundColor
: CupertinoColors.transparent,
borderRadius:
BorderRadius.circular(5),
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
const SizedBox(
height: 5,
),
Container(
padding: const EdgeInsets
.symmetric(
horizontal: 6,
vertical: 2),
decoration: BoxDecoration(
color: update <= 0
? CustomTheme
.pointLossColor
: CustomTheme
.pointGainColor,
borderRadius:
BorderRadius.circular(
6),
),
child: Text(
'${update >= 0 ? '+' : ''}$update',
style: const TextStyle(
color:
CupertinoColors.white,
fontWeight:
FontWeight.bold,
),
),
),
const SizedBox(height: 4),
Text(
'$score',
style: TextStyle(
color: CustomTheme.white,
fontWeight: saidCabo
? FontWeight.bold
: FontWeight.normal,
),
),
],
),
),
),
));
}),
],
);
},
),
DataRow(
cells: [
const DataCell(Align(
alignment: Alignment.center,
child: Text(
'Σ',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold),
),
)),
...widget.gameSession.playerScores.map(
(score) => DataCell(
Center(
child: Text(
'$score',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
),
),
], ],
), ),
), ],
);
}),
],
);
},
),
DataRow(
cells: [
const DataCell(Align(
alignment: Alignment.center,
child: Text(
'Σ',
style:
TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
)),
...widget.gameSession.playerScores.map(
(score) => DataCell(
Center(
child: Text(
'$score',
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
), ),
), ),
), )),
),
],
), ),
], ],
), );
), })));
),
);
} }
} }

View File

@@ -2,7 +2,7 @@ name: cabo_counter
description: "Mobile app for the card game Cabo" description: "Mobile app for the card game Cabo"
publish_to: 'none' publish_to: 'none'
version: 0.5.4+609 version: 0.5.5+639
environment: environment:
sdk: ^3.5.4 sdk: ^3.5.4