mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
122 lines
3.0 KiB
Dart
122 lines
3.0 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:PiliPlus/utils/storage_pref.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
abstract class CommonSlidePage extends StatefulWidget {
|
|
const CommonSlidePage({super.key, this.enableSlide});
|
|
|
|
final bool? enableSlide;
|
|
}
|
|
|
|
abstract class CommonSlidePageState<T extends CommonSlidePage> extends State<T>
|
|
with TickerProviderStateMixin {
|
|
Offset? downPos;
|
|
bool? isSliding;
|
|
|
|
late final bool enableSlide;
|
|
AnimationController? _animController;
|
|
Animation<Offset>? _anim;
|
|
|
|
static bool slideDismissReplyPage = Pref.slideDismissReplyPage;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
enableSlide = widget.enableSlide != false && slideDismissReplyPage;
|
|
if (enableSlide) {
|
|
_animController = AnimationController(
|
|
vsync: this,
|
|
reverseDuration: const Duration(milliseconds: 500),
|
|
);
|
|
_anim = Tween<Offset>(
|
|
begin: Offset.zero,
|
|
end: const Offset(0, 1),
|
|
).animate(_animController!);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animController?.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
return enableSlide
|
|
? SlideTransition(
|
|
position: _anim!,
|
|
child: buildPage(theme),
|
|
)
|
|
: buildPage(theme);
|
|
}
|
|
|
|
Widget buildPage(ThemeData theme);
|
|
|
|
Widget buildList(ThemeData theme) => throw UnimplementedError();
|
|
|
|
Widget slideList(ThemeData theme) => LayoutBuilder(
|
|
builder: (_, constrains) {
|
|
final maxWidth = constrains.maxWidth;
|
|
|
|
void onDismiss() {
|
|
if (isSliding == true) {
|
|
if (_animController!.value * maxWidth + downPos!.dx >= 100) {
|
|
Get.back();
|
|
} else {
|
|
_animController!.reverse();
|
|
}
|
|
}
|
|
downPos = null;
|
|
isSliding = null;
|
|
}
|
|
|
|
void onPan(Offset localPosition) {
|
|
if (isSliding == false) {
|
|
return;
|
|
} else if (isSliding == null) {
|
|
if (downPos != null) {
|
|
Offset cumulativeDelta = localPosition - downPos!;
|
|
if (cumulativeDelta.dx.abs() >= cumulativeDelta.dy.abs()) {
|
|
downPos = localPosition;
|
|
isSliding = true;
|
|
} else {
|
|
isSliding = false;
|
|
}
|
|
}
|
|
} else if (isSliding == true) {
|
|
if (localPosition.dx < 0) {
|
|
return;
|
|
}
|
|
_animController!.value =
|
|
max(0, (localPosition.dx - downPos!.dx)) / maxWidth;
|
|
}
|
|
}
|
|
|
|
return GestureDetector(
|
|
onPanDown: (details) {
|
|
if (details.localPosition.dx > 30) {
|
|
isSliding = false;
|
|
} else {
|
|
downPos = details.localPosition;
|
|
}
|
|
},
|
|
onPanStart: (details) {
|
|
onPan(details.localPosition);
|
|
},
|
|
onPanUpdate: (details) {
|
|
onPan(details.localPosition);
|
|
},
|
|
onPanCancel: onDismiss,
|
|
onPanEnd: (_) {
|
|
onDismiss();
|
|
},
|
|
child: buildList(theme),
|
|
);
|
|
},
|
|
);
|
|
}
|