Flutterバスケアプリ | プレイ内容一覧専用スクリーンを追加

はじめに

プレイ内容の一覧を専用スクリーンで表示し、編集や削除、一括操作を行える機能を追加しました。この記事では、新しいプレイ内容一覧スクリーンの概要、実装方法、そして関連コードを紹介します。

プレイ内容一覧スクリーンの概要

これまでプレイ内容の編集や削除はスコア入力スクリーン内で行っていました。しかし、プレイ数が増えるにつれて管理が煩雑になるため、プレイ内容を専用のスクリーンで一括管理できるようにすることが求められました。新しく追加されたプレイ内容一覧スクリーンでは、以下の機能が提供されています。

  • プレイ内容の編集
  • プレイ内容の削除
  • プレイ内容の一括削除
  • プレイ内容の並べ替え

これにより、プレイ内容の管理がより直感的かつ効率的になりました。

実装の詳細

プレイ内容一覧スクリーンの実装は、FlutterのStatefulWidgetをベースにしています。このスクリーンでは、プレイ内容の一覧表示、編集、削除、一括操作が可能です。

プレイ内容一覧の表示

まず、プレイ内容をリスト形式で表示するために、ReorderableListViewを使用しています。これにより、プレイ内容をドラッグ&ドロップで並べ替えることができます。

Expanded(
  child: ReorderableListView.builder(
    itemCount: _plays.length,
    onReorder: (int oldIndex, int newIndex) {
      setState(() {
        if (newIndex > oldIndex) {
          newIndex -= 1;
        }
        final PlayEntry play = _plays.removeAt(oldIndex);
        _plays.insert(newIndex, play);
      });
    },
    itemBuilder: (context, index) {
      final play = _plays[index];
      final teamName = _teams
          .firstWhere((team) => team.id == play.teamId, orElse: () => Team(id: 0, name: '不明なチーム'))
          .name;

      return ListTile(
        key: ValueKey(play.id),
        title: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Expanded(child: Text('${play.quarter}Q', textAlign: TextAlign.center)),
            Expanded(child: Text(teamName, textAlign: TextAlign.center)),
            Expanded(child: Text('#${play.playerNumber}', textAlign: TextAlign.center)),
            Expanded(child: Text(play.playType, textAlign: TextAlign.center)),
            Expanded(child: Text(play.time, textAlign: TextAlign.center)),
            Expanded(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  IconButton(icon: Icon(Icons.edit), onPressed: () => _showEditPlayDialog(play)),
                  IconButton(icon: Icon(Icons.delete), onPressed: () => _showDeleteConfirmationDialog(play.id!)),
                ],
              ),
            ),
          ],
        ),
        trailing: ReorderableDragStartListener(
          index: index,
          child: Icon(Icons.drag_handle),
        ),
      );
    },
  ),
)

このコードでは、各プレイ内容がリスト形式で表示され、編集や削除が簡単に行えます。また、プレイの順番を並べ替えることも可能です。

プレイ内容の編集と削除

プレイ内容の編集は、ダイアログを表示して行います。編集ダイアログでは、プレイの詳細を変更し、更新を保存できます。

Future<void> _showEditPlayDialog(PlayEntry play) async {
  int? selectedPlayerNumber = int.tryParse(play.playerNumber);
  String selectedPlayType = play.playType;
  int? selectedTeamId = play.teamId;
  List<int> availablePlayerNumbers = [];

  if (selectedTeamId != null) {
    availablePlayerNumbers = _members
        .where((member) => member.teamId == selectedTeamId)
        .map((member) => member.number)
        .toList();
  }

  await showDialog<void>(
    context: context,
    builder: (BuildContext context) {
      return StatefulBuilder(
        builder: (context, setState) {
          return AlertDialog(
            title: Text('プレイ内容の編集'),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                DropdownButtonFormField<int>(
                  decoration: InputDecoration(hintText: 'チームを選択'),
                  value: selectedTeamId,
                  items: _teams.map((team) {
                    return DropdownMenuItem<int>(
                      value: team.id,
                      child: Text(team.name),
                    );
                  }).toList(),
                  onChanged: (value) {
                    setState(() {
                      selectedTeamId = value;
                      availablePlayerNumbers = _members
                          .where((member) => member.teamId == selectedTeamId)
                          .map((member) => member.number)
                          .toList();
                    });
                  },
                ),
                DropdownButtonFormField<int>(
                  decoration: InputDecoration(hintText: 'プレイヤー番号を選択'),
                  value: selectedPlayerNumber,
                  items: availablePlayerNumbers.map((number) {
                    return DropdownMenuItem<int>(
                      value: number,
                      child: Text(number == 999 ? 'TEAM' : '$number'),
                    );
                  }).toList(),
                  onChanged: (value) {
                    setState(() {
                      selectedPlayerNumber = value;
                    });
                  },
                ),
                DropdownButtonFormField<String>(
                  decoration: InputDecoration(hintText: 'プレイ内容を選択'),
                  value: selectedPlayType,
                  items: ['FT', '2P', '3P', 'ファウル', 'タイムアウト'].map((type) {
                    return DropdownMenuItem<String>(
                      value: type,
                      child: Text(type),
                    );
                  }).toList(),
                  onChanged: (value) {
                    setState(() {
                      selectedPlayType = value!;
                    });
                  },
                ),
              ],
            ),
            actions: [
              TextButton(onPressed: () => Navigator.of(context).pop(), child: Text('キャンセル')),
              TextButton(
                onPressed: () async {
                  PlayEntry updatedPlay = PlayEntry(
                    id: play.id,
                    teamId: selectedTeamId!,
                    points: play.points,
                    quarter: play.quarter,
                    playType: selectedPlayType,
                    time: play.time,
                    playerNumber: selectedPlayerNumber?.toString() ?? '0',
                    gameId: play.gameId,
                  );
                  await _playProvider.updatePlay(updatedPlay);
                  _loadPlaysForCurrentGame();
                  Navigator.of(context).pop();
                },
                child: Text('保存'),
              ),
            ],
          );
        },
      );
    },
  );
}

削除機能では、選択したプレイを削除する際に確認ダイアログを表示し、誤操作を防ぐようにしています。

プレイ内容の一括削除

プレイ内容を一括削除できる機能も実装しました。これにより、複数のプレイを選択して一度に削除することができます。

IconButton(
  icon: Icon(Icons.delete),
  onPressed: () => _showDeleteConfirmationDialog(_selectedPlayIds),
),

一括削除のためのチェックボックスをリストアイテムに追加し、選択状態を管理しています。

スクリーンショット

以下は、新しく追加されたプレイ内容一覧スクリーンのスクリーンショットです。

このスクリーンでは、各プレイの詳細を確認できるだけでなく、編集や削除が可能です。また、プレイ内容を並べ替えたり、一括で削除することもできます。

まとめ

今回のアップデートにより、プレイ内容の管理がさらに効率的になりました。これにより、試合中のスコア入力がよりスムーズに行えるようになり、管理者にとっても利便性が向上しました。今後もユーザーのフィードバックを反映しながら、アプリをより使いやすくしていきたいと思います。

関連記事

コメント

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