import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:grouped_list/grouped_list.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/history.dart'; import 'package:mangayomi/modules/history/providers/isar_providers.dart'; import 'package:mangayomi/modules/manga/reader/providers/push_router.dart'; import 'package:mangayomi/utils/cached_network.dart'; import 'package:mangayomi/utils/date.dart'; import 'package:mangayomi/utils/headers.dart'; import 'package:mangayomi/modules/library/search_text_form_field.dart'; import 'package:mangayomi/modules/widgets/error_text.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart'; class HistoryScreen extends ConsumerStatefulWidget { const HistoryScreen({super.key}); @override ConsumerState createState() => _HistoryScreenState(); } class _HistoryScreenState extends ConsumerState { final _textEditingController = TextEditingController(); bool _isSearch = false; List entriesData = []; @override Widget build(BuildContext context) { final history = ref.watch(getAllHistoryStreamProvider); return Scaffold( appBar: AppBar( elevation: 0, backgroundColor: Colors.transparent, title: _isSearch ? null : Text( 'History', style: TextStyle(color: Theme.of(context).hintColor), ), actions: [ _isSearch ? SeachFormTextField( onChanged: (value) { setState(() {}); }, onSuffixPressed: () { _textEditingController.clear(); setState(() {}); }, onPressed: () { setState(() { _isSearch = false; }); _textEditingController.clear(); }, controller: _textEditingController, ) : IconButton( splashRadius: 20, onPressed: () { setState(() { _isSearch = true; }); }, icon: Icon(Icons.search, color: Theme.of(context).hintColor)), IconButton( splashRadius: 20, onPressed: () { showDialog( context: context, builder: (context) { return AlertDialog( title: const Text( "Remove everything", ), content: const Text( 'Are you sure? All history will be lost.'), actions: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { Navigator.pop(context); }, child: const Text("Cancel")), const SizedBox( width: 15, ), TextButton( onPressed: () async { List ids = []; for (var i = 0; i < entriesData.length; i++) { ids.add(entriesData[i].id!); } await isar.writeTxn(() async { await isar.historys.deleteAll(ids); }); if (mounted) { Navigator.pop(context); } }, child: const Text("Ok")), ], ) ], ); }); }, icon: Icon(Icons.delete_sweep_outlined, color: Theme.of(context).hintColor)), ], ), body: history.when( data: (data) { final entries = data .where((element) => _textEditingController.text.isNotEmpty ? element.chapter.value!.manga.value!.name! .toLowerCase() .contains(_textEditingController.text.toLowerCase()) : true) .toList(); if (entries.isNotEmpty) { return GroupedListView( elements: entries, groupBy: (element) => dateFormat(element.date!, ref: ref), groupSeparatorBuilder: (String groupByValue) => Padding( padding: const EdgeInsets.only(bottom: 8, left: 12), child: Row( children: [ Text(groupByValue), ], ), ), itemBuilder: (context, History element) { final manga = element.chapter.value!.manga.value!; final chapter = element.chapter.value!; return ElevatedButton( style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(0), backgroundColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), elevation: 0, shadowColor: Colors.transparent), onPressed: () { pushMangaReaderView(context: context, chapter: chapter); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: SizedBox( height: 105, child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: 60, height: 90, child: ElevatedButton( style: ElevatedButton.styleFrom( padding: const EdgeInsets.all(0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(7)), ), onPressed: () { context.push('/manga-reader/detail', extra: manga.id); }, child: ClipRRect( borderRadius: BorderRadius.circular(7), child: cachedNetworkImage( headers: ref.watch(headersProvider( source: manga.source!)), imageUrl: manga.imageUrl!, width: 60, height: 90, fit: BoxFit.cover), ), ), ), Flexible( child: Row( children: [ Expanded( child: Container( color: Colors.transparent, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( manga.name!, style: TextStyle( fontSize: 14, color: Theme.of(context) .textTheme .bodyLarge! .color, fontWeight: FontWeight.bold), textAlign: TextAlign.start, ), Wrap( crossAxisAlignment: WrapCrossAlignment.end, children: [ Text( chapter.name!, style: TextStyle( fontSize: 11, color: Theme.of(context) .textTheme .bodyLarge! .color, ), ), Text( " - ${dateFormatHour(element.date!)}", style: TextStyle( fontSize: 11, color: Theme.of(context) .textTheme .bodyLarge! .color, fontWeight: FontWeight.w400), ), ], ), ], ), ), ), ), IconButton( onPressed: () { showDialog( context: context, builder: (context) { return AlertDialog( title: const Text( "Remove", ), content: const Text( 'This will remove the read date of this chapter. Are you sure?'), actions: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { Navigator.pop( context); }, child: const Text( "Cancel")), const SizedBox( width: 15, ), TextButton( onPressed: () async { await isar.writeTxn( () async { await isar .historys .delete( element .id!); }); if (mounted) { Navigator.pop( context); } }, child: const Text( "Remove")), ], ) ], ); }); }, icon: Icon( Icons.delete_outline, size: 25, color: Theme.of(context) .textTheme .bodyLarge! .color, )), ], ), ) ], ), ), ), ); }, itemComparator: (item1, item2) => item1.date!.compareTo(item2.date!), order: GroupedListOrder.DESC, ); } return const Center( child: Text('Nothing read recently'), ); }, error: (Object error, StackTrace stackTrace) { return ErrorText(error); }, loading: () { return const ProgressCenter(); }, )); } }