checked items on db

This commit is contained in:
marcoabat
2023-08-07 11:11:47 +02:00
parent a17bfb6408
commit f4c0555354
3 changed files with 79 additions and 25 deletions

View File

@@ -24,6 +24,7 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
Checklist? _checklist; Checklist? _checklist;
late Future<List<Object>> _checklistFutures; late Future<List<Object>> _checklistFutures;
late final ChecklistProvider _checklistProvider; late final ChecklistProvider _checklistProvider;
List<int> _checkedItemIds = [];
List<Item> _items = []; List<Item> _items = [];
int? _selectedItemId; int? _selectedItemId;
bool _titleEditMode = false; bool _titleEditMode = false;
@@ -45,14 +46,22 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
return Future.wait([ return Future.wait([
DbHelper.getChecklistById(checklistId), DbHelper.getChecklistById(checklistId),
DbHelper.getItemsByChecklistId(checklistId), DbHelper.getItemsByChecklistId(checklistId),
DbHelper.fetchcheckedItemIds(checklistId),
]); ]);
} }
Widget _futureBuilder( Widget _futureBuilder(
BuildContext context, AsyncSnapshot<List<Object>> snapshot) { BuildContext context, AsyncSnapshot<List<Object>> snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
_checklist = snapshot.data!.first as Checklist; _checklist = snapshot.data!.elementAt(0) as Checklist;
_items = snapshot.data!.last as List<Item>; _items = snapshot.data!.elementAt(1) as List<Item>;
_checkedItemIds = snapshot.data!.elementAt(2) as List<int>;
if (pageTitle == null) {
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() =>
pageTitle = _checklist!.title == ''
? 'Unnamed ${_checklist!.id}'
: _checklist!.title));
}
return StreamBuilder( return StreamBuilder(
stream: DbHelper.itemsChangeEventStream, stream: DbHelper.itemsChangeEventStream,
builder: (BuildContext context, builder: (BuildContext context,
@@ -130,13 +139,17 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
} }
Widget? _itemListBuilder(BuildContext context, int index) { Widget? _itemListBuilder(BuildContext context, int index) {
Item item = _items.elementAt(index);
return ItemListTile( return ItemListTile(
title: _items.elementAt(index).title, title: item.title,
description: _items.elementAt(index).description, description: item.description,
onTap: () => _itemTapped(index), onTap: () => _itemTapped(index),
itemSelectionChanged: (isSelected) => itemSelectionChanged: (isSelected) =>
_itemSelectionChanged(isSelected, index), _itemSelectionChanged(isSelected, index),
selectionMode: selectedItemIndexes.isNotEmpty, selectionMode: selectedItemIndexes.isNotEmpty,
isChecked: _checkedItemIds.contains(item.id),
onCheckedChanged: (isSelected) =>
_onItemCheckedChanged(isSelected, item.id),
); );
} }
@@ -170,10 +183,12 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
child: Text(pageTitle ?? '')); child: Text(pageTitle ?? ''));
} else { } else {
titleController.text = pageTitle ?? ''; titleController.text = pageTitle ?? '';
return Expanded( return TextField(
child: TextField(
autofocus: true, autofocus: true,
controller: titleController, controller: titleController,
onSubmitted: (value) => _onTitleChanged(
_checklist!.id,
titleController.text,
), ),
); );
} }
@@ -192,12 +207,6 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
AsyncSnapshot<List<Map<String, dynamic>>> snapshot, AsyncSnapshot<List<Map<String, dynamic>>> snapshot,
Checklist? checklist, Checklist? checklist,
List<Item> items) { List<Item> items) {
if (pageTitle != _checklist!.title) {
WidgetsBinding.instance.addPostFrameCallback((_) => setState(() =>
pageTitle = _checklist!.title == ''
? 'Unnamed ${_checklist!.id}'
: _checklist!.title));
}
if (snapshot.hasData) { if (snapshot.hasData) {
_items = DbHelper.resToItemList(snapshot.data!); _items = DbHelper.resToItemList(snapshot.data!);
} }
@@ -250,4 +259,12 @@ class _DetailChecklistPageState extends State<DetailChecklistPage> {
), ),
); );
} }
_onItemCheckedChanged(bool isSelected, int? id) async {
if (isSelected) {
await DbHelper.insertCheckedEntry(_checklist!.id, id!);
} else {
await DbHelper.deleteCheckedEntry(_checklist!.id, id!);
}
}
} }

