From 2917e71db119210ae64935fb53572cad4001d57d Mon Sep 17 00:00:00 2001 From: marco Date: Mon, 13 Apr 2026 15:59:46 +0200 Subject: [PATCH] small ux improvements --- lib/pages/collection_page.dart | 6 +- lib/pages/collections_list_page.dart | 191 ++++++++++++++++----------- lib/service/storage.dart | 7 + 3 files changed, 125 insertions(+), 79 deletions(-) diff --git a/lib/pages/collection_page.dart b/lib/pages/collection_page.dart index d193d4d..035a050 100644 --- a/lib/pages/collection_page.dart +++ b/lib/pages/collection_page.dart @@ -72,7 +72,7 @@ class _CollectionPageState extends State { selected: selected, onTap: () { if (selected) { - onCancelSelectionPressed(); + deselectBookmark(); setState(() {}); } else if (selectedBookmarkId != -1 && !selected) { selectedBookmarkId = bookmark.id; @@ -131,7 +131,7 @@ class _CollectionPageState extends State { bottomNavigationBar: selectedBookmarkId > 0 ? ListItemActionsWidget( onDeletePressed: onDeleteBookmarkPressed, - onCancelPressed: onCancelSelectionPressed, + onCancelPressed: deselectBookmark, onEditPressed: () => editBookmark( bookmarks.firstWhere( (element) => element.id == selectedBookmarkId, @@ -158,8 +158,6 @@ class _CollectionPageState extends State { ); } - void onCancelSelectionPressed() => deselectBookmark(); - void onDeleteBookmarkPressed() { Storage.deleteBookmarkById( selectedBookmarkId, diff --git a/lib/pages/collections_list_page.dart b/lib/pages/collections_list_page.dart index b1a9bfc..cd6fe37 100644 --- a/lib/pages/collections_list_page.dart +++ b/lib/pages/collections_list_page.dart @@ -6,6 +6,8 @@ import '../model/collection.dart'; import '../service/bookmarks_provider.dart'; import '../service/shared_link_provider.dart'; import '../service/storage.dart'; +import '../widgets/collection_page_widgets/list_item_actions_widget.dart' + show ListItemActionsWidget; import '../widgets/create_bookmark_collection_dialog.dart'; import 'collection_page.dart'; import 'search_page.dart' show SearchPage; @@ -23,6 +25,7 @@ class CollectionsListPage extends StatefulWidget { class _CollectionsListPageState extends State { bool addingNewBookmark = false; var bookmarkCountMap = {}; + int selectedCollectionId = -1; Widget bottomSheetBuilder(BuildContext context) { final titleTextFieldController = TextEditingController( @@ -52,11 +55,27 @@ class _CollectionsListPageState extends State { BuildContext context, Collection collection, ) { + final selected = selectedCollectionId == collection.id; return ListTile( title: Text(collection.name), - onTap: () => navigateToCollection(collection.id), - onLongPress: () => onEditCollection(collection), + onTap: () { + if (selected) { + deselectCollection(); + setState(() {}); + } else if (selectedCollectionId != -1 && !selected) { + selectedCollectionId = collection.id; + setState(() {}); + } else { + navigateToCollection(collection.id); + } + }, + onLongPress: () => addingNewBookmark + ? null + : setState(() { + selectedCollectionId = collection.id; + }), leading: const Icon(Icons.list_rounded), + selected: selected, trailing: Text( bookmarkCountMap[collection.id]?.toString() ?? '0', style: Theme.of(context).textTheme.bodyMedium, @@ -74,13 +93,8 @@ class _CollectionsListPageState extends State { builder: (context) => CreateBookmarkCollectionDialog( selectedCollection: selectedCollection, onSavePressed: onCollectionSaved, - onDeletePressed: () { - Storage.deleteCollection( - selectedCollection, - ).whenComplete(() => setState(() {})); - }, ), - ); + ).whenComplete(deselectCollection); @override Widget build(BuildContext context) { @@ -89,78 +103,105 @@ class _CollectionsListPageState extends State { addingNewBookmark = Provider.of(context).currentMapsLinkMetadata != null; - return Scaffold( - appBar: AppBar( - title: addingNewBookmark - ? Text(AppLocalizations.of(context)!.chooseCollection) - : Text(AppLocalizations.of(context)!.collections), - actions: [ - if (addingNewBookmark) - TextButton( - onPressed: () => Provider.of( - context, - listen: false, - ).removeCurrentMapsLink(), - child: Text(AppLocalizations.of(context)!.cancel), - ) - else - IconButton( - onPressed: () => - Navigator.of(context).pushNamed(SearchPage.routeName), - icon: Icon(Icons.search_rounded), - ), - if (!addingNewBookmark) - IconButton( - onPressed: () => - Navigator.of(context).pushNamed(SettingsPage.routeName), - icon: Icon(Icons.settings_rounded), - ), - ], - ), - bottomNavigationBar: addingNewBookmark - ? Container( - decoration: BoxDecoration( - borderRadius: BorderRadiusGeometry.circular(12), + return PopScope( + canPop: selectedCollectionId == -1, + onPopInvokedWithResult: (didPop, result) { + if (didPop == false) deselectCollection(); + }, + child: Scaffold( + appBar: AppBar( + title: addingNewBookmark + ? Text(AppLocalizations.of(context)!.chooseCollection) + : Text(AppLocalizations.of(context)!.collections), + actions: [ + if (addingNewBookmark) + TextButton( + onPressed: () => Provider.of( + context, + listen: false, + ).removeCurrentMapsLink(), + child: Text(AppLocalizations.of(context)!.cancel), + ) + else + IconButton( + onPressed: () => + Navigator.of(context).pushNamed(SearchPage.routeName), + icon: Icon(Icons.search_rounded), + ), + if (!addingNewBookmark) + IconButton( + onPressed: () => + Navigator.of(context).pushNamed(SettingsPage.routeName), + icon: Icon(Icons.settings_rounded), + ), + ], + ), + bottomNavigationBar: addingNewBookmark + ? Container( + decoration: BoxDecoration( + borderRadius: BorderRadiusGeometry.circular(12), - color: Theme.of(context).colorScheme.surfaceContainer, - ), - height: 100, - child: Padding( - padding: EdgeInsetsGeometry.fromLTRB( - MediaQuery.of(context).size.width * 0.05, - 15, - MediaQuery.of(context).size.width * 0.05, - MediaQuery.of(context).viewInsets.bottom, + color: Theme.of(context).colorScheme.surfaceContainer, ), - child: Text( - Provider.of( - context, - ).currentMapsLinkMetadata!.placeName, - ), - ), - ) - : null, - floatingActionButton: FloatingActionButton( - onPressed: onAddButtonPressed, - child: Icon(Icons.add), - ), - body: collections.isNotEmpty - ? Center( - child: SizedBox( - width: MediaQuery.of(context).size.width * 0.9, - child: ListView.separated( - itemBuilder: (context, index) => collectionsListItemBuilder( - context, - collections.elementAt(index), + height: 100, + child: Padding( + padding: EdgeInsetsGeometry.fromLTRB( + MediaQuery.of(context).size.width * 0.05, + 15, + MediaQuery.of(context).size.width * 0.05, + MediaQuery.of(context).viewInsets.bottom, + ), + child: Text( + Provider.of( + context, + ).currentMapsLinkMetadata!.placeName, ), - itemCount: collections.length, - separatorBuilder: (context, index) => SizedBox(height: 10), ), + ) + : selectedCollectionId > 0 + ? ListItemActionsWidget( + onDeletePressed: onDeleteCollectionPressed, + onCancelPressed: deselectCollection, + onEditPressed: () => onEditCollection( + collections.firstWhere( + (element) => element.id == selectedCollectionId, + ), + ), + ) + : null, + floatingActionButton: FloatingActionButton( + onPressed: onAddButtonPressed, + child: Icon(Icons.add), + ), + body: collections.isNotEmpty + ? Center( + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.9, + child: ListView.separated( + itemBuilder: (context, index) => collectionsListItemBuilder( + context, + collections.elementAt(index), + ), + itemCount: collections.length, + separatorBuilder: (context, index) => SizedBox(height: 10), + ), + ), + ) + : Center( + child: Text(AppLocalizations.of(context)!.tipCreateCollections), ), - ) - : Center( - child: Text(AppLocalizations.of(context)!.tipCreateCollections), - ), + ), ); } + + void onDeleteCollectionPressed() { + Storage.deleteCollectionById( + selectedCollectionId, + ).whenComplete(() => deselectCollection()); + } + + void deselectCollection() { + selectedCollectionId = -1; + setState(() {}); + } } diff --git a/lib/service/storage.dart b/lib/service/storage.dart index 8427a85..1287c3d 100644 --- a/lib/service/storage.dart +++ b/lib/service/storage.dart @@ -163,6 +163,13 @@ class Storage { await saveCollections(collections); } + static Future deleteCollectionById(int collectionId) async { + final collections = loadCollections(); + await deleteCollection( + collections.firstWhere((collection) => collection.id == collectionId), + ); + } + static Map getStats() { final statsJson = _prefs.getString(_statsKey) ?? '{}'; final stats = jsonDecode(statsJson) as Map;