diff --git a/docs/plans/PROGRESS.md b/docs/plans/PROGRESS.md index 1b2c8d8..d6f438c 100644 --- a/docs/plans/PROGRESS.md +++ b/docs/plans/PROGRESS.md @@ -1260,3 +1260,5 @@ $ flutter test - 页面背景改为暖黑三段纵向渐变,用户区与 VIP 卡布局保持不变。 - 行式入口替换为 4 列图标网格,7 个原入口按顺序保留,第 8 格为空占位。 - 网格使用 14 边距、半透明深灰底、圆角 12 和仅内部 1px 分隔线;`flutter analyze`:No issues found。 +- 渐变增强为 `#3A1B0E`/`#1A0C07`/黑色并叠加顶部品牌橙径向光晕,同时移除页面级「我的」标题栏。 +- 7 个宫格图标分别使用金币金、天蓝、薄荷绿、粉红、紫色、青色和冷灰;`flutter analyze`:No issues found。 diff --git a/lib/core/theme/app_colors.dart b/lib/core/theme/app_colors.dart index db57bdd..84ec3fe 100644 --- a/lib/core/theme/app_colors.dart +++ b/lib/core/theme/app_colors.dart @@ -84,13 +84,21 @@ abstract final class AppColors { /// 「我的」页卡片与描边。 static const mineCard = Color(0xFF16161A); static const mineOutline = Color(0xFF4A4A4A); - static const mineGradientTop = Color(0xFF1A0F0A); - static const mineGradientMiddle = Color(0xFF0D0908); + static const mineGradientTop = Color(0xFF3A1B0E); + static const mineGradientMiddle = Color(0xFF1A0C07); static const mineGradientBottom = Color(0xFF000000); + static const mineGradientGlow = Color(0x33FF6B2C); static const mineGridSurface = Color(0x99101010); static const mineGridDivider = Color(0xFF2A2A2A); static const mineGridIconSurface = Color(0xFF1C1C1E); static const mineGridLabel = Color(0xFFE6E6EB); + static const mineIconWallet = Color(0xFFF5C451); + static const mineIconDownloads = Color(0xFF4DA3FF); + static const mineIconHistory = Color(0xFF4ADE80); + static const mineIconPreferences = Color(0xFFFF6B9A); + static const mineIconSupport = Color(0xFFA78BFA); + static const mineIconLanguage = Color(0xFF22D3EE); + static const mineIconSettings = Color(0xFFA1A1AA); /// 次级文字与列表 chevron。 static const textPrimary = Color(0xFFFFFFFF); diff --git a/lib/core/theme/app_dimens.dart b/lib/core/theme/app_dimens.dart index 99641fb..3e7e345 100644 --- a/lib/core/theme/app_dimens.dart +++ b/lib/core/theme/app_dimens.dart @@ -179,7 +179,6 @@ abstract final class AppDimens { /// 「我的」页中性视觉。 static const double mineCardRadius = 16; - static const double minePageTitle = 17; static const double mineSectionTitle = 15; static const double mineAvatar = 56; static const double mineUserName = 20; diff --git a/lib/pages/mine/mine_view.dart b/lib/pages/mine/mine_view.dart index 43ce56b..bb866e7 100644 --- a/lib/pages/mine/mine_view.dart +++ b/lib/pages/mine/mine_view.dart @@ -80,7 +80,6 @@ class _MyPageState extends State { } Widget _page(BuildContext context) { - final l10n = AppLocalizations.of(context)!; final content = DecoratedBox( key: const Key('mine-page-surface'), decoration: const BoxDecoration( @@ -92,18 +91,32 @@ class _MyPageState extends State { AppColors.mineGradientMiddle, AppColors.mineGradientBottom, ], - stops: [0, 0.48, 1], + stops: [0, 0.4, 0.75], ), ), - child: SafeArea( - bottom: false, - child: Column( - children: [ - _topBar(l10n), - Expanded(child: _body(context)), - if (!embedded) _bottomNav(), - ], - ), + child: Stack( + fit: StackFit.expand, + children: [ + const DecoratedBox( + key: Key('mine-page-glow'), + decoration: BoxDecoration( + gradient: RadialGradient( + center: Alignment(0, -0.95), + radius: 0.9, + colors: [AppColors.mineGradientGlow, AppColors.transparent], + ), + ), + ), + SafeArea( + bottom: false, + child: Column( + children: [ + Expanded(child: _body(context)), + if (!embedded) _bottomNav(), + ], + ), + ), + ], ), ); return AnnotatedRegion( @@ -117,29 +130,6 @@ class _MyPageState extends State { ); } - Widget _topBar(AppLocalizations l10n) { - return SizedBox( - height: AppDimens.contentHeaderHeight, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: AppDimens.pageHorizontal, - ), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - l10n.myTab, - style: const TextStyle( - fontFamily: 'Outfit', - color: AppColors.textPrimary, - fontSize: AppDimens.minePageTitle, - fontWeight: FontWeight.w700, - ), - ), - ), - ), - ); - } - Widget _body(BuildContext context) { return ListView( key: const Key('mine-page-scroll'), diff --git a/lib/pages/mine/widgets/mine_menu.dart b/lib/pages/mine/widgets/mine_menu.dart index 6146127..a146200 100644 --- a/lib/pages/mine/widgets/mine_menu.dart +++ b/lib/pages/mine/widgets/mine_menu.dart @@ -153,6 +153,7 @@ class MineMenuList extends StatelessWidget { index: 0, actionKey: const Key('mine-wallet'), icon: Icons.account_balance_wallet_outlined, + iconColor: AppColors.mineIconWallet, label: l10n.wallet, onTap: () => onOpen(MineDestination.wallet), ), @@ -160,6 +161,7 @@ class MineMenuList extends StatelessWidget { index: 1, actionKey: const Key('mine-downloads'), icon: Icons.download_outlined, + iconColor: AppColors.mineIconDownloads, label: l10n.offlineDownloads, onTap: () => onOpen(MineDestination.downloads), ), @@ -167,6 +169,7 @@ class MineMenuList extends StatelessWidget { index: 2, actionKey: const Key('mine-history'), icon: Icons.history_rounded, + iconColor: AppColors.mineIconHistory, label: l10n.watchHistory, onTap: () => onOpen(MineDestination.history), ), @@ -174,6 +177,7 @@ class MineMenuList extends StatelessWidget { index: 3, actionKey: const Key('mine-watch-preferences'), icon: Icons.tune_rounded, + iconColor: AppColors.mineIconPreferences, label: l10n.watchPreferences, onTap: () => onOpen(MineDestination.preferences), ), @@ -185,6 +189,7 @@ class MineMenuList extends StatelessWidget { index: 4, actionKey: const Key('mine-help'), icon: Icons.support_agent_rounded, + iconColor: AppColors.mineIconSupport, label: l10n.contactSupport, onTap: () => onOpen(MineDestination.help), ), @@ -192,6 +197,7 @@ class MineMenuList extends StatelessWidget { index: 5, actionKey: const Key('mine-language'), icon: Icons.language_rounded, + iconColor: AppColors.mineIconLanguage, label: l10n.language, onTap: onLanguage, ), @@ -199,6 +205,7 @@ class MineMenuList extends StatelessWidget { index: 6, actionKey: const Key('mine-settings'), icon: Icons.settings_outlined, + iconColor: AppColors.mineIconSettings, label: l10n.settings, onTap: () => onOpen(MineDestination.settings), ), @@ -215,6 +222,7 @@ class MineMenuList extends StatelessWidget { required int index, Key? actionKey, IconData? icon, + Color? iconColor, String? label, VoidCallback? onTap, }) { @@ -237,10 +245,16 @@ class MineMenuList extends StatelessWidget { color: AppColors.mineGridIconSurface, shape: BoxShape.circle, ), - child: Icon( - icon, - color: AppColors.primary, - size: AppDimens.mineGridIcon, + child: DecoratedBox( + decoration: BoxDecoration( + color: iconColor?.withValues(alpha: 0.08), + shape: BoxShape.circle, + ), + child: Icon( + icon, + color: iconColor, + size: AppDimens.mineGridIcon, + ), ), ), const SizedBox(height: AppDimens.spaceXs + 2), diff --git a/test/mine/mine_preview_layout_test.dart b/test/mine/mine_preview_layout_test.dart index b017ed0..2d03568 100644 --- a/test/mine/mine_preview_layout_test.dart +++ b/test/mine/mine_preview_layout_test.dart @@ -41,14 +41,6 @@ void main() { expect(find.byKey(const Key('mine-vip')), findsOneWidget); expect(find.byKey(const Key('mine-vip-open')), findsOneWidget); expect(find.byKey(const Key('mine-menu')), findsOneWidget); - final title = tester.widget( - find.descendant( - of: find.byKey(const Key('mine-page-surface')), - matching: find.text('My'), - ), - ); - expect(title.style?.fontSize, AppDimens.minePageTitle); - expect(title.style?.fontWeight, FontWeight.w700); expect(find.byKey(const Key('mine-mini-player')), findsNothing); final surface = tester.widget( find.byKey(const Key('mine-page-surface')), @@ -62,6 +54,25 @@ void main() { AppColors.mineGradientMiddle, AppColors.mineGradientBottom, ]); + expect(background.stops, const [0, 0.4, 0.75]); + expect( + find.descendant( + of: find.byKey(const Key('mine-page-surface')), + matching: find.text('My'), + ), + findsNothing, + ); + final glow = tester.widget( + find.byKey(const Key('mine-page-glow')), + ); + final glowDecoration = glow.decoration as BoxDecoration; + final radialGlow = glowDecoration.gradient! as RadialGradient; + expect(radialGlow.center, const Alignment(0, -0.95)); + expect(radialGlow.radius, 0.9); + expect(radialGlow.colors, const [ + AppColors.mineGradientGlow, + AppColors.transparent, + ]); for (final oldShortcut in const [ Key('mine-watchlist'), Key('mine-history-shortcut'), @@ -83,6 +94,49 @@ void main() { for (final entryKey in entryKeys) { expect(find.byKey(entryKey), findsOneWidget); } + const coloredIcons = [ + ( + Key('mine-wallet'), + Icons.account_balance_wallet_outlined, + AppColors.mineIconWallet, + ), + ( + Key('mine-downloads'), + Icons.download_outlined, + AppColors.mineIconDownloads, + ), + (Key('mine-history'), Icons.history_rounded, AppColors.mineIconHistory), + ( + Key('mine-watch-preferences'), + Icons.tune_rounded, + AppColors.mineIconPreferences, + ), + ( + Key('mine-help'), + Icons.support_agent_rounded, + AppColors.mineIconSupport, + ), + ( + Key('mine-language'), + Icons.language_rounded, + AppColors.mineIconLanguage, + ), + ( + Key('mine-settings'), + Icons.settings_outlined, + AppColors.mineIconSettings, + ), + ]; + for (final entry in coloredIcons) { + final icon = tester.widget( + find.descendant( + of: find.byKey(entry.$1), + matching: find.byIcon(entry.$2), + ), + ); + expect(icon.color, entry.$3); + expect(icon.size, AppDimens.mineGridIcon); + } for (var index = 0; index < 8; index++) { expect(find.byKey(Key('mine-menu-cell-$index')), findsOneWidget); }