1
0

Add Group Frontend

Dieser Commit ist enthalten in:
Chaoscaot 2023-01-21 22:29:54 +01:00
Ursprung cdca1c8562
Commit 3cfdbbcdbd
5 geänderte Dateien mit 232 neuen und 25 gelöschten Zeilen

Datei anzeigen

@ -17,6 +17,12 @@ final eventsListProvider = FutureProvider<List<ShortEvent>>((ref) async {
return repo.listEvents();
}, dependencies: [eventRepositoryProvider]);
final groupsProvider = FutureProvider.autoDispose<List<String>>((ref) async {
return (await ref.watch(httpClient.future)).get("/data/groups").then((value) {
return (value.data as List).map((e) => e as String).toList();
});
}, dependencies: [httpClient]);
class EventRepository {
final Dio _client;
@ -71,15 +77,8 @@ class EventRepository {
await _client.delete("/fights/$id");
}
Future<void> createFight(
int eventId,
DateTime start,
String mode,
String map,
Team blue,
Team red,
int referee,
) {
Future<void> createFight(int eventId, DateTime start, String mode, String map,
Team blue, Team red, int referee, String? group) {
return _client.post("/fights", data: {
"event": eventId,
"spielmodus": mode,
@ -88,6 +87,7 @@ class EventRepository {
"blueTeam": blue.id,
"redTeam": red.id,
"kampfleiter": referee,
"group": group ?? "null",
});
}
@ -97,7 +97,7 @@ class EventRepository {
}
Future<void> updateFight(int id, DateTime start, String mode, String map,
int referee, Team blue, Team red) {
int referee, Team blue, Team red, String? group) {
return _client.put("/fights/$id", data: {
"spielmodus": mode,
"map": map,
@ -105,6 +105,7 @@ class EventRepository {
"kampfleiter": referee,
"blueTeam": blue.id,
"redTeam": red.id,
"group": group ?? "null",
});
}
}
@ -118,9 +119,10 @@ class EventFight {
final Team blueTeam;
final User kampfleiter;
final int score;
final String? group;
EventFight(this.id, this.gameMode, this.map, this.start, this.redTeam,
this.blueTeam, this.kampfleiter, this.score);
this.blueTeam, this.kampfleiter, this.score, this.group);
Team get winner {
return getTeamWithContextColor(Colors.white);
@ -150,7 +152,8 @@ class EventFight {
Team.fromJson(json["redTeam"]),
Team.fromJson(json["blueTeam"]),
User.fromJson(json["kampfleiter"]),
json["ergebnis"]);
json["ergebnis"],
json["group"]);
}
}

Datei anzeigen

@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:steamwar_multitool/src/util/event_fight_exporter.dart';
@ -414,7 +415,7 @@ class _EventFightList extends HookConsumerWidget {
[date.value, lowest]);
return AlertDialog(
title: const Text("Reshedule Fights"),
title: const Text("Reschedule Fights"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -448,14 +449,15 @@ class _EventFightList extends HookConsumerWidget {
final repo = await ref
.read(eventRepositoryProvider.future);
for (final fight in selectedFights) {
repo.updateFight(
await repo.updateFight(
fight.id,
fight.start.add(offset),
fight.gameMode,
fight.map,
fight.kampfleiter.id,
fight.blueTeam,
fight.redTeam);
fight.redTeam,
fight.group);
}
update();
Navigator.of(context).pop();
@ -490,14 +492,15 @@ class _EventFightList extends HookConsumerWidget {
await ref.read(eventRepositoryProvider.future);
for (final fight in fights.value) {
if (selected.value.contains(fight.id)) {
repo.updateFight(
await repo.updateFight(
fight.id,
fight.start,
fight.gameMode,
fight.map,
kampfleiter.id,
fight.blueTeam,
fight.redTeam);
fight.redTeam,
fight.group);
}
}
update();
@ -505,6 +508,42 @@ class _EventFightList extends HookConsumerWidget {
},
icon: const Icon(Icons.person)),
),
Tooltip(
message: "Change Group",
child: IconButton(
onPressed: () async {
if (selected.value.isEmpty) {
return;
}
final group = await showSearch(
context: context,
delegate: GroupSearchDelegate(
await ref.read(groupsProvider.future)));
if (group == null) {
return;
} else {
final repo =
await ref.read(eventRepositoryProvider.future);
for (final fight in fights.value) {
if (selected.value.contains(fight.id)) {
await repo.updateFight(
fight.id,
fight.start,
fight.gameMode,
fight.map,
fight.kampfleiter.id,
fight.blueTeam,
fight.redTeam,
group);
}
}
update();
}
},
icon: const Icon(Icons.group)),
),
Tooltip(
message: "Delete Fights",
child: IconButton(
@ -531,7 +570,7 @@ class _EventFightList extends HookConsumerWidget {
final repo = await ref
.read(eventRepositoryProvider.future);
for (final fight in selected.value) {
repo.deleteFight(fight);
await repo.deleteFight(fight);
}
update();
Navigator.of(context).pop();
@ -579,7 +618,8 @@ class _EventFightList extends HookConsumerWidget {
openExportedFights(fights.value, event.name);
}
},
)
),
const SizedBox(width: 8),
],
),
const Divider(),
@ -588,8 +628,51 @@ class _EventFightList extends HookConsumerWidget {
const Center(
child: Text("No fights yet"),
),
for (final fight in fights.value)
ListTile(
GroupedListView(
elements: fights.value,
groupBy: (fight) => fight.group ?? "Ungrouped",
shrinkWrap: true,
itemComparator: (fight1, fight2) =>
fight1.start.compareTo(fight2.start),
groupComparator: (group1, group2) => group1.compareTo(group2),
floatingHeader: true,
groupSeparatorBuilder: (group) => InkWell(
onTap: () {
final g = group == "Ungrouped" ? null : group;
final isAllSelected = selected.value
.where((element) =>
fights.value
.firstWhere((element2) => element2.id == element)
.group ==
g)
.length ==
fights.value.where((element) => element.group == g).length;
if (isAllSelected) {
selected.value = selected.value
.where((element) =>
fights.value
.firstWhere((element2) => element2.id == element)
.group !=
g)
.toList();
} else {
selected.value = [
...selected.value,
...fights.value
.where((element) => element.group == g)
.map((e) => e.id)
];
}
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
group,
style: Theme.of(context).textTheme.headline6,
),
),
),
itemBuilder: (context, fight) => ListTile(
title: Text(
"${fight.blueTeam.name} vs ${fight.redTeam.name}",
style: TextStyle(
@ -639,7 +722,8 @@ class _EventFightList extends HookConsumerWidget {
.toList();
}
}),
)
),
)
],
);
}
@ -665,6 +749,7 @@ class EditEventFightDialog extends HookConsumerWidget {
final mode = useState(fight.gameMode);
final map = useState(fight.map);
final referrer = useState(fight.kampfleiter);
final group = useState(fight.group ?? "");
return AlertDialog(
title: Text("${fight.blueTeam.name} vs ${fight.redTeam.name}"),
@ -741,6 +826,24 @@ class EditEventFightDialog extends HookConsumerWidget {
? "None"
: "${referrer.value.name} (${referrer.value!.id})"),
),
const SizedBox(height: 8),
const Text("Group"),
const SizedBox(height: 8),
TextButton(
onPressed: () async {
final selGroup = await showSearch(
context: context,
delegate: GroupSearchDelegate(
await ref.read(groupsProvider.future)));
if (selGroup != null) {
if (selGroup.isEmpty) {
group.value = "";
} else {
group.value = selGroup;
}
}
},
child: Text(group.value.isEmpty ? "None" : group.value)),
],
),
actions: [
@ -784,8 +887,15 @@ class EditEventFightDialog extends HookConsumerWidget {
onPressed: () async {
var nav = Navigator.of(context);
final repo = await ref.read(eventRepositoryProvider.future);
await repo.updateFight(fight.id, start.value, mode.value,
map.value, referrer.value.id, blueTeam.value, redTeam.value);
await repo.updateFight(
fight.id,
start.value,
mode.value,
map.value,
referrer.value.id,
blueTeam.value,
redTeam.value,
group.value.isEmpty ? null : group.value);
fightsRefresher();
nav.pop();
},
@ -813,6 +923,7 @@ class _AddFightWidget extends HookConsumerWidget {
final redTeam = useState<Team?>(null);
final date = useState<DateTime>(event.start);
final referrer = useState<User?>(null);
final group = useState<String>("");
final canCreate = useMemoized(() {
return gamemode.value != null &&
@ -883,6 +994,24 @@ class _AddFightWidget extends HookConsumerWidget {
? "None"
: "${referrer.value!.name} (${referrer.value!.id})"),
),
const SizedBox(height: 8),
const Text("Group"),
const SizedBox(height: 8),
TextButton(
onPressed: () async {
final selGroup = await showSearch(
context: context,
delegate: GroupSearchDelegate(
await ref.read(groupsProvider.future)));
if (selGroup != null) {
if (selGroup.isEmpty) {
group.value = "";
} else {
group.value = selGroup;
}
}
},
child: Text(group.value.isEmpty ? "None" : group.value)),
],
),
actions: [
@ -903,7 +1032,8 @@ class _AddFightWidget extends HookConsumerWidget {
map.value!,
blueTeam.value!,
redTeam.value!,
referrer.value?.id ?? 0);
referrer.value?.id ?? 0,
group.value.isEmpty ? null : group.value);
onAdded.call();
nav.pop();
}

Datei anzeigen

@ -317,3 +317,69 @@ class TeamSearchDelegate extends SearchDelegate<Team?> {
);
}
}
class GroupSearchDelegate extends SearchDelegate<String?> {
final List<String> groups;
GroupSearchDelegate(this.groups);
@override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query = "";
},
)
];
}
@override
Widget? buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
close(context, null);
},
);
}
@override
Widget buildResults(BuildContext context) {
return buildSuggestions(context);
}
@override
Widget buildSuggestions(BuildContext context) {
return ListView(
children: [
ListTile(
title: Text(query),
onTap: query.isEmpty
? null
: () {
close(context, query);
},
subtitle: const Text("Create new group"),
leading: const Icon(Icons.add),
),
ListTile(
leading: const Icon(Icons.clear),
title: const Text("Reset"),
onTap: () {
close(context, "");
},
),
for (final group in groups)
if (group.toLowerCase().contains(query.toLowerCase()))
ListTile(
title: Text(group),
onTap: () {
close(context, group);
},
)
],
);
}
}

Datei anzeigen

@ -282,6 +282,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
grouped_list:
dependency: "direct main"
description:
name: grouped_list
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.2"
hooks_riverpod:
dependency: "direct main"
description:

Datei anzeigen

@ -23,6 +23,7 @@ dependencies:
go_router: ^6.0.0
intl: ^0.18.0
csv: ^5.0.1
grouped_list: ^5.1.2
dev_dependencies: