はじめに
プレイ内容の一覧を専用スクリーンで表示し、編集や削除、一括操作を行える機能を追加しました。この記事では、新しいプレイ内容一覧スクリーンの概要、実装方法、そして関連コードを紹介します。
プレイ内容一覧スクリーンの概要
これまでプレイ内容の編集や削除はスコア入力スクリーン内で行っていました。しかし、プレイ数が増えるにつれて管理が煩雑になるため、プレイ内容を専用のスクリーンで一括管理できるようにすることが求められました。新しく追加されたプレイ内容一覧スクリーンでは、以下の機能が提供されています。
- プレイ内容の編集
- プレイ内容の削除
- プレイ内容の一括削除
- プレイ内容の並べ替え
これにより、プレイ内容の管理がより直感的かつ効率的になりました。
実装の詳細
プレイ内容一覧スクリーンの実装は、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),
),
一括削除のためのチェックボックスをリストアイテムに追加し、選択状態を管理しています。
スクリーンショット
以下は、新しく追加されたプレイ内容一覧スクリーンのスクリーンショットです。
このスクリーンでは、各プレイの詳細を確認できるだけでなく、編集や削除が可能です。また、プレイ内容を並べ替えたり、一括で削除することもできます。
まとめ
今回のアップデートにより、プレイ内容の管理がさらに効率的になりました。これにより、試合中のスコア入力がよりスムーズに行えるようになり、管理者にとっても利便性が向上しました。今後もユーザーのフィードバックを反映しながら、アプリをより使いやすくしていきたいと思います。
コメント