feat(flutter): 播放页长按手势与加速态

This commit is contained in:
Zhou Weidong committed 2026-10-20 12:36:35 +08:00
1 parent 7bb2714941
commit 96074bc5e8
11 files changed
+231 -4

No files matched your search

+53 -4
View File
@@ -16,6 +16,8 @@ const double _topButtonSize = 36;
const double _topBarHeight = 58;
const double _railButtonSize = 34;
const double _railGap = 18;
const double _boostHintIconSize = 16;
const double _boostHintFontSize = 13;
const List<Shadow> _playerTextShadows = [
Shadow(color: Colors.black54, blurRadius: 5, offset: Offset(0, 1)),
];
@@ -45,10 +47,16 @@ class PlayerPlaybackOverlay extends StatelessWidget {
child: Stack(
children: [
Positioned.fill(
child: GestureDetector(
key: const Key('player-video-tap'),
behavior: HitTestBehavior.opaque,
onTap: actions.onTogglePlay,
child: LayoutBuilder(
builder: (context, constraints) => GestureDetector(
key: const Key('player-video-tap'),
behavior: HitTestBehavior.opaque,
onTap: actions.onTogglePlay,
onLongPressStart: (details) =>
_handleLongPressStart(details, constraints.maxWidth),
onLongPressEnd: (_) => actions.onBoostEnd(),
onLongPressCancel: actions.onBoostEnd,
),
),
),
_top(context),
@@ -120,6 +128,17 @@ class PlayerPlaybackOverlay extends StatelessWidget {
);
}
/// 长按分区:中间 1/3 弹更多,左右各 1/3 开始加速。
void _handleLongPressStart(LongPressStartDetails details, double width) {
final third = width / 3;
final dx = details.localPosition.dx;
if (dx < third || dx > width - third) {
actions.onBoostStart();
return;
}
actions.onLongPressCenter();
}
Widget _rail(BuildContext context) {
final compact = MediaQuery.sizeOf(context).height < 700;
return Positioned(
@@ -149,6 +168,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
if (controlsVisible) _bottomInfo(context),
if (data.boosting) _boostHint(),
_bottomProgress(),
_bottomActions(),
],
@@ -156,6 +176,35 @@ class PlayerPlaybackOverlay extends StatelessWidget {
);
}
/// 加速提示:橙色小三角 + 当前倍速文案,悬在进度条上方。
Widget _boostHint() {
return Padding(
key: const Key('player-speed-boost-hint'),
padding: const EdgeInsets.only(bottom: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.play_arrow_rounded,
color: AppColors.blue,
size: _boostHintIconSize,
shadows: _playerTextShadows,
),
const SizedBox(width: 4),
Text(
data.l10n.speedBoosting(data.playbackSpeed.toStringAsFixed(1)),
style: const TextStyle(
color: AppColors.blue,
fontSize: _boostHintFontSize,
fontWeight: FontWeight.w700,
shadows: _playerTextShadows,
),
),
],
),
);
}
Widget _bottomInfo(BuildContext context) {
final series = localizedDramaTitle(data.l10n, data.drama);
final synopsis = localizedDramaSynopsis(data.l10n, data.drama);
@@ -22,6 +22,7 @@ class PlayerOverlayData {
required this.playing,
required this.playbackSpeed,
required this.totalEpisodes,
required this.boosting,
this.authorNote = '',
});
@@ -61,6 +62,9 @@ class PlayerOverlayData {
/// 可见集数量。
final int totalEpisodes;
/// 是否处于长按加速态。
final bool boosting;
/// 作者声明;没有后端字段时为空。
final String authorNote;
}
@@ -83,6 +87,9 @@ class PlayerOverlayActions {
required this.onMore,
required this.onScrubStart,
required this.onSeek,
required this.onLongPressCenter,
required this.onBoostStart,
required this.onBoostEnd,
});
/// 返回上一页。
@@ -126,4 +133,13 @@ class PlayerOverlayActions {
/// 提交进度跳转。
final Future<void> Function(Duration)? onSeek;
/// 长按画面中间:弹出更多面板。
final VoidCallback onLongPressCenter;
/// 长按画面两侧:开始加速。
final VoidCallback onBoostStart;
/// 长按结束或取消:结束加速。
final VoidCallback onBoostEnd;
}