Update UI
Dieser Commit ist enthalten in:
Ursprung
4c54b65b5c
Commit
2278546f01
@ -17,6 +17,28 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
export 'date_time_editor.dart';
|
||||
export 'error.dart';
|
||||
export 'team_chip.dart';
|
||||
export 'select_gamemode_component.dart';
|
||||
export 'select_map_component.dart';
|
||||
|
||||
class Disabled extends StatelessWidget {
|
||||
final String? initialValue;
|
||||
const Disabled({Key? key, this.initialValue = ""}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DropdownMenu(
|
||||
width: 200,
|
||||
label: Text(initialValue!),
|
||||
enabled: false,
|
||||
dropdownMenuEntries: [
|
||||
if (initialValue != null)
|
||||
DropdownMenuEntry(value: initialValue, label: initialValue!),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
70
lib/src/components/select_gamemode_component.dart
Normale Datei
70
lib/src/components/select_gamemode_component.dart
Normale Datei
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:steamwar_multitool/src/provider/data.dart';
|
||||
|
||||
import 'components.dart';
|
||||
|
||||
class SelectGameModeComponent extends HookConsumerWidget {
|
||||
final String? initialValue;
|
||||
final void Function(String?) onChanged;
|
||||
|
||||
const SelectGameModeComponent({
|
||||
Key? key,
|
||||
required this.initialValue,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return ref.watch(fightServersProvider).when(
|
||||
data: (data) {
|
||||
if (initialValue != null && !data.contains(initialValue)) {
|
||||
return Disabled(
|
||||
initialValue: initialValue,
|
||||
);
|
||||
}
|
||||
|
||||
return DropdownMenu<String?>(
|
||||
width: 200,
|
||||
menuHeight: 300,
|
||||
initialSelection: initialValue,
|
||||
onSelected: onChanged,
|
||||
enableFilter: true,
|
||||
enableSearch: true,
|
||||
label: const Text("Game Mode"),
|
||||
dropdownMenuEntries: [
|
||||
const DropdownMenuEntry(value: null, label: ""),
|
||||
for (final gameMode in data)
|
||||
DropdownMenuEntry(
|
||||
value: gameMode,
|
||||
label: gameMode,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
error: (error, stack) => Disabled(
|
||||
initialValue: initialValue,
|
||||
),
|
||||
loading: () => const Disabled(initialValue: "Game Mode"),
|
||||
);
|
||||
}
|
||||
}
|
110
lib/src/components/select_map_component.dart
Normale Datei
110
lib/src/components/select_map_component.dart
Normale Datei
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:steamwar_multitool/src/components/components.dart';
|
||||
import 'package:steamwar_multitool/src/provider/data.dart';
|
||||
|
||||
class SelectMapComponent extends HookConsumerWidget {
|
||||
final String? gameMode;
|
||||
final String? initialValue;
|
||||
final void Function(String?) onChanged;
|
||||
|
||||
const SelectMapComponent({
|
||||
Key? key,
|
||||
required this.gameMode,
|
||||
required this.initialValue,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
if (gameMode == null) {
|
||||
return const Disabled(initialValue: "Select Map");
|
||||
}
|
||||
|
||||
return ProviderScope(
|
||||
overrides: [
|
||||
mapGameModeProvider.overrideWithValue(gameMode!),
|
||||
mapsProvider
|
||||
],
|
||||
child: _SelectMapInternal(
|
||||
initialValue: initialValue,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SelectMapInternal extends HookConsumerWidget {
|
||||
final String? initialValue;
|
||||
final void Function(String?) onChanged;
|
||||
|
||||
const _SelectMapInternal({
|
||||
Key? key,
|
||||
required this.initialValue,
|
||||
required this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final maps = ref.watch(mapsProvider);
|
||||
return maps.when(
|
||||
data: (data) {
|
||||
return DropdownMenu<String?>(
|
||||
width: 200,
|
||||
menuHeight: 300,
|
||||
initialSelection: initialValue,
|
||||
onSelected: (value) {
|
||||
if (value == "%random%") {
|
||||
onChanged(data[Random().nextInt(data.length)]);
|
||||
return;
|
||||
}
|
||||
onChanged(value);
|
||||
},
|
||||
enableSearch: true,
|
||||
enableFilter: true,
|
||||
label: const Text("Select Map"),
|
||||
dropdownMenuEntries: [
|
||||
const DropdownMenuEntry(
|
||||
value: null,
|
||||
label: "",
|
||||
),
|
||||
const DropdownMenuEntry(
|
||||
value: "%random%",
|
||||
label: "Random",
|
||||
),
|
||||
for (final map in data)
|
||||
DropdownMenuEntry(
|
||||
value: map,
|
||||
label: map,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
error: (error, stack) => Disabled(
|
||||
initialValue: initialValue,
|
||||
),
|
||||
loading: () => const Disabled(initialValue: "Select Map"),
|
||||
);
|
||||
}
|
||||
}
|
@ -43,15 +43,17 @@ final schematicTypesProvider = FutureProvider((ref) async {
|
||||
});
|
||||
});
|
||||
|
||||
final mapsProvider = FutureProvider<Map<String, List<String>>>((ref) async {
|
||||
final mapGameModeProvider = Provider<String>((ref) {
|
||||
throw UnimplementedError("mapGameModeProvider");
|
||||
});
|
||||
|
||||
final mapsProvider = FutureProvider<List<String>>((ref) async {
|
||||
final client = await ref.watch(httpClient.future);
|
||||
final servers = await ref.watch(fightServersProvider.future);
|
||||
final ret = <String, List<String>>{};
|
||||
for (final server in servers) {
|
||||
final res = await client.get("/data/gamemodes/$server/maps");
|
||||
ret[server] = (res.data as List<dynamic>).map((e) => e.toString()).toList();
|
||||
}
|
||||
return ret;
|
||||
final gameMode = ref.watch(mapGameModeProvider);
|
||||
return ((await client.get("/data/gamemodes/$gameMode/maps")).data
|
||||
as List<dynamic>)
|
||||
.map((e) => e.toString())
|
||||
.toList();
|
||||
});
|
||||
|
||||
final usersProvider = FutureProvider((ref) async {
|
||||
|
@ -20,7 +20,9 @@
|
||||
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/components/date_time_editor.dart';
|
||||
import 'package:steamwar_multitool/src/components/select_map_component.dart';
|
||||
import 'package:steamwar_multitool/src/provider/provider.dart';
|
||||
import 'package:steamwar_multitool/src/screens/event/components/team_selector.dart';
|
||||
import 'package:steamwar_multitool/src/delegates/delegates.dart';
|
||||
@ -61,33 +63,18 @@ class AddFightDialog extends HookConsumerWidget {
|
||||
const Divider(),
|
||||
const Text("Gamemode"),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final modes = await ref.read(fightServersProvider.future);
|
||||
final mode = await showSearch(
|
||||
context: context, delegate: GamemodeSearchDelegate(modes));
|
||||
if (mode != null) {
|
||||
gamemode.value = mode;
|
||||
}
|
||||
},
|
||||
child: Text(gamemode.value ?? "Select"),
|
||||
),
|
||||
SelectGameModeComponent(
|
||||
initialValue: gamemode.value,
|
||||
onChanged: (p0) => gamemode.value = p0),
|
||||
const SizedBox(height: 8),
|
||||
const Text("Map"),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
onPressed: gamemode.value != null
|
||||
? () async {
|
||||
final maps = await ref.read(mapsProvider.future);
|
||||
final sMap = await showSearch(
|
||||
context: context,
|
||||
delegate: MapSearchDelegate(maps[gamemode.value]!));
|
||||
if (sMap != null) {
|
||||
map.value = sMap;
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(map.value ?? "Select"),
|
||||
SelectMapComponent(
|
||||
gameMode: gamemode.value,
|
||||
initialValue: map.value,
|
||||
onChanged: (p0) {
|
||||
map.value = p0;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text("Blue Team"),
|
||||
|
@ -21,6 +21,8 @@ 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/date_time_editor.dart';
|
||||
import 'package:steamwar_multitool/src/components/select_gamemode_component.dart';
|
||||
import 'package:steamwar_multitool/src/components/select_map_component.dart';
|
||||
import 'package:steamwar_multitool/src/provider/provider.dart';
|
||||
import 'package:steamwar_multitool/src/screens/event/components/team_selector.dart';
|
||||
import 'package:steamwar_multitool/src/delegates/delegates.dart';
|
||||
@ -79,32 +81,25 @@ class EditEventFightDialog extends HookConsumerWidget {
|
||||
const SizedBox(height: 8),
|
||||
const Text("Game Mode"),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final modes = await ref.read(fightServersProvider.future);
|
||||
final out = await showSearch(
|
||||
context: context, delegate: GamemodeSearchDelegate(modes));
|
||||
if (out != null) {
|
||||
mode.value = out;
|
||||
SelectGameModeComponent(
|
||||
initialValue: mode.value,
|
||||
onChanged: (p0) {
|
||||
if (p0 != null) {
|
||||
mode.value = p0;
|
||||
}
|
||||
},
|
||||
child: Text(mode.value),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text("Map"),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
final maps = await ref.read(mapsProvider.future);
|
||||
final out = await showSearch(
|
||||
context: context,
|
||||
delegate: MapSearchDelegate(maps[mode.value] ?? []));
|
||||
if (out != null) {
|
||||
map.value = out;
|
||||
fightsRefresher();
|
||||
SelectMapComponent(
|
||||
gameMode: mode.value,
|
||||
initialValue: map.value,
|
||||
onChanged: (p0) {
|
||||
if (p0 != null) {
|
||||
map.value = p0;
|
||||
}
|
||||
},
|
||||
child: Text(map.value),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text("Kampfleiter"),
|
||||
@ -180,7 +175,7 @@ class EditEventFightDialog extends HookConsumerWidget {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text("Cancel")),
|
||||
ElevatedButton(
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
var nav = Navigator.of(context);
|
||||
final repo = await ref.read(eventRepositoryProvider.future);
|
||||
|
@ -55,11 +55,11 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
final spectateSystemState = useState(event.spectateSystem);
|
||||
final tabController = useTabController(initialLength: 3);
|
||||
|
||||
useMemoized(() {
|
||||
ref.read(schematicTypesProvider.future).then((value) {
|
||||
schematicTypeState.value = catchToNull(
|
||||
() => value.firstWhere((element) => element.db == event.schemType));
|
||||
});
|
||||
useMemoized(() async {
|
||||
schematicTypeState.value = await ref
|
||||
.read(schematicTypesProvider.future)
|
||||
.then((value) => catchToNull(() =>
|
||||
value.firstWhere((element) => element.db == event.schemType)));
|
||||
});
|
||||
|
||||
final changed = useState(false);
|
||||
@ -184,7 +184,6 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text("Deadline: "),
|
||||
DateTimeEditor((p0) {
|
||||
@ -195,7 +194,6 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text("Start: "),
|
||||
DateTimeEditor((p0) {
|
||||
@ -206,7 +204,6 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text("End: "),
|
||||
DateTimeEditor((p0) {
|
||||
@ -264,10 +261,17 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ref.watch(schematicTypesProvider).when(
|
||||
ref.read(schematicTypesProvider).when(
|
||||
data: (data) {
|
||||
return DropdownMenu(
|
||||
dropdownMenuEntries: [
|
||||
const DropdownMenuEntry(value: null, label: ""),
|
||||
if (schematicTypeState.value != null &&
|
||||
!data.contains(schematicTypeState.value))
|
||||
DropdownMenuEntry(
|
||||
value: schematicTypeState.value!,
|
||||
label: schematicTypeState.value!.name,
|
||||
),
|
||||
for (final type in data)
|
||||
DropdownMenuEntry(
|
||||
value: type,
|
||||
@ -276,21 +280,21 @@ class LoadedEventScreen extends HookConsumerWidget {
|
||||
],
|
||||
initialSelection: schematicTypeState.value,
|
||||
enableSearch: true,
|
||||
width: 300,
|
||||
enableFilter: true,
|
||||
width: 200,
|
||||
menuHeight: 300,
|
||||
label: const Text("Schematic Type"),
|
||||
onSelected: (value) {
|
||||
schematicTypeState.value = value;
|
||||
onSelected: (v) async {
|
||||
schematicTypeState.value = v;
|
||||
changed.value = true;
|
||||
},
|
||||
enableFilter: true,
|
||||
);
|
||||
},
|
||||
error: (err, stk) {
|
||||
return ErrorComponent(err, stk);
|
||||
},
|
||||
loading: () {
|
||||
return LinearProgressIndicator();
|
||||
return const Disabled(initialValue: "Schematic Type");
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
@ -24,6 +24,7 @@ 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/select_map_component.dart';
|
||||
import 'package:steamwar_multitool/src/delegates/delegates.dart';
|
||||
import 'package:steamwar_multitool/src/provider/data.dart';
|
||||
import 'package:steamwar_multitool/src/provider/events.dart';
|
||||
@ -158,7 +159,7 @@ class GroupBracketGenerator extends HookConsumerWidget {
|
||||
},
|
||||
),
|
||||
],
|
||||
leading: BackButton(),
|
||||
leading: const BackButton(),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
icon: const Icon(Icons.check),
|
||||
@ -307,7 +308,7 @@ class GroupBracketGenerator extends HookConsumerWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
const Divider(),
|
||||
Column(
|
||||
children: [
|
||||
Row(
|
||||
@ -352,20 +353,11 @@ class GroupBracketGenerator extends HookConsumerWidget {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Text('Map:'),
|
||||
TextButton(
|
||||
onPressed: gamemode.value != null
|
||||
? () async {
|
||||
final newmap = await showSearch(
|
||||
context: context,
|
||||
delegate: MapSearchDelegate(await ref
|
||||
.read(mapsProvider.future)
|
||||
.then((value) =>
|
||||
value[gamemode.value]!)));
|
||||
map.value = newmap;
|
||||
}
|
||||
: null,
|
||||
child: Text(map.value ?? 'None')),
|
||||
SelectMapComponent(
|
||||
gameMode: gamemode.value,
|
||||
initialValue: map.value,
|
||||
onChanged: (p0) => map.value = p0,
|
||||
)
|
||||
],
|
||||
),
|
||||
const Divider(),
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren