fix(player): 完善进度预览清屏与下拉刷新
This commit is contained in:
1 parent
9b1afbdb36
commit
f8500bbaca
15 files changed
+949
-251
No files matched your search
@@ -1,7 +1,12 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/data/services/catalog_controller.dart';
|
||||
import '../../../core/formatting/localized_content.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
@@ -17,6 +22,7 @@ const double _topButtonSize = 36;
|
||||
const double _topBarHeight = 58;
|
||||
const double _boostHintIconSize = 16;
|
||||
const double _boostHintFontSize = 13;
|
||||
const double _synopsisRailInset = 54;
|
||||
const List<Shadow> _playerTextShadows = [
|
||||
Shadow(color: AppColors.shadow, blurRadius: 5, offset: Offset(0, 1)),
|
||||
];
|
||||
@@ -29,6 +35,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
required this.data,
|
||||
required this.actions,
|
||||
required this.controlsVisible,
|
||||
required this.scrubbing,
|
||||
});
|
||||
|
||||
/// 展示数据。
|
||||
@@ -40,6 +47,9 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
/// 控制层是否可见。
|
||||
final bool controlsVisible;
|
||||
|
||||
/// 正在拖动进度条。拖动期间清屏,只留进度条。
|
||||
final bool scrubbing;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
@@ -61,7 +71,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
_top(context),
|
||||
_bottom(context),
|
||||
if (controlsVisible) _rail(context),
|
||||
if (!data.playing)
|
||||
if (!data.playing && !scrubbing)
|
||||
Center(
|
||||
child: PlayerCenterToggle(
|
||||
key: const Key('player-play-toggle'),
|
||||
@@ -79,49 +89,55 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
key: const Key('player-controls-top'),
|
||||
height: _topBarHeight,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
if (actions.onBack != null)
|
||||
_TopButton(
|
||||
key: const Key('player-back'),
|
||||
tooltip: data.l10n.backToSeries,
|
||||
icon: Icons.chevron_left_rounded,
|
||||
onPressed: actions.onBack!,
|
||||
)
|
||||
else
|
||||
const SizedBox(width: _topButtonSize),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
data.l10n.episodeLabel(data.episode.number),
|
||||
key: const Key('player-episode-heading'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
shadows: _playerTextShadows,
|
||||
child: IgnorePointer(
|
||||
ignoring: scrubbing,
|
||||
child: Opacity(
|
||||
opacity: scrubbing ? 0 : 1,
|
||||
child: Container(
|
||||
key: const Key('player-controls-top'),
|
||||
height: _topBarHeight,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
if (actions.onBack != null)
|
||||
_TopButton(
|
||||
key: const Key('player-back'),
|
||||
tooltip: data.l10n.backToSeries,
|
||||
icon: Icons.chevron_left_rounded,
|
||||
onPressed: actions.onBack!,
|
||||
)
|
||||
else
|
||||
const SizedBox(width: _topButtonSize),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
data.l10n.episodeLabel(data.episode.number),
|
||||
key: const Key('player-episode-heading'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
shadows: _playerTextShadows,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
_SpeedEntry(
|
||||
key: const Key('player-speed-entry'),
|
||||
speed: data.playbackSpeed,
|
||||
onTap: actions.onSpeed,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_TopButton(
|
||||
key: const Key('player-more'),
|
||||
tooltip: data.l10n.more,
|
||||
icon: Icons.more_vert_rounded,
|
||||
onPressed: actions.onMore,
|
||||
),
|
||||
],
|
||||
),
|
||||
_SpeedEntry(
|
||||
key: const Key('player-speed-entry'),
|
||||
speed: data.playbackSpeed,
|
||||
onTap: actions.onSpeed,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_TopButton(
|
||||
key: const Key('player-more'),
|
||||
tooltip: data.l10n.more,
|
||||
icon: Icons.more_vert_rounded,
|
||||
onPressed: actions.onMore,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -143,43 +159,49 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
return Positioned(
|
||||
right: AppDimens.spaceMd,
|
||||
top: MediaQuery.sizeOf(context).height * (compact ? 0.30 : 0.43),
|
||||
child: InteractionRail(
|
||||
key: const Key('player-interaction-rail'),
|
||||
items: [
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-save'),
|
||||
asset: 'assets/icon/rail/rail_save.png',
|
||||
label: data.l10n.favorite,
|
||||
count: data.favoriteCount,
|
||||
countKey: const Key('player-rail-save-count'),
|
||||
selected: data.saved,
|
||||
onTap: actions.onSave,
|
||||
child: IgnorePointer(
|
||||
ignoring: scrubbing,
|
||||
child: Opacity(
|
||||
opacity: scrubbing ? 0 : 1,
|
||||
child: InteractionRail(
|
||||
key: const Key('player-interaction-rail'),
|
||||
items: [
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-save'),
|
||||
asset: 'assets/icon/rail/rail_save.png',
|
||||
label: data.l10n.favorite,
|
||||
count: data.favoriteCount,
|
||||
countKey: const Key('player-rail-save-count'),
|
||||
selected: data.saved,
|
||||
onTap: actions.onSave,
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-comments'),
|
||||
asset: 'assets/icon/rail/rail_comment.png',
|
||||
label: data.l10n.comments,
|
||||
count: data.commentCount,
|
||||
countKey: const Key('player-rail-comments-count'),
|
||||
onTap: actions.onComments,
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-like'),
|
||||
asset: 'assets/icon/rail/rail_like.png',
|
||||
label: data.l10n.like,
|
||||
count: data.likeCount,
|
||||
countKey: const Key('player-rail-like-count'),
|
||||
selected: data.liked,
|
||||
selectedColor: AppColors.doubleTapHeartRed,
|
||||
onTap: actions.onLike,
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-share'),
|
||||
asset: 'assets/icon/rail/rail_share.png',
|
||||
label: data.l10n.share,
|
||||
onTap: actions.onShare,
|
||||
),
|
||||
],
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-comments'),
|
||||
asset: 'assets/icon/rail/rail_comment.png',
|
||||
label: data.l10n.comments,
|
||||
count: data.commentCount,
|
||||
countKey: const Key('player-rail-comments-count'),
|
||||
onTap: actions.onComments,
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-like'),
|
||||
asset: 'assets/icon/rail/rail_like.png',
|
||||
label: data.l10n.like,
|
||||
count: data.likeCount,
|
||||
countKey: const Key('player-rail-like-count'),
|
||||
selected: data.liked,
|
||||
selectedColor: AppColors.doubleTapHeartRed,
|
||||
onTap: actions.onLike,
|
||||
),
|
||||
InteractionRailItem(
|
||||
key: const Key('player-rail-share'),
|
||||
asset: 'assets/icon/rail/rail_share.png',
|
||||
label: data.l10n.share,
|
||||
onTap: actions.onShare,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -192,11 +214,17 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (controlsVisible) _bottomInfo(context),
|
||||
Offstage(
|
||||
offstage: !controlsVisible || scrubbing,
|
||||
child: _bottomInfo(context),
|
||||
),
|
||||
if (data.boosting) _boostHint(),
|
||||
_bottomProgress(),
|
||||
// 加速态只保留进度条与提示,便于全屏快进时看清画面。
|
||||
if (!data.boosting) _bottomActions(),
|
||||
// 加速或拖动进度时只留进度条,避免挡住画面。
|
||||
Offstage(
|
||||
offstage: data.boosting || scrubbing,
|
||||
child: _bottomActions(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -243,12 +271,16 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
children: [
|
||||
_detailRow(series),
|
||||
const SizedBox(height: 4),
|
||||
_EpisodeSynopsis(
|
||||
key: const Key('player-episode-synopsis'),
|
||||
l10n: data.l10n,
|
||||
episodeNumber: data.episode.number,
|
||||
synopsis: synopsis,
|
||||
authorNote: data.authorNote,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: _synopsisRailInset),
|
||||
child: _EpisodeSynopsis(
|
||||
key: const Key('player-episode-synopsis'),
|
||||
l10n: data.l10n,
|
||||
drama: data.drama,
|
||||
episodeNumber: data.episode.number,
|
||||
synopsis: synopsis,
|
||||
authorNote: data.authorNote,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -273,6 +305,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
posterUrl: data.drama.posterUrl,
|
||||
inactiveTrackColor: AppColors.inactiveTrack,
|
||||
onScrubStart: actions.onScrubStart,
|
||||
onScrubEnd: actions.onScrubEnd,
|
||||
onSeek: actions.onSeek,
|
||||
),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user