diff --git a/lib/pages/collection_page.dart b/lib/pages/collection_page.dart index 087de80..d193d4d 100644 --- a/lib/pages/collection_page.dart +++ b/lib/pages/collection_page.dart @@ -9,6 +9,7 @@ import '../service/notifying.dart'; import '../service/shared_link_provider.dart'; import '../service/storage.dart'; import '../service/url_launcher.dart'; +import '../widgets/collection_page_widgets/list_item_actions_widget.dart'; import '../widgets/create_bookmark_dialog.dart'; class CollectionPage extends StatefulWidget { @@ -22,6 +23,7 @@ class CollectionPage extends StatefulWidget { class _CollectionPageState extends State { MapsLinkMetadata? selectedMapsLink; + int selectedBookmarkId = -1; @override void initState() { @@ -52,29 +54,46 @@ class _CollectionPageState extends State { ).whenComplete(() => setState(() {})); }, ), - ); + ).whenComplete(deselectBookmark); void onBookmarkSaved(Bookmark bookmark) { Storage.addOrUpdateBookmark(bookmark); setState(() {}); - context.read().removeCurrentMapsLink(); + Provider.of( + context, + listen: false, + ).removeCurrentMapsLink(); } Widget bookmarksListItemBuilder(BuildContext context, Bookmark bookmark) { + final selected = selectedBookmarkId == bookmark.id; return ListTile( title: Text(bookmark.name), - onTap: () => launchUrlFromString(bookmark.link).then((errorCode) { - if (context.mounted) { - return Notifying.showUrlErrorSnackbar(context, errorCode); + selected: selected, + onTap: () { + if (selected) { + onCancelSelectionPressed(); + setState(() {}); + } else if (selectedBookmarkId != -1 && !selected) { + selectedBookmarkId = bookmark.id; + setState(() {}); + } else { + launchUrlFromString(bookmark.link).then((errorCode) { + if (context.mounted) { + return Notifying.showUrlErrorSnackbar(context, errorCode); + } + }); } + }, + onLongPress: () => setState(() { + selectedBookmarkId = bookmark.id; }), - onLongPress: () => editBookmark(bookmark), ); } @override Widget build(BuildContext context) { - SharedLinkProvider provider = context.watch(); + SharedLinkProvider provider = Provider.of(context); selectedMapsLink = provider.currentMapsLinkMetadata; if (BookmarksProvider.selectedCollectionId == null) { @@ -87,36 +106,69 @@ class _CollectionPageState extends State { (c) => c.id == BookmarksProvider.selectedCollectionId, ); - return Scaffold( - appBar: AppBar( - title: selectedMapsLink != null - ? Text( - AppLocalizations.of(context)!.addToCollection(collection.name), + return PopScope( + canPop: selectedBookmarkId == -1, + onPopInvokedWithResult: (didPop, result) { + if (didPop == false) deselectBookmark(); + }, + child: Scaffold( + appBar: AppBar( + title: selectedMapsLink != null + ? Text( + AppLocalizations.of( + context, + )!.addToCollection(collection.name), + ) + : Text(collection.name), + actions: [ + if (selectedMapsLink != null) + TextButton( + onPressed: () => provider.removeCurrentMapsLink(), + child: Text(AppLocalizations.of(context)!.cancel), + ), + ], + ), + bottomNavigationBar: selectedBookmarkId > 0 + ? ListItemActionsWidget( + onDeletePressed: onDeleteBookmarkPressed, + onCancelPressed: onCancelSelectionPressed, + onEditPressed: () => editBookmark( + bookmarks.firstWhere( + (element) => element.id == selectedBookmarkId, + ), + ), ) - : Text(collection.name), - actions: [ - if (selectedMapsLink != null) - TextButton( - onPressed: () => provider.removeCurrentMapsLink(), - child: Text(AppLocalizations.of(context)!.cancel), + : null, + body: Center( + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: ListView.separated( + itemBuilder: (context, index) => + bookmarksListItemBuilder(context, bookmarks.elementAt(index)), + itemCount: bookmarks.length, + separatorBuilder: (context, index) => SizedBox(height: 10), ), - ], - ), - body: Center( - child: SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: ListView.separated( - itemBuilder: (context, index) => - bookmarksListItemBuilder(context, bookmarks.elementAt(index)), - itemCount: bookmarks.length, - separatorBuilder: (context, index) => SizedBox(height: 10), ), ), - ), - floatingActionButton: FloatingActionButton( - onPressed: onAddButtonPressed, - child: Icon(selectedMapsLink != null ? Icons.save : Icons.add), + floatingActionButton: FloatingActionButton( + onPressed: onAddButtonPressed, + child: Icon(selectedMapsLink != null ? Icons.save : Icons.add), + ), ), ); } + + void onCancelSelectionPressed() => deselectBookmark(); + + void onDeleteBookmarkPressed() { + Storage.deleteBookmarkById( + selectedBookmarkId, + ).whenComplete(() => setState(() {})); + deselectBookmark(); + } + + void deselectBookmark() { + selectedBookmarkId = -1; + setState(() {}); + } } diff --git a/lib/pages/collections_list_page.dart b/lib/pages/collections_list_page.dart index e4dd272..59266b6 100644 --- a/lib/pages/collections_list_page.dart +++ b/lib/pages/collections_list_page.dart @@ -87,7 +87,8 @@ class _CollectionsListPageState extends State { final collections = Storage.loadCollections(); bookmarkCountMap = Storage.loadPerCollectionBookmarkCount(); addingNewBookmark = - context.watch().currentMapsLinkMetadata != null; + Provider.of(context).currentMapsLinkMetadata != + null; return Scaffold( appBar: AppBar( title: addingNewBookmark @@ -96,8 +97,10 @@ class _CollectionsListPageState extends State { actions: [ if (addingNewBookmark) TextButton( - onPressed: () => - context.read().removeCurrentMapsLink(), + onPressed: () => Provider.of( + context, + listen: false, + ).removeCurrentMapsLink(), child: Text(AppLocalizations.of(context)!.cancel), ) else diff --git a/lib/widgets/collection_page_widgets/list_item_actions_widget.dart b/lib/widgets/collection_page_widgets/list_item_actions_widget.dart new file mode 100644 index 0000000..9bc0835 --- /dev/null +++ b/lib/widgets/collection_page_widgets/list_item_actions_widget.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +class ListItemActionsWidget extends StatelessWidget { + final VoidCallback _onDeletePressed; + final VoidCallback _onCancelPressed; + final VoidCallback _onEditPressed; + + const ListItemActionsWidget({ + super.key, + required void Function() onDeletePressed, + required void Function() onCancelPressed, + required void Function() onEditPressed, + }) : _onEditPressed = onEditPressed, + _onCancelPressed = onCancelPressed, + _onDeletePressed = onDeletePressed; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsetsGeometry.fromLTRB( + 10, + 10, + 10, + MediaQuery.of(context).viewPadding.bottom, + ), + color: Theme.of(context).colorScheme.surfaceContainer, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + IconButton( + onPressed: _onCancelPressed, + icon: const Icon(Icons.close_rounded), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: _onDeletePressed, + icon: const Icon(Icons.delete_forever_rounded), + ), + IconButton( + onPressed: _onEditPressed, + icon: const Icon(Icons.edit_rounded), + ), + ], + ), + ], + ), + ); + } +}