diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart index b034884..b1530f4 100644 --- a/lib/pages/reader/images.dart +++ b/lib/pages/reader/images.dart @@ -140,12 +140,12 @@ class _GalleryModeState extends State<_GalleryMode> int get totalPages { if (!reader.showSingleImageOnFirstPage()) { return (reader.images!.length / - reader.imagesPerPage()) + reader.imagesPerPage) .ceil(); } else { return 1 + ((reader.images!.length - 1) / - reader.imagesPerPage()) + reader.imagesPerPage) .ceil(); } } @@ -169,7 +169,7 @@ class _GalleryModeState extends State<_GalleryMode> /// Get the range of images for the given page. [page] is 1-based. (int start, int end) getPageImagesRange(int page) { - var imagesPerPage = reader.imagesPerPage(); + var imagesPerPage = reader.imagesPerPage; if (reader.showSingleImageOnFirstPage()) { if (page == 1) { return (0, 1); @@ -191,6 +191,16 @@ class _GalleryModeState extends State<_GalleryMode> } } + /// Get the image indices for current page. Returns null if no images. + /// Returns a single index if only one image, or a range if multiple images. + (int, int)? getCurrentPageImageRange() { + if (reader.images == null || reader.images!.isEmpty) { + return null; + } + var (startIndex, endIndex) = getPageImagesRange(reader.page); + return (startIndex, endIndex); + } + /// [cache] is used to cache the images. /// The count of images to cache is determined by the [preCacheCount] setting. /// For previous page and next page, it will do a memory cache. @@ -259,7 +269,7 @@ class _GalleryModeState extends State<_GalleryMode> photoViewControllers[index] ??= PhotoViewController(); - if (reader.imagesPerPage() == 1 || + if (reader.imagesPerPage == 1 || pageImages.length == 1) { return PhotoViewGalleryPageOptions( filterQuality: FilterQuality.medium, @@ -533,17 +543,27 @@ class _GalleryModeState extends State<_GalleryMode> @override String? getImageKeyByOffset(Offset offset) { - String? imageKey; - if (reader.imagesPerPage() == 1) { - imageKey = reader.images![reader.page - 1]; - } else { - for (var imageState in imageStates) { - if ((imageState as _ComicImageState).containsPoint(offset)) { - imageKey = (imageState.widget.image as ReaderImageProvider).imageKey; + var range = getCurrentPageImageRange(); + if (range == null) return null; + + var (startIndex, endIndex) = range; + int actualImageCount = endIndex - startIndex; + + if (actualImageCount == 1) { + return reader.images![startIndex]; + } + + for (var imageState in imageStates) { + if ((imageState as _ComicImageState).containsPoint(offset)) { + var imageKey = (imageState.widget.image as ReaderImageProvider).imageKey; + int index = reader.images!.indexOf(imageKey); + if (index >= startIndex && index < endIndex) { + return imageKey; } } } - return imageKey; + + return reader.images![startIndex]; } } diff --git a/lib/pages/reader/reader.dart b/lib/pages/reader/reader.dart index ce5de8c..0f17b64 100644 --- a/lib/pages/reader/reader.dart +++ b/lib/pages/reader/reader.dart @@ -116,9 +116,9 @@ class _ReaderState extends State return 1; } if (!showSingleImageOnFirstPage()) { - return (images!.length / imagesPerPage()).ceil(); + return (images!.length / imagesPerPage).ceil(); } else { - return 1 + ((images!.length - 1) / imagesPerPage()).ceil(); + return 1 + ((images!.length - 1) / imagesPerPage).ceil(); } } @@ -277,13 +277,13 @@ class _ReaderState extends State history!.page = images?.length ?? 1; } else { /// Record the first image of the page - if (!showSingleImageOnFirstPage() || imagesPerPage() == 1) { - history!.page = (page - 1) * imagesPerPage() + 1; + if (!showSingleImageOnFirstPage() || imagesPerPage == 1) { + history!.page = (page - 1) * imagesPerPage + 1; } else { if (page == 1) { history!.page = 1; } else { - history!.page = (page - 2) * imagesPerPage() + 2; + history!.page = (page - 2) * imagesPerPage + 2; } } } @@ -371,13 +371,13 @@ abstract mixin class _ImagePerPageHandler { ComicType get type; void initImagesPerPage(int initialPage) { - _lastImagesPerPage = imagesPerPage(); + _lastImagesPerPage = imagesPerPage; _lastOrientation = isPortrait; - if (imagesPerPage() != 1) { + if (imagesPerPage != 1) { if (showSingleImageOnFirstPage()) { - page = ((initialPage - 1) / imagesPerPage()).ceil() + 1; + page = ((initialPage - 1) / imagesPerPage).ceil() + 1; } else { - page = (initialPage / imagesPerPage()).ceil(); + page = (initialPage / imagesPerPage).ceil(); } } } @@ -386,7 +386,7 @@ abstract mixin class _ImagePerPageHandler { appdata.settings.getReaderSetting(cid, type.sourceKey, 'showSingleImageOnFirstPage'); /// The number of images displayed on one screen - int imagesPerPage() { + int get imagesPerPage { if (mode.isContinuous) return 1; if (isPortrait) { return appdata.settings.getReaderSetting(cid, type.sourceKey, 'readerScreenPicNumberForPortrait') ?? 1; @@ -397,7 +397,7 @@ abstract mixin class _ImagePerPageHandler { /// Check if the number of images per page has changed void _checkImagesPerPageChange() { - int currentImagesPerPage = imagesPerPage(); + int currentImagesPerPage = imagesPerPage; bool currentOrientation = isPortrait; if (_lastImagesPerPage != currentImagesPerPage || _lastOrientation != currentOrientation) { diff --git a/lib/pages/reader/scaffold.dart b/lib/pages/reader/scaffold.dart index e1257aa..ee052da 100644 --- a/lib/pages/reader/scaffold.dart +++ b/lib/pages/reader/scaffold.dart @@ -599,22 +599,24 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { } void saveCurrentImage() async { - var data = await selectImageToData(); - if (data == null) { + var result = await selectImageToData(); + if (result == null) { return; } + var (imageIndex, data) = result; var fileType = detectFileType(data); - var filename = "${context.reader.page}${fileType.ext}"; + var filename = "${context.reader.widget.name}_${imageIndex + 1}${fileType.ext}"; saveFile(data: data, filename: filename); } void share() async { - var data = await selectImageToData(); - if (data == null) { + var result = await selectImageToData(); + if (result == null) { return; } + var (imageIndex, data) = result; var fileType = detectFileType(data); - var filename = "${context.reader.page}${fileType.ext}"; + var filename = "${context.reader.widget.name}_${imageIndex + 1}${fileType.ext}"; Share.shareFile(data: data, filename: filename, mime: fileType.mime); } @@ -719,8 +721,29 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { Future selectImage() async { var reader = context.reader; var imageViewController = context.reader._imageViewController; - if (imageViewController is _GalleryModeState && reader.imagesPerPage == 1) { - return reader.page - 1; + + bool needsSelection = false; + int? singleImageIndex; + + if (imageViewController is _GalleryModeState) { + var range = imageViewController.getCurrentPageImageRange(); + if (range != null) { + var (startIndex, endIndex) = range; + int actualImageCount = endIndex - startIndex; + if (actualImageCount == 1) { + needsSelection = false; + singleImageIndex = startIndex; + } else { + needsSelection = true; + } + } + } else if (imageViewController is _ContinuousModeState) { + needsSelection = false; + singleImageIndex = reader.page - 1; + } + + if (!needsSelection && singleImageIndex != null) { + return singleImageIndex; } else { var location = await _showSelectImageOverlay(); if (location == null) { @@ -734,20 +757,23 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { } } - /// Same as [selectImage], but return the image data. - Future selectImageToData() async { + /// Same as [selectImage], but return the image data with its index. + /// Returns (imageIndex, imageData) or null if cancelled. + Future<(int, Uint8List)?> selectImageToData() async { var i = await selectImage(); if (i == null) { return null; } var imageKey = context.reader.images![i]; + Uint8List data; if (imageKey.startsWith("file://")) { - return await File(imageKey.substring(7)).readAsBytes(); + data = await File(imageKey.substring(7)).readAsBytes(); } else { - return (await CacheManager().findCache( + data = await (await CacheManager().findCache( "$imageKey@${context.reader.type.sourceKey}@${context.reader.cid}@${context.reader.eid}", ))!.readAsBytes(); } + return (i, data); } Future _showSelectImageOverlay() {