1
0

Add Leaderboard to Display and Remove some Dependencies

Dieser Commit ist enthalten in:
Chaoscaot 2023-02-11 10:25:34 +01:00
Ursprung 1a515603b0
Commit fafee69216
11 geänderte Dateien mit 366 neuen und 222 gelöschten Zeilen

Datei anzeigen

@ -65,7 +65,10 @@ final _routes = GoRouter(
return const SizedBox();
}
final group = state.queryParams['group'];
return DisplayScreen(eventId, group);
final showLeaderboard = state.queryParams['leaderboard'] == "true";
final threePointSystem = state.queryParams['threepoint'] == "true";
return DisplayScreen(
eventId, group, showLeaderboard, threePointSystem);
}),
],
redirect: (context, state) async {

Datei anzeigen

@ -19,3 +19,4 @@
export 'date_time_editor.dart';
export 'error.dart';
export 'team_chip.dart';

Datei anzeigen

@ -0,0 +1,40 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
import 'package:steamwar_multitool/src/types/types.dart';
class TeamChip extends StatelessWidget {
final Team team;
final bool short;
const TeamChip(this.team, {this.short = false, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Chip(
side: const BorderSide(color: Colors.transparent),
label: Text(short ? team.kuerzel : team.name,
style: TextStyle(
color: team.color.computeLuminance() > 0.4
? Colors.black
: Colors.white)),
backgroundColor: team.color,
);
}
}

Datei anzeigen

@ -0,0 +1,119 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:steamwar_multitool/src/components/components.dart';
import 'package:steamwar_multitool/src/types/types.dart';
import 'package:steamwar_multitool/src/util/constants.dart';
class FightList extends HookConsumerWidget {
final List<EventFight> fights;
const FightList(this.fights, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final scrollController = useScrollController();
void launchScroller() {
Future.delayed(const Duration(seconds: 5), () async {
var npos;
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
npos = 0.0;
} else {
npos = min(scrollController.offset + 325,
scrollController.position.maxScrollExtent);
}
await scrollController.animateTo(
npos,
curve: Curves.easeOut,
duration: const Duration(seconds: 2),
);
launchScroller();
});
}
useMemoized(launchScroller);
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: fights.map((fight) {
return Card(
margin: const EdgeInsets.all(8),
child: Row(
children: [
const SizedBox(width: 8),
Chip(label: Text(kTimeFormat.format(fight.start))),
const SizedBox(width: 16),
TeamChip(fight.blueTeam, short: true),
const SizedBox(width: 8),
Text(fight.blueTeam.name, style: const TextStyle(fontSize: 24)),
const SizedBox(width: 8),
const Text("vs.", style: TextStyle(fontSize: 20)),
const SizedBox(width: 8),
TeamChip(fight.redTeam, short: true),
const SizedBox(width: 8),
Text(fight.redTeam.name, style: const TextStyle(fontSize: 24)),
const Spacer(),
if (fight.score == 0) const Icon(Icons.access_time, size: 24),
if (fight.score == 1 || fight.score == 2)
Chip(
label: Row(
children: [
Icon(Icons.military_tech,
size: 24,
color: fight.winner.color.computeLuminance() > 0.5
? Colors.black
: Colors.white),
const SizedBox(width: 8),
Text(fight.winner.kuerzel,
style: TextStyle(
color:
fight.winner.color.computeLuminance() > 0.5
? Colors.black
: Colors.white)),
],
),
backgroundColor: fight.winner.color,
),
if (fight.score == 3)
Chip(
label: Row(
children: const [
Icon(Icons.handshake, size: 24, color: Colors.black),
SizedBox(width: 8),
Text("Draw", style: TextStyle(color: Colors.black)),
],
),
backgroundColor: Colors.grey[100],
),
const SizedBox(width: 8),
],
),
);
}).toList(),
),
);
}
}

Datei anzeigen

