From f4c05553540ba57d3786d3d82982a4d09ec534b7 Mon Sep 17 00:00:00 2001 From: marcoabat Date: Mon, 7 Aug 2023 11:11:47 +0200 Subject: [PATCH] checked items on db --- lib/pages/detail_checklist_page.dart | 45 +++++++++++++++++++--------- lib/services/dbhelper.dart | 31 ++++++++++++++++++- lib/widgets/item_list_tile.dart | 28 ++++++++++------- 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/lib/pages/detail_checklist_page.dart b/lib/pages/detail_checklist_page.dart index cd305b0..81fd312 100644 --- a/lib/pages/detail_checklist_page.dart +++ b/lib/pages/detail_checklist_page.dart @@ -24,6 +24,7 @@ class _DetailChecklistPageState extends State { Checklist? _checklist; late Future> _checklistFutures; late final ChecklistProvider _checklistProvider; + List _checkedItemIds = []; List _items = []; int? _selectedItemId; bool _titleEditMode = false; @@ -45,14 +46,22 @@ class _DetailChecklistPageState extends State { return Future.wait([ DbHelper.getChecklistById(checklistId), DbHelper.getItemsByChecklistId(checklistId), + DbHelper.fetchcheckedItemIds(checklistId), ]); } Widget _futureBuilder( BuildContext context, AsyncSnapshot> snapshot) { if (snapshot.hasData) { - _checklist = snapshot.data!.first as Checklist; - _items = snapshot.data!.last as List; + _checklist = snapshot.data!.elementAt(0) as Checklist; + _items = snapshot.data!.elementAt(1) as List; + _checkedItemIds = snapshot.data!.elementAt(2) as List; + if (pageTitle == null) { + WidgetsBinding.instance.addPostFrameCallback((_) => setState(() => + pageTitle = _checklist!.title == '' + ? 'Unnamed ${_checklist!.id}' + : _checklist!.title)); + } return StreamBuilder( stream: DbHelper.itemsChangeEventStream, builder: (BuildContext context, @@ -130,13 +139,17 @@ class _DetailChecklistPageState extends State { } Widget? _itemListBuilder(BuildContext context, int index) { + Item item = _items.elementAt(index); return ItemListTile( - title: _items.elementAt(index).title, - description: _items.elementAt(index).description, + title: item.title, + description: item.description, onTap: () => _itemTapped(index), itemSelectionChanged: (isSelected) => _itemSelectionChanged(isSelected, index), selectionMode: selectedItemIndexes.isNotEmpty, + isChecked: _checkedItemIds.contains(item.id), + onCheckedChanged: (isSelected) => + _onItemCheckedChanged(isSelected, item.id), ); } @@ -170,10 +183,12 @@ class _DetailChecklistPageState extends State { child: Text(pageTitle ?? '')); } else { titleController.text = pageTitle ?? ''; - return Expanded( - child: TextField( - autofocus: true, - controller: titleController, + return TextField( + autofocus: true, + controller: titleController, + onSubmitted: (value) => _onTitleChanged( + _checklist!.id, + titleController.text, ), ); } @@ -192,12 +207,6 @@ class _DetailChecklistPageState extends State { AsyncSnapshot>> snapshot, Checklist? checklist, List items) { - if (pageTitle != _checklist!.title) { - WidgetsBinding.instance.addPostFrameCallback((_) => setState(() => - pageTitle = _checklist!.title == '' - ? 'Unnamed ${_checklist!.id}' - : _checklist!.title)); - } if (snapshot.hasData) { _items = DbHelper.resToItemList(snapshot.data!); } @@ -250,4 +259,12 @@ class _DetailChecklistPageState extends State { ), ); } + + _onItemCheckedChanged(bool isSelected, int? id) async { + if (isSelected) { + await DbHelper.insertCheckedEntry(_checklist!.id, id!); + } else { + await DbHelper.deleteCheckedEntry(_checklist!.id, id!); + } + } } diff --git a/lib/services/dbhelper.dart b/lib/services/dbhelper.dart index 896c0c9..33a9e91 100644 --- a/lib/services/dbhelper.dart +++ b/lib/services/dbhelper.dart @@ -10,10 +10,10 @@ import 'package:provider/provider.dart' as provider; class DbHelper { static const checkedItemsTableName = 'checkedItems'; static const checklistsTableName = 'checklists'; + static ChecklistProvider? clProvider; static const itemsTableName = 'items'; static late final SupabaseClient _client; - static ChecklistProvider? clProvider; static Future init() async { await Supabase.initialize( @@ -58,6 +58,26 @@ class DbHelper { return checklists; } + static Future> fetchcheckedItemIds(int checklistId) async { + List itemIdList = []; + final res = await _client + .from(checkedItemsTableName) + .select>>('item_id'); + for (final element in res) { + itemIdList.add(element['item_id']); + } + return itemIdList; + } + + static Future 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 updateChecklistTitle(int id, String title) async { await _client .from(checklistsTableName) @@ -155,6 +175,15 @@ class DbHelper { ); } + static Future 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 deleteItemById(int id) async { await _client.from(itemsTableName).delete().eq('id', id); } diff --git a/lib/widgets/item_list_tile.dart b/lib/widgets/item_list_tile.dart index c5ddcc6..0f412bd 100644 --- a/lib/widgets/item_list_tile.dart +++ b/lib/widgets/item_list_tile.dart @@ -10,26 +10,28 @@ class ItemListTile extends StatefulWidget { required this.onTap, required this.itemSelectionChanged, required this.selectionMode, - this.isSelected = false, + required this.isChecked, + required this.onCheckedChanged, }); final String title; final String description; final bool selectionMode; + final bool isChecked; final VoidCallback onTap; + final BoolCallback onCheckedChanged; final BoolCallback itemSelectionChanged; - final bool isSelected; @override State createState() => _ItemListTileState(); } class _ItemListTileState extends State { - late bool isSelected; + late bool isChecked; @override void initState() { super.initState(); - isSelected = widget.isSelected; + isChecked = widget.isChecked; } @override @@ -39,19 +41,25 @@ class _ItemListTileState extends State { subtitle: Text(widget.description), onTap: _onTap, onLongPress: _onLongPress, - selected: isSelected, + trailing: Checkbox( + value: isChecked, + onChanged: (value) { + setState(() => isChecked = value!); + widget.onCheckedChanged(value!); + }, + ), ); } void _onLongPress() { - setState(() => isSelected = true); - widget.itemSelectionChanged(isSelected); + setState(() => isChecked = true); + widget.itemSelectionChanged(isChecked); } void _onTap() { - if (isSelected || widget.selectionMode) { - setState(() => isSelected = !isSelected); - widget.itemSelectionChanged(isSelected); + if (isChecked || widget.selectionMode) { + setState(() => isChecked = !isChecked); + widget.itemSelectionChanged(isChecked); } else { widget.onTap(); }