View File

@@ -10,10 +10,10 @@ import 'package:provider/provider.dart' as provider;
class DbHelper { class DbHelper {
static const checkedItemsTableName = 'checkedItems'; static const checkedItemsTableName = 'checkedItems';
static const checklistsTableName = 'checklists'; static const checklistsTableName = 'checklists';
static ChecklistProvider? clProvider;
static const itemsTableName = 'items'; static const itemsTableName = 'items';
static late final SupabaseClient _client; static late final SupabaseClient _client;
static ChecklistProvider? clProvider;
static Future<void> init() async { static Future<void> init() async {
await Supabase.initialize( await Supabase.initialize(
@@ -58,6 +58,26 @@ class DbHelper {
return checklists; return checklists;
} }
static Future<List<int>> fetchcheckedItemIds(int checklistId) async {
List<int> itemIdList = [];
final res = await _client
.from(checkedItemsTableName)
.select<List<Map<String, dynamic>>>('item_id');
for (final element in res) {
itemIdList.add(element['item_id']);
}
return itemIdList;
}
static Future<void> insertCheckedEntry(int checklistId, int itemId) async {
final ownerId = _client.auth.currentSession!.user.id;
await _client.from(checkedItemsTableName).insert({
'id': ownerId,
'checklist_id': checklistId,
'item_id': itemId,
});
}
static Future<void> updateChecklistTitle(int id, String title) async { static Future<void> updateChecklistTitle(int id, String title) async {
await _client await _client
.from(checklistsTableName) .from(checklistsTableName)
@@ -155,6 +175,15 @@ class DbHelper {
); );
} }
static Future<void> deleteCheckedEntry(int checklistId, int itemId) async {
final ownerId = _client.auth.currentSession!.user.id;
await _client.from(checkedItemsTableName).delete().match({
'id': ownerId,
'checklist_id': checklistId,
'item_id': itemId,
});
}
static Future<void> deleteItemById(int id) async { static Future<void> deleteItemById(int id) async {
await _client.from(itemsTableName).delete().eq('id', id); await _client.from(itemsTableName).delete().eq('id', id);
} }

View File

@@ -10,26 +10,28 @@ class ItemListTile extends StatefulWidget {
required this.onTap, required this.onTap,
required this.itemSelectionChanged, required this.itemSelectionChanged,
required this.selectionMode, required this.selectionMode,
this.isSelected = false, required this.isChecked,
required this.onCheckedChanged,
}); });
final String title; final String title;
final String description; final String description;
final bool selectionMode; final bool selectionMode;
final bool isChecked;
final VoidCallback onTap; final VoidCallback onTap;
final BoolCallback onCheckedChanged;
final BoolCallback itemSelectionChanged; final BoolCallback itemSelectionChanged;
final bool isSelected;
@override @override
State<ItemListTile> createState() => _ItemListTileState(); State<ItemListTile> createState() => _ItemListTileState();
} }
class _ItemListTileState extends State<ItemListTile> { class _ItemListTileState extends State<ItemListTile> {
late bool isSelected; late bool isChecked;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
isSelected = widget.isSelected; isChecked = widget.isChecked;
} }
@override @override
@@ -39,19 +41,25 @@ class _ItemListTileState extends State<ItemListTile> {
subtitle: Text(widget.description), subtitle: Text(widget.description),
onTap: _onTap, onTap: _onTap,
onLongPress: _onLongPress, onLongPress: _onLongPress,
selected: isSelected, trailing: Checkbox(
value: isChecked,
onChanged: (value) {
setState(() => isChecked = value!);
widget.onCheckedChanged(value!);
},
),
); );
} }
void _onLongPress() { void _onLongPress() {
setState(() => isSelected = true); setState(() => isChecked = true);
widget.itemSelectionChanged(isSelected); widget.itemSelectionChanged(isChecked);
} }
void _onTap() { void _onTap() {
if (isSelected || widget.selectionMode) { if (isChecked || widget.selectionMode) {
setState(() => isSelected = !isSelected); setState(() => isChecked = !isChecked);
widget.itemSelectionChanged(isSelected); widget.itemSelectionChanged(isChecked);
} else { } else {
widget.onTap(); widget.onTap();
} }