import 'package:flutter/material.dart'; import 'package:venera/components/components.dart'; import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/comic_source/comic_source.dart'; import 'package:venera/foundation/comic_type.dart'; import 'package:venera/foundation/history.dart'; import 'package:venera/utils/translations.dart'; class HistoryPage extends StatefulWidget { const HistoryPage({super.key}); @override State createState() => _HistoryPageState(); } class _HistoryPageState extends State { @override void initState() { HistoryManager().addListener(onUpdate); super.initState(); } @override void dispose() { HistoryManager().removeListener(onUpdate); super.dispose(); } void onUpdate() { setState(() { comics = HistoryManager().getAll(); if (multiSelectMode) { selectedComics.removeWhere((comic, _) => !comics.contains(comic)); if (selectedComics.isEmpty) { multiSelectMode = false; } } }); } 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); }); } void _removeHistory(History comic) { 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), ); } } @override Widget build(BuildContext context) { 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 : () { final comicsToDelete = List.from(selectedComics.keys); setState(() { multiSelectMode = false; selectedComics.clear(); }); for (final comic in comicsToDelete) { _removeHistory(comic); } }, ), ]; List normalActions = [ IconButton( icon: const Icon(Icons.checklist), tooltip: multiSelectMode ? "Exit Multi-Select".tl : "Multi-Select".tl, onPressed: () { setState(() { multiSelectMode = !multiSelectMode; }); }, ), 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(); }, ), ), ) ]; 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 { 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: null, 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: () { _removeHistory(c as History); }, ), ]; }, ), ], ), ), ); } String getDescription(History h) { var res = ""; if (h.ep >= 1) { res += "Chapter @ep".tlParams({ "ep": h.ep, }); } if (h.page >= 1) { if (h.ep >= 1) { res += " - "; } res += "Page @page".tlParams({ "page": h.page, }); } return res; } }