Flutterバスケアプリ | 保存済み試合データの一括削除機能を追加

今回は、保存済みの試合データに対して一括で削除を行う機能を追加しました。この機能により、複数の試合データを簡単に選択して、一度に削除できるようになります。

主な機能

  • 試合データの一括削除: チェックボックスで複数の試合データを選択し、一括で削除が可能。
  • 確認ダイアログ: 削除時には確認用のダイアログが表示されるため、誤って削除することを防止します。

実装の背景

試合データの管理が煩雑になってきたため、複数の試合を一度に削除できる機能が求められていました。この機能によって、ユーザーは必要なデータのみを素早く残すことができるようになり、操作性が向上します。

実装内容

チェックボックスの追加
各試合データの横にチェックボックスを追加し、複数選択ができるようにしました。これにより、不要な試合データを一括して選択可能です。

一括削除ボタン
画面右上に削除アイコンを配置し、チェックボックスで選択されたデータを一括削除することができます。

実際のコード

以下は、この機能を実装したコードです。

import 'package:flutter/material.dart';
import 'game_entry_provider.dart';
import 'score_input_screen.dart';

class GameDataScreen extends StatefulWidget {
  @override
  _GameDataScreenState createState() => _GameDataScreenState();
}

class _GameDataScreenState extends State<GameDataScreen> {
  final GameEntryProvider _gameProvider = GameEntryProvider();
  List<GameEntry> _games = [];
  Set<int> _selectedGameIds = Set<int>(); // チェックボックスで選択されたゲームIDを格納

  @override
  void initState() {
    super.initState();
    _loadGames();
  }

  Future<void> _loadGames() async {
    List<GameEntry> games = await _gameProvider.getAllGames();
    setState(() {
      _games = games;
    });
  }

  Future<void> _deleteGame(int gameId) async {
    await _gameProvider.deleteGame(gameId);
    _loadGames(); // データを再読み込みしてUIを更新
  }

  Future<void> _deleteSelectedGames() async {
    for (int gameId in _selectedGameIds) {
      await _gameProvider.deleteGame(gameId);
    }
    _selectedGameIds.clear(); // 削除後に選択をクリア
    _loadGames(); // データを再読み込みしてUIを更新
  }

  void _showDeleteConfirmationDialog(int? gameId) {
    String contentText;
    VoidCallback onConfirm;

    if (gameId != null) {
      contentText = "この試合データを削除しますか?";
      onConfirm = () {
        _deleteGame(gameId);
        Navigator.of(context).pop(); // ダイアログを閉じる
      };
    } else {
      contentText = "選択した試合データをすべて削除しますか?";
      onConfirm = () {
        _deleteSelectedGames();
        Navigator.of(context).pop(); // ダイアログを閉じる
      };
    }

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("試合データの削除"),
          content: Text(contentText),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(), // ダイアログを閉じる
              child: Text("キャンセル"),
            ),
            TextButton(
              onPressed: onConfirm,
              child: Text("削除"),
            ),
          ],
        );
      },
    );
  }

  void _showEditGameDialog(GameEntry game) {
    TextEditingController nameController =
        TextEditingController(text: game.name);
    TextEditingController venueController =
        TextEditingController(text: game.venue);

    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("試合情報の編集"),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              TextField(
                controller: nameController,
                decoration: InputDecoration(hintText: '試合名'),
              ),
              TextField(
                controller: venueController,
                decoration: InputDecoration(hintText: '会場名'),
              ),
            ],
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: Text("キャンセル"),
            ),
            TextButton(
              onPressed: () async {
                GameEntry updatedGame = GameEntry(
                  id: game.id,
                  name: nameController.text,
                  venue: venueController.text,
                  date: game.date, // 日付はそのまま
                  teamAId: game.teamAId, // 既存のteamAIdを保持
                  teamBId: game.teamBId, // 既存のteamBIdを保持
                );
                await _gameProvider.updateGame(updatedGame);
                _loadGames();
                Navigator.of(context).pop();
              },
              child: Text("保存"),
            ),
          ],
        );
      },
    );
  }

  void _showLoadGameDialog(GameEntry game) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("試合を再開"),
          content: Text("この試合を再開しますか?"),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: Text("キャンセル"),
            ),
            TextButton(
              onPressed: () {
                Navigator.of(context).pop(); // ダイアログを閉じる
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => ScoreInputScreen(gameId: game.id),
                  ),
                );
              },
              child: Text("再開"),
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('保存済みの試合データ'),
        actions: [
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: _selectedGameIds.isNotEmpty
                ? () => _showDeleteConfirmationDialog(null)
                : null, // 選択されているデータがあれば削除ボタンを有効にする
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: _games.length,
        itemBuilder: (context, index) {
          final game = _games[index];
          final isSelected = _selectedGameIds.contains(game.id);

          return ListTile(
            leading: Checkbox(
              value: isSelected,
              onChanged: (bool? value) {
                setState(() {
                  if (value == true) {
                    _selectedGameIds.add(game.id!); // ゲームIDをセットに追加
                  } else {
                    _selectedGameIds.remove(game.id); // ゲームIDをセットから削除
                  }
                });
              },
            ),
            title: Text(game.name),
            subtitle: Text('会場: ${game.venue} - 日付: ${game.date}'),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () => _showEditGameDialog(game),
                ),
                IconButton(
                  icon: Icon(Icons.delete),
                  onPressed: () => _showDeleteConfirmationDialog(game.id),
                ),
              ],
            ),
            onTap: () => _showLoadGameDialog(game),
          );
        },
      ),
    );
  }
}

スクリーンショット

データ管理スクリーン

確認ダイアログ

関連記事

コメント

タイトルとURLをコピーしました