Implemented basic game choosing functionality
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tallee/core/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/data/models/game.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart';
|
||||||
@@ -13,14 +13,14 @@ class ChooseGameView extends StatefulWidget {
|
|||||||
const ChooseGameView({
|
const ChooseGameView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.games,
|
required this.games,
|
||||||
required this.initialGameIndex,
|
required this.initialGameId,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// A list of tuples containing the game name, description and ruleset
|
/// A list of tuples containing the game name, description and ruleset
|
||||||
final List<(String, String, Ruleset)> games;
|
final List<Game> games;
|
||||||
|
|
||||||
/// The index of the initially selected game
|
/// The id of the initially selected game
|
||||||
final int initialGameIndex;
|
final String initialGameId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChooseGameView> createState() => _ChooseGameViewState();
|
State<ChooseGameView> createState() => _ChooseGameViewState();
|
||||||
@@ -31,11 +31,11 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
final TextEditingController searchBarController = TextEditingController();
|
final TextEditingController searchBarController = TextEditingController();
|
||||||
|
|
||||||
/// Currently selected game index
|
/// Currently selected game index
|
||||||
late int selectedGameIndex;
|
late String selectedGameId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
selectedGameIndex = widget.initialGameIndex;
|
selectedGameId = widget.initialGameId;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,13 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(selectedGameIndex);
|
Navigator.of(context).pop(
|
||||||
|
selectedGameId == ''
|
||||||
|
? null
|
||||||
|
: widget.games.firstWhere(
|
||||||
|
(game) => game.id == selectedGameId,
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: Text(loc.choose_game),
|
title: Text(loc.choose_game),
|
||||||
@@ -62,7 +68,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
if (didPop) {
|
if (didPop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Navigator.of(context).pop(selectedGameIndex);
|
Navigator.of(context).pop(widget.initialGameId);
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -79,19 +85,19 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
itemCount: widget.games.length,
|
itemCount: widget.games.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return TitleDescriptionListTile(
|
return TitleDescriptionListTile(
|
||||||
title: widget.games[index].$1,
|
title: widget.games[index].name,
|
||||||
description: widget.games[index].$2,
|
description: widget.games[index].description,
|
||||||
badgeText: translateRulesetToString(
|
badgeText: translateRulesetToString(
|
||||||
widget.games[index].$3,
|
widget.games[index].ruleset,
|
||||||
context,
|
context,
|
||||||
),
|
),
|
||||||
isHighlighted: selectedGameIndex == index,
|
isHighlighted: selectedGameId == widget.games[index].id,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedGameIndex == index) {
|
if (selectedGameId != widget.games[index].id) {
|
||||||
selectedGameIndex = -1;
|
selectedGameId = widget.games[index].id;
|
||||||
} else {
|
} else {
|
||||||
selectedGameIndex = index;
|
selectedGameId = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import 'package:tallee/presentation/widgets/tiles/choose_tile.dart';
|
|||||||
|
|
||||||
class CreateMatchView extends StatefulWidget {
|
class CreateMatchView extends StatefulWidget {
|
||||||
/// A view that allows creating a new match
|
/// A view that allows creating a new match
|
||||||
/// [onWinnerChanged]: Optional callback invoked when the winner is changed
|
/// - [onWinnerChanged]: Optional callback invoked when the winner is changed
|
||||||
|
/// - [matchToEdit]: An optional match to prefill the fields for editing.
|
||||||
|
/// - [onMatchUpdated]: Optional callback invoked when the match is updated (only in
|
||||||
const CreateMatchView({
|
const CreateMatchView({
|
||||||
super.key,
|
super.key,
|
||||||
this.onWinnerChanged,
|
this.onWinnerChanged,
|
||||||
@@ -28,13 +30,11 @@ class CreateMatchView extends StatefulWidget {
|
|||||||
this.onMatchUpdated,
|
this.onMatchUpdated,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Optional callback invoked when the winner is changed
|
|
||||||
final VoidCallback? onWinnerChanged;
|
final VoidCallback? onWinnerChanged;
|
||||||
|
|
||||||
/// Optional callback invoked when the match is updated
|
|
||||||
final void Function(Match)? onMatchUpdated;
|
final void Function(Match)? onMatchUpdated;
|
||||||
|
|
||||||
/// An optional match to prefill the fields
|
/// An optional match to prefill the fields for editing.
|
||||||
final Match? matchToEdit;
|
final Match? matchToEdit;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -50,20 +50,12 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// Hint text for the match name input field
|
/// Hint text for the match name input field
|
||||||
String? hintText;
|
String? hintText;
|
||||||
|
|
||||||
/// List of all groups from the database
|
|
||||||
List<Group> groupsList = [];
|
List<Group> groupsList = [];
|
||||||
|
|
||||||
/// List of all players from the database
|
|
||||||
List<Player> playerList = [];
|
List<Player> playerList = [];
|
||||||
|
List<Game> gamesList = [];
|
||||||
|
|
||||||
/// The currently selected group
|
|
||||||
Group? selectedGroup;
|
Group? selectedGroup;
|
||||||
|
Game? selectedGame;
|
||||||
/// The index of the currently selected game in [games] to mark it in
|
|
||||||
/// the [ChooseGameView]
|
|
||||||
int selectedGameIndex = -1;
|
|
||||||
|
|
||||||
/// The currently selected players
|
|
||||||
List<Player> selectedPlayers = [];
|
List<Player> selectedPlayers = [];
|
||||||
|
|
||||||
/// GlobalKey for ScaffoldMessenger to show snackbars
|
/// GlobalKey for ScaffoldMessenger to show snackbars
|
||||||
@@ -81,12 +73,14 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
Future.wait([
|
Future.wait([
|
||||||
db.groupDao.getAllGroups(),
|
db.groupDao.getAllGroups(),
|
||||||
db.playerDao.getAllPlayers(),
|
db.playerDao.getAllPlayers(),
|
||||||
|
db.gameDao.getAllGames(),
|
||||||
]).then((result) async {
|
]).then((result) async {
|
||||||
groupsList = result[0] as List<Group>;
|
groupsList = result[0] as List<Group>;
|
||||||
playerList = result[1] as List<Player>;
|
playerList = result[1] as List<Player>;
|
||||||
|
gamesList = (result[2] as List<Game>);
|
||||||
|
|
||||||
// If a match is provided, prefill the fields
|
// If a match is provided, prefill the fields
|
||||||
if (widget.matchToEdit != null) {
|
if (isEditMode()) {
|
||||||
prefillMatchDetails();
|
prefillMatchDetails();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -105,20 +99,11 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
hintText ??= loc.match_name;
|
hintText ??= loc.match_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(String, String, Ruleset)> games = [
|
|
||||||
('Example Game 1', 'This is a description', Ruleset.lowestScore),
|
|
||||||
('Example Game 2', '', Ruleset.singleWinner),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
final buttonText = widget.matchToEdit != null
|
final buttonText = isEditMode() ? loc.save_changes : loc.create_match;
|
||||||
? loc.save_changes
|
final viewTitle = isEditMode() ? loc.edit_match : loc.create_new_match;
|
||||||
: loc.create_match;
|
|
||||||
final viewTitle = widget.matchToEdit != null
|
|
||||||
? loc.edit_match
|
|
||||||
: loc.create_new_match;
|
|
||||||
|
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
key: _scaffoldMessengerKey,
|
key: _scaffoldMessengerKey,
|
||||||
@@ -140,21 +125,21 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
),
|
),
|
||||||
ChooseTile(
|
ChooseTile(
|
||||||
title: loc.game,
|
title: loc.game,
|
||||||
trailingText: selectedGameIndex == -1
|
trailingText: selectedGame == null
|
||||||
? loc.none
|
? loc.none_group
|
||||||
: games[selectedGameIndex].$1,
|
: selectedGame!.name,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
selectedGameIndex = await Navigator.of(context).push(
|
selectedGame = await Navigator.of(context).push(
|
||||||
adaptivePageRoute(
|
adaptivePageRoute(
|
||||||
builder: (context) => ChooseGameView(
|
builder: (context) => ChooseGameView(
|
||||||
games: games,
|
games: gamesList,
|
||||||
initialGameIndex: selectedGameIndex,
|
initialGameId: selectedGame?.id ?? '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedGameIndex != -1) {
|
if (selectedGame != null) {
|
||||||
hintText = games[selectedGameIndex].$1;
|
hintText = selectedGame!.name;
|
||||||
} else {
|
} else {
|
||||||
hintText = loc.match_name;
|
hintText = loc.match_name;
|
||||||
}
|
}
|
||||||
@@ -225,6 +210,10 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isEditMode() {
|
||||||
|
return widget.matchToEdit != null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines whether the "Create Match" button should be enabled.
|
/// Determines whether the "Create Match" button should be enabled.
|
||||||
///
|
///
|
||||||
/// Returns `true` if:
|
/// Returns `true` if:
|
||||||
@@ -232,7 +221,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// - Either a group is selected OR at least 2 players are selected
|
/// - Either a group is selected OR at least 2 players are selected
|
||||||
bool _enableCreateGameButton() {
|
bool _enableCreateGameButton() {
|
||||||
return (selectedGroup != null ||
|
return (selectedGroup != null ||
|
||||||
(selectedPlayers.length > 1) && selectedGameIndex != -1);
|
(selectedPlayers.length > 1) && selectedGame != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a match was provided to the view, it updates the match in the database
|
// If a match was provided to the view, it updates the match in the database
|
||||||
@@ -240,7 +229,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
// If no match was provided, it creates a new match in the database and
|
// If no match was provided, it creates a new match in the database and
|
||||||
// navigates to the MatchResultView for the newly created match.
|
// navigates to the MatchResultView for the newly created match.
|
||||||
void buttonNavigation(BuildContext context) async {
|
void buttonNavigation(BuildContext context) async {
|
||||||
if (widget.matchToEdit != null) {
|
if (isEditMode()) {
|
||||||
await updateMatch();
|
await updateMatch();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -266,9 +255,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// Updates attributes of the existing match in the database based on the
|
/// Updates attributes of the existing match in the database based on the
|
||||||
/// changes made in the edit view.
|
/// changes made in the edit view.
|
||||||
Future<void> updateMatch() async {
|
Future<void> updateMatch() async {
|
||||||
//TODO: Remove when Games implemented
|
|
||||||
final tempGame = await getTemporaryGame();
|
|
||||||
|
|
||||||
final updatedMatch = Match(
|
final updatedMatch = Match(
|
||||||
id: widget.matchToEdit!.id,
|
id: widget.matchToEdit!.id,
|
||||||
name: _matchNameController.text.isEmpty
|
name: _matchNameController.text.isEmpty
|
||||||
@@ -276,7 +262,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
: _matchNameController.text.trim(),
|
: _matchNameController.text.trim(),
|
||||||
group: selectedGroup,
|
group: selectedGroup,
|
||||||
players: selectedPlayers,
|
players: selectedPlayers,
|
||||||
game: tempGame,
|
game: widget.matchToEdit!.game,
|
||||||
createdAt: widget.matchToEdit!.createdAt,
|
createdAt: widget.matchToEdit!.createdAt,
|
||||||
endedAt: widget.matchToEdit!.endedAt,
|
endedAt: widget.matchToEdit!.endedAt,
|
||||||
notes: widget.matchToEdit!.notes,
|
notes: widget.matchToEdit!.notes,
|
||||||
@@ -322,8 +308,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
// Creates a new match and adds it to the database.
|
// Creates a new match and adds it to the database.
|
||||||
// Returns the created match.
|
// Returns the created match.
|
||||||
Future<Match> createMatch() async {
|
Future<Match> createMatch() async {
|
||||||
final tempGame = await getTemporaryGame();
|
|
||||||
|
|
||||||
Match match = Match(
|
Match match = Match(
|
||||||
name: _matchNameController.text.isEmpty
|
name: _matchNameController.text.isEmpty
|
||||||
? (hintText ?? '')
|
? (hintText ?? '')
|
||||||
@@ -331,35 +315,18 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
group: selectedGroup,
|
group: selectedGroup,
|
||||||
players: selectedPlayers,
|
players: selectedPlayers,
|
||||||
game: tempGame,
|
game: selectedGame!,
|
||||||
);
|
);
|
||||||
await db.matchDao.addMatch(match: match);
|
await db.matchDao.addMatch(match: match);
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove when games fully implemented
|
|
||||||
Future<Game> getTemporaryGame() async {
|
|
||||||
Game? game;
|
|
||||||
|
|
||||||
final selectedGame = games[selectedGameIndex];
|
|
||||||
game = Game(
|
|
||||||
name: selectedGame.$1,
|
|
||||||
description: selectedGame.$2,
|
|
||||||
ruleset: selectedGame.$3,
|
|
||||||
color: GameColor.blue,
|
|
||||||
icon: '',
|
|
||||||
);
|
|
||||||
|
|
||||||
await db.gameDao.addGame(game: game);
|
|
||||||
return game;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a match was provided to the view, this method prefills the input fields
|
// If a match was provided to the view, this method prefills the input fields
|
||||||
void prefillMatchDetails() {
|
void prefillMatchDetails() {
|
||||||
final match = widget.matchToEdit!;
|
final match = widget.matchToEdit!;
|
||||||
_matchNameController.text = match.name;
|
_matchNameController.text = match.name;
|
||||||
selectedPlayers = match.players;
|
selectedPlayers = match.players;
|
||||||
selectedGameIndex = 0;
|
selectedGame = match.game;
|
||||||
|
|
||||||
if (match.group != null) {
|
if (match.group != null) {
|
||||||
selectedGroup = match.group;
|
selectedGroup = match.group;
|
||||||
|
|||||||
Reference in New Issue
Block a user