style: 增强我的页渐变与图标配色

This commit is contained in:
Zhou Weidong committed 2026-10-22 21:38:49 +08:00
1 parent 647f6afd77
commit a81bec4d47
6 files changed
+116 -49

No files matched your search

+2
View File
@@ -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。
+10 -2
View File
@@ -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);
-1
View File
@@ -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;
+24 -34
View File
@@ -80,7 +80,6 @@ class _MyPageState extends State<MyPage> {
}
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<MyPage> {
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<SystemUiOverlayStyle>(
@@ -117,29 +130,6 @@ class _MyPageState extends State<MyPage> {
);
}
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'),
+18 -4
View File
@@ -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),
+62 -8
View File
@@ -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<Text>(
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<DecoratedBox>(
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<DecoratedBox>(
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<Icon>(
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);
}