diff --git a/lib/app/modules/browse/controllers/browse_controller.dart b/lib/app/modules/browse/controllers/browse_controller.dart index 3e33f9d1..2bc55656 100644 --- a/lib/app/modules/browse/controllers/browse_controller.dart +++ b/lib/app/modules/browse/controllers/browse_controller.dart @@ -22,7 +22,7 @@ class BrowseController extends GetxController int get tabIndex => _tabIndex.value; final TextEditingController textEditingController = TextEditingController(); - + late ScrollController scrollController; final RxBool _isSearching = false.obs; bool get isSearching => _isSearching.value; set isSearching(bool value) => _isSearching.value = value; @@ -87,7 +87,14 @@ class BrowseController extends GetxController void onInit() { tabController = TabController(length: 2, vsync: this, initialIndex: 0); tabController.addListener(() => _tabIndex.value = tabController.index); + scrollController = ScrollController()..addListener(() => update()); super.onInit(); } + + @override + void onClose() { + scrollController.dispose(); + super.onClose(); + } } diff --git a/lib/app/modules/browse/views/browse_view.dart b/lib/app/modules/browse/views/browse_view.dart index 17c0b399..5c29429d 100644 --- a/lib/app/modules/browse/views/browse_view.dart +++ b/lib/app/modules/browse/views/browse_view.dart @@ -1,40 +1,84 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:tachidesk_sorayomi/app/modules/browse/widgets/browse_appbar_actions.dart'; +import 'package:tachidesk_sorayomi/app/modules/home/controllers/home_controller.dart'; import '../../../../generated/locales.g.dart'; import '../../extensions/views/extensions_view.dart'; +import '../../home/views/home_view.dart'; import '../../sources/views/sources_view.dart'; import '../controllers/browse_controller.dart'; class BrowseView extends GetView { @override Widget build(BuildContext context) { + final _ = Get.find(); return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, - appBar: TabBar( - physics: BouncingScrollPhysics(), - controller: controller.tabController, - padding: EdgeInsets.all(8), - isScrollable: context.width > 700 ? true : false, - labelColor: context.theme.indicatorColor, - unselectedLabelColor: context.textTheme.bodyText1!.color, - indicator: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: context.theme.indicatorColor.withOpacity(.3), + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverAppBar( + toolbarHeight: 70, + pinned: true, + floating: true, + snap: true, + // stretch: true, + actions: [ + Obx(() => + _.selectedIndex == 2 ? BrowseAppBarActions() : SizedBox()) + ], + title: Text(navigationBarTitles[2].tr), + bottom: TabBar( + physics: BouncingScrollPhysics(), + controller: controller.tabController, + isScrollable: context.width > 700 ? true : false, + labelColor: context.theme.indicatorColor, + unselectedLabelColor: context.textTheme.bodyText1!.color, + indicatorSize: TabBarIndicatorSize.label, + indicatorColor: Theme.of(context).colorScheme.primary, + tabs: [ + Tab(text: LocaleKeys.screenTitle_sources.tr), + Tab(text: LocaleKeys.screenTitle_extensions.tr), + ], + ), ), - tabs: [ - Tab(text: LocaleKeys.screenTitle_sources.tr), - Tab(text: LocaleKeys.screenTitle_extensions.tr), - ]), - body: TabBarView( - controller: controller.tabController, - physics: BouncingScrollPhysics(), - children: [ - SourcesView(), - ExtensionsView(), ], + body: TabBarView( + controller: controller.tabController, + physics: BouncingScrollPhysics(), + children: [ + SourcesView(), + ExtensionsView(), + ], + ), ), ); + // return Scaffold( + // backgroundColor: Theme.of(context).colorScheme.background, + // appBar: TabBar( + // physics: BouncingScrollPhysics(), + // controller: controller.tabController, + // padding: EdgeInsets.all(8), + // isScrollable: context.width > 700 ? true : false, + // labelColor: context.theme.indicatorColor, + // unselectedLabelColor: context.textTheme.bodyText1!.color, + // indicator: BoxDecoration( + // borderRadius: BorderRadius.circular(16), + // color: context.theme.indicatorColor.withOpacity(.3), + // ), + // tabs: [ + // Tab(text: LocaleKeys.screenTitle_sources.tr), + // Tab(text: LocaleKeys.screenTitle_extensions.tr), + // ]), + // body: TabBarView( + // controller: controller.tabController, + // physics: BouncingScrollPhysics(), + // children: [ + // SourcesView(), + // ExtensionsView(), + // ], + // ), + // ); } } diff --git a/lib/app/modules/extensions/views/extensions_view.dart b/lib/app/modules/extensions/views/extensions_view.dart index c87a6b70..d3a3dd1e 100644 --- a/lib/app/modules/extensions/views/extensions_view.dart +++ b/lib/app/modules/extensions/views/extensions_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:get/get.dart'; +import 'package:tachidesk_sorayomi/app/modules/browse/controllers/browse_controller.dart'; import '../../../../generated/locales.g.dart'; import '../../../core/utils/language.dart'; @@ -14,6 +15,7 @@ import '../controllers/extensions_controller.dart'; class ExtensionsView extends GetView { @override Widget build(BuildContext context) { + final _ = Get.find(); return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, body: Obx( @@ -23,6 +25,8 @@ class ExtensionsView extends GetView { ) : controller.groupByMap.keys.isNotEmpty ? ListView.builder( + controller: _.scrollController, + shrinkWrap: true, physics: BouncingScrollPhysics(), itemCount: controller.groupByMap.keys.length, itemBuilder: (context, index) { diff --git a/lib/app/modules/global_search/widgets/source_search_grid.dart b/lib/app/modules/global_search/widgets/source_search_grid.dart index 472859a9..c3ced0c7 100644 --- a/lib/app/modules/global_search/widgets/source_search_grid.dart +++ b/lib/app/modules/global_search/widgets/source_search_grid.dart @@ -41,53 +41,55 @@ class SourceSearchGrid extends StatelessWidget { @override Widget build(BuildContext context) { searchQuery(); - return Obx(() => Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: Text(source.displayName ?? source.name!), - trailing: Icon(Icons.arrow_forward_rounded), - onTap: () => Get.toNamed( - "${Routes.sourceManga}/${source.id}/search?query=$query", - ), + return Obx( + () => Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: Text(source.displayName ?? source.name!), + trailing: Icon(Icons.arrow_forward_rounded), + onTap: () => Get.toNamed( + "${Routes.sourceManga}/${source.id}/search?query=$query", ), - isLoading - ? SizedBox( - height: 205, - child: Center(child: CircularProgressIndicator()), - ) - : sourceMangaListModel.mangaList?.isNotEmpty ?? false - ? SizedBox( - height: 205, - child: Scrollbar( - thumbVisibility: true, + ), + isLoading + ? SizedBox( + height: 205, + child: Center(child: CircularProgressIndicator()), + ) + : sourceMangaListModel.mangaList?.isNotEmpty ?? false + ? SizedBox( + height: 205, + child: Scrollbar( + thumbVisibility: true, + controller: controller, + child: GridView.builder( controller: controller, - child: GridView.builder( - controller: controller, - scrollDirection: Axis.horizontal, - gridDelegate: - const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 205, - crossAxisSpacing: 2.0, - mainAxisSpacing: 2.0, - childAspectRatio: 1.43, - ), - itemCount: (sourceMangaListModel.mangaList!.length), - itemBuilder: (BuildContext context, int index) { - return MangaGridDesign( - manga: sourceMangaListModel.mangaList![index], - onTap: () => Get.toNamed( - "${Routes.manga}/" - "${sourceMangaListModel.mangaList?[index].id}", - ), - isLibraryScreen: true, - ); - }, + scrollDirection: Axis.horizontal, + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 205, + crossAxisSpacing: 2.0, + mainAxisSpacing: 2.0, + childAspectRatio: 1.43, ), + itemCount: (sourceMangaListModel.mangaList!.length), + itemBuilder: (BuildContext context, int index) { + return MangaGridDesign( + isLibraryScreen: true, + manga: sourceMangaListModel.mangaList![index], + onTap: () => Get.toNamed( + "${Routes.manga}/" + "${sourceMangaListModel.mangaList?[index].id}", + ), + ); + }, ), - ) - : Text("No Results found"), - ], - )); + ), + ) + : Text("No Results found"), + ], + ), + ); } } diff --git a/lib/app/modules/home/bindings/home_binding.dart b/lib/app/modules/home/bindings/home_binding.dart index b19f62e7..b2eecf70 100644 --- a/lib/app/modules/home/bindings/home_binding.dart +++ b/lib/app/modules/home/bindings/home_binding.dart @@ -1,4 +1,5 @@ import 'package:get/get.dart'; +import 'package:tachidesk_sorayomi/app/modules/home/widgets/small_screen_navigation_bar.dart'; import '../../browse/controllers/browse_controller.dart'; import '../../downloads/controllers/downloads_controller.dart'; @@ -20,5 +21,7 @@ class HomeBinding extends Bindings { Get.lazyPut(() => ExtensionsController()); Get.lazyPut(() => SourcesController()); Get.lazyPut(() => LibraryController()); + Get.lazyPut( + () => ScrollToHideWidgetStateController()); } } diff --git a/lib/app/modules/home/widgets/small_screen_navigation_bar.dart b/lib/app/modules/home/widgets/small_screen_navigation_bar.dart index dc690953..f052f497 100644 --- a/lib/app/modules/home/widgets/small_screen_navigation_bar.dart +++ b/lib/app/modules/home/widgets/small_screen_navigation_bar.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; +import 'package:tachidesk_sorayomi/app/modules/browse/controllers/browse_controller.dart'; +import 'package:tachidesk_sorayomi/app/modules/updates/controllers/updates_controller.dart'; +import '../../library/controllers/library_controller.dart'; import '../controllers/home_controller.dart'; class SmallScreenNavigationBar extends StatelessWidget { @@ -19,7 +22,6 @@ class SmallScreenNavigationBar extends StatelessWidget { Widget build(BuildContext context) { return GetBuilder( builder: (controller) => ScrollToHideWidgetState( - scrollcontroller: controller.scrollController, child: NavigationBarTheme( data: NavigationBarThemeData( labelTextStyle: MaterialStateProperty.all( @@ -131,23 +133,19 @@ class SmallScreenNavigationBar extends StatelessWidget { class ScrollToHideWidgetState extends GetView { final Widget child; - final ScrollController scrollcontroller; + final Duration duration; final double height; const ScrollToHideWidgetState( {Key? key, required this.child, - required this.scrollcontroller, this.duration = const Duration(milliseconds: 200), this.height = kBottomNavigationBarHeight}) : super(key: key); @override Widget build(BuildContext context) { - Get.put(ScrollToHideWidgetStateController( - scrollcontroller: scrollcontroller, - )); return Obx( () => AnimatedContainer( duration: duration, @@ -161,27 +159,46 @@ class ScrollToHideWidgetState } class ScrollToHideWidgetStateController extends GetxController { - final ScrollController scrollcontroller; - - ScrollToHideWidgetStateController({required this.scrollcontroller}); + final libraryControllerscroll = Get.find(); + final updatesControllerscroll = Get.find(); + final browseControllerscroll = Get.find(); RxBool isVisible = true.obs; @override void onInit() { - scrollcontroller.addListener(listen); - + browseControllerscroll.scrollController.addListener(listen); + libraryControllerscroll.scrollController.addListener(listen2); + updatesControllerscroll.scrollController.addListener(listen3); super.onInit(); } @override void dispose() { - scrollcontroller.removeListener(listen); + browseControllerscroll.scrollController.removeListener(listen); + libraryControllerscroll.scrollController.removeListener(listen2); + updatesControllerscroll.scrollController.removeListener(listen3); super.dispose(); } void listen() { - if (scrollcontroller.position.pixels >= 68) { + if (browseControllerscroll.scrollController.position.pixels >= 68) { + hide(); + } else { + show(); + } + } + + void listen2() { + if (libraryControllerscroll.scrollController.position.pixels >= 68) { + hide(); + } else { + show(); + } + } + + void listen3() { + if (updatesControllerscroll.scrollController.position.pixels >= 68) { hide(); } else { show(); diff --git a/lib/app/modules/library/views/library_view.dart b/lib/app/modules/library/views/library_view.dart index 2054cb53..cbb5dfc3 100644 --- a/lib/app/modules/library/views/library_view.dart +++ b/lib/app/modules/library/views/library_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:grouped_list/sliver_grouped_list.dart'; import 'package:tachidesk_sorayomi/app/modules/browse/widgets/browse_appbar_actions.dart'; import 'package:tachidesk_sorayomi/app/modules/home/controllers/home_controller.dart'; import 'package:tachidesk_sorayomi/app/modules/home/views/home_view.dart'; @@ -20,7 +21,7 @@ class LibraryView extends GetView { return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, body: NestedScrollView( - controller: _.scrollController, + controller: controller.scrollController, body: Obx( () => controller.categoryListLength >= 1 ? TabBarView( @@ -32,31 +33,43 @@ class LibraryView extends GetView { List? mangaList = controller.categoryMangaMap[index]; return mangaList != null && mangaList.isNotEmpty - ? GetBuilder( - builder: (controller) => GridView.builder( - // controller: c.scrollController, - // shrinkWrap: true, - - padding: EdgeInsets.only( - right: 4, left: 4, top: 2, bottom: 2), - gridDelegate: - SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 205, - crossAxisSpacing: 2.0, - mainAxisSpacing: 2.0, - childAspectRatio: 0.7, - ), - itemCount: mangaList.length, - itemBuilder: (context, index) => - MangaGridDesign( - colorBlendMode: BlendMode.darken, - manga: mangaList[index], - onTap: () => Get.toNamed( - "${Routes.manga}/${mangaList[index].id}", - ), - isLibraryScreen: true, + ? ListView.builder( + physics: NeverScrollableScrollPhysics(), + primary: true, + itemCount: mangaList.length, + itemBuilder: (context, index) => MangaGridDesign( + colorBlendMode: BlendMode.darken, + manga: mangaList[index], + onTap: () => Get.toNamed( + "${Routes.manga}/${mangaList[index].id}", ), + isLibraryScreen: true, ), + + // GridView.builder( + // // controller: c.scrollController, + // // shrinkWrap: true, + + // padding: EdgeInsets.only( + // right: 4, left: 4, top: 2, bottom: 2), + // gridDelegate: + // SliverGridDelegateWithMaxCrossAxisExtent( + // maxCrossAxisExtent: 205, + // crossAxisSpacing: 2.0, + // mainAxisSpacing: 2.0, + // childAspectRatio: 0.7, + // ), + // itemCount: mangaList.length, + // itemBuilder: (context, index) => + // MangaGridDesign( + // colorBlendMode: BlendMode.darken, + // manga: mangaList[index], + // onTap: () => Get.toNamed( + // "${Routes.manga}/${mangaList[index].id}", + // ), + // isLibraryScreen: true, + // ), + // ), ) : (controller.isLoading ? Center( @@ -129,7 +142,7 @@ class LibraryView extends GetView { indicatorColor: Theme.of(context).colorScheme.primary, // padding: EdgeInsets.all(8), tabs: controller.categoryList - .map((e) => Tab(text: e?.name ?? "")) + .map((e) => Tab(text: e?.name ?? "Default")) .toList(), ), )), diff --git a/lib/app/modules/sources/views/sources_view.dart b/lib/app/modules/sources/views/sources_view.dart index 5dc69076..e634cb33 100644 --- a/lib/app/modules/sources/views/sources_view.dart +++ b/lib/app/modules/sources/views/sources_view.dart @@ -10,16 +10,20 @@ import '../../../data/enums/auth_type.dart'; import '../../../data/source_model.dart'; import '../../../routes/app_pages.dart'; import '../../../widgets/emoticons.dart'; +import '../../browse/controllers/browse_controller.dart'; import '../controllers/sources_controller.dart'; class SourcesView extends GetView { @override Widget build(BuildContext context) { + final _ = Get.find(); return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, body: Obx( () => controller.groupByMap.keys.isNotEmpty ? ListView.builder( + shrinkWrap: true, + controller: _.scrollController, physics: BouncingScrollPhysics(), itemCount: controller.groupByMap.keys.length, itemBuilder: (context, index) { diff --git a/lib/app/modules/updates/controllers/updates_controller.dart b/lib/app/modules/updates/controllers/updates_controller.dart index 778e9ca8..a753c13f 100644 --- a/lib/app/modules/updates/controllers/updates_controller.dart +++ b/lib/app/modules/updates/controllers/updates_controller.dart @@ -8,7 +8,9 @@ import '../../../data/update_recent_chapter_model.dart'; import '../../downloads/controllers/downloads_controller.dart'; import '../repository/updates_repository.dart'; -class UpdatesController extends GetxController { +class UpdatesController extends GetxController + with GetSingleTickerProviderStateMixin { + late AnimationController animationController; final UpdatesRepository repository = UpdatesRepository(); int _page = 0; final ScrollController scrollController = ScrollController(); @@ -79,4 +81,13 @@ class UpdatesController extends GetxController { @override void onClose() {} + + @override + void onInit() { + animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: 1000), + ); + super.onInit(); + } } diff --git a/lib/app/modules/updates/views/updates_view.dart b/lib/app/modules/updates/views/updates_view.dart index 620889b5..910b10d4 100644 --- a/lib/app/modules/updates/views/updates_view.dart +++ b/lib/app/modules/updates/views/updates_view.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:animated_icon_button/animated_icon_button.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -14,6 +15,8 @@ import '../../../data/enums/auth_type.dart'; import '../../../data/manga_page_model.dart'; import '../../../routes/app_pages.dart'; import '../../../widgets/emoticons.dart'; +import '../../home/controllers/home_controller.dart'; +import '../../home/views/home_view.dart'; import '../controllers/updates_controller.dart'; class UpdatesView extends GetView { @@ -21,98 +24,123 @@ class UpdatesView extends GetView { Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, - floatingActionButton: Obx(() => FloatingActionButton( - backgroundColor: Get.theme.colorScheme.primary, - child: controller.isFirstPage - ? CircularProgressIndicator( - color: Get.theme.colorScheme.onPrimary, - ) - : Icon( - Icons.refresh_outlined, - color: Get.theme.colorScheme.onPrimary, - ), - onPressed: () => controller.getNextPage(isRefresh: true), - )), - body: Obx( - () => controller.isFirstPage - ? Center(child: CircularProgressIndicator()) - : ((controller.updateRecentChapter.pageList?.isNotEmpty ?? false)) - ? GroupedListView( - padding: EdgeInsets.all(8), - controller: controller.scrollController, - order: GroupedListOrder.DESC, - itemComparator: (MangaPage element1, MangaPage element2) => - element1.chapter!.uploadDate!.compareTo( - element2.chapter!.uploadDate!, - ), - elements: controller.updateRecentChapter.pageList!.reversed - .toList(), - groupBy: (MangaPage element) { - final time = DateTime.fromMillisecondsSinceEpoch( - element.chapter!.fetchedAt! * 1000); - return DateTime(time.year, time.month, time.day); - }, - itemBuilder: (context, MangaPage item) { - return ListTile( - onTap: () => - Get.toNamed("${Routes.manga}/${item.manga!.id}" - "/chapter/${item.chapter!.index}"), - contentPadding: - EdgeInsets.symmetric(vertical: 8, horizontal: 16), - leading: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: CachedNetworkImage( - imageUrl: controller.localStorageService.baseURL + - (item.manga?.thumbnailUrl ?? ""), - height: 48, - httpHeaders: - controller.localStorageService.baseAuthType == + floatingActionButton: FloatingActionButton( + backgroundColor: Get.theme.colorScheme.primary, + child: GetBuilder( + builder: (_) { + return AnimatedIconButton( + animationDirection: AnimationDirection.forward(), + splashColor: Colors.transparent, + animationController: _.animationController, + icons: [ + AnimatedIconItem( + icon: Icon(Icons.refresh_rounded, color: Colors.purple), + ), + ], + onPressed: () => _.getNextPage(isRefresh: true), + ); + }, + ), + onPressed: () {}, + ), + body: NestedScrollView( + floatHeaderSlivers: true, + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverAppBar( + floating: true, + + pinned: false, + // leading: Icon(Icons.refresh_outlined), + toolbarHeight: 70, + title: Text(navigationBarTitles[1].tr), + ), + ], + body: Obx( + () => controller.isFirstPage + ? Center(child: CircularProgressIndicator()) + : ((controller.updateRecentChapter.pageList?.isNotEmpty ?? + false)) + ? GroupedListView( + padding: EdgeInsets.all(8), + controller: controller.scrollController, + shrinkWrap: true, + // controller: controller.scrollController, + order: GroupedListOrder.DESC, + itemComparator: + (MangaPage element1, MangaPage element2) => + element1.chapter!.uploadDate!.compareTo( + element2.chapter!.uploadDate!, + ), + elements: controller + .updateRecentChapter.pageList!.reversed + .toList(), + groupBy: (MangaPage element) { + final time = DateTime.fromMillisecondsSinceEpoch( + element.chapter!.fetchedAt! * 1000); + return DateTime(time.year, time.month, time.day); + }, + itemBuilder: (context, MangaPage item) { + return ListTile( + onTap: () => + Get.toNamed("${Routes.manga}/${item.manga!.id}" + "/chapter/${item.chapter!.index}"), + contentPadding: EdgeInsets.symmetric( + vertical: 8, horizontal: 16), + leading: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: CachedNetworkImage( + imageUrl: + controller.localStorageService.baseURL + + (item.manga?.thumbnailUrl ?? ""), + height: 48, + httpHeaders: controller + .localStorageService.baseAuthType == AuthType.basic ? { "Authorization": controller .localStorageService.basicAuth, } : null, - width: 48, - fit: BoxFit.cover, - errorWidget: (context, object, stack) => - Image.asset( - iconPngURL, - height: 48, - width: 48, - fit: BoxFit.cover, + width: 48, + fit: BoxFit.cover, + errorWidget: (context, object, stack) => + Image.asset( + iconPngURL, + height: 48, + width: 48, + fit: BoxFit.cover, + ), + ), ), - ), - ), - title: Text( - item.manga?.title ?? "", - style: TextStyle( - color: item.chapter?.read ?? false - ? Colors.grey - : null), - ), - subtitle: Text( - item.chapter?.name ?? "", - style: TextStyle( - color: item.chapter?.read ?? false - ? Colors.grey - : null), - ), - trailing: DownloadState( - controller: controller, - item: item, + title: Text( + item.manga?.title ?? "", + style: TextStyle( + color: item.chapter?.read ?? false + ? Colors.grey + : null), + ), + subtitle: Text( + item.chapter?.name ?? "", + style: TextStyle( + color: item.chapter?.read ?? false + ? Colors.grey + : null), + ), + trailing: DownloadState( + controller: controller, + item: item, + ), + ); + }, + groupSeparatorBuilder: (DateTime value) => ListTile( + title: Text(convertToAgo(value)), ), - ); - }, - groupSeparatorBuilder: (DateTime value) => ListTile( - title: Text(convertToAgo(value)), - ), - ) - : EmoticonsView( - text: - "${LocaleKeys.no.tr} ${LocaleKeys.screenTitle_updates.tr}", - ), - ), + ) + : EmoticonsView( + text: + "${LocaleKeys.no.tr} ${LocaleKeys.screenTitle_updates.tr}", + ), + )), ); } } diff --git a/lib/app/widgets/manga_grid_design copy.dart b/lib/app/widgets/manga_grid_design copy.dart new file mode 100644 index 00000000..031a0a52 --- /dev/null +++ b/lib/app/widgets/manga_grid_design copy.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:get/get.dart'; + +import '../../generated/locales.g.dart'; +import '../data/enums/auth_type.dart'; +import '../data/manga_model.dart'; +import '../data/services/local_storage_service.dart'; + +class MangaGridDesign extends StatelessWidget { + const MangaGridDesign({ + Key? key, + required this.manga, + this.isLibraryScreen = false, + this.onTap, + this.colorBlendMode, + this.onDoubleTap, + }) : super(key: key); + final Manga manga; + final BlendMode? colorBlendMode; + final void Function()? onTap; + final void Function()? onDoubleTap; + final bool isLibraryScreen; + @override + Widget build(BuildContext context) { + LocalStorageService localStorageService = Get.find(); + return InkResponse( + onTap: onTap, + onDoubleTap: () {}, + child: Card( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: GridTile( + header: !isLibraryScreen + ? manga.inLibrary ?? false + ? Row( + children: [ + Card( + color: Get.theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + LocaleKeys.mangaGridDesign_inLibrary.tr, + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ), + ], + ) + : null + : Padding( + padding: const EdgeInsets.all(4.0), + child: Row(mainAxisSize: MainAxisSize.min, children: [ + (manga.unreadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + left: Radius.circular(5), + right: (manga.downloadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), + ), + color: Get.theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.unreadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ) + : Container(), + (manga.downloadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + color: Get.theme.colorScheme.secondary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + right: Radius.circular(5), + left: (manga.unreadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.downloadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ) + : Container(), + ]), + ), + child: manga.thumbnailUrl != null && manga.thumbnailUrl!.isNotEmpty + ? Container( + child: CachedNetworkImage( + color: Colors.black.withOpacity(0.29), + colorBlendMode: colorBlendMode, + imageUrl: localStorageService.baseURL + + manga.thumbnailUrl.toString(), + fit: BoxFit.cover, + httpHeaders: + localStorageService.baseAuthType == AuthType.basic + ? { + "Authorization": localStorageService.basicAuth, + } + : null, + errorWidget: (context, error, stackTrace) => SizedBox( + height: context.height * .3, + child: Center( + child: Icon( + Icons.book_rounded, + color: Colors.grey, + size: context.height * .1, + ), + ), + ), + progressIndicatorBuilder: (BuildContext context, _, + DownloadProgress? loadingProgress) { + return Center( + child: CircularProgressIndicator( + value: loadingProgress?.progress, + ), + ); + }, + ), + foregroundDecoration: BoxDecoration( + border: Border.all( + width: 0, + color: Get.theme.canvasColor, + ), + boxShadow: !isLibraryScreen && (manga.inLibrary ?? false) + ? [ + BoxShadow( + color: Get.theme.canvasColor.withOpacity(.5)) + ] + : null, + ), + ) + : SizedBox( + height: context.height * .3, + child: Icon( + Icons.book_rounded, + color: Colors.grey, + size: context.height * .2, + ), + ), + footer: ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 8), + dense: true, + title: Text( + (manga.title ?? manga.author ?? ""), + overflow: TextOverflow.ellipsis, + ), + ), + ), + ), + ); + } +} diff --git a/lib/app/widgets/manga_grid_design.dart b/lib/app/widgets/manga_grid_design.dart index 031a0a52..37541445 100644 --- a/lib/app/widgets/manga_grid_design.dart +++ b/lib/app/widgets/manga_grid_design.dart @@ -28,153 +28,509 @@ class MangaGridDesign extends StatelessWidget { return InkResponse( onTap: onTap, onDoubleTap: () {}, - child: Card( - clipBehavior: Clip.antiAlias, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), - child: GridTile( - header: !isLibraryScreen - ? manga.inLibrary ?? false - ? Row( - children: [ - Card( - color: Get.theme.colorScheme.primary, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - horizontal: 4.0, - ), - child: Text( - LocaleKeys.mangaGridDesign_inLibrary.tr, - style: TextStyle( - color: Get.theme.colorScheme.onPrimary, + child: isLibraryScreen + ? ListTile( + subtitle: Row( + children: [ + Padding( + padding: const EdgeInsets.all(4.0), + child: Row(mainAxisSize: MainAxisSize.min, children: [ + (manga.unreadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + left: Radius.circular(5), + right: (manga.downloadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), ), - ), - ), - ), - ], - ) - : null - : Padding( - padding: const EdgeInsets.all(4.0), - child: Row(mainAxisSize: MainAxisSize.min, children: [ - (manga.unreadCount ?? 0) != 0 - ? Card( - margin: EdgeInsets.zero, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal( - left: Radius.circular(5), - right: (manga.downloadCount ?? 0) == 0 - ? Radius.circular(5) - : Radius.zero, + color: Get.theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.unreadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), ), - ), - color: Get.theme.colorScheme.primary, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - horizontal: 4.0, + ) + : Container(), + (manga.downloadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + color: Get.theme.colorScheme.tertiary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + right: Radius.circular(5), + left: (manga.unreadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), ), - child: Text( - "${manga.unreadCount}", - style: TextStyle( - color: Get.theme.colorScheme.onPrimary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.downloadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), ), ), - ), + ) + : Container(), + ]), + ), + ], + ), + leading: Container( + height: 150, + width: 50, + decoration: BoxDecoration( + image: DecorationImage( + image: CachedNetworkImageProvider( + localStorageService.baseURL + + manga.thumbnailUrl.toString(), + errorListener: () => SizedBox( + height: context.height * .3, + child: Center( + child: Icon( + Icons.book_rounded, + color: Colors.grey, + size: context.height * .1, + ), + ), + ), + ), + filterQuality: FilterQuality.high, + fit: BoxFit.cover, + ), + borderRadius: BorderRadius.circular(8), + ), + ), + title: Text( + (manga.title ?? manga.author ?? ""), + overflow: TextOverflow.ellipsis, + ), + ) + : Card( + clipBehavior: Clip.antiAlias, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10)), + child: GridTile( + header: !isLibraryScreen + ? manga.inLibrary ?? false + ? Row( + children: [ + Card( + color: Get.theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + LocaleKeys.mangaGridDesign_inLibrary.tr, + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ), + ], ) - : Container(), - (manga.downloadCount ?? 0) != 0 - ? Card( - margin: EdgeInsets.zero, - color: Get.theme.colorScheme.secondary, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal( - right: Radius.circular(5), - left: (manga.unreadCount ?? 0) == 0 - ? Radius.circular(5) - : Radius.zero, + : null + : Padding( + padding: const EdgeInsets.all(4.0), + child: Row(mainAxisSize: MainAxisSize.min, children: [ + (manga.unreadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + left: Radius.circular(5), + right: (manga.downloadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), + ), + color: Get.theme.colorScheme.primary, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.unreadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ) + : Container(), + (manga.downloadCount ?? 0) != 0 + ? Card( + margin: EdgeInsets.zero, + color: Get.theme.colorScheme.secondary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.horizontal( + right: Radius.circular(5), + left: (manga.unreadCount ?? 0) == 0 + ? Radius.circular(5) + : Radius.zero, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 2.0, + horizontal: 4.0, + ), + child: Text( + "${manga.downloadCount}", + style: TextStyle( + color: Get.theme.colorScheme.onPrimary, + ), + ), + ), + ) + : Container(), + ]), + ), + child: manga.thumbnailUrl != null && + manga.thumbnailUrl!.isNotEmpty + ? Container( + child: CachedNetworkImage( + colorBlendMode: BlendMode.darken, + imageUrl: localStorageService.baseURL + + manga.thumbnailUrl.toString(), + fit: BoxFit.cover, + httpHeaders: + localStorageService.baseAuthType == AuthType.basic + ? { + "Authorization": + localStorageService.basicAuth, + } + : null, + errorWidget: (context, error, stackTrace) => SizedBox( + height: context.height * .3, + child: Center( + child: Icon( + Icons.book_rounded, + color: Colors.grey, + size: context.height * .1, ), ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 2.0, - horizontal: 4.0, - ), - child: Text( - "${manga.downloadCount}", - style: TextStyle( - color: Get.theme.colorScheme.onPrimary, - ), + ), + progressIndicatorBuilder: (BuildContext context, _, + DownloadProgress? loadingProgress) { + return Center( + child: CircularProgressIndicator( + value: loadingProgress?.progress, ), - ), - ) - : Container(), - ]), - ), - child: manga.thumbnailUrl != null && manga.thumbnailUrl!.isNotEmpty - ? Container( - child: CachedNetworkImage( - color: Colors.black.withOpacity(0.29), - colorBlendMode: colorBlendMode, - imageUrl: localStorageService.baseURL + - manga.thumbnailUrl.toString(), - fit: BoxFit.cover, - httpHeaders: - localStorageService.baseAuthType == AuthType.basic - ? { - "Authorization": localStorageService.basicAuth, - } - : null, - errorWidget: (context, error, stackTrace) => SizedBox( - height: context.height * .3, - child: Center( + ); + }, + ), + foregroundDecoration: BoxDecoration( + border: Border.all( + width: 0, + color: Get.theme.canvasColor, + ), + ), + ) + : SizedBox( + height: context.height * .3, child: Icon( Icons.book_rounded, color: Colors.grey, - size: context.height * .1, + size: context.height * .2, ), ), - ), - progressIndicatorBuilder: (BuildContext context, _, - DownloadProgress? loadingProgress) { - return Center( - child: CircularProgressIndicator( - value: loadingProgress?.progress, - ), - ); - }, - ), - foregroundDecoration: BoxDecoration( - border: Border.all( - width: 0, - color: Get.theme.canvasColor, - ), - boxShadow: !isLibraryScreen && (manga.inLibrary ?? false) - ? [ - BoxShadow( - color: Get.theme.canvasColor.withOpacity(.5)) - ] - : null, - ), - ) - : SizedBox( - height: context.height * .3, - child: Icon( - Icons.book_rounded, - color: Colors.grey, - size: context.height * .2, + footer: ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 8), + dense: true, + title: Text( + (manga.title ?? manga.author ?? ""), + overflow: TextOverflow.ellipsis, ), ), - footer: ListTile( - contentPadding: const EdgeInsets.symmetric(horizontal: 8), - dense: true, - title: Text( - (manga.title ?? manga.author ?? ""), - overflow: TextOverflow.ellipsis, + ), ), - ), - ), - ), + + // : Container( + // color: Get.theme.colorScheme.background, + // child: Padding( + // padding: const EdgeInsets.only(top: 10.0, right: 5, left: 5), + // child: ClipRRect( + // borderRadius: BorderRadius.all(Radius.circular(15)), + // child: Stack( + // children: [ + // Align( + // alignment: Alignment.topCenter, + // child: Text("${manga.unreadCount}", + // style: TextStyle( + // color: Get.theme.colorScheme.onPrimary, + // )), + // ), + // CachedNetworkImage( + // height: 350, + // color: Colors.black.withOpacity(0.29), + // imageUrl: localStorageService.baseURL + + // manga.thumbnailUrl.toString(), + // fit: BoxFit.cover, + // colorBlendMode: BlendMode.darken, + // httpHeaders: + // localStorageService.baseAuthType == AuthType.basic + // ? { + // "Authorization": + // localStorageService.basicAuth, + // } + // : null, + // errorWidget: (context, error, stackTrace) => SizedBox( + // height: context.height * .3, + // child: Center( + // child: Icon( + // Icons.book_rounded, + // color: Colors.grey, + // size: context.height * .1, + // ), + // ), + // ), + // progressIndicatorBuilder: (BuildContext context, _, + // DownloadProgress? loadingProgress) { + // return Center( + // child: CircularProgressIndicator( + // value: loadingProgress?.progress, + // ), + // ); + // }, + // ), + // ], + // ), + // // foregroundDecoration: BoxDecoration( + // // border: Border.all( + // // width: 0, + // // color: Get.theme.canvasColor, + // // ), + // // ), + // ), + // ), + // ) + // child: Stack( + // children: [ + // manga.thumbnailUrl != null && manga.thumbnailUrl!.isNotEmpty + // ? Container( + // child: CachedNetworkImage( + // color: Colors.black.withOpacity(0.29), + // colorBlendMode: colorBlendMode, + // imageUrl: localStorageService.baseURL + + // manga.thumbnailUrl.toString(), + // fit: BoxFit.cover, + // httpHeaders: + // localStorageService.baseAuthType == AuthType.basic + // ? { + // "Authorization": localStorageService.basicAuth, + // } + // : null, + // errorWidget: (context, error, stackTrace) => SizedBox( + // height: context.height * .3, + // child: Center( + // child: Icon( + // Icons.book_rounded, + // color: Colors.grey, + // size: context.height * .1, + // ), + // ), + // ), + // progressIndicatorBuilder: (BuildContext context, _, + // DownloadProgress? loadingProgress) { + // return Center( + // child: CircularProgressIndicator( + // value: loadingProgress?.progress, + // ), + // ); + // }, + // ), + // foregroundDecoration: BoxDecoration( + // border: Border.all( + // width: 0, + // color: Get.theme.canvasColor, + // ), + // boxShadow: !isLibraryScreen && (manga.inLibrary ?? false) + // ? [ + // BoxShadow( + // color: Get.theme.canvasColor.withOpacity(.5)) + // ] + // : null, + // ), + // ) + // : SizedBox( + // height: context.height * .3, + // child: Icon( + // Icons.book_rounded, + // color: Colors.grey, + // size: context.height * .2, + // ), + // ), + // ], + // ), ); + + // Card( + // clipBehavior: Clip.antiAlias, + // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + // child: GridTile( + // header: !isLibraryScreen + // ? manga.inLibrary ?? false + // ? Row( + // children: [ + // Card( + // color: Get.theme.colorScheme.primary, + // child: Padding( + // padding: const EdgeInsets.symmetric( + // vertical: 2.0, + // horizontal: 4.0, + // ), + // child: Text( + // LocaleKeys.mangaGridDesign_inLibrary.tr, + // style: TextStyle( + // color: Get.theme.colorScheme.onPrimary, + // ), + // ), + // ), + // ), + // ], + // ) + // : null + // : Padding( + // padding: const EdgeInsets.all(4.0), + // child: Row(mainAxisSize: MainAxisSize.min, children: [ + // (manga.unreadCount ?? 0) != 0 + // ? Card( + // margin: EdgeInsets.zero, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.horizontal( + // left: Radius.circular(5), + // right: (manga.downloadCount ?? 0) == 0 + // ? Radius.circular(5) + // : Radius.zero, + // ), + // ), + // color: Get.theme.colorScheme.primary, + // child: Padding( + // padding: const EdgeInsets.symmetric( + // vertical: 2.0, + // horizontal: 4.0, + // ), + // child: Text( + // "${manga.unreadCount}", + // style: TextStyle( + // color: Get.theme.colorScheme.onPrimary, + // ), + // ), + // ), + // ) + // : Container(), + // (manga.downloadCount ?? 0) != 0 + // ? Card( + // margin: EdgeInsets.zero, + // color: Get.theme.colorScheme.secondary, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.horizontal( + // right: Radius.circular(5), + // left: (manga.unreadCount ?? 0) == 0 + // ? Radius.circular(5) + // : Radius.zero, + // ), + // ), + // child: Padding( + // padding: const EdgeInsets.symmetric( + // vertical: 2.0, + // horizontal: 4.0, + // ), + // child: Text( + // "${manga.downloadCount}", + // style: TextStyle( + // color: Get.theme.colorScheme.onPrimary, + // ), + // ), + // ), + // ) + // : Container(), + // ]), + // ), + // child: manga.thumbnailUrl != null && manga.thumbnailUrl!.isNotEmpty + // ? Container( + // child: CachedNetworkImage( + // color: Colors.black.withOpacity(0.29), + // colorBlendMode: colorBlendMode, + // imageUrl: localStorageService.baseURL + + // manga.thumbnailUrl.toString(), + // fit: BoxFit.cover, + // httpHeaders: + // localStorageService.baseAuthType == AuthType.basic + // ? { + // "Authorization": localStorageService.basicAuth, + // } + // : null, + // errorWidget: (context, error, stackTrace) => SizedBox( + // height: context.height * .3, + // child: Center( + // child: Icon( + // Icons.book_rounded, + // color: Colors.grey, + // size: context.height * .1, + // ), + // ), + // ), + // progressIndicatorBuilder: (BuildContext context, _, + // DownloadProgress? loadingProgress) { + // return Center( + // child: CircularProgressIndicator( + // value: loadingProgress?.progress, + // ), + // ); + // }, + // ), + // foregroundDecoration: BoxDecoration( + // border: Border.all( + // width: 0, + // color: Get.theme.canvasColor, + // ), + // boxShadow: !isLibraryScreen && (manga.inLibrary ?? false) + // ? [ + // BoxShadow( + // color: Get.theme.canvasColor.withOpacity(.5)) + // ] + // : null, + // ), + // ) + // : SizedBox( + // height: context.height * .3, + // child: Icon( + // Icons.book_rounded, + // color: Colors.grey, + // size: context.height * .2, + // ), + // ), + // footer: ListTile( + // contentPadding: const EdgeInsets.symmetric(horizontal: 8), + // dense: true, + // title: Text( + // (manga.title ?? manga.author ?? ""), + // overflow: TextOverflow.ellipsis, + // ), + // ), + // ), + // ), + // ); } } diff --git a/pubspec.lock b/pubspec.lock index 43adc1e2..5e3a4b77 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,13 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + animated_icon_button: + dependency: "direct main" + description: + name: animated_icon_button + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" async: dependency: transitive description: @@ -156,6 +163,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "10.1.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" get: dependency: "direct main" description: @@ -212,6 +226,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.5.0" lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 06fc25ec..3c0dcbcf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,12 @@ name: tachidesk_sorayomi -version: 1.0.8+1 +version: 1.0.12+1 publish_to: none description: A new Flutter frontend for Tachidesk. environment: sdk: ">=2.16.0-80.1.beta <3.0.0" dependencies: + animated_icon_button: ^1.0.2 cached_network_image: ^3.2.0 collection: ^1.15.0 cupertino_icons: ^1.0.2