feat: games with match associations cant be deleted
This commit is contained in:
@@ -176,4 +176,25 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
||||
final rowsAffected = await query.go();
|
||||
return rowsAffected > 0;
|
||||
}
|
||||
|
||||
/// Retrieves all games with their respective match counts.
|
||||
/// Returns a list of tuples (Game, matchCount).
|
||||
Future<List<(Game, int)>> getGameUsage() async {
|
||||
final games = await getAllGames();
|
||||
|
||||
final results = <(Game, int)>[];
|
||||
|
||||
for (final game in games) {
|
||||
final matchCount =
|
||||
await (selectOnly(db.matchTable)
|
||||
..where(db.matchTable.gameId.equals(game.id))
|
||||
..addColumns([db.matchTable.id.count()]))
|
||||
.map((row) => row.read(db.matchTable.id.count()))
|
||||
.getSingle();
|
||||
|
||||
results.add((game, matchCount ?? 0));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tallee/core/adaptive_page_route.dart';
|
||||
import 'package:tallee/core/common.dart';
|
||||
import 'package:tallee/core/custom_theme.dart';
|
||||
import 'package:tallee/data/db/database.dart';
|
||||
import 'package:tallee/data/models/game.dart';
|
||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_game/create_game_view.dart';
|
||||
@@ -34,6 +36,10 @@ class ChooseGameView extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
late final AppDatabase db;
|
||||
|
||||
late List<(Game, int)> gameCounts = [];
|
||||
|
||||
/// Controller for the search bar
|
||||
final TextEditingController searchBarController = TextEditingController();
|
||||
|
||||
@@ -45,6 +51,9 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
db = Provider.of<AppDatabase>(context, listen: false);
|
||||
fetchGameCounts();
|
||||
|
||||
selectedGameId = widget.initialGameId;
|
||||
|
||||
// Start with all games visible
|
||||
@@ -150,6 +159,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
adaptivePageRoute(
|
||||
builder: (context) => CreateGameView(
|
||||
gameToEdit: game,
|
||||
canDelete: canDeleteGame(game),
|
||||
onGameChanged: () {
|
||||
widget.onGamesUpdated?.call();
|
||||
},
|
||||
@@ -209,4 +219,16 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
||||
void _refreshFromSource() {
|
||||
_applySearchFilter(searchBarController.text);
|
||||
}
|
||||
|
||||
Future<void> fetchGameCounts() async {
|
||||
gameCounts = await db.gameDao.getGameUsage();
|
||||
}
|
||||
|
||||
// A game can only be deleted if there are no matches using it
|
||||
bool canDeleteGame(Game game) {
|
||||
final count = gameCounts
|
||||
.firstWhere((gc) => gc.$1.id == game.id, orElse: () => (game, 0))
|
||||
.$2;
|
||||
return count == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,15 +23,18 @@ import 'package:tallee/presentation/widgets/tiles/choose_tile.dart';
|
||||
class CreateGameView extends StatefulWidget {
|
||||
const CreateGameView({
|
||||
super.key,
|
||||
this.gameToEdit,
|
||||
required this.onGameChanged,
|
||||
this.gameToEdit,
|
||||
this.canDelete = false,
|
||||
});
|
||||
|
||||
/// Callback to invoke when the game is created or edited
|
||||
final VoidCallback onGameChanged;
|
||||
|
||||
/// An optional game to prefill the fields
|
||||
final Game? gameToEdit;
|
||||
|
||||
/// Callback to invoke when the game is created or edited
|
||||
final VoidCallback onGameChanged;
|
||||
final bool canDelete;
|
||||
|
||||
@override
|
||||
State<CreateGameView> createState() => _CreateGameViewState();
|
||||
@@ -41,7 +44,6 @@ class _CreateGameViewState extends State<CreateGameView> {
|
||||
/// GlobalKey for ScaffoldMessenger to show snackbars
|
||||
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||
|
||||
/// The database instance for accessing game data.
|
||||
late final AppDatabase db;
|
||||
|
||||
/// The currently selected ruleset for the game.
|
||||
@@ -133,13 +135,12 @@ class _CreateGameViewState extends State<CreateGameView> {
|
||||
backgroundColor: CustomTheme.backgroundColor,
|
||||
appBar: AppBar(
|
||||
title: Text(isEditing ? loc.edit_game : loc.create_game),
|
||||
actions: widget.gameToEdit == null
|
||||
? []
|
||||
: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () async {
|
||||
if (widget.gameToEdit != null) {
|
||||
actions: [
|
||||
if (isEditMode())
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: widget.canDelete
|
||||
? () async {
|
||||
showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => CustomAlertDialog(
|
||||
@@ -176,9 +177,9 @@ class _CreateGameViewState extends State<CreateGameView> {
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
|
||||
Reference in New Issue
Block a user