From 3da00595b731ce05fc854468c99b43260762ce81 Mon Sep 17 00:00:00 2001 From: nyne Date: Wed, 2 Apr 2025 16:23:51 +0800 Subject: [PATCH] Add a setting for long press position. Close #287 --- assets/translation.json | 10 +++- lib/components/layout.dart | 26 ++++++++++ lib/foundation/appdata.dart | 1 + lib/pages/reader/images.dart | 43 +++++++++++++--- lib/pages/reader/reader.dart | 7 +++ lib/pages/settings/reader.dart | 89 +++++++++++++++------------------- 6 files changed, 117 insertions(+), 59 deletions(-) diff --git a/assets/translation.json b/assets/translation.json index df33077..4b42aa2 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -381,7 +381,10 @@ "A valid WebDav directory URL": "有效的WebDav目录URL", "Shut Down": "关闭", "Uploading data...": "正在上传数据...", - "Pages": "页数" + "Pages": "页数", + "Long press zoom position": "长按缩放位置", + "Press position": "按压位置", + "Screen center": "屏幕中心" }, "zh_TW": { "Home": "首頁", @@ -765,6 +768,9 @@ "A valid WebDav directory URL": "有效的WebDav目錄URL", "Shut Down": "關閉", "Uploading data...": "正在上傳數據...", - "Pages": "頁數" + "Pages": "頁數", + "Long press zoom position": "長按縮放位置", + "Press position": "按壓位置", + "Screen center": "螢幕中心" } } diff --git a/lib/components/layout.dart b/lib/components/layout.dart index 0238863..e4bf0c6 100644 --- a/lib/components/layout.dart +++ b/lib/components/layout.dart @@ -163,3 +163,29 @@ class SliverLazyToBoxAdapter extends StatelessWidget { ]); } } + +class SliverAnimatedVisibility extends StatelessWidget { + const SliverAnimatedVisibility({ + super.key, + required this.visible, + required this.child, + }); + + final bool visible; + + final Widget child; + + @override + Widget build(BuildContext context) { + var child = visible ? this.child : const SizedBox.shrink(); + + return SliverToBoxAdapter( + child: AnimatedSize( + duration: const Duration(milliseconds: 200), + curve: Curves.easeInOut, + alignment: Alignment.topCenter, + child: child, + ), + ); + } +} diff --git a/lib/foundation/appdata.dart b/lib/foundation/appdata.dart index b4e4073..ecb64cc 100644 --- a/lib/foundation/appdata.dart +++ b/lib/foundation/appdata.dart @@ -161,6 +161,7 @@ class Settings with ChangeNotifier { 'cacheSize': 2048, // in MB 'downloadThreads': 5, 'enableLongPressToZoom': true, + 'longPressZoomPosition': "press", // press, center 'checkUpdateOnStart': false, 'limitImageWidth': true, 'webdav': [], // empty means not configured diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart index e2693e4..456ef64 100644 --- a/lib/pages/reader/images.dart +++ b/lib/pages/reader/images.dart @@ -343,10 +343,19 @@ class _GalleryModeState extends State<_GalleryMode> } var photoViewController = photoViewControllers[reader.page]!; double target = photoViewController.getInitialScale!.call()! * 1.75; - var size = MediaQuery.of(context).size; + var size = reader.size; + Offset zoomPosition; + if (appdata.settings['longPressZoomPosition'] != 'center') { + zoomPosition = Offset( + size.width / 2 - location.dx, + size.height / 2 - location.dy, + ); + } else { + zoomPosition = Offset(0, 0); + } photoViewController.animateScale?.call( target, - Offset(size.width / 2 - location.dx, size.height / 2 - location.dy), + zoomPosition, ); isLongPressing = true; } @@ -608,6 +617,13 @@ class _ContinuousModeState extends State<_ContinuousMode> } bool onScaleUpdate([double? scale]) { + if (prepareToNextChapter || prepareToPrevChapter) { + setState(() { + prepareToPrevChapter = false; + prepareToNextChapter = false; + }); + context.readerScaffold.setFloatingButton(0); + } var isZoomedIn = (scale ?? photoViewController.scale) != 1.0; if (isZoomedIn != this.isZoomedIn) { setState(() { @@ -731,7 +747,7 @@ class _ContinuousModeState extends State<_ContinuousMode> } Offset offset; var sp = scrollController.position; - if (sp.pixels < sp.minScrollExtent || sp.pixels > sp.maxScrollExtent) { + if (sp.pixels <= sp.minScrollExtent || sp.pixels >= sp.maxScrollExtent) { offset = Offset(value.dx, value.dy); } else { if (reader.mode == ReaderMode.continuousTopToBottom) { @@ -759,7 +775,10 @@ class _ContinuousModeState extends State<_ContinuousMode> delayedSetIsScrolling(false); } - if (notification is ScrollUpdateNotification) { + var scale = photoViewController.scale ?? 1.0; + + if (notification is ScrollUpdateNotification && + (scale - 1).abs() < 0.05) { if (!scrollController.hasClients) return false; if (scrollController.position.pixels <= scrollController.position.minScrollExtent && @@ -800,8 +819,8 @@ class _ContinuousModeState extends State<_ContinuousMode> }, child: widget, ); - var width = MediaQuery.of(context).size.width; - var height = MediaQuery.of(context).size.height; + var width = reader.size.width; + var height = reader.size.height; if (appdata.settings['limitImageWidth'] && width / height > 0.7 && reader.mode == ReaderMode.continuousTopToBottom) { @@ -882,9 +901,19 @@ class _ContinuousModeState extends State<_ContinuousMode> return; } double target = photoViewController.getInitialScale!.call()! * 1.75; + var size = reader.size; + Offset zoomPosition; + if (appdata.settings['longPressZoomPosition'] != 'center') { + zoomPosition = Offset( + size.width / 2 - location.dx, + size.height / 2 - location.dy, + ); + } else { + zoomPosition = Offset(0, 0); + } photoViewController.animateScale?.call( target, - Offset(0, 0), + zoomPosition, ); onScaleUpdate(target); isLongPressing = true; diff --git a/lib/pages/reader/reader.dart b/lib/pages/reader/reader.dart index 5321f10..5bf73c8 100644 --- a/lib/pages/reader/reader.dart +++ b/lib/pages/reader/reader.dart @@ -309,6 +309,13 @@ class _ReaderState extends State } return chapter == maxChapter; } + + /// Get the size of the reader. + /// The size is not always the same as the size of the screen. + Size get size { + var renderBox = context.findRenderObject() as RenderBox; + return renderBox.size; + } } abstract mixin class _ImagePerPageHandler { diff --git a/lib/pages/settings/reader.dart b/lib/pages/settings/reader.dart index fc282ed..ea04a78 100644 --- a/lib/pages/settings/reader.dart +++ b/lib/pages/settings/reader.dart @@ -48,6 +48,7 @@ class _ReaderSettingsState extends State { "continuousTopToBottom": "Continuous (Top to Bottom)".tl, }, onChanged: () { + setState(() {}); var readerMode = appdata.settings['readerMode']; if (readerMode?.toLowerCase().startsWith('continuous') ?? false) { appdata.settings['readerScreenPicNumberForLandscape'] = 1; @@ -68,67 +69,55 @@ 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 for landscape (Only Gallery Mode)".tl, - settingsIndex: "readerScreenPicNumberForLandscape", - interval: 1, - min: 1, - max: 5, - onChanged: () { - widget.onChanged?.call("readerScreenPicNumberForLandscape"); - }, - ), - ), + SliverAnimatedVisibility( + visible: appdata.settings['readerMode']!.startsWith('gallery'), + child: _SliderSetting( + title: + "The number of pic in screen for landscape (Only Gallery Mode)" + .tl, + settingsIndex: "readerScreenPicNumberForLandscape", + interval: 1, + min: 1, + max: 5, + onChanged: () { + widget.onChanged?.call("readerScreenPicNumberForLandscape"); + }, ), ), - 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 for portrait (Only Gallery Mode)".tl, - settingsIndex: "readerScreenPicNumberForPortrait", - interval: 1, - min: 1, - max: 5, - onChanged: () { - widget.onChanged?.call("readerScreenPicNumberForPortrait"); - }, - ), - ), + SliverAnimatedVisibility( + visible: appdata.settings['readerMode']!.startsWith('gallery'), + child: _SliderSetting( + title: + "The number of pic in screen for portrait (Only Gallery Mode)" + .tl, + settingsIndex: "readerScreenPicNumberForPortrait", + interval: 1, + min: 1, + max: 5, + onChanged: () { + widget.onChanged?.call("readerScreenPicNumberForPortrait"); + }, ), ), _SwitchSetting( title: 'Long press to zoom'.tl, settingKey: 'enableLongPressToZoom', onChanged: () { + setState(() {}); widget.onChanged?.call('enableLongPressToZoom'); }, ).toSliver(), + SliverAnimatedVisibility( + visible: appdata.settings['enableLongPressToZoom'] == true, + child: SelectSetting( + title: "Long press zoom position".tl, + settingKey: "longPressZoomPosition", + optionTranslation: { + "press": "Press position".tl, + "center": "Screen center".tl, + }, + ), + ), _SwitchSetting( title: 'Limit image width'.tl, subtitle: 'When using Continuous(Top to Bottom) mode'.tl,