merge: 合并 K29.6 更多面板精简
This commit is contained in:
commit
1e3e5b64dc
8 files changed
+175
-310
No files matched your search
@@ -21,7 +21,6 @@ import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/auth_gate.dart';
|
||||
import '../../core/widgets/download_action.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../interaction/widgets/report_dialog.dart';
|
||||
import 'player_binding.dart';
|
||||
import 'player_logic.dart';
|
||||
import 'widgets/home_feed_overlay.dart';
|
||||
@@ -83,7 +82,6 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
||||
late final PlayerLogic logic;
|
||||
bool _chromeVisible = true;
|
||||
double _playbackSpeed = 1.0;
|
||||
double _textScale = 1.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -125,10 +123,6 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
||||
setState(() => _playbackSpeed = value);
|
||||
}
|
||||
|
||||
void _updateTextScale(double value) {
|
||||
setState(() => _textScale = value);
|
||||
}
|
||||
|
||||
void _hideChrome() {
|
||||
setState(() => _chromeVisible = false);
|
||||
}
|
||||
@@ -389,7 +383,6 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
||||
saved: context.watch<FavoriteController>().isSaved(drama.id),
|
||||
playing: logic.session.userWantsPlay,
|
||||
playbackSpeed: _playbackSpeed,
|
||||
textScale: _textScale,
|
||||
totalEpisodes: logic.visibleIndices.length,
|
||||
),
|
||||
actions: PlayerOverlayActions(
|
||||
@@ -408,7 +401,7 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
||||
unawaited(_toggleLike(context, interactions, drama)),
|
||||
onSave: () => unawaited(_toggleSave(context, drama)),
|
||||
onShare: () => logic.shareDrama(context, drama),
|
||||
onMore: () => _openMore(context, drama, episode),
|
||||
onMore: () => _openMore(context, episode),
|
||||
onScrubStart: ready ? () => logic.beginScrub(videoPort!) : null,
|
||||
onSeek: ready
|
||||
? (position) => logic.seekTo(context, videoPort!, position)
|
||||
|
||||
@@ -15,11 +15,7 @@ extension _PlayerViewActions on _PlayerPageState {
|
||||
await logic.setPlaybackSpeed(selected);
|
||||
}
|
||||
|
||||
Future<void> _openMore(
|
||||
BuildContext context,
|
||||
Drama drama,
|
||||
Episode episode,
|
||||
) async {
|
||||
Future<void> _openMore(BuildContext context, Episode episode) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
@@ -31,21 +27,14 @@ extension _PlayerViewActions on _PlayerPageState {
|
||||
state: PlayerMoreState(
|
||||
speed: _playbackSpeed,
|
||||
qualities: logic.qualities,
|
||||
textScale: _textScale,
|
||||
pipAvailable: logic.pictureInPicture.isPlatformSupported,
|
||||
),
|
||||
actions: PlayerMoreActions(
|
||||
onSpeedChanged: (value) {
|
||||
_updatePlaybackSpeed(value);
|
||||
unawaited(logic.setPlaybackSpeed(value));
|
||||
},
|
||||
onTextScaleChanged: _updateTextScale,
|
||||
onClear: _hideChrome,
|
||||
onDownload: () => requestEpisodeDownload(context, episode.id),
|
||||
onReport: () => unawaited(_reportDrama(context, drama, l10n)),
|
||||
onPip: logic.pictureInPicture.isPlatformSupported
|
||||
? () => unawaited(logic.enterPip(context))
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -86,32 +75,6 @@ extension _PlayerViewActions on _PlayerPageState {
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _reportDrama(
|
||||
BuildContext context,
|
||||
Drama drama,
|
||||
AppLocalizations l10n,
|
||||
) async {
|
||||
if (!await ensureSignedIn(context) || !context.mounted) return;
|
||||
final draft = await showReportDialog(context, title: l10n.reportDrama);
|
||||
if (draft == null || !context.mounted) return;
|
||||
unawaited(context.read<Haptics>().lightImpact());
|
||||
final result = await context.read<InteractionController>().reportDrama(
|
||||
drama.id,
|
||||
reason: draft.reason,
|
||||
description: draft.description,
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
result.isSuccess
|
||||
? l10n.reportSubmitted
|
||||
: result.errorMessage ?? l10n.reportFailed,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleLike(
|
||||
BuildContext context,
|
||||
InteractionController interactions,
|
||||
|
||||
@@ -4,9 +4,14 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import 'player_text_scale.dart';
|
||||
|
||||
const double _sheetRadius = 20;
|
||||
const double _rowHeight = 44;
|
||||
const double _groupGap = 12;
|
||||
const double _segmentHeight = 28;
|
||||
const double _segmentRadius = 8;
|
||||
const double _segmentPadding = 10;
|
||||
const double _segmentGap = 6;
|
||||
const List<double> _speedOptions = [0.75, 1.0, 1.25, 1.5, 2.0, 3.0];
|
||||
const List<String> _qualityOptions = ['AUTO', '720P', '1080P'];
|
||||
const String _autoQuality = 'AUTO';
|
||||
@@ -14,24 +19,13 @@ const String _autoQuality = 'AUTO';
|
||||
/// 更多面板运行状态。
|
||||
class PlayerMoreState {
|
||||
/// 创建更多面板状态。
|
||||
const PlayerMoreState({
|
||||
required this.speed,
|
||||
required this.qualities,
|
||||
required this.textScale,
|
||||
required this.pipAvailable,
|
||||
});
|
||||
const PlayerMoreState({required this.speed, required this.qualities});
|
||||
|
||||
/// 当前倍速。
|
||||
final double speed;
|
||||
|
||||
/// 后端下发的清晰度档位。
|
||||
final List<String> qualities;
|
||||
|
||||
/// 当前文字缩放比例。
|
||||
final double textScale;
|
||||
|
||||
/// 设备是否提供画中画入口。
|
||||
final bool pipAvailable;
|
||||
}
|
||||
|
||||
/// 更多面板动作集合。
|
||||
@@ -39,33 +33,21 @@ class PlayerMoreActions {
|
||||
/// 创建动作集合。
|
||||
const PlayerMoreActions({
|
||||
required this.onSpeedChanged,
|
||||
required this.onTextScaleChanged,
|
||||
required this.onClear,
|
||||
required this.onDownload,
|
||||
required this.onReport,
|
||||
this.onPip,
|
||||
});
|
||||
|
||||
/// 倍速变化。
|
||||
final ValueChanged<double> onSpeedChanged;
|
||||
|
||||
/// 字体大小变化。
|
||||
final ValueChanged<double> onTextScaleChanged;
|
||||
|
||||
/// 进入清屏播放。
|
||||
final VoidCallback onClear;
|
||||
|
||||
/// 离线缓存当前集。
|
||||
final VoidCallback onDownload;
|
||||
|
||||
/// 投诉当前剧。
|
||||
final VoidCallback onReport;
|
||||
|
||||
/// 进入画中画;平台不支持时为空。
|
||||
final VoidCallback? onPip;
|
||||
}
|
||||
|
||||
/// K29 播放页白色更多面板。
|
||||
/// K29.6 精简版播放页更多面板。
|
||||
class PlayerMoreSheet extends StatefulWidget {
|
||||
/// 创建更多面板。
|
||||
const PlayerMoreSheet({
|
||||
@@ -90,84 +72,55 @@ class PlayerMoreSheet extends StatefulWidget {
|
||||
|
||||
class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
|
||||
late double _speed = widget.state.speed;
|
||||
late double _textScale = widget.state.textScale;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = widget.l10n;
|
||||
return Container(
|
||||
return Material(
|
||||
key: const Key('player-more-sheet'),
|
||||
constraints: const BoxConstraints(maxHeight: 620),
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(_sheetRadius)),
|
||||
color: AppColors.card,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(_sheetRadius),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(18, 14, 18, 18),
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
key: const Key('player-more-drag-handle'),
|
||||
width: 36,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.border,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_header(l10n),
|
||||
_sectionTitle(l10n.playbackSpeed),
|
||||
_speedPicker(),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: _groupGap),
|
||||
_sectionTitle(l10n.playbackQuality),
|
||||
_qualityPicker(l10n),
|
||||
const SizedBox(height: 12),
|
||||
_disabledRow(
|
||||
key: const Key('player-more-not-interested'),
|
||||
icon: Icons.thumb_down_alt_outlined,
|
||||
title: l10n.notInterested,
|
||||
),
|
||||
_enabledRow(
|
||||
const SizedBox(height: _groupGap),
|
||||
_actionRow(
|
||||
key: const Key('player-more-clear'),
|
||||
icon: Icons.fullscreen_rounded,
|
||||
title: l10n.clearPlayback,
|
||||
onTap: _clear,
|
||||
),
|
||||
_disabledSwitchRow(
|
||||
key: const Key('player-more-danmaku'),
|
||||
icon: Icons.subtitles_rounded,
|
||||
title: l10n.danmaku,
|
||||
unavailable: l10n.danmakuUnavailable,
|
||||
),
|
||||
_disabledRow(
|
||||
key: const Key('player-more-danmaku-settings'),
|
||||
icon: Icons.tune_rounded,
|
||||
title: l10n.danmakuSettings,
|
||||
),
|
||||
_enabledRow(
|
||||
_actionRow(
|
||||
key: const Key('player-more-offline'),
|
||||
icon: Icons.download_rounded,
|
||||
title: l10n.offlineCache,
|
||||
onTap: () => _closeThen(widget.actions.onDownload),
|
||||
),
|
||||
if (widget.state.pipAvailable && widget.actions.onPip != null)
|
||||
_enabledRow(
|
||||
key: const Key('player-more-pip'),
|
||||
icon: Icons.picture_in_picture_alt_rounded,
|
||||
title: l10n.pictureInPicture,
|
||||
onTap: () => _closeThen(widget.actions.onPip!),
|
||||
),
|
||||
_textSizeRow(l10n),
|
||||
_disabledRow(
|
||||
key: const Key('player-more-cast'),
|
||||
icon: Icons.cast_rounded,
|
||||
title: l10n.screenCast,
|
||||
),
|
||||
_disabledRow(
|
||||
key: const Key('player-more-timer'),
|
||||
icon: Icons.timer_outlined,
|
||||
title: l10n.sleepTimer,
|
||||
),
|
||||
_enabledRow(
|
||||
key: const Key('player-more-report'),
|
||||
icon: Icons.flag_outlined,
|
||||
title: l10n.reportDrama,
|
||||
onTap: () => _closeThen(widget.actions.onReport),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -182,44 +135,47 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
|
||||
l10n.more,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
key: const Key('player-more-close'),
|
||||
tooltip: l10n.close,
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
SizedBox.square(
|
||||
dimension: 32,
|
||||
child: IconButton(
|
||||
key: const Key('player-more-close'),
|
||||
tooltip: l10n.close,
|
||||
padding: EdgeInsets.zero,
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close_rounded, size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _sectionTitle(String title) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.only(bottom: 8, top: 2),
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.muted,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _speedPicker() => Wrap(
|
||||
key: const Key('player-more-speed'),
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
spacing: _segmentGap,
|
||||
runSpacing: _segmentGap,
|
||||
children: [
|
||||
for (final value in _speedOptions)
|
||||
ChoiceChip(
|
||||
_SegmentButton(
|
||||
key: Key('player-more-speed-$value'),
|
||||
label: Text('${value}x'),
|
||||
label: '${value}x',
|
||||
selected: (_speed - value).abs() < 0.001,
|
||||
showCheckmark: false,
|
||||
onSelected: (_) {
|
||||
onTap: () {
|
||||
setState(() => _speed = value);
|
||||
widget.actions.onSpeedChanged(value);
|
||||
},
|
||||
@@ -229,110 +185,69 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
|
||||
|
||||
Widget _qualityPicker(AppLocalizations l10n) => Wrap(
|
||||
key: const Key('player-more-quality'),
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
spacing: _segmentGap,
|
||||
runSpacing: _segmentGap,
|
||||
children: [
|
||||
for (final quality in _qualityOptions) _qualityChip(l10n, quality),
|
||||
for (final quality in _qualityOptions) _qualitySegment(l10n, quality),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _qualityChip(AppLocalizations l10n, String quality) {
|
||||
Widget _qualitySegment(AppLocalizations l10n, String quality) {
|
||||
final enabled = widget.state.qualities.contains(quality);
|
||||
final selected =
|
||||
quality == _autoQuality && enabled ||
|
||||
!widget.state.qualities.contains(_autoQuality) &&
|
||||
widget.state.qualities.isNotEmpty &&
|
||||
widget.state.qualities.first == quality;
|
||||
return ChoiceChip(
|
||||
return _SegmentButton(
|
||||
key: Key('player-more-quality-$quality'),
|
||||
label: Text(enabled ? quality : '$quality · ${l10n.qualityUnavailable}'),
|
||||
label: enabled ? quality : '$quality · ${l10n.qualityUnavailable}',
|
||||
selected: selected,
|
||||
showCheckmark: false,
|
||||
onSelected: enabled ? (_) {} : null,
|
||||
enabled: enabled,
|
||||
onTap: enabled ? () {} : null,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _textSizeRow(AppLocalizations l10n) => Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||
child: Row(
|
||||
key: const Key('player-more-text-size'),
|
||||
children: [
|
||||
const Icon(Icons.format_size_rounded, color: AppColors.muted, size: 21),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
l10n.textSize,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuButton<double>(
|
||||
tooltip: l10n.textSize,
|
||||
initialValue: _textScale,
|
||||
onSelected: (value) {
|
||||
setState(() => _textScale = value);
|
||||
widget.actions.onTextScaleChanged(value);
|
||||
},
|
||||
itemBuilder: (_) => [
|
||||
PopupMenuItem(
|
||||
key: const Key('player-text-size-small'),
|
||||
value: playerTextSizeSmall,
|
||||
child: Text(l10n.textSizeSmall),
|
||||
),
|
||||
PopupMenuItem(
|
||||
key: const Key('player-text-size-standard'),
|
||||
value: playerTextSizeStandard,
|
||||
child: Text(l10n.textSizeStandard),
|
||||
),
|
||||
PopupMenuItem(
|
||||
key: const Key('player-text-size-large'),
|
||||
value: playerTextSizeLarge,
|
||||
child: Text(l10n.textSizeLarge),
|
||||
),
|
||||
],
|
||||
child: Text(
|
||||
playerTextSizeLabel(l10n, _textScale),
|
||||
style: const TextStyle(
|
||||
color: AppColors.blue,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _enabledRow({
|
||||
Widget _actionRow({
|
||||
required Key key,
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required VoidCallback onTap,
|
||||
}) =>
|
||||
_MoreRow(key: key, icon: icon, title: title, enabled: true, onTap: onTap);
|
||||
|
||||
Widget _disabledRow({
|
||||
required Key key,
|
||||
required IconData icon,
|
||||
required String title,
|
||||
}) => _MoreRow(key: key, icon: icon, title: title, enabled: false);
|
||||
|
||||
Widget _disabledSwitchRow({
|
||||
required Key key,
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String unavailable,
|
||||
}) => _MoreRow(
|
||||
key: key,
|
||||
icon: icon,
|
||||
title: title,
|
||||
enabled: false,
|
||||
value: unavailable,
|
||||
trailing: const Switch(value: false, onChanged: null),
|
||||
);
|
||||
}) {
|
||||
return Material(
|
||||
key: key,
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: _rowHeight,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: AppColors.muted, size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.subtle,
|
||||
size: 18,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _clear() {
|
||||
Navigator.pop(context);
|
||||
@@ -347,56 +262,53 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
|
||||
}
|
||||
}
|
||||
|
||||
class _MoreRow extends StatelessWidget {
|
||||
const _MoreRow({
|
||||
class _SegmentButton extends StatelessWidget {
|
||||
const _SegmentButton({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.enabled,
|
||||
this.value = '',
|
||||
this.trailing,
|
||||
required this.label,
|
||||
required this.selected,
|
||||
this.enabled = true,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String label;
|
||||
final bool selected;
|
||||
final bool enabled;
|
||||
final String value;
|
||||
final Widget? trailing;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = enabled ? AppColors.onSurface : AppColors.subtle;
|
||||
final background = selected
|
||||
? AppColors.blue
|
||||
: enabled
|
||||
? AppColors.raised
|
||||
: AppColors.cardAlt;
|
||||
final foreground = selected
|
||||
? AppColors.onPrimary
|
||||
: enabled
|
||||
? AppColors.onSurface
|
||||
: AppColors.subtle;
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: background,
|
||||
borderRadius: BorderRadius.circular(_segmentRadius),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
onTap: enabled ? onTap : null,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 11),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: color, size: 21),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(_segmentRadius),
|
||||
child: SizedBox(
|
||||
height: _segmentHeight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: _segmentPadding),
|
||||
child: Center(
|
||||
child: Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: foreground,
|
||||
fontSize: 12,
|
||||
fontWeight: selected ? FontWeight.w700 : FontWeight.w500,
|
||||
),
|
||||
),
|
||||
if (value.isNotEmpty)
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(color: AppColors.subtle, fontSize: 11),
|
||||
),
|
||||
?trailing,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -173,7 +173,6 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
episodeNumber: data.episode.number,
|
||||
synopsis: synopsis,
|
||||
authorNote: data.authorNote,
|
||||
textScale: data.textScale,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -216,7 +215,7 @@ class PlayerPlaybackOverlay extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontFamily: 'Outfit',
|
||||
fontSize: 18 * data.textScale,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w800,
|
||||
shadows: _playerTextShadows,
|
||||
),
|
||||
|
||||
@@ -21,7 +21,6 @@ class PlayerOverlayData {
|
||||
required this.saved,
|
||||
required this.playing,
|
||||
required this.playbackSpeed,
|
||||
required this.textScale,
|
||||
required this.totalEpisodes,
|
||||
this.authorNote = '',
|
||||
});
|
||||
@@ -59,9 +58,6 @@ class PlayerOverlayData {
|
||||
/// 当前倍速。
|
||||
final double playbackSpeed;
|
||||
|
||||
/// 信息文字缩放比例。
|
||||
final double textScale;
|
||||
|
||||
/// 可见集数量。
|
||||
final int totalEpisodes;
|
||||
|
||||
|
||||
@@ -221,14 +221,12 @@ class _EpisodeSynopsis extends StatefulWidget {
|
||||
required this.episodeNumber,
|
||||
required this.synopsis,
|
||||
required this.authorNote,
|
||||
required this.textScale,
|
||||
});
|
||||
|
||||
final AppLocalizations l10n;
|
||||
final int episodeNumber;
|
||||
final String synopsis;
|
||||
final String authorNote;
|
||||
final double textScale;
|
||||
|
||||
@override
|
||||
State<_EpisodeSynopsis> createState() => _EpisodeSynopsisState();
|
||||
@@ -255,7 +253,7 @@ class _EpisodeSynopsisState extends State<_EpisodeSynopsis> {
|
||||
key: const Key('player-episode-label'),
|
||||
style: TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 11 * widget.textScale,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
shadows: _playerTextShadows,
|
||||
),
|
||||
@@ -278,7 +276,7 @@ class _EpisodeSynopsisState extends State<_EpisodeSynopsis> {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: AppColors.playerMuted,
|
||||
fontSize: 11 * widget.textScale,
|
||||
fontSize: 11,
|
||||
height: 1.35,
|
||||
shadows: _playerTextShadows,
|
||||
),
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
/// 播放信息小号文字比例。
|
||||
const double playerTextSizeSmall = 0.9;
|
||||
|
||||
/// 播放信息标准文字比例。
|
||||
const double playerTextSizeStandard = 1.0;
|
||||
|
||||
/// 播放信息大号文字比例。
|
||||
const double playerTextSizeLarge = 1.15;
|
||||
|
||||
/// 返回播放信息文字档位的本地化名称。
|
||||
String playerTextSizeLabel(AppLocalizations l10n, double scale) {
|
||||
if (scale <= playerTextSizeSmall) return l10n.textSizeSmall;
|
||||
if (scale >= playerTextSizeLarge) return l10n.textSizeLarge;
|
||||
return l10n.textSizeStandard;
|
||||
}
|
||||
@@ -370,7 +370,7 @@ void main() {
|
||||
expect(find.byKey(const Key('player-episode-2')), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('should_open_more_actions_and_change_text_size', (tester) async {
|
||||
testWidgets('should_open_compact_more_actions', (tester) async {
|
||||
await _pumpApp(tester);
|
||||
await _openSeriesPlayer(tester);
|
||||
await tester.tap(find.byKey(const Key('player-more')));
|
||||
@@ -381,22 +381,35 @@ void main() {
|
||||
expect(find.byKey(const Key('player-more-quality-AUTO')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-offline')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-clear')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-danmaku')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-drag-handle')), findsOneWidget);
|
||||
for (final removed in const [
|
||||
Key('player-more-not-interested'),
|
||||
Key('player-more-danmaku'),
|
||||
Key('player-more-danmaku-settings'),
|
||||
Key('player-more-text-size'),
|
||||
Key('player-more-cast'),
|
||||
Key('player-more-timer'),
|
||||
Key('player-more-pip'),
|
||||
Key('player-more-report'),
|
||||
]) {
|
||||
expect(find.byKey(removed), findsNothing);
|
||||
}
|
||||
expect(
|
||||
find.byKey(const Key('player-more-danmaku-settings')),
|
||||
findsOneWidget,
|
||||
tester.getSize(find.byKey(const Key('player-more-speed-1.0'))).height,
|
||||
28,
|
||||
);
|
||||
expect(
|
||||
tester
|
||||
.widget<Text>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('player-more-speed-1.0')),
|
||||
matching: find.text('1.0x'),
|
||||
),
|
||||
)
|
||||
.style
|
||||
?.fontSize,
|
||||
12,
|
||||
);
|
||||
expect(find.byKey(const Key('player-more-cast')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-timer')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-text-size')), findsOneWidget);
|
||||
expect(find.byKey(const Key('player-more-report')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byTooltip('Text size'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('player-text-size-large')), findsOneWidget);
|
||||
await tester.tap(find.byKey(const Key('player-text-size-large')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Large'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('should_disable_quality_not_supplied_by_ticket', (tester) async {
|
||||
@@ -418,14 +431,24 @@ void main() {
|
||||
|
||||
expect(
|
||||
tester
|
||||
.widget<ChoiceChip>(find.byKey(const Key('player-more-quality-AUTO')))
|
||||
.onSelected,
|
||||
.widget<InkWell>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('player-more-quality-AUTO')),
|
||||
matching: find.byType(InkWell),
|
||||
),
|
||||
)
|
||||
.onTap,
|
||||
isNotNull,
|
||||
);
|
||||
expect(
|
||||
tester
|
||||
.widget<ChoiceChip>(find.byKey(const Key('player-more-quality-720P')))
|
||||
.onSelected,
|
||||
.widget<InkWell>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('player-more-quality-720P')),
|
||||
matching: find.byType(InkWell),
|
||||
),
|
||||
)
|
||||
.onTap,
|
||||
isNull,
|
||||
);
|
||||
expect(find.text('720P · Unavailable'), findsOneWidget);
|
||||
|
||||
Reference in new issue
Block a user