import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:flutter/material.dart' hide TabBarView; Widget tabBarView({ required List children, TabController? controller, }) => TabBarView( controller: controller, physics: clampingScrollPhysics, horizontalDragGestureRecognizer: CustomHorizontalDragGestureRecognizer.new, children: children, ); final _springDescription = _customSpringDescription(); SpringDescription _customSpringDescription() { final List springDescription = Pref.springDescription; return SpringDescription( mass: springDescription[0], stiffness: springDescription[1], damping: springDescription[2], ); } const clampingScrollPhysics = CustomTabBarViewScrollPhysics( parent: ClampingScrollPhysics(), ); class CustomTabBarViewScrollPhysics extends ScrollPhysics { const CustomTabBarViewScrollPhysics({super.parent}); @override CustomTabBarViewScrollPhysics applyTo(ScrollPhysics? ancestor) { return CustomTabBarViewScrollPhysics(parent: buildParent(ancestor)); } @override SpringDescription get spring => _springDescription; } mixin ReloadMixin { late bool reload = false; } class ReloadScrollPhysics extends AlwaysScrollableScrollPhysics { const ReloadScrollPhysics({super.parent, required this.controller}); final ReloadMixin controller; @override ReloadScrollPhysics applyTo(ScrollPhysics? ancestor) { return ReloadScrollPhysics( parent: buildParent(ancestor), controller: controller, ); } @override double adjustPositionForNewDimensions({ required ScrollMetrics oldPosition, required ScrollMetrics newPosition, required bool isScrolling, required double velocity, }) { if (controller.reload) { controller.reload = false; return 0; } return super.adjustPositionForNewDimensions( oldPosition: oldPosition, newPosition: newPosition, isScrolling: isScrolling, velocity: velocity, ); } } final platformClampingPhysics = PlatformUtils.isDarwin ? const BouncingScrollPhysicsExt() : const ClampingScrollPhysics(); final platformAlwaysClampingPhysics = PlatformUtils.isDarwin ? const AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysicsExt()) : const AlwaysScrollableScrollPhysics(parent: ClampingScrollPhysics()); class BouncingScrollPhysicsExt extends BouncingScrollPhysics with ClampingBoundaryMixin { const BouncingScrollPhysicsExt({super.parent}); @override BouncingScrollPhysicsExt applyTo(ScrollPhysics? ancestor) { return BouncingScrollPhysicsExt(parent: buildParent(ancestor)); } } /// [ClampingScrollPhysics.applyBoundaryConditions] mixin ClampingBoundaryMixin on ScrollPhysics { @override double applyBoundaryConditions(ScrollMetrics position, double value) { if (value < position.pixels && position.pixels <= position.minScrollExtent) { // Underscroll. return value - position.pixels; } if (position.maxScrollExtent <= position.pixels && position.pixels < value) { // Overscroll. return value - position.pixels; } if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) { // Hit top edge. return value - position.minScrollExtent; } if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) { // Hit bottom edge. return value - position.maxScrollExtent; } return 0.0; } }