diff --git a/lib/pages/reader/images.dart b/lib/pages/reader/images.dart index dbe3575..6e7c91c 100644 --- a/lib/pages/reader/images.dart +++ b/lib/pages/reader/images.dart @@ -323,6 +323,13 @@ class _ContinuousModeState extends State<_ContinuousMode> void smoothTo(double offset) { futurePosition ??= scrollController.offset; + if (futurePosition! > scrollController.position.maxScrollExtent && + offset > 0) { + return; + } else if (futurePosition! < scrollController.position.minScrollExtent && + offset < 0) { + return; + } futurePosition = futurePosition! + offset * 1.2; futurePosition = futurePosition!.clamp( scrollController.position.minScrollExtent, @@ -435,6 +442,27 @@ class _ContinuousModeState extends State<_ContinuousMode> child: widget, ); + widget = NotificationListener( + onNotification: (notification) { + var length = reader.maxChapter; + if (!scrollController.hasClients) return false; + if (scrollController.position.pixels <= + scrollController.position.minScrollExtent && + reader.chapter != 1) { + context.readerScaffold.setFloatingButton(-1); + } else if (scrollController.position.pixels >= + scrollController.position.maxScrollExtent && + reader.chapter < length) { + context.readerScaffold.setFloatingButton(1); + } else { + context.readerScaffold.setFloatingButton(0); + } + + return true; + }, + child: widget, + ); + return PhotoView.customChild( backgroundDecoration: BoxDecoration( color: context.colorScheme.surface, @@ -510,7 +538,7 @@ class _ContinuousModeState extends State<_ContinuousMode> } }); } - if(event is KeyUpEvent) { + if (event is KeyUpEvent) { return; } bool? forward; diff --git a/lib/pages/reader/scaffold.dart b/lib/pages/reader/scaffold.dart index a2429f8..87739ae 100644 --- a/lib/pages/reader/scaffold.dart +++ b/lib/pages/reader/scaffold.dart @@ -18,6 +18,27 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { bool get isOpen => _isOpen; + int showFloatingButtonValue = 0; + + double fABValue = 0; + + void setFloatingButton(int value) { + if (value == 0) { + if (showFloatingButtonValue != 0) { + showFloatingButtonValue = 0; + fABValue = 0; + update(); + } + } + if (value == 1 && showFloatingButtonValue == 0) { + showFloatingButtonValue = 1; + update(); + } else if (value == -1 && showFloatingButtonValue == 0) { + showFloatingButtonValue = -1; + update(); + } + } + @override void initState() { sliderFocus.canRequestFocus = false; @@ -71,6 +92,12 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { height: kBottomBarHeight + context.padding.bottom, child: buildBottom(), ), + AnimatedPositioned( + duration: const Duration(milliseconds: 180), + right: 16, + bottom: showFloatingButtonValue == 0 ? -58 : 16, + child: buildEpChangeButton(), + ), ], ); } @@ -371,6 +398,75 @@ class _ReaderScaffoldState extends State<_ReaderScaffold> { width: 400, ); } + + Widget buildEpChangeButton() { + if (context.reader.widget.chapters == null) return const SizedBox(); + switch (showFloatingButtonValue) { + case -1: + return FloatingActionButton( + onPressed: () => context.reader.toPrevChapter(), + child: const Icon(Icons.arrow_back_ios_outlined), + ); + case 0: + return Container( + width: 58, + height: 58, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(16), + ), + child: Icon( + Icons.arrow_forward_ios, + size: 24, + color: Theme.of(context).colorScheme.onPrimaryContainer, + ), + ); + case 1: + return Container( + width: 58, + height: 58, + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer, + borderRadius: BorderRadius.circular(16), + ), + child: Stack( + children: [ + Positioned.fill( + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => context.reader.toNextChapter(), + borderRadius: BorderRadius.circular(16), + child: Center( + child: Icon( + Icons.arrow_forward_ios, + size: 24, + color: Theme.of(context).colorScheme.onPrimaryContainer, + )), + ), + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + height: fABValue, + child: ColoredBox( + color: Theme.of(context) + .colorScheme + .surfaceTint + .withOpacity(0.2), + child: const SizedBox.expand(), + ), + ) + ], + ), + ); + } + return const SizedBox(); + } } class _ChaptersView extends StatefulWidget {