@ -0,0 +1,120 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:steamwar_multitool/src/components/components.dart';
import 'package:steamwar_multitool/src/types/types.dart';
import 'package:steamwar_multitool/src/util/constants.dart';
class TeamScore {
final Team team;
final int score;
const TeamScore(this.team, this.score);
}
class Leaderboard extends HookConsumerWidget {
final List<EventFight> fights;
final List<Team> teams;
final bool threePoints;
const Leaderboard(this.fights, this.teams, this.threePoints, {Key? key})
: super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final scrollController = useScrollController();
void launchScroller() {
Future.delayed(const Duration(seconds: 5), () async {
var npos;
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
npos = 0.0;
} else {
npos = min(scrollController.offset + 325,
scrollController.position.maxScrollExtent);
}
await scrollController.animateTo(
npos,
curve: Curves.easeOut,
duration: const Duration(seconds: 2),
);
launchScroller();
});
}
useMemoized(launchScroller);
final scores = useMemoized(() {
final scores = <int, int>{};
for (var team in teams) {
scores[team.id] = 0;
}
for (var fight in fights) {
if (fight.score == 1) {
scores[fight.blueTeam.id] =
(scores[fight.blueTeam.id] ?? 0) + (threePoints ? 3 : 1);
} else if (fight.score == 2) {
scores[fight.redTeam.id] =
(scores[fight.redTeam.id] ?? 0) + (threePoints ? 3 : 1);
} else if (fight.score == 3 && threePoints) {
scores[fight.blueTeam.id] = (scores[fight.blueTeam.id] ?? 0) + 1;
scores[fight.redTeam.id] = (scores[fight.redTeam.id] ?? 0) + 1;
}
}
final scoresList = <TeamScore>[];
for (final entry in scores.entries) {
try {
scoresList.add(TeamScore(
teams.firstWhere((element) => element.id == entry.key),
entry.value));
} catch (e) {}
}
scoresList.sort((a, b) => b.score.compareTo(a.score));
return scoresList;
}, [fights, teams, threePoints]);
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: [
for (final entry in scores)
Card(
margin: const EdgeInsets.all(8.0),
child: Row(
children: [
const SizedBox(width: 8.0),
TeamChip(entry.team, short: true),
const SizedBox(width: 8.0),
Text(entry.team.name, style: const TextStyle(fontSize: 24.0)),
const Spacer(),
Text(entry.score.toString(),
style: const TextStyle(fontSize: 24.0)),
const SizedBox(width: 8.0),
],
),
),
],
),
);
}
}

Datei anzeigen

