fix(flutter): 收窄清屏范围并保留底栏
This commit is contained in:
1 parent
a26b0071e4
commit
3068eb99da
2 files changed
+136
-134
No files matched your search
@@ -5,7 +5,6 @@ import '../../../core/formatting/localized_content.dart';
|
|||||||
import '../../../core/theme/app_colors.dart';
|
import '../../../core/theme/app_colors.dart';
|
||||||
import '../../../core/theme/app_dimens.dart';
|
import '../../../core/theme/app_dimens.dart';
|
||||||
import '../../../l10n/app_localizations.dart';
|
import '../../../l10n/app_localizations.dart';
|
||||||
import 'exit_clear_screen_button.dart';
|
|
||||||
import 'player_center_toggle.dart';
|
import 'player_center_toggle.dart';
|
||||||
import 'player_overlay_models.dart';
|
import 'player_overlay_models.dart';
|
||||||
import 'seek_progress_bar.dart';
|
import 'seek_progress_bar.dart';
|
||||||
@@ -51,21 +50,9 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
|||||||
onTap: actions.onTogglePlay,
|
onTap: actions.onTogglePlay,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (controlsVisible) ...[
|
_top(context),
|
||||||
_top(context),
|
_bottom(context),
|
||||||
_bottom(context),
|
if (controlsVisible) _rail(context),
|
||||||
_rail(context),
|
|
||||||
],
|
|
||||||
if (!controlsVisible)
|
|
||||||
Positioned(
|
|
||||||
top: AppDimens.spaceSm,
|
|
||||||
right: AppDimens.spaceMd,
|
|
||||||
child: ExitClearScreenButton(
|
|
||||||
key: const Key('player-exit-clear-screen'),
|
|
||||||
tooltip: data.l10n.exitClearScreen,
|
|
||||||
onPressed: actions.onExitClear,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!data.playing)
|
if (!data.playing)
|
||||||
Center(
|
Center(
|
||||||
child: PlayerCenterToggle(
|
child: PlayerCenterToggle(
|
||||||
@@ -153,43 +140,49 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottom(BuildContext context) {
|
Widget _bottom(BuildContext context) {
|
||||||
final series = localizedDramaTitle(data.l10n, data.drama);
|
|
||||||
final synopsis = localizedDramaSynopsis(data.l10n, data.drama);
|
|
||||||
return Positioned(
|
return Positioned(
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
child: Padding(
|
child: Column(
|
||||||
key: const Key('player-controls-bottom'),
|
mainAxisSize: MainAxisSize.min,
|
||||||
padding: const EdgeInsets.fromLTRB(14, 8, 14, 6),
|
children: [if (controlsVisible) _bottomInfo(context), _bottomActions()],
|
||||||
child: Column(
|
),
|
||||||
mainAxisSize: MainAxisSize.min,
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
}
|
||||||
children: [
|
|
||||||
_detailRow(series),
|
Widget _bottomInfo(BuildContext context) {
|
||||||
const SizedBox(height: 4),
|
final series = localizedDramaTitle(data.l10n, data.drama);
|
||||||
_EpisodeSynopsis(
|
final synopsis = localizedDramaSynopsis(data.l10n, data.drama);
|
||||||
key: const Key('player-episode-synopsis'),
|
return Padding(
|
||||||
l10n: data.l10n,
|
key: const Key('player-controls-bottom'),
|
||||||
episodeNumber: data.episode.number,
|
padding: const EdgeInsets.fromLTRB(14, 8, 14, 0),
|
||||||
synopsis: synopsis,
|
child: Column(
|
||||||
authorNote: data.authorNote,
|
mainAxisSize: MainAxisSize.min,
|
||||||
textScale: data.textScale,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
const SizedBox(height: 2),
|
_detailRow(series),
|
||||||
SeekProgressBar(
|
const SizedBox(height: 4),
|
||||||
key: const Key('player-progress'),
|
_EpisodeSynopsis(
|
||||||
valueListenable: data.controller,
|
key: const Key('player-episode-synopsis'),
|
||||||
semanticsLabel: data.l10n.seekVideo,
|
l10n: data.l10n,
|
||||||
showTimes: true,
|
episodeNumber: data.episode.number,
|
||||||
compact: true,
|
synopsis: synopsis,
|
||||||
inactiveTrackColor: Colors.white24,
|
authorNote: data.authorNote,
|
||||||
onScrubStart: actions.onScrubStart,
|
textScale: data.textScale,
|
||||||
onSeek: actions.onSeek,
|
),
|
||||||
),
|
const SizedBox(height: 2),
|
||||||
_bottomActions(),
|
SeekProgressBar(
|
||||||
],
|
key: const Key('player-progress'),
|
||||||
),
|
valueListenable: data.controller,
|
||||||
|
semanticsLabel: data.l10n.seekVideo,
|
||||||
|
showTimes: true,
|
||||||
|
compact: true,
|
||||||
|
inactiveTrackColor: Colors.white24,
|
||||||
|
onScrubStart: actions.onScrubStart,
|
||||||
|
onSeek: actions.onSeek,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -234,61 +227,69 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomActions() {
|
Widget _bottomActions() {
|
||||||
return Row(
|
return Padding(
|
||||||
children: [
|
key: const Key('player-bottom-actions'),
|
||||||
Expanded(
|
padding: const EdgeInsets.fromLTRB(14, 6, 14, 6),
|
||||||
child: Material(
|
child: Row(
|
||||||
key: const Key('player-episodes-pill'),
|
children: [
|
||||||
color: AppColors.playerOverlayPill,
|
Expanded(
|
||||||
borderRadius: BorderRadius.circular(999),
|
child: Material(
|
||||||
clipBehavior: Clip.antiAlias,
|
key: const Key('player-episodes-pill'),
|
||||||
child: InkWell(
|
color: AppColors.playerOverlayPill,
|
||||||
key: const Key('player-episodes'),
|
|
||||||
onTap: actions.onEpisodes,
|
|
||||||
borderRadius: BorderRadius.circular(999),
|
borderRadius: BorderRadius.circular(999),
|
||||||
child: Padding(
|
clipBehavior: Clip.antiAlias,
|
||||||
padding: const EdgeInsets.symmetric(
|
child: InkWell(
|
||||||
horizontal: 12,
|
key: const Key('player-episodes'),
|
||||||
vertical: 4,
|
onTap: actions.onEpisodes,
|
||||||
),
|
borderRadius: BorderRadius.circular(999),
|
||||||
child: Row(
|
child: Padding(
|
||||||
children: [
|
padding: const EdgeInsets.symmetric(
|
||||||
Flexible(
|
horizontal: 12,
|
||||||
child: Text(
|
vertical: 4,
|
||||||
'${data.l10n.episodes} · '
|
),
|
||||||
'${data.l10n.allEpisodesBadge(data.totalEpisodes)} · '
|
child: Row(
|
||||||
'${data.l10n.freeWatch}',
|
children: [
|
||||||
maxLines: 1,
|
Flexible(
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
style: const TextStyle(
|
'${data.l10n.episodes} · '
|
||||||
color: AppColors.onPrimary,
|
'${data.l10n.allEpisodesBadge(data.totalEpisodes)} · '
|
||||||
fontSize: 11,
|
'${data.l10n.freeWatch}',
|
||||||
fontWeight: FontWeight.w700,
|
maxLines: 1,
|
||||||
shadows: _playerTextShadows,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.onPrimary,
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
shadows: _playerTextShadows,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 3),
|
||||||
const SizedBox(width: 3),
|
const Icon(
|
||||||
const Icon(
|
Icons.keyboard_arrow_up_rounded,
|
||||||
Icons.keyboard_arrow_up_rounded,
|
color: AppColors.onPrimary,
|
||||||
color: AppColors.onPrimary,
|
size: 16,
|
||||||
size: 16,
|
shadows: _playerTextShadows,
|
||||||
shadows: _playerTextShadows,
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 8),
|
||||||
const SizedBox(width: 8),
|
_BottomIconButton(
|
||||||
_BottomIconButton(
|
key: const Key('player-bottom-clear-screen'),
|
||||||
key: const Key('player-bottom-clear-screen'),
|
tooltip: controlsVisible
|
||||||
tooltip: data.l10n.clearScreen,
|
? data.l10n.clearScreen
|
||||||
icon: Icons.fullscreen_rounded,
|
: data.l10n.exitClearScreen,
|
||||||
onPressed: actions.onClear,
|
icon: controlsVisible
|
||||||
),
|
? Icons.fullscreen_rounded
|
||||||
],
|
: Icons.fullscreen_exit_rounded,
|
||||||
|
onPressed: controlsVisible ? actions.onClear : actions.onExitClear,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,8 +110,10 @@ void main() {
|
|||||||
await _clearFromMore(tester);
|
await _clearFromMore(tester);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
||||||
|
expect(find.byKey(const Key('player-bottom-actions')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsNothing);
|
||||||
expect(find.byType(PlayerCenterToggle), findsOneWidget);
|
expect(find.byType(PlayerCenterToggle), findsOneWidget);
|
||||||
expect(
|
expect(
|
||||||
tester
|
tester
|
||||||
@@ -122,45 +124,30 @@ void main() {
|
|||||||
isFalse,
|
isFalse,
|
||||||
);
|
);
|
||||||
expect(find.byKey(const Key('player-video-tap')), findsOneWidget);
|
expect(find.byKey(const Key('player-video-tap')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
expect(find.byKey(const Key('player-bottom-clear-screen')), findsOneWidget);
|
||||||
|
expect(find.byTooltip('Exit clear screen'), findsOneWidget);
|
||||||
expect(
|
expect(
|
||||||
tester.getSize(find.byKey(const Key('player-exit-clear-screen'))),
|
tester.getSize(find.byKey(const Key('player-bottom-clear-screen'))),
|
||||||
const Size(36, 36),
|
const Size(30, 30),
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.tapAt(const Offset(80, 300));
|
await tester.tapAt(const Offset(80, 300));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
expect(find.byKey(const Key('player-bottom-actions')), findsOneWidget);
|
||||||
expect(find.byType(PlayerCenterToggle), findsNothing);
|
expect(find.byType(PlayerCenterToggle), findsNothing);
|
||||||
|
|
||||||
await tester.tapAt(const Offset(80, 300));
|
await tester.tapAt(const Offset(80, 300));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byType(PlayerCenterToggle), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
|
||||||
expect(
|
|
||||||
tester
|
|
||||||
.widget<PlayerCenterToggle>(
|
|
||||||
find.byKey(const Key('player-play-toggle')),
|
|
||||||
)
|
|
||||||
.playing,
|
|
||||||
isFalse,
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.tap(find.byKey(const Key('player-exit-clear-screen')));
|
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
|
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsOneWidget);
|
||||||
expect(find.byType(PlayerCenterToggle), findsOneWidget);
|
expect(find.byType(PlayerCenterToggle), findsOneWidget);
|
||||||
expect(
|
expect(find.byTooltip('Clear screen'), findsOneWidget);
|
||||||
tester
|
|
||||||
.widget<PlayerCenterToggle>(
|
|
||||||
find.byKey(const Key('player-play-toggle')),
|
|
||||||
)
|
|
||||||
.playing,
|
|
||||||
isFalse,
|
|
||||||
);
|
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsNothing);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_fit_player_header_on_320_width', (tester) async {
|
testWidgets('should_fit_player_header_on_320_width', (tester) async {
|
||||||
@@ -251,20 +238,22 @@ void main() {
|
|||||||
|
|
||||||
await _clearFromMore(tester);
|
await _clearFromMore(tester);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
|
|
||||||
await tester.drag(find.byType(PageView), const Offset(0, -550));
|
await tester.drag(find.byType(PageView), const Offset(0, -550));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
expect(find.byKey(const Key('player-bottom-actions')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsNothing);
|
||||||
|
expect(find.byKey(const Key('player-bottom-clear-screen')), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.byKey(const Key('player-exit-clear-screen')));
|
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
|
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsNothing);
|
expect(find.byKey(const Key('player-interaction-rail')), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_open_speed_sheet_and_apply_selected_speed', (
|
testWidgets('should_open_speed_sheet_and_apply_selected_speed', (
|
||||||
@@ -309,9 +298,9 @@ void main() {
|
|||||||
|
|
||||||
await _clearFromMore(tester);
|
await _clearFromMore(tester);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(find.byKey(const Key('player-more')), findsNothing);
|
expect(find.byKey(const Key('player-more')), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.byKey(const Key('player-exit-clear-screen')));
|
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.drag(find.byType(PageView), const Offset(0, -550));
|
await tester.drag(find.byType(PageView), const Offset(0, -550));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
@@ -448,9 +437,11 @@ void main() {
|
|||||||
await tester.tap(find.byKey(const Key('player-more-clear')));
|
await tester.tap(find.byKey(const Key('player-more-clear')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
expect(find.byKey(const Key('player-bottom-actions')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsNothing);
|
||||||
|
expect(find.byTooltip('Exit clear screen'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_enter_clear_screen_from_bottom_button', (tester) async {
|
testWidgets('should_enter_clear_screen_from_bottom_button', (tester) async {
|
||||||
@@ -462,9 +453,19 @@ void main() {
|
|||||||
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.byKey(const Key('player-controls-top')), findsNothing);
|
expect(find.byKey(const Key('player-controls-top')), findsOneWidget);
|
||||||
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
expect(find.byKey(const Key('player-controls-bottom')), findsNothing);
|
||||||
expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget);
|
expect(find.byKey(const Key('player-bottom-actions')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsNothing);
|
||||||
|
expect(find.byType(PlayerCenterToggle), findsNothing);
|
||||||
|
expect(find.byTooltip('Exit clear screen'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.byKey(const Key('player-bottom-clear-screen')));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget);
|
||||||
|
expect(find.byKey(const Key('player-interaction-rail')), findsOneWidget);
|
||||||
|
expect(find.byType(PlayerCenterToggle), findsNothing);
|
||||||
|
expect(find.byTooltip('Clear screen'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_open_unlock_panel_with_honest_method_states', (
|
testWidgets('should_open_unlock_panel_with_honest_method_states', (
|
||||||
|
|||||||
Reference in new issue
Block a user