feat(ui): 登录页重设计并统一弹框主题渐变外壳

This commit is contained in:
Vicky authored and trae-solo-agent committed 2026-10-28 16:36:43 +08:00
1 parent c027acc91f
commit de7da64886
25 files changed
+905 -317

No files matched your search

@@ -14,6 +14,7 @@ import '../../../core/data/repositories/interaction_repository.dart';
import '../../../core/data/services/comment_controller.dart';
import '../../../core/formatting/error_text.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/widgets/app_glow_panel.dart';
import '../../../core/widgets/empty_state.dart';
import '../../../l10n/app_localizations.dart';
import 'comment_composer_sheet.dart';
@@ -176,14 +177,14 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
child: SizedBox(
key: const Key('comment-sheet-constraints'),
height: sheetHeight,
child: Container(
decoration: const BoxDecoration(
color: AppColors.card,
borderRadius: BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
child: AppGlowPanel(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
child: SafeArea(
border: false,
child: Container(
decoration: const BoxDecoration(color: AppColors.transparent),
child: SafeArea(
top: false,
child: ListenableBuilder(
listenable: _controller,
@@ -193,6 +194,7 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
child: _content(context),
);
},
),
),
),
),
@@ -238,7 +240,7 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
style: const TextStyle(
color: AppColors.onSurface,
fontSize: 16,
fontWeight: FontWeight.w600,
fontWeight: FontWeight.w400,
),
),
Positioned(
@@ -7,6 +7,7 @@ import '../../../core/data/models/drama.dart';
import '../../../core/formatting/localized_content.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimens.dart';
import '../../../core/widgets/app_glow_panel.dart';
import '../../../l10n/app_localizations.dart';
import 'episode_picker_cell.dart';
@@ -47,16 +48,16 @@ class EpisodePickerSheet extends StatelessWidget {
systemNavigationBarIconBrightness: Brightness.light,
systemNavigationBarContrastEnforced: false,
),
child: Container(
key: const Key('player-episodes-sheet'),
height: MediaQuery.sizeOf(context).height * _sheetHeightFactor,
decoration: const BoxDecoration(
color: AppColors.card,
borderRadius: BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
child: AppGlowPanel(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
child: SafeArea(
border: false,
child: Container(
key: const Key('player-episodes-sheet'),
height: MediaQuery.sizeOf(context).height * _sheetHeightFactor,
decoration: const BoxDecoration(color: AppColors.transparent),
child: SafeArea(
top: false,
bottom: true,
child: Column(
@@ -139,6 +140,7 @@ class EpisodePickerSheet extends StatelessWidget {
],
),
),
),
),
);
}
@@ -3,6 +3,7 @@
import 'package:flutter/material.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/widgets/app_glow_panel.dart';
import '../../../l10n/app_localizations.dart';
const double _sheetRadius = 20;
@@ -52,6 +53,8 @@ class PlayerMoreActions {
required this.onDownload,
required this.onQualityChanged,
this.onPip,
this.autoPipEnabled = false,
this.onAutoPipChanged,
});
/// 倍速变化。
@@ -68,6 +71,12 @@ class PlayerMoreActions {
/// 进入小窗播放;平台不支持时为 null。
final VoidCallback? onPip;
/// 退出 App 自动小窗开关的当前状态(仅支持自动小窗的平台展示开关行)。
final bool autoPipEnabled;
/// 切换退出 App 自动小窗;为 null 时隐藏开关行。
final ValueChanged<bool>? onAutoPipChanged;
}
/// K29.6 精简版播放页更多面板。
@@ -96,16 +105,19 @@ class PlayerMoreSheet extends StatefulWidget {
class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
late double _speed = widget.state.speed;
late String _quality = widget.state.selectedQuality.toUpperCase();
late bool _autoPip = widget.actions.autoPipEnabled;
@override
Widget build(BuildContext context) {
final l10n = widget.l10n;
return Material(
key: const Key('player-more-sheet'),
color: AppColors.ink,
return AppGlowPanel(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
border: false,
child: Material(
key: const Key('player-more-sheet'),
type: MaterialType.transparency,
clipBehavior: Clip.antiAlias,
child: SafeArea(
top: false,
@@ -142,6 +154,17 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
title: l10n.pictureInPicture,
onTap: () => _closeThen(widget.actions.onPip!),
),
if (widget.actions.onAutoPipChanged != null)
_switchRow(
key: const Key('player-more-auto-pip'),
icon: Icons.auto_awesome_motion_outlined,
title: l10n.autoEnterPip,
value: _autoPip,
onChanged: (value) {
setState(() => _autoPip = value);
widget.actions.onAutoPipChanged!(value);
},
),
_actionRow(
key: const Key('player-more-offline'),
icon: Icons.download_outlined,
@@ -153,6 +176,7 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
),
),
),
),
);
}
@@ -160,7 +184,7 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: _groupVerticalPadding),
decoration: BoxDecoration(
color: AppColors.card,
color: Colors.white.withValues(alpha: 0.06),
borderRadius: BorderRadius.circular(_groupRadius),
),
child: Column(mainAxisSize: MainAxisSize.min, children: rows),
@@ -241,7 +265,7 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
horizontal: _segmentTrackPadding,
),
decoration: BoxDecoration(
color: AppColors.raised,
color: Colors.white.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(_segmentTrackRadius),
),
child: Row(
@@ -286,6 +310,54 @@ class _PlayerMoreSheetState extends State<PlayerMoreSheet> {
);
}
/// 开关行:左侧图标+标题,右侧主题色 Switch。
Widget _switchRow({
required Key key,
required IconData icon,
required String title,
required bool value,
required ValueChanged<bool> onChanged,
}) {
return SizedBox(
key: key,
height: _rowHeight,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: _rowHorizontalPadding),
child: Row(
children: [
Icon(icon, color: AppColors.onSurface, size: _rowIconSize),
const SizedBox(width: _rowIconGap),
Expanded(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.onSurface,
fontSize: _rowLabelSize,
fontWeight: FontWeight.w500,
),
),
),
Transform.scale(
scale: 0.7,
child: Switch(
key: const Key('player-more-auto-pip-switch'),
value: value,
activeThumbColor: AppColors.onSurface,
activeTrackColor: AppColors.brandRed,
inactiveThumbColor: AppColors.textSecondary,
inactiveTrackColor: AppColors.contentBorder,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: onChanged,
),
),
],
),
),
);
}
Widget _actionRow({
required Key key,
required IconData icon,
@@ -380,7 +452,9 @@ class _SegmentButton extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: _segmentPadding),
alignment: Alignment.center,
decoration: BoxDecoration(
color: selected ? AppColors.card : AppColors.transparent,
color: selected
? Colors.white.withValues(alpha: 0.16)
: AppColors.transparent,
borderRadius: BorderRadius.circular(_segmentRadius),
boxShadow: selected
? const [
@@ -3,6 +3,7 @@
import 'package:flutter/material.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/widgets/app_glow_panel.dart';
import '../../../l10n/app_localizations.dart';
const List<double> _speedOptions = [0.75, 1.0, 1.25, 1.5, 2.0, 3.0];
@@ -19,14 +20,16 @@ class PlayerSpeedSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Material(
key: const Key('player-speed-sheet'),
color: AppColors.card,
return AppGlowPanel(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(_sheetRadius),
),
clipBehavior: Clip.antiAlias,
child: SafeArea(
border: false,
child: Material(
key: const Key('player-speed-sheet'),
type: MaterialType.transparency,
clipBehavior: Clip.antiAlias,
child: SafeArea(
top: false,
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -50,6 +53,7 @@ class PlayerSpeedSheet extends StatelessWidget {
],
),
),
),
);
}
@@ -6,6 +6,7 @@ import '../../../core/data/models/drama.dart';
import '../../../core/data/models/play_ticket.dart';
import '../../../core/formatting/error_text.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/widgets/app_glow_panel.dart';
import '../../../l10n/app_localizations.dart';
const double _cardRadius = 20;
@@ -209,12 +210,10 @@ class _PlayerUnlockSheetState extends State<PlayerUnlockSheet> {
@override
Widget build(BuildContext context) {
final l10n = widget.l10n;
return Container(
return AppGlowPanel(
key: const Key('player-unlock-panel'),
decoration: const BoxDecoration(
color: AppColors.card,
borderRadius: BorderRadius.vertical(top: Radius.circular(_cardRadius)),
),
borderRadius: const BorderRadius.vertical(top: Radius.circular(_cardRadius)),
border: false,
child: SafeArea(
top: false,
child: Padding(