From 66ebdb03b16cbf22424a06bc855d3de07ff6f712 Mon Sep 17 00:00:00 2001 From: buste <32890006+bustesoul@users.noreply.github.com> Date: Sun, 1 Dec 2024 19:56:38 +0800 Subject: [PATCH] =?UTF-8?q?Feat=20=E4=B8=BA=E7=94=BB=E5=BB=8A=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E6=B7=BB=E5=8A=A0=E6=AF=8F=E9=A1=B5=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E6=95=B0=E9=87=8F=E7=9A=84=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=20(#82)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat: Add dynamic image-per-page configuration for gallery mode - Implemented a slider to configure the number of images displayed per page (1-5) in gallery mode. - Updated the reader to dynamically reflect changes in the `imagesPerPage` setting without requiring a mode switch or reopening. - Ensured compatibility with existing continuous reading mode. * fix currentImagesPerPage * fix Continuous mode * improve readerScreenPicNumber setting disable view * improve PhotoViewController --- assets/translation.json | 2 + lib/foundation/appdata.dart | 1 + lib/pages/reader/images.dart | 101 ++++++++++++++++++++++++--------- lib/pages/reader/reader.dart | 29 +++++++++- lib/pages/settings/reader.dart | 24 ++++++++ 5 files changed, 130 insertions(+), 27 deletions(-) diff --git a/assets/translation.json b/assets/translation.json index d03fb34..985ab59 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -105,6 +105,7 @@ "Continuous (Right to Left)": "连续(从右到左)", "Continuous (Top to Bottom)": "连续(从上到下)", "Auto page turning interval": "自动翻页间隔", + "The number of pic in screen (Only Gallery Mode)": "同屏幕图片数量(仅画廊模式)", "Theme Mode": "主题模式", "System": "系统", "Light": "浅色", @@ -353,6 +354,7 @@ "Continuous (Right to Left)": "連續(從右到左)", "Continuous (Top to Bottom)": "連續(從上到下)", "Auto page turning interval": "自動翻頁間隔", + "The number of pic in screen (Only Gallery Mode)": "同螢幕圖片數量(僅畫廊模式)", "Theme Mode": "主題模式", "System": "系統", "Light": "浅色", diff --git a/lib/foundation/appdata.dart b/lib/foundation/appdata.dart index 8c5d347..c113a00 100644 --- a/lib/foundation/appdata.dart +++ b/lib/foundation/appdata.dart @@ -106,6 +106,7 @@ class _Settings with ChangeNotifier { 'defaultSearchTarget': null, 'autoPageTurningInterval': 5, // in seconds 'readerMode': 'galleryLeftToRight', // values of [ReaderMode] + 'readerScreenPicNumber': 1, // 1 - 5 'enableTapToTurnPages': true, 'enablePageAnimation': true, 'language': 'system', // system, zh-CN, zh-TW, en-US diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart index d273eca..4d12a64 100644 --- a/lib/pages/reader/images.dart +++ b/lib/pages/reader/images.dart @@ -83,7 +83,8 @@ class _ReaderImagesState extends State<_ReaderImages> { ); } else { if (reader.mode.isGallery) { - return _GalleryMode(key: Key(reader.mode.key)); + return _GalleryMode( + key: Key('${reader.mode.key}_${reader.imagesPerPage}')); } else { return _ContinuousMode(key: Key(reader.mode.key)); } @@ -110,6 +111,10 @@ class _GalleryModeState extends State<_GalleryMode> late _ReaderState reader; + int get totalPages => ((reader.images!.length + reader.imagesPerPage - 1) / + reader.imagesPerPage) + .ceil(); + @override void initState() { reader = context.reader; @@ -124,8 +129,14 @@ class _GalleryModeState extends State<_GalleryMode> void cache(int current) { for (int i = current + 1; i <= current + preCacheCount; i++) { - if (i <= reader.maxPage && !cached[i]) { - _precacheImage(i, context); + if (i <= totalPages && !cached[i]) { + int startIndex = (i - 1) * reader.imagesPerPage; + int endIndex = + math.min(startIndex + reader.imagesPerPage, reader.images!.length); + for (int i = startIndex; i < endIndex; i++) { + precacheImage( + _createImageProviderFromKey(reader.images![i], context), context); + } cached[i] = true; } } @@ -141,32 +152,34 @@ class _GalleryModeState extends State<_GalleryMode> scrollDirection: reader.mode == ReaderMode.galleryTopToBottom ? Axis.vertical : Axis.horizontal, - itemCount: reader.images!.length + 2, + itemCount: totalPages + 2, builder: (BuildContext context, int index) { - ImageProvider? imageProvider; - if (index != 0 && index != reader.images!.length + 1) { - imageProvider = _createImageProvider(index, context); - } else { + if (index == 0 || index == totalPages + 1) { return PhotoViewGalleryPageOptions.customChild( scaleStateController: PhotoViewScaleStateController(), child: const SizedBox(), ); + } else { + int pageIndex = index - 1; + int startIndex = pageIndex * reader.imagesPerPage; + int endIndex = math.min(startIndex + reader.imagesPerPage, reader.images!.length); + List pageImages = reader.images!.sublist(startIndex, endIndex); + + cached[index] = true; + cache(index); + + photoViewControllers[index] = PhotoViewController(); + + return PhotoViewGalleryPageOptions.customChild( + child: PhotoView.customChild( + key: ValueKey('photo_view_$index'), + controller: photoViewControllers[index], + minScale: PhotoViewComputedScale.contained * 1.0, + maxScale: PhotoViewComputedScale.covered * 10.0, + child: buildPageImages(pageImages), + ), + ); } - - cached[index] = true; - cache(index); - - photoViewControllers[index] ??= PhotoViewController(); - - return PhotoViewGalleryPageOptions( - filterQuality: FilterQuality.medium, - controller: photoViewControllers[index], - imageProvider: imageProvider, - fit: BoxFit.contain, - errorBuilder: (_, error, s, retry) { - return NetworkError(message: error.toString(), retry: retry); - }, - ); }, pageController: controller, loadingBuilder: (context, event) => Center( @@ -186,9 +199,9 @@ class _GalleryModeState extends State<_GalleryMode> if (!reader.toPrevChapter()) { reader.toPage(1); } - } else if (i == reader.maxPage + 1) { + } else if (i == totalPages + 1) { if (!reader.toNextChapter()) { - reader.toPage(reader.maxPage); + reader.toPage(totalPages); } } else { reader.setPage(i); @@ -198,9 +211,30 @@ class _GalleryModeState extends State<_GalleryMode> ); } + Widget buildPageImages(List images) { + Axis axis = (reader.mode == ReaderMode.galleryTopToBottom) + ? Axis.vertical + : Axis.horizontal; + + List imageWidgets = images.map((imageKey) { + ImageProvider imageProvider = + _createImageProviderFromKey(imageKey, context); + return Expanded( + child: Image( + image: imageProvider, + fit: BoxFit.contain, + ), + ); + }).toList(); + + return axis == Axis.vertical + ? Column(children: imageWidgets) + : Row(children: imageWidgets); + } + @override Future animateToPage(int page) { - if ((page - controller.page!).abs() > 1) { + if ((page - controller.page!.round()).abs() > 1) { controller.jumpToPage(page > controller.page! ? page - 1 : page + 1); } return controller.animateToPage( @@ -600,6 +634,21 @@ class _ContinuousModeState extends State<_ContinuousMode> } } +ImageProvider _createImageProviderFromKey( + String imageKey, BuildContext context) { + if (imageKey.startsWith('file://')) { + return FileImage(File(imageKey.replaceFirst("file://", ''))); + } else { + var reader = context.reader; + return ReaderImageProvider( + imageKey, + reader.type.comicSource!.key, + reader.cid, + reader.eid, + ); + } +} + ImageProvider _createImageProvider(int page, BuildContext context) { var reader = context.reader; var imageKey = reader.images![page - 1]; diff --git a/lib/pages/reader/reader.dart b/lib/pages/reader/reader.dart index 5a828de..8f91306 100644 --- a/lib/pages/reader/reader.dart +++ b/lib/pages/reader/reader.dart @@ -1,6 +1,7 @@ library venera_reader; import 'dart:async'; +import 'dart:math' as math; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -82,7 +83,8 @@ class _ReaderState extends State with _ReaderLocation, _ReaderWindow { } @override - int get maxPage => images?.length ?? 1; + int get maxPage => + ((images?.length ?? 1) + imagesPerPage - 1) ~/ imagesPerPage; ComicType get type => widget.type; @@ -94,6 +96,30 @@ class _ReaderState extends State with _ReaderLocation, _ReaderWindow { late ReaderMode mode; + int get imagesPerPage => appdata.settings['readerScreenPicNumber'] ?? 1; + + int _lastImagesPerPage = appdata.settings['readerScreenPicNumber'] ?? 1; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _checkImagesPerPageChange(); + } + + void _checkImagesPerPageChange() { + int currentImagesPerPage = imagesPerPage; + if (_lastImagesPerPage != currentImagesPerPage) { + _adjustPageForImagesPerPageChange(_lastImagesPerPage, currentImagesPerPage); + _lastImagesPerPage = currentImagesPerPage; + } + } + + void _adjustPageForImagesPerPageChange(int oldImagesPerPage, int newImagesPerPage) { + int previousImageIndex = (page - 1) * oldImagesPerPage; + int newPage = (previousImageIndex ~/ newImagesPerPage) + 1; + page = newPage; + } + History? history; @override @@ -133,6 +159,7 @@ class _ReaderState extends State with _ReaderLocation, _ReaderWindow { @override Widget build(BuildContext context) { + _checkImagesPerPageChange(); return KeyboardListener( focusNode: focusNode, autofocus: true, diff --git a/lib/pages/settings/reader.dart b/lib/pages/settings/reader.dart index 2bba6b9..810734a 100644 --- a/lib/pages/settings/reader.dart +++ b/lib/pages/settings/reader.dart @@ -41,6 +41,11 @@ class _ReaderSettingsState extends State { "continuousTopToBottom": "Continuous (Top to Bottom)".tl, }, onChanged: () { + var readerMode = appdata.settings['readerMode']; + if (readerMode?.toLowerCase().startsWith('continuous') ?? false) { + appdata.settings['readerScreenPicNumber'] = 1; + widget.onChanged?.call('readerScreenPicNumber'); + } widget.onChanged?.call("readerMode"); }, ).toSliver(), @@ -54,6 +59,25 @@ class _ReaderSettingsState extends State { widget.onChanged?.call("autoPageTurningInterval"); }, ).toSliver(), + SliverToBoxAdapter( + child: AbsorbPointer( + absorbing: (appdata.settings['readerMode']?.toLowerCase().startsWith('continuous') ?? false), + child: AnimatedOpacity( + opacity: (appdata.settings['readerMode']?.toLowerCase().startsWith('continuous') ?? false) ? 0.5 : 1.0, + duration: Duration(milliseconds: 300), + child: _SliderSetting( + title: "The number of pic in screen (Only Gallery Mode)".tl, + settingsIndex: "readerScreenPicNumber", + interval: 1, + min: 1, + max: 5, + onChanged: () { + widget.onChanged?.call("readerScreenPicNumber"); + }, + ), + ), + ), + ), _SwitchSetting( title: 'Long press to zoom'.tl, settingKey: 'enableLongPressToZoom',