mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
Feat 为画廊模式添加每页显示图片数量的配置 (#82)
* 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
This commit is contained in:
@@ -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": "浅色",
|
||||
|
@@ -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
|
||||
|
@@ -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<String> pageImages = reader.images!.sublist(startIndex, endIndex);
|
||||
|
||||
cached[index] = true;
|
||||
cache(index);
|
||||
|
||||
photoViewControllers[index] ??= PhotoViewController();
|
||||
photoViewControllers[index] = PhotoViewController();
|
||||
|
||||
return PhotoViewGalleryPageOptions(
|
||||
filterQuality: FilterQuality.medium,
|
||||
return PhotoViewGalleryPageOptions.customChild(
|
||||
child: PhotoView.customChild(
|
||||
key: ValueKey('photo_view_$index'),
|
||||
controller: photoViewControllers[index],
|
||||
imageProvider: imageProvider,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (_, error, s, retry) {
|
||||
return NetworkError(message: error.toString(), retry: retry);
|
||||
},
|
||||
minScale: PhotoViewComputedScale.contained * 1.0,
|
||||
maxScale: PhotoViewComputedScale.covered * 10.0,
|
||||
child: buildPageImages(pageImages),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
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<String> images) {
|
||||
Axis axis = (reader.mode == ReaderMode.galleryTopToBottom)
|
||||
? Axis.vertical
|
||||
: Axis.horizontal;
|
||||
|
||||
List<Widget> 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<void> 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];
|
||||
|
@@ -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<Reader> 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<Reader> 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<Reader> with _ReaderLocation, _ReaderWindow {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_checkImagesPerPageChange();
|
||||
return KeyboardListener(
|
||||
focusNode: focusNode,
|
||||
autofocus: true,
|
||||
|
@@ -41,6 +41,11 @@ class _ReaderSettingsState extends State<ReaderSettings> {
|
||||
"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<ReaderSettings> {
|
||||
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',
|
||||
|
Reference in New Issue
Block a user