diff --git a/lib/views/browse/browse_screen.dart b/lib/views/browse/browse_screen.dart index 13b2819..6bd117b 100644 --- a/lib/views/browse/browse_screen.dart +++ b/lib/views/browse/browse_screen.dart @@ -62,6 +62,7 @@ class _BrowseScreenState extends State setState(() { _isSearch = false; }); + _textEditingController.clear(); }, controller: _textEditingController, ) diff --git a/lib/views/general/general_screen.dart b/lib/views/general/general_screen.dart index 76563a2..8b230f0 100644 --- a/lib/views/general/general_screen.dart +++ b/lib/views/general/general_screen.dart @@ -44,7 +44,7 @@ class _GeneralScreenState extends ConsumerState { height: 20, ), child: NavigationBar( - animationDuration: const Duration(seconds: 1), + animationDuration: const Duration(milliseconds: 500), selectedIndex: currentIndex, destinations: const [ NavigationDestination( @@ -68,7 +68,7 @@ class _GeneralScreenState extends ConsumerState { Icons.history, ), icon: Icon( - Icons.history_outlined, + Icons.history_sharp, ), label: "History"), NavigationDestination( diff --git a/lib/views/history/history_screen.dart b/lib/views/history/history_screen.dart index 4c29870..f111842 100644 --- a/lib/views/history/history_screen.dart +++ b/lib/views/history/history_screen.dart @@ -55,6 +55,7 @@ class _HistoryScreenState extends ConsumerState { setState(() { _isSearch = false; }); + _textEditingController.clear(); }, controller: _textEditingController, ) @@ -79,10 +80,12 @@ class _HistoryScreenState extends ConsumerState { valueListenable: ref.watch(hiveBoxMangaHistory).listenable(), builder: (context, value, child) { final entries = value.values.toList(); - entriesData = entries; + final entriesHistory = _textEditingController.text.isNotEmpty + ? entriesFilter + : entries; if (entries.isNotEmpty) { return GroupedListView( - elements: entriesFilter.isNotEmpty ? entriesFilter : entries, + elements: entriesHistory, groupBy: (element) => element.date.substring(0, 10), groupSeparatorBuilder: (String groupByValue) => Padding( padding: const EdgeInsets.only(bottom: 8), diff --git a/lib/views/library/library_screen.dart b/lib/views/library/library_screen.dart index 2d4fb5a..16c1c29 100644 --- a/lib/views/library/library_screen.dart +++ b/lib/views/library/library_screen.dart @@ -5,10 +5,13 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:mangayomi/models/model_manga.dart'; import 'package:mangayomi/providers/hive_provider.dart'; import 'package:mangayomi/utils/cached_network.dart'; +import 'package:mangayomi/utils/media_query.dart'; +import 'package:mangayomi/views/library/providers/state_providers.dart'; import 'package:mangayomi/views/library/search_text_form_field.dart'; import 'package:mangayomi/views/widgets/bottom_text_widget.dart'; import 'package:mangayomi/views/widgets/cover_view_widget.dart'; import 'package:mangayomi/views/widgets/gridview_widget.dart'; +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class LibraryScreen extends ConsumerStatefulWidget { const LibraryScreen({super.key}); @@ -17,13 +20,16 @@ class LibraryScreen extends ConsumerStatefulWidget { ConsumerState createState() => _LibraryScreenState(); } -class _LibraryScreenState extends ConsumerState { +class _LibraryScreenState extends ConsumerState + with TickerProviderStateMixin { + bool isOk = false; bool isSearch = false; List entries = []; List entriesFilter = []; final _textEditingController = TextEditingController(); @override Widget build(BuildContext context) { + final reverse = ref.watch(reverseStateProvider); return Scaffold( appBar: AppBar( elevation: 0, @@ -49,7 +55,8 @@ class _LibraryScreenState extends ConsumerState { setState(() { isSearch = false; }); - }, controller: _textEditingController, + }, + controller: _textEditingController, ) : IconButton( splashRadius: 20, @@ -57,11 +64,14 @@ class _LibraryScreenState extends ConsumerState { setState(() { isSearch = true; }); + _textEditingController.clear(); }, icon: Icon(Icons.search, color: Theme.of(context).hintColor)), IconButton( splashRadius: 20, - onPressed: () {}, + onPressed: () { + _showModalSort(); + }, icon: Icon(Icons.filter_list_sharp, color: Theme.of(context).hintColor)), PopupMenuButton( @@ -90,8 +100,11 @@ class _LibraryScreenState extends ConsumerState { valueListenable: ref.watch(hiveBoxManga).listenable(), builder: (context, value, child) { entries = value.values.where((element) => element.favorite).toList(); - final entriesManga = - _textEditingController.text.isNotEmpty ? entriesFilter : entries; + final entriesManga = _textEditingController.text.isNotEmpty + ? entriesFilter + : reverse + ? entries.reversed.toList() + : entries; if (entries.isNotEmpty || entriesFilter.isNotEmpty) { return GridViewWidget( itemCount: entriesManga.length, @@ -117,11 +130,33 @@ class _LibraryScreenState extends ConsumerState { }, child: CoverViewWidget( children: [ - cachedNetworkImage( - imageUrl: entriesManga[index].imageUrl!, - width: 200, - height: 270, - fit: BoxFit.cover), + Stack( + children: [ + cachedNetworkImage( + imageUrl: entriesManga[index].imageUrl!, + width: 200, + height: 270, + fit: BoxFit.cover), + Positioned( + top: 0, + left: 0, + child: Padding( + padding: const EdgeInsets.all(5), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(3), + color: Theme.of(context).cardColor), + child: Padding( + padding: const EdgeInsets.all(1), + child: Text(entriesManga[index] + .chapterDate! + .length + .toString()), + ), + ), + )) + ], + ), BottomTextWidget(text: entriesManga[index].name!) ], ), @@ -134,4 +169,87 @@ class _LibraryScreenState extends ConsumerState { ), ); } + + _showModalSort() { + List sortList = [ + "Alphabetically", + "Total chapters", + "Latest chapter", + "Date added" + ]; + late TabController tabBarController; + showMaterialModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(5), topRight: Radius.circular(5))), + enableDrag: true, + expand: false, + context: context, + backgroundColor: Colors.transparent, + builder: (context) { + if (!isOk) { + tabBarController = TabController(length: 3, vsync: this); + tabBarController.animateTo(0); + } + return SizedBox( + height: mediaHeight(context, 0.4), + child: DefaultTabController( + length: 3, + child: Scaffold( + body: Column( + children: [ + TabBar( + controller: tabBarController, + tabs: const [ + Tab(text: "Filter"), + Tab(text: "Sort"), + Tab(text: "Display"), + ], + ), + Flexible( + child: TabBarView( + controller: tabBarController, + children: [ + const Center(child: Text("soon")), + Consumer(builder: (context, ref, chil) { + final reverse = + ref.watch(reverseStateProvider); + final sortedValue = + ref.watch(sortedValueStateProvider); + return Column( + children: [ + for (var i = 0; i < sortList.length; i++) + ListTile( + onTap: () { + ref + .read(reverseStateProvider + .notifier) + .state = !reverse; + ref + .read(sortedValueStateProvider + .notifier) + .state = sortList[i]; + }, + dense: true, + leading: sortedValue == sortList[i] + ? Icon(reverse + ? Icons.arrow_downward_sharp + : Icons.arrow_upward_sharp) + : const Icon( + Icons.arrow_upward_sharp, + color: Colors.transparent, + ), + title: Text(sortList[i]), + ), + ], + ); + }), + const Center(child: Text("soon")) + ]), + ), + ], + ), + ))); + }); + } } diff --git a/lib/views/library/providers/state_providers.dart b/lib/views/library/providers/state_providers.dart new file mode 100644 index 0000000..56ec168 --- /dev/null +++ b/lib/views/library/providers/state_providers.dart @@ -0,0 +1,9 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final reverseStateProvider = StateProvider.autoDispose( + (ref) => false, +); + +final sortedValueStateProvider = StateProvider.autoDispose( + (ref) => 'Alphabetically', +); diff --git a/lib/views/manga/detail/manga_detail_view.dart b/lib/views/manga/detail/manga_detail_view.dart index 395fb96..7304f73 100644 --- a/lib/views/manga/detail/manga_detail_view.dart +++ b/lib/views/manga/detail/manga_detail_view.dart @@ -299,14 +299,14 @@ class _MangaDetailViewState extends ConsumerState { child: Container( alignment: Alignment.centerLeft, padding: const EdgeInsets.only(left: 100), - width: MediaQuery.of(context).size.width, - height: 70, + width: MediaQuery.of(context).size.width * 0.9, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.modelManga!.name!, - style: - const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + style: const TextStyle( + fontSize: 18, + )), widget.titleDescription!, ], ), diff --git a/lib/views/manga/detail/manga_details_view.dart b/lib/views/manga/detail/manga_details_view.dart index d1fb4a0..9f77777 100644 --- a/lib/views/manga/detail/manga_details_view.dart +++ b/lib/views/manga/detail/manga_details_view.dart @@ -161,6 +161,13 @@ class _MangaDetailsViewState extends ConsumerState { ), Row( children: [ + const Icon( + FontAwesomeIcons.clock, + size: 12, + ), + const SizedBox( + width: 4, + ), Text(widget.modelManga.status!), const Text(' • '), Text(widget.modelManga.source!) diff --git a/lib/views/manga/home/home.dart b/lib/views/manga/home/home.dart index 326b7d0..ceed245 100644 --- a/lib/views/manga/home/home.dart +++ b/lib/views/manga/home/home.dart @@ -175,7 +175,10 @@ class _MangaHomeImageCardState extends ConsumerState height: 270, ), ), - BottomTextWidget(text: widget.name) + BottomTextWidget( + text: widget.name, + isLoading: true, + ) ]), error: (error, stackTrace) => const Center(child: Text("Error")), ); diff --git a/lib/views/widgets/bottom_text_widget.dart b/lib/views/widgets/bottom_text_widget.dart index 15bf877..a922980 100644 --- a/lib/views/widgets/bottom_text_widget.dart +++ b/lib/views/widgets/bottom_text_widget.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; class BottomTextWidget extends StatelessWidget { + final bool isLoading; final String text; - const BottomTextWidget({super.key, required this.text}); + const BottomTextWidget( + {super.key, required this.text, this.isLoading = false}); @override Widget build(BuildContext context) { @@ -10,28 +12,59 @@ class BottomTextWidget extends StatelessWidget { bottom: 0, left: 0, right: 0, - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [Colors.transparent, Colors.black.withOpacity(0.4)], - stops: const [0, 1], - ), - ), - child: Text( - text, - style: const TextStyle( - fontSize: 13.0, - color: Colors.white, - shadows: [ - Shadow(offset: Offset(0.5, 0.9), blurRadius: 3.0) - ], - ), - textAlign: TextAlign.center, - ), - ), + child: isLoading + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5), + child: Text( + text, + style: const TextStyle( + fontSize: 13.0, + color: Colors.white, + shadows: [ + Shadow(offset: Offset(0.5, 0.9), blurRadius: 3.0) + ], + ), + textAlign: TextAlign.start, + ), + ), + ], + ) + : Container( + height: 70, + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Colors.transparent, Colors.black.withOpacity(0.6)], + stops: const [0, 1], + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5), + child: Text( + text, + style: const TextStyle( + fontSize: 13.0, + color: Colors.white, + shadows: [ + Shadow(offset: Offset(0.5, 0.9), blurRadius: 3.0) + ], + ), + textAlign: TextAlign.start, + ), + ), + ], + ), + ), ); } } diff --git a/lib/views/widgets/gridview_widget.dart b/lib/views/widgets/gridview_widget.dart index f4270e3..d0237c6 100644 --- a/lib/views/widgets/gridview_widget.dart +++ b/lib/views/widgets/gridview_widget.dart @@ -3,12 +3,14 @@ import 'package:flutter/material.dart'; class GridViewWidget extends StatelessWidget { final ScrollController? controller; final int? itemCount; + final bool reverse; final Widget? Function(BuildContext, int) itemBuilder; const GridViewWidget( {super.key, this.controller, required this.itemCount, - required this.itemBuilder}); + required this.itemBuilder, + this.reverse = false}); @override Widget build(BuildContext context) {