merge: 共享清屏状态并左贴集数

This commit is contained in:
Zhou Weidong committed 2026-10-19 17:29:39 +08:00
commit 5ca5846a26
4 files changed
+78 -50

No files matched your search

+22 -21
View File
@@ -71,7 +71,7 @@ class PlayerPage extends StatefulWidget {
class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
late final PlayerLogic logic;
bool _feedChromeVisible = true;
bool _chromeVisible = true;
@override
void initState() {
@@ -190,7 +190,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
children: [
const ColoredBox(color: AppColors.ink),
?video,
if (!logic.chromeHidden && (!widget.homeMode || _feedChromeVisible))
if (!logic.chromeHidden && (!widget.homeMode || _chromeVisible))
IgnorePointer(
key: widget.homeMode ? const Key('home-feed-scrim') : null,
child: const DecoratedBox(
@@ -209,7 +209,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
),
),
),
if (widget.homeMode && _feedChromeVisible && !logic.chromeHidden)
if (widget.homeMode && _chromeVisible && !logic.chromeHidden)
Positioned.fill(
child: GestureDetector(
key: const Key('home-feed-video-toggle'),
@@ -317,7 +317,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
if (logic.pip || logic.pipPreparing)
const SizedBox.expand()
else if (widget.homeMode)
_feedChromeVisible
_chromeVisible
? HomeFeedOverlay(
l10n: l10n,
drama: drama,
@@ -359,7 +359,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
onShare: () => logic.shareDrama(context, drama),
onEpisodes: () => logic.showEpisodes(context),
onDownload: () => requestEpisodeDownload(context, episode.id),
onClear: () => setState(() => _feedChromeVisible = false),
onClear: () => setState(() => _chromeVisible = false),
onSearch:
widget.onSearch ?? () => logic.showDiscover(context),
onPip: logic.pictureInPicture.isPlatformSupported
@@ -384,6 +384,9 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
? () => unawaited(logic.playNextEpisode())
: null,
playing: logic.session.userWantsPlay,
controlsVisible: _chromeVisible,
onClear: () => setState(() => _chromeVisible = false),
onExitClear: () => setState(() => _chromeVisible = true),
onTogglePlay: () =>
logic.session.setUserWantsPlay(!logic.session.userWantsPlay),
// 收藏/点赞要对到具体账号:未登录先引导登录(首页/详情仍可匿名浏览)
@@ -427,7 +430,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
? (position) => logic.seekTo(context, videoPort!, position)
: null,
),
if (widget.homeMode && !_feedChromeVisible)
if (widget.homeMode && !_chromeVisible)
Positioned.fill(
child: GestureDetector(
key: const Key('home-feed-video-tap'),
@@ -436,7 +439,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
logic.session.setUserWantsPlay(!logic.session.userWantsPlay),
),
),
if (widget.homeMode && !_feedChromeVisible)
if (widget.homeMode && !_chromeVisible)
Positioned(
top: 0,
right: 0,
@@ -447,7 +450,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
child: ExitClearScreenButton(
key: const Key('home-feed-exit-clear-screen'),
tooltip: l10n.exitClearScreen,
onPressed: () => setState(() => _feedChromeVisible = true),
onPressed: () => setState(() => _chromeVisible = true),
),
),
),
@@ -599,7 +602,10 @@ class _PlaybackOverlay extends StatefulWidget {
required this.liked,
required this.saved,
required this.playing,
required this.controlsVisible,
required this.onTogglePlay,
required this.onClear,
required this.onExitClear,
required this.onBack,
required this.onEpisodes,
required this.onComments,
@@ -620,7 +626,10 @@ class _PlaybackOverlay extends StatefulWidget {
final bool liked;
final bool saved;
final bool playing;
final bool controlsVisible;
final VoidCallback onTogglePlay;
final VoidCallback onClear;
final VoidCallback onExitClear;
final VoidCallback? onBack;
final VoidCallback onEpisodes;
final VoidCallback onComments;
@@ -638,14 +647,6 @@ class _PlaybackOverlay extends StatefulWidget {
}
class _PlaybackOverlayState extends State<_PlaybackOverlay> {
bool _controlsVisible = true;
void _onVideoTap() {
widget.onTogglePlay();
}
void _clearScreen() => setState(() => _controlsVisible = false);
@override
Widget build(BuildContext context) {
return SafeArea(
@@ -655,10 +656,10 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> {
child: GestureDetector(
key: const Key('player-video-tap'),
behavior: HitTestBehavior.opaque,
onTap: _onVideoTap,
onTap: widget.onTogglePlay,
),
),
if (_controlsVisible)
if (widget.controlsVisible)
Column(
key: const Key('player-controls-visible'),
children: [
@@ -766,14 +767,14 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> {
),
],
),
if (!_controlsVisible)
if (!widget.controlsVisible)
Positioned(
top: 8,
right: 12,
child: ExitClearScreenButton(
key: const Key('player-exit-clear-screen'),
tooltip: widget.l10n.exitClearScreen,
onPressed: () => setState(() => _controlsVisible = true),
onPressed: widget.onExitClear,
),
),
if (!widget.playing)
@@ -828,7 +829,7 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> {
key: const Key('player-clear-screen'),
tooltip: widget.l10n.clearScreen,
icon: Icons.fullscreen_rounded,
onPressed: _clearScreen,
onPressed: widget.onClear,
),
const SizedBox(width: 8),
_TopAction(
+18 -29
View File
@@ -167,38 +167,27 @@ class HomeFeedOverlay extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
Wrap(
spacing: 6,
runSpacing: 4,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Expanded(
child: Wrap(
spacing: 6,
runSpacing: 4,
children: [
if (genre.isNotEmpty)
_tag(
genre,
background: AppColors.blue,
foreground: AppColors.onPrimary,
),
if (drama.category.isNotEmpty && drama.category != genre)
_tag(
drama.category,
background: const Color(0xFF333333),
foreground: const Color(0xFFDDDDDD),
),
],
if (genre.isNotEmpty)
_tag(
genre,
background: AppColors.blue,
foreground: AppColors.onPrimary,
),
),
const SizedBox(width: 8),
Flexible(
child: Text(
l10n.episodeOfTotal(episode.number, drama.episodeCount),
key: const Key('home-feed-episode'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.right,
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9),
if (drama.category.isNotEmpty && drama.category != genre)
_tag(
drama.category,
background: const Color(0xFF333333),
foreground: const Color(0xFFDDDDDD),
),
Text(
l10n.episodeOfTotal(episode.number, drama.episodeCount),
key: const Key('home-feed-episode'),
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9),
),
],
),
+7
View File
@@ -54,6 +54,13 @@ void main() {
expect(find.byKey(const Key('home-feed-title')), findsOneWidget);
expect(find.byKey(const Key('home-feed-info-card')), findsOneWidget);
expect(find.byKey(const Key('home-feed-episode')), findsOneWidget);
final cardRect = tester.getRect(
find.byKey(const Key('home-feed-info-card')),
);
final episodeRect = tester.getRect(
find.byKey(const Key('home-feed-episode')),
);
expect(episodeRect.left, lessThan(cardRect.center.dx));
expect(find.byKey(const Key('home-feed-follow-series')), findsOneWidget);
expect(find.byKey(const Key('home-feed-episodes')), findsOneWidget);
for (final key in const [Key('home-feed-search'), Key('home-feed-more')]) {
+31
View File
@@ -216,6 +216,37 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('should_keep_series_clear_state_when_swiping_next_episode', (
tester,
) async {
await _pumpApp(tester);
await tester.binding.handlePopRoute();
await tester.pumpAndSettle();
await tester.binding.handlePopRoute();
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('drawer-open-series')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('detail-cta')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('player-clear-screen')));
await tester.pump();
expect(find.byKey(const Key('player-controls-top')), findsNothing);
await tester.drag(find.byType(PageView), const Offset(0, -550));
await tester.pumpAndSettle();
expect(find.byKey(const Key('player-controls-top')), findsNothing);
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
await tester.tap(find.byKey(const Key('player-exit-clear-screen')));
await tester.pump();
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
expect(find.byKey(const Key('player-exit-clear-screen')), findsNothing);
});
testWidgets('should_clear_and_restore_home_feed_chrome', (tester) async {
await _pumpApp(tester);
await tester.tap(find.byKey(const Key('tab-home')));