From c28f4d40c2ed75652754b9e63be605cbf2722c97 Mon Sep 17 00:00:00 2001 From: buste <32890006+bustesoul@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:30:30 +0800 Subject: [PATCH] Add selection in history page and refresh home page after history changed (#199) --- lib/pages/history_page.dart | 254 ++++++++++++++++++++++++++---------- lib/pages/home_page.dart | 10 +- 2 files changed, 193 insertions(+), 71 deletions(-) diff --git a/lib/pages/history_page.dart b/lib/pages/history_page.dart index b4ea318..f813d1a 100644 --- a/lib/pages/history_page.dart +++ b/lib/pages/history_page.dart @@ -33,82 +33,202 @@ class _HistoryPageState extends State { } var comics = HistoryManager().getAll(); - var controller = FlyoutController(); + + bool multiSelectMode = false; + Map selectedComics = {}; + + void selectAll() { + setState(() { + selectedComics = comics.asMap().map((k, v) => MapEntry(v, true)); + }); + } + + void deSelect() { + setState(() { + selectedComics.clear(); + }); + } + + void invertSelection() { + setState(() { + comics.asMap().forEach((k, v) { + selectedComics[v] = !selectedComics.putIfAbsent(v, () => false); + }); + selectedComics.removeWhere((k, v) => !v); + }); + } @override Widget build(BuildContext context) { - return Scaffold( - body: SmoothCustomScrollView( - slivers: [ - SliverAppbar( - title: Text('History'.tl), - actions: [ - Tooltip( - message: 'Clear History'.tl, - child: Flyout( - controller: controller, - flyoutBuilder: (context) { - return FlyoutContent( - title: 'Clear History'.tl, - content: Text( - 'Are you sure you want to clear your history?'.tl), - actions: [ - Button.filled( - color: context.colorScheme.error, - onPressed: () { - HistoryManager().clearHistory(); - context.pop(); - }, - child: Text('Clear'.tl), - ), - ], - ); - }, - child: IconButton( - icon: const Icon(Icons.clear_all), - onPressed: () { - controller.show(); - }, - ), - ), - ) - ], - ), - SliverGridComics( - comics: comics, - badgeBuilder: (c) { - return ComicSource.find(c.sourceKey)?.name; - }, - menuBuilder: (c) { - return [ - MenuEntry( - icon: Icons.remove, - text: 'Remove'.tl, + List selectActions = [ + IconButton( + icon: const Icon(Icons.select_all), + tooltip: "Select All".tl, + onPressed: selectAll + ), + IconButton( + icon: const Icon(Icons.deselect), + tooltip: "Deselect".tl, + onPressed: deSelect + ), + IconButton( + icon: const Icon(Icons.flip), + tooltip: "Invert Selection".tl, + onPressed: invertSelection + ), + IconButton( + icon: const Icon(Icons.delete), + tooltip: "Delete".tl, + onPressed: selectedComics.isEmpty ? null : () { + for (final comic in selectedComics.keys) { + if (comic.sourceKey.startsWith("Unknown")) { + HistoryManager().remove( + comic.id, + ComicType(int.parse(comic.sourceKey.split(':')[1])), + ); + } else if (comic.sourceKey == 'local') { + HistoryManager().remove( + comic.id, + ComicType.local, + ); + } else { + HistoryManager().remove( + comic.id, + ComicType(comic.sourceKey.hashCode), + ); + } + } + setState(() { + multiSelectMode = false; + selectedComics.clear(); + }); + }, + ), + ]; + + List normalActions = [ + Tooltip( + message: 'Clear History'.tl, + child: Flyout( + controller: controller, + flyoutBuilder: (context) { + return FlyoutContent( + title: 'Clear History'.tl, + content: Text('Are you sure you want to clear your history?'.tl), + actions: [ + Button.filled( color: context.colorScheme.error, - onClick: () { - if (c.sourceKey.startsWith("Unknown")) { - HistoryManager().remove( - c.id, - ComicType(int.parse(c.sourceKey.split(':')[1])), - ); - } else if (c.sourceKey == 'local') { - HistoryManager().remove( - c.id, - ComicType.local, - ); + onPressed: () { + HistoryManager().clearHistory(); + context.pop(); + }, + child: Text('Clear'.tl), + ), + ], + ); + }, + child: IconButton( + icon: const Icon(Icons.clear_all), + onPressed: () { + controller.show(); + }, + ), + ), + ) + ]; + + return PopScope( + canPop: !multiSelectMode, + onPopInvokedWithResult: (didPop, result) { + if (multiSelectMode) { + setState(() { + multiSelectMode = false; + selectedComics.clear(); + }); + } + }, + child: Scaffold( + body: SmoothCustomScrollView( + slivers: [ + SliverAppbar( + leading: Tooltip( + message: multiSelectMode ? "Cancel".tl : "Back".tl, + child: IconButton( + onPressed: () { + if (multiSelectMode) { + setState(() { + multiSelectMode = false; + selectedComics.clear(); + }); } else { - HistoryManager().remove( - c.id, - ComicType(c.sourceKey.hashCode), - ); + context.pop(); } }, + icon: multiSelectMode + ? const Icon(Icons.close) + : const Icon(Icons.arrow_back), ), - ]; - }, - ), - ], + ), + title: multiSelectMode + ? Text(selectedComics.length.toString()) + : Text('History'.tl), + actions: multiSelectMode ? selectActions : normalActions, + ), + SliverGridComics( + comics: comics, + selections: selectedComics, + onLongPressed: (c) { + setState(() { + multiSelectMode = true; + selectedComics[c as History] = true; + }); + }, + onTap: multiSelectMode ? (c) { + setState(() { + if (selectedComics.containsKey(c as History)) { + selectedComics.remove(c); + } else { + selectedComics[c] = true; + } + if (selectedComics.isEmpty) { + multiSelectMode = false; + } + }); + } : null, + badgeBuilder: (c) { + return ComicSource.find(c.sourceKey)?.name; + }, + menuBuilder: (c) { + return [ + MenuEntry( + icon: Icons.remove, + text: 'Remove'.tl, + color: context.colorScheme.error, + onClick: () { + if (c.sourceKey.startsWith("Unknown")) { + HistoryManager().remove( + c.id, + ComicType(int.parse(c.sourceKey.split(':')[1])), + ); + } else if (c.sourceKey == 'local') { + HistoryManager().remove( + c.id, + ComicType.local, + ); + } else { + HistoryManager().remove( + c.id, + ComicType(c.sourceKey.hashCode), + ); + } + }, + ), + ]; + }, + ), + ], + ), ), ); } diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index f11e6d2..ddb9584 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -197,10 +197,12 @@ class _HistoryState extends State<_History> { late int count; void onHistoryChange() { - setState(() { - history = HistoryManager().getRecent(); - count = HistoryManager().count(); - }); + if (mounted) { + setState(() { + history = HistoryManager().getRecent(); + count = HistoryManager().count(); + }); + } } @override