diff --git a/lib/common/widgets/flutter/refresh_indicator.dart b/lib/common/widgets/flutter/refresh_indicator.dart index a1aebf392..9fdbd99c1 100644 --- a/lib/common/widgets/flutter/refresh_indicator.dart +++ b/lib/common/widgets/flutter/refresh_indicator.dart @@ -549,7 +549,6 @@ class RefreshIndicatorState extends State if (widget.isClampingScrollPhysics) { return ScrollConfiguration( behavior: RefreshScrollBehavior( - desktopDragDevices, scrollPhysics: RefreshScrollPhysicsIOS( parent: const RangeMaintainingScrollPhysics(), onDrag: _onDrag, @@ -562,7 +561,6 @@ class RefreshIndicatorState extends State } return ScrollConfiguration( behavior: RefreshScrollBehavior( - desktopDragDevices, scrollPhysics: RefreshScrollPhysics( parent: const RangeMaintainingScrollPhysics(), onDrag: _onDrag, @@ -625,8 +623,7 @@ class RefreshIndicatorState extends State typedef refreshIndicator = RefreshIndicator; class RefreshScrollBehavior extends CustomScrollBehavior { - const RefreshScrollBehavior( - super.dragDevices, { + const RefreshScrollBehavior({ required this.scrollPhysics, }); diff --git a/lib/common/widgets/scroll_behavior.dart b/lib/common/widgets/scroll_behavior.dart index 10520d10a..a67f9939b 100644 --- a/lib/common/widgets/scroll_behavior.dart +++ b/lib/common/widgets/scroll_behavior.dart @@ -1,8 +1,19 @@ +import 'dart:io' show Platform; + import 'package:flutter/gestures.dart' show PointerDeviceKind; import 'package:flutter/material.dart'; +const Set desktopDragDevices = { + .touch, + .mouse, + .trackpad, + .stylus, + .invertedStylus, + .unknown, +}; + class CustomScrollBehavior extends MaterialScrollBehavior { - const CustomScrollBehavior(this.dragDevices); + const CustomScrollBehavior(); @override Widget buildScrollbar( @@ -12,14 +23,32 @@ class CustomScrollBehavior extends MaterialScrollBehavior { ) => child; @override - final Set dragDevices; + Widget buildOverscrollIndicator( + BuildContext context, + Widget child, + ScrollableDetails details, + ) { + if (Platform.isAndroid) { + return StretchingOverscrollIndicator( + axisDirection: details.direction, + clipBehavior: details.decorationClipBehavior ?? .hardEdge, + child: child, + ); + } + return child; + } + + @override + Set get dragDevices => desktopDragDevices; } -const Set desktopDragDevices = { - PointerDeviceKind.touch, - PointerDeviceKind.stylus, - PointerDeviceKind.invertedStylus, - PointerDeviceKind.trackpad, - PointerDeviceKind.unknown, - PointerDeviceKind.mouse, -}; +class NoOverscrollIndicator extends CustomScrollBehavior { + const NoOverscrollIndicator(); + + @override + Widget buildOverscrollIndicator( + BuildContext context, + Widget child, + ScrollableDetails details, + ) => child; +} diff --git a/lib/main.dart b/lib/main.dart index 05b649822..a6e0ce9d2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -288,7 +288,7 @@ class MyApp extends StatelessWidget { FlutterSmartDialog.observer, ], scrollBehavior: PlatformUtils.isDesktop - ? const CustomScrollBehavior(desktopDragDevices) + ? const CustomScrollBehavior() : null, ); } diff --git a/lib/pages/dynamics_detail/view.dart b/lib/pages/dynamics_detail/view.dart index 896b9e024..e44e24a92 100644 --- a/lib/pages/dynamics_detail/view.dart +++ b/lib/pages/dynamics_detail/view.dart @@ -5,6 +5,8 @@ import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/flutter/text_field/controller.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; +import 'package:PiliPlus/common/widgets/scroll_behavior.dart' + show NoOverscrollIndicator; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_to_box_adapter.dart'; @@ -412,6 +414,7 @@ class _DynamicDetailPageState return Padding( padding: EdgeInsets.symmetric(horizontal: padding), child: NestedScrollView( + scrollBehavior: const NoOverscrollIndicator(), headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverToBoxWithOffsetAdapter( diff --git a/lib/pages/live_dm_block/view.dart b/lib/pages/live_dm_block/view.dart index d8a4d519f..7e55891ce 100644 --- a/lib/pages/live_dm_block/view.dart +++ b/lib/pages/live_dm_block/view.dart @@ -1,6 +1,8 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; +import 'package:PiliPlus/common/widgets/scroll_behavior.dart' + show NoOverscrollIndicator; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_header.dart'; import 'package:PiliPlus/models/common/live/live_dm_silent_type.dart'; @@ -93,6 +95,7 @@ class _LiveDmBlockPageState extends State { isPortrait ? ExtendedNestedScrollView( onlyOneScrollInBody: true, + scrollBehavior: const NoOverscrollIndicator(), headerSliverBuilder: (context, innerBoxIsScrolled) { return [ SliverToBoxAdapter(child: left), diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index e0b52d4dc..9a958a760 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -7,6 +7,8 @@ import 'package:PiliPlus/common/widgets/dialog/report_member.dart'; import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/dynamic_sliver_app_bar.dart'; import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; +import 'package:PiliPlus/common/widgets/scroll_behavior.dart' + show NoOverscrollIndicator; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/http/live.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -92,8 +94,9 @@ class _MemberPageState extends State { () => switch (_userController.loadingState.value) { Loading() => m3eLoading, Success(:final response) => ExtendedNestedScrollView( - key: _userController.scrollKey, onlyOneScrollInBody: true, + key: _userController.scrollKey, + scrollBehavior: const NoOverscrollIndicator(), pinnedHeaderSliverHeightBuilder: () => kToolbarHeight + MediaQuery.viewPaddingOf(context).top, headerSliverBuilder: (context, innerBoxIsScrolled) { diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 0cb0908da..ead42d988 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -8,6 +8,8 @@ import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; +import 'package:PiliPlus/common/widgets/scroll_behavior.dart' + show NoOverscrollIndicator; import 'package:PiliPlus/common/widgets/scroll_physics.dart' show tabBarView, platformAlwaysClampingPhysics, platformClampingPhysics; import 'package:PiliPlus/common/widgets/sliver/video_header.dart'; @@ -520,6 +522,7 @@ class _VideoDetailPageVState extends State physics: platformClampingPhysics, key: videoDetailController.scrollKey, controller: videoDetailController.scrollCtr, + scrollBehavior: const NoOverscrollIndicator(), pinnedHeaderSliverHeightBuilder: () { double pinnedHeight = this.isFullScreen || !isPortrait ? maxHeight - (isWindowMode && !isPortrait ? 0 : padding.top) diff --git a/lib/scripts/patch.ps1 b/lib/scripts/patch.ps1 index 83b98a326..d5dfbed71 100644 --- a/lib/scripts/patch.ps1 +++ b/lib/scripts/patch.ps1 @@ -84,7 +84,6 @@ $patches = @($ModalBarrierPatch, $TextSelectionPatch, $MouseCursorPatch, switch ($platform.ToLower()) { "android" { - $reverts += $NewOverScrollIndicator $patches += $BottomSheetAndroidPatch $patches += $ScrollViewPatch $patches += $NavigatorPatch