@ -17,18 +17,29 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:steamwar_multitool/src/components/components.dart';
import 'package:steamwar_multitool/src/provider/events.dart';
import 'package:steamwar_multitool/src/screens/display/components/fightlist.dart';
import 'package:steamwar_multitool/src/screens/display/components/leaderboard.dart';
import 'package:steamwar_multitool/src/types/types.dart';
import 'package:steamwar_multitool/src/util/constants.dart';
class DisplayScreen extends HookConsumerWidget {
final int eventId;
final String? group;
final bool showLeaderboard;
final bool threePointSystem;
const DisplayScreen(this.eventId, this.group, {Key? key}) : super(key: key);
const DisplayScreen(
this.eventId, this.group, this.showLeaderboard, this.threePointSystem,
{Key? key})
: super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
@ -64,6 +75,8 @@ class DisplayScreen extends HookConsumerWidget {
return DisplayScreenLoaded(
eventData,
group,
showLeaderboard,
threePointSystem,
);
},
);
@ -73,7 +86,11 @@ class DisplayScreen extends HookConsumerWidget {
class DisplayScreenLoaded extends HookConsumerWidget {
final EventExtended eventData;
final String? group;
const DisplayScreenLoaded(this.eventData, this.group, {Key? key})
final bool showLeaderboard;
final bool threePointSystem;
const DisplayScreenLoaded(
this.eventData, this.group, this.showLeaderboard, this.threePointSystem,
{Key? key})
: super(key: key);
@override
@ -120,16 +137,16 @@ class DisplayScreenLoaded extends HookConsumerWidget {
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Flexible(
child: ChipClock(),
const Flexible(
flex: 1,
child: ChipClock(),
),
Spacer(
const Spacer(
flex: 4,
),
Text('SteamWar.de - ${eventData.event.name}',
style: const TextStyle(fontSize: 24)),
Spacer(
const Spacer(
flex: 5,
),
],
@ -140,28 +157,47 @@ class DisplayScreenLoaded extends HookConsumerWidget {
),
),
Expanded(
child: FightList(
fights.value
.where(
(element) => group == null || element.group == group)
.toList(),
)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: FightList(
fights.value
.where((element) =>
group == null || element.group == group)
.toList(),
),
),
if (showLeaderboard)
Expanded(
child: Leaderboard(
fights.value
.where((element) =>
group == null || element.group == group)
.toList(),
eventData.teams,
threePointSystem),
),
],
),
),
if (nextFight != null)
SizedBox(
width: double.infinity,
child: Card(
margin: const EdgeInsets.all(8),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(
'Nächster Kampf: ${kTimeFormat.format(nextFight.start)} - ${nextFight.blueTeam.name} vs. ${nextFight.redTeam.name}',
style: const TextStyle(fontSize: 24))),
),
],
)),
margin: const EdgeInsets.all(8),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(
'Nächster Kampf: ${kTimeFormat.format(nextFight.start)} - ${nextFight.blueTeam.name} vs. ${nextFight.redTeam.name}',
style: const TextStyle(fontSize: 24))),
),
],
),
),
),
],
),
@ -190,114 +226,3 @@ class ChipClock extends HookConsumerWidget {
);
}
}
final kTimeFormat = DateFormat('HH:mm');
class FightList extends HookConsumerWidget {
final List<EventFight> fights;
const FightList(this.fights, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final scrollController = useScrollController();
void launchScroller() {
Future.delayed(const Duration(seconds: 5), () async {
var npos;
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
npos = 0.0;
} else {
npos = scrollController.offset + 325;
}
await scrollController.animateTo(
npos,
curve: Curves.easeOut,
duration: const Duration(seconds: 2),
);
launchScroller();
});
}
useMemoized(launchScroller);
return LayoutBuilder(builder: (context, layout) {
return SingleChildScrollView(
controller: scrollController,
child: Column(
children: fights.map((fight) {
return Card(
margin: const EdgeInsets.all(8),
child: Row(
children: [
const SizedBox(width: 8),
Chip(label: Text(kTimeFormat.format(fight.start))),
const SizedBox(width: 16),
Chip(
label: Text(fight.blueTeam.kuerzel,
style: TextStyle(
color: fight.blueTeam.color.computeLuminance() > 0.5
? Colors.black
: Colors.white)),
backgroundColor: fight.blueTeam.color,
),
const SizedBox(width: 8),
Text(fight.blueTeam.name,
style: const TextStyle(fontSize: 24)),
const SizedBox(width: 8),
const Text("vs.", style: TextStyle(fontSize: 20)),
const SizedBox(width: 8),
Chip(
label: Text(fight.redTeam.kuerzel,
style: TextStyle(
color: fight.redTeam.color.computeLuminance() > 0.5
? Colors.black
: Colors.white)),
backgroundColor: fight.redTeam.color,
),
const SizedBox(width: 8),
Text(fight.redTeam.name,
style: const TextStyle(fontSize: 24)),
const Spacer(),
if (fight.score == 0) const Icon(Icons.access_time, size: 24),
if (fight.score == 1 || fight.score == 2)
Chip(
label: Row(
children: [
Icon(Icons.military_tech,
size: 24,
color: fight.winner.color.computeLuminance() > 0.5
? Colors.black
: Colors.white),
const SizedBox(width: 8),
Text(fight.winner.kuerzel,
style: TextStyle(
color: fight.winner.color.computeLuminance() >
0.5
? Colors.black
: Colors.white)),
],
),
backgroundColor: fight.winner.color,
),
if (fight.score == 3)
Chip(
label: Row(
children: const [
Icon(Icons.handshake, size: 24, color: Colors.black),
SizedBox(width: 8),
Text("Draw", style: TextStyle(color: Colors.black)),
],
),
backgroundColor: Colors.grey[100],
),
const SizedBox(width: 8),
],
),
);
}).toList(),
),
);
});
}
}

Datei anzeigen

@ -23,6 +23,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:steamwar_multitool/src/components/components.dart';
import 'package:steamwar_multitool/src/components/date_time_editor.dart';
import 'package:steamwar_multitool/src/provider/provider.dart';
import 'package:steamwar_multitool/src/screens/event/components/fight_list.dart';
@ -278,15 +279,7 @@ class LoadedEventScreen extends HookConsumerWidget {
for (final team in eventData.teams)
Padding(
padding: const EdgeInsets.all(8.0),
child: Chip(
side: const BorderSide(color: Colors.transparent),
label: Text(team.name,
style: TextStyle(
color: team.color.computeLuminance() > 0.4
? Colors.black
: Colors.white)),
backgroundColor: team.color,
),
child: TeamChip(team),
)
],
),

Datei anzeigen

@ -208,8 +208,8 @@ class GroupBracketGenerator extends HookConsumerWidget {
child: Draggable<Team>(
data: team,
feedback: Material(
color: Colors.transparent, child: _TeamChip(team)),
child: _TeamChip(team),
color: Colors.transparent, child: TeamChip(team)),
child: TeamChip(team),
),
),
],
@ -240,7 +240,7 @@ class GroupBracketGenerator extends HookConsumerWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
child: _TeamChip(
child: TeamChip(
event.teams.firstWhere((element) =>
element.id == teamId),
),
@ -413,20 +413,3 @@ class GroupBracketGenerator extends HookConsumerWidget {
);
}
}
class _TeamChip extends StatelessWidget {
final Team team;
const _TeamChip(this.team, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Chip(
label: Text(team.name,
style: TextStyle(
color: team.color.computeLuminance() > 0.5
? Colors.black
: Colors.white)),
backgroundColor: team.color,
);
}
}

Datei anzeigen

@ -20,3 +20,5 @@
import 'package:intl/intl.dart';
final kDateFormat = DateFormat("dd.MM.yyyy HH:mm:ss");
final kTimeFormat = DateFormat('HH:mm');

Datei anzeigen

@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: args
sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.4.0"
async:
dependency: transitive
description:
@ -169,14 +169,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
url: "https://pub.dev"
source: hosted
version: "1.0.5"
dart_style:
dependency: transitive
description:
@ -193,14 +185,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.6"
equatable:
dependency: transitive
description:
name: equatable
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
url: "https://pub.dev"
source: hosted
version: "2.0.5"
fake_async:
dependency: transitive
description:
@ -229,10 +213,10 @@ packages:
dependency: transitive
description:
name: fixnum
sha256: "04be3e934c52e082558cc9ee21f42f5c1cd7a1262f4c63cd0357c08d5bba81ec"
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
@ -308,10 +292,10 @@ packages:
dependency: "direct main"
description:
name: go_router
sha256: f611d4396469c46db1c61e934a86e2a590ce02de2a6050d01f677879ce151f4a
sha256: "5a0b2e0bc88a006c09d2b419004ffabecf83a74520b8852ea148f22e82634c27"
url: "https://pub.dev"
source: hosted
version: "6.0.1"
version: "6.0.6"
graphs:
dependency: transitive
description:
@ -388,10 +372,10 @@ packages:
dependency: "direct dev"
description:
name: json_serializable
sha256: "040088d9eb2337f3a51ddabe35261e2fea1c351e3dd29d755ed1290b6b700a75"
sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a
url: "https://pub.dev"
source: hosted
version: "6.6.0"
version: "6.6.1"
lints:
dependency: transitive
description:
@ -404,10 +388,10 @@ packages:
dependency: transitive
description:
name: logging
sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
matcher:
dependency: transitive
description:
@ -488,14 +472,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0"
platform_info:
dependency: transitive
description:
name: platform_info
sha256: "012e73712166cf0b56d3eb95c0d33491f56b428c169eca385f036448474147e4"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
plugin_platform_interface:
dependency: transitive
description:
@ -536,14 +512,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
quiver:
dependency: transitive
description:
name: quiver
sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
url: "https://pub.dev"
source: hosted
version: "3.2.1"
riverpod:
dependency: transitive
description:
@ -572,10 +540,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "1ffa239043ab8baf881ec3094a3c767af9d10399b2839020b9e4d44c0bb23951"
sha256: "2b55c18636a4edc529fa5cd44c03d3f3100c00513f518c5127c951978efcccd0"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
shared_preferences_linux:
dependency: transitive
description:
@ -633,10 +601,10 @@ packages:
dependency: transitive
description:
name: source_gen
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298
url: "https://pub.dev"
source: hosted
version: "1.2.6"
version: "1.2.7"
source_helper:
dependency: transitive
description:
@ -765,14 +733,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.0+3"
xterm:
dependency: "direct main"
description:
name: xterm
sha256: "990286eead883ff5ad9b8ea7674183dced2fe5421771e95ce32cbaa9117d24d8"
url: "https://pub.dev"
source: hosted
version: "3.4.0"
yaml:
dependency: transitive
description:
@ -782,5 +742,5 @@ packages:
source: hosted
version: "3.1.1"
sdks:
dart: ">=2.18.1 <4.0.0"
dart: ">=2.19.0 <4.0.0"
flutter: ">=3.3.0"

Datei anzeigen

@ -13,12 +13,10 @@ environment:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
flutter_hooks: ^0.18.5+1
hooks_riverpod: ^2.0.2
json_annotation: ^4.8.0
shared_preferences: ^2.0.15
xterm: ^3.4.0
dio: ^4.0.6
go_router: ^6.0.0
intl: ^0.18.0