merge: 统一我的页深色视觉风格
This commit is contained in:
commit
0ef2438100
7 files changed
+242
-82
No files matched your search
@@ -903,3 +903,37 @@ $ flutter test
|
||||
解读:三列网格、分类顺序、动态入口隐藏、角标、卡片信息、分页大小、
|
||||
下一页追加和卡片进入播放器均有测试覆盖。`home_view.dart` 为 478 行,
|
||||
其余新增组件均低于 500 行。`pubspec.lock` 未提交,未操作真机。
|
||||
|
||||
## 2026-10-22 「我的」页视觉风格统一
|
||||
|
||||
- 分支:`feature/mine-visual-style`
|
||||
- 基线:`develop` / `origin/develop` = `47bf645`
|
||||
- 实现提交:`83129ac feat(mine): 统一我的页深色视觉风格`
|
||||
|
||||
### Token 与改动
|
||||
|
||||
- 复用 P11 的 `appBackground/contentCard/contentSurface/contentBorder`,
|
||||
新增 `textPrimary/mineCardRadius/mineRowHeight/minePageTitle/mineSectionTitle`。
|
||||
- 页面底色改为纯黑,移除「我的」页的旧深蓝渐变;页头白色标题 21/w700。
|
||||
- 头像、三宫格、金币卡、会员卡、菜单统一为深灰 16 圆角、1px 极淡描边,
|
||||
无阴影、无渐变、无发光。
|
||||
- 主文字/昵称/金额使用 `#FFFFFF`,次级说明和 chevron 使用 `#8E8E93`。
|
||||
- 三宫格等宽,入口图标 24 线性;菜单行高 52、标题 15,分割线只存在行间。
|
||||
- 橙色仅保留在充值、加入 VIP 等主操作;头像与菜单图标不再使用粉色/橙色装饰。
|
||||
- 区块顺序、全部入口、跳转与交互逻辑保持不变。
|
||||
|
||||
### 门禁命令与原始输出
|
||||
|
||||
```text
|
||||
$ flutter analyze
|
||||
Analyzing reelshort-bottom-nav...
|
||||
No issues found!
|
||||
```
|
||||
|
||||
```text
|
||||
$ flutter test
|
||||
00:56 +651: All tests passed!
|
||||
```
|
||||
|
||||
解读:背景、卡片 token、圆角/描边、无渐变阴影、三宫格等宽、菜单 52 行高、
|
||||
入口保留和收藏页跳转均有测试覆盖。`pubspec.lock` 未提交,未操作真机。
|
||||
@@ -70,6 +70,7 @@ abstract final class AppColors {
|
||||
static const contentBorder = Color(0x1AFFFFFF);
|
||||
|
||||
/// 次级文字与列表 chevron。
|
||||
static const textPrimary = Color(0xFFFFFFFF);
|
||||
static const textSecondary = Color(0xFF8E8E93);
|
||||
|
||||
/// 原生开屏与冷启动过渡底色。
|
||||
|
||||
@@ -87,4 +87,10 @@ abstract final class AppDimens {
|
||||
static const double homeSectionIndicator = 2;
|
||||
static const double homeIconSlot = 44;
|
||||
static const double homeHeaderIcon = 22;
|
||||
|
||||
/// 「我的」页中性视觉。
|
||||
static const double mineCardRadius = 16;
|
||||
static const double mineRowHeight = 52;
|
||||
static const double minePageTitle = 21;
|
||||
static const double mineSectionTitle = 15;
|
||||
}
|
||||
@@ -80,21 +80,25 @@ class _MyPageState extends State<MyPage> {
|
||||
|
||||
Widget _page(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final content = SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_topBar(l10n),
|
||||
Expanded(child: _body(context, l10n)),
|
||||
if (!embedded) _bottomNav(),
|
||||
],
|
||||
final content = ColoredBox(
|
||||
key: const Key('mine-page-surface'),
|
||||
color: AppColors.appBackground,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
_topBar(l10n),
|
||||
Expanded(child: _body(context, l10n)),
|
||||
if (!embedded) _bottomNav(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
child: embedded
|
||||
? content
|
||||
: Scaffold(backgroundColor: AppColors.ink, body: content),
|
||||
: Scaffold(backgroundColor: AppColors.appBackground, body: content),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,9 +115,9 @@ class _MyPageState extends State<MyPage> {
|
||||
l10n.myTab,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Outfit',
|
||||
color: AppColors.onSurface,
|
||||
fontSize: AppDimens.pageTitle,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.minePageTitle,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -280,8 +284,10 @@ class _LanguageSheet extends StatelessWidget {
|
||||
];
|
||||
return Material(
|
||||
key: const Key('mine-language-sheet'),
|
||||
color: AppColors.card,
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(AppDimens.mineCardRadius),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
@@ -297,9 +303,9 @@ class _LanguageSheet extends StatelessWidget {
|
||||
child: Text(
|
||||
l10n.language,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -316,7 +322,10 @@ class _LanguageSheet extends StatelessWidget {
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
title: Text(option.$3),
|
||||
trailing: selected?.languageCode == option.$1.languageCode
|
||||
? const Icon(Icons.check_rounded, color: AppColors.blue)
|
||||
? const Icon(
|
||||
Icons.check_rounded,
|
||||
color: AppColors.textPrimary,
|
||||
)
|
||||
: null,
|
||||
onTap: () => Navigator.pop(context, option.$1),
|
||||
),
|
||||
@@ -351,7 +360,7 @@ class _MinePlaceholderPage extends StatelessWidget {
|
||||
child: Text(
|
||||
l10n.comingSoon,
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.body,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:provider/provider.dart';
|
||||
import '../../../core/data/services/auth_controller.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../core/widgets/remote_image.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
@@ -31,13 +30,13 @@ class MineHeader extends StatelessWidget {
|
||||
return Container(
|
||||
key: const Key('mine-user-row'),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
border: Border.all(color: AppColors.contentBorder),
|
||||
),
|
||||
child: Material(
|
||||
color: AppColors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
@@ -50,7 +49,7 @@ class MineHeader extends StatelessWidget {
|
||||
Expanded(child: _labels(name, subtitle)),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.subtle,
|
||||
color: AppColors.textSecondary,
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
@@ -67,14 +66,14 @@ class MineHeader extends StatelessWidget {
|
||||
width: 64,
|
||||
height: 64,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.badgePink,
|
||||
color: AppColors.contentSurface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: path.isEmpty
|
||||
? const Icon(
|
||||
Icons.person_rounded,
|
||||
color: AppColors.badgePinkText,
|
||||
color: AppColors.textPrimary,
|
||||
size: 30,
|
||||
)
|
||||
: RemoteImage(path, fit: BoxFit.cover),
|
||||
@@ -91,9 +90,9 @@ class MineHeader extends StatelessWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Outfit',
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
@@ -102,7 +101,7 @@ class MineHeader extends StatelessWidget {
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.caption,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../mine_types.dart';
|
||||
|
||||
@@ -22,12 +21,12 @@ class MineShortcutGrid extends StatelessWidget {
|
||||
Expanded(
|
||||
child: _ShortcutTile(
|
||||
key: const Key('mine-watchlist'),
|
||||
icon: Icons.bookmark_rounded,
|
||||
icon: Icons.bookmark_border_rounded,
|
||||
label: l10n.watchlist,
|
||||
onTap: () => onOpen(MineDestination.watchlist),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const SizedBox(width: AppDimens.homeGridGap),
|
||||
Expanded(
|
||||
child: _ShortcutTile(
|
||||
key: const Key('mine-history'),
|
||||
@@ -36,11 +35,11 @@ class MineShortcutGrid extends StatelessWidget {
|
||||
onTap: () => onOpen(MineDestination.history),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
const SizedBox(width: AppDimens.homeGridGap),
|
||||
Expanded(
|
||||
child: _ShortcutTile(
|
||||
key: const Key('mine-downloads'),
|
||||
icon: Icons.download_rounded,
|
||||
icon: Icons.download_outlined,
|
||||
label: l10n.downloads,
|
||||
onTap: () => onOpen(MineDestination.downloads),
|
||||
),
|
||||
@@ -66,13 +65,13 @@ class _ShortcutTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
border: Border.all(color: AppColors.contentBorder),
|
||||
),
|
||||
child: Material(
|
||||
color: AppColors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
@@ -81,16 +80,16 @@ class _ShortcutTile extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: AppColors.blue, size: 24),
|
||||
Icon(icon, color: AppColors.textPrimary, size: 24),
|
||||
const SizedBox(height: AppDimens.spaceSm),
|
||||
Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.caption,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -122,20 +121,16 @@ class MineWalletCard extends StatelessWidget {
|
||||
key: const Key('mine-wallet'),
|
||||
padding: const EdgeInsets.all(AppDimens.cardPadding),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [AppColors.goldCard, AppColors.card],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
border: Border.all(color: AppColors.contentBorder),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.monetization_on_rounded,
|
||||
color: AppColors.gold,
|
||||
size: 30,
|
||||
Icons.toll_outlined,
|
||||
color: AppColors.textSecondary,
|
||||
size: 28,
|
||||
),
|
||||
const SizedBox(width: AppDimens.spaceMd),
|
||||
Expanded(
|
||||
@@ -147,7 +142,7 @@ class MineWalletCard extends StatelessWidget {
|
||||
Text(
|
||||
l10n.coinBalance,
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.caption,
|
||||
),
|
||||
),
|
||||
@@ -155,9 +150,9 @@ class MineWalletCard extends StatelessWidget {
|
||||
Text(
|
||||
balance,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.pageTitle,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -171,7 +166,9 @@ class MineWalletCard extends StatelessWidget {
|
||||
backgroundColor: AppColors.blue,
|
||||
foregroundColor: AppColors.onPrimary,
|
||||
minimumSize: const Size(64, AppDimens.buttonCompact),
|
||||
shape: const StadiumBorder(),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(AppDimens.buttonRadius),
|
||||
),
|
||||
),
|
||||
child: Text(l10n.topUpWallet),
|
||||
),
|
||||
@@ -193,13 +190,13 @@ class MineVipCard extends StatelessWidget {
|
||||
return Container(
|
||||
key: const Key('mine-vip'),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
border: Border.all(color: AppColors.contentBorder),
|
||||
),
|
||||
child: Material(
|
||||
color: AppColors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
onTap: onOpen,
|
||||
@@ -211,12 +208,12 @@ class MineVipCard extends StatelessWidget {
|
||||
width: AppDimens.buttonLarge,
|
||||
height: AppDimens.buttonLarge,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.badgePink,
|
||||
color: AppColors.contentSurface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.workspace_premium_rounded,
|
||||
color: AppColors.badgePinkText,
|
||||
color: AppColors.textPrimary,
|
||||
size: 22,
|
||||
),
|
||||
),
|
||||
@@ -228,9 +225,9 @@ class MineVipCard extends StatelessWidget {
|
||||
Text(
|
||||
l10n.vipMembership,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: AppDimens.listTitle,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.mineSectionTitle,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
@@ -239,7 +236,7 @@ class MineVipCard extends StatelessWidget {
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.caption,
|
||||
),
|
||||
),
|
||||
@@ -250,7 +247,7 @@ class MineVipCard extends StatelessWidget {
|
||||
l10n.joinVip,
|
||||
style: const TextStyle(
|
||||
color: AppColors.blue,
|
||||
fontSize: AppDimens.caption,
|
||||
fontSize: AppDimens.body,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
@@ -282,13 +279,13 @@ class MineMenuList extends StatelessWidget {
|
||||
return Container(
|
||||
key: const Key('mine-menu'),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
color: AppColors.contentCard,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
border: Border.all(color: AppColors.contentBorder),
|
||||
),
|
||||
child: Material(
|
||||
color: AppColors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -338,18 +335,19 @@ class MineMenuList extends StatelessWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ListTile(
|
||||
key: const Key('mine-language'),
|
||||
minTileHeight: 48,
|
||||
minTileHeight: AppDimens.mineRowHeight,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
leading: const Icon(
|
||||
Icons.language_rounded,
|
||||
color: AppColors.blue,
|
||||
color: AppColors.textSecondary,
|
||||
size: 20,
|
||||
),
|
||||
title: Text(
|
||||
l10n.language,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: AppDimens.body,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.listTitle,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
trailing: Row(
|
||||
@@ -357,12 +355,15 @@ class MineMenuList extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
languageLabel,
|
||||
style: const TextStyle(color: AppColors.muted, fontSize: 11),
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.caption,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.subtle,
|
||||
color: AppColors.textSecondary,
|
||||
size: 18,
|
||||
),
|
||||
],
|
||||
@@ -379,19 +380,20 @@ class MineMenuList extends StatelessWidget {
|
||||
}) {
|
||||
return ListTile(
|
||||
key: key,
|
||||
minTileHeight: 48,
|
||||
minTileHeight: AppDimens.mineRowHeight,
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
leading: Icon(icon, color: AppColors.blue, size: 20),
|
||||
leading: Icon(icon, color: AppColors.textSecondary, size: 20),
|
||||
title: Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: AppDimens.body,
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.listTitle,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
trailing: const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.subtle,
|
||||
color: AppColors.textSecondary,
|
||||
size: 18,
|
||||
),
|
||||
onTap: () => onOpen(destination),
|
||||
@@ -399,6 +401,11 @@ class MineMenuList extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _divider() {
|
||||
return const Divider(height: 1, indent: 14, endIndent: 14);
|
||||
return const Divider(
|
||||
height: 1,
|
||||
indent: 14,
|
||||
endIndent: 14,
|
||||
color: AppColors.contentSurface,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import 'package:fruitshorts/app.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/favorite_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/playback_repository.dart';
|
||||
import 'package:fruitshorts/core/data/repositories/watch_history_repository.dart';
|
||||
import 'package:fruitshorts/core/theme/app_colors.dart';
|
||||
import 'package:fruitshorts/core/theme/app_dimens.dart';
|
||||
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
|
||||
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
|
||||
|
||||
@@ -69,6 +71,108 @@ void main() {
|
||||
expect(find.byKey(const Key('mine-library-tab-0')), findsNothing);
|
||||
expect(find.byKey(const Key('mine-library-tab-1')), findsNothing);
|
||||
expect(find.byKey(const Key('mine-library-tab-2')), findsNothing);
|
||||
final surface = tester.widget<ColoredBox>(
|
||||
find.byKey(const Key('mine-page-surface')),
|
||||
);
|
||||
expect(surface.color, AppColors.appBackground);
|
||||
final title = tester.widget<Text>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('mine-page-surface')),
|
||||
matching: find.text('My'),
|
||||
),
|
||||
);
|
||||
expect(title.style?.color, AppColors.textPrimary);
|
||||
expect(title.style?.fontSize, AppDimens.minePageTitle);
|
||||
expect(title.style?.fontWeight, FontWeight.w700);
|
||||
|
||||
for (final key in const [
|
||||
Key('mine-user-row'),
|
||||
Key('mine-wallet'),
|
||||
Key('mine-vip'),
|
||||
Key('mine-menu'),
|
||||
]) {
|
||||
final container = tester.widget<Container>(find.byKey(key));
|
||||
final decoration = container.decoration! as BoxDecoration;
|
||||
expect(decoration.color, AppColors.contentCard);
|
||||
expect(
|
||||
decoration.borderRadius,
|
||||
BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
);
|
||||
expect(decoration.gradient, isNull);
|
||||
expect(decoration.boxShadow, isNull);
|
||||
expect((decoration.border! as Border).top.color, AppColors.contentBorder);
|
||||
}
|
||||
|
||||
final shortcutIcon = tester.widget<Icon>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('mine-watchlist')),
|
||||
matching: find.byType(Icon),
|
||||
),
|
||||
);
|
||||
expect(shortcutIcon.size, 24);
|
||||
expect(shortcutIcon.color, AppColors.textPrimary);
|
||||
final shortcutKeys = [
|
||||
const Key('mine-watchlist'),
|
||||
const Key('mine-history'),
|
||||
const Key('mine-downloads'),
|
||||
];
|
||||
final shortcutWidths = shortcutKeys
|
||||
.map((key) => tester.getSize(find.byKey(key)).width)
|
||||
.toList();
|
||||
expect(shortcutWidths.toSet(), hasLength(1));
|
||||
final shortcutCard = tester.widget<Container>(
|
||||
find
|
||||
.descendant(
|
||||
of: find.byKey(const Key('mine-watchlist')),
|
||||
matching: find.byType(Container),
|
||||
)
|
||||
.first,
|
||||
);
|
||||
final shortcutDecoration = shortcutCard.decoration! as BoxDecoration;
|
||||
expect(shortcutDecoration.color, AppColors.contentCard);
|
||||
expect(
|
||||
shortcutDecoration.borderRadius,
|
||||
BorderRadius.circular(AppDimens.mineCardRadius),
|
||||
);
|
||||
expect(shortcutDecoration.boxShadow, isNull);
|
||||
final menuRows = find.descendant(
|
||||
of: find.byKey(const Key('mine-menu')),
|
||||
matching: find.byType(ListTile),
|
||||
);
|
||||
expect(menuRows, findsNWidgets(6));
|
||||
for (final row in tester.widgetList<ListTile>(menuRows)) {
|
||||
expect(row.minTileHeight, AppDimens.mineRowHeight);
|
||||
}
|
||||
final settingsRow = tester.widget<ListTile>(
|
||||
find.byKey(const Key('mine-settings')),
|
||||
);
|
||||
final settingsTitle = settingsRow.title! as Text;
|
||||
expect(settingsTitle.style?.color, AppColors.textPrimary);
|
||||
expect(settingsTitle.style?.fontSize, AppDimens.listTitle);
|
||||
expect((settingsRow.trailing! as Icon).color, AppColors.textSecondary);
|
||||
final recharge = tester.widget<TextButton>(
|
||||
find.byKey(const Key('mine-wallet-recharge')),
|
||||
);
|
||||
expect(recharge.style?.backgroundColor?.resolve(const {}), AppColors.blue);
|
||||
expect(
|
||||
tester.widget<Text>(find.text('Join VIP')).style?.color,
|
||||
AppColors.blue,
|
||||
);
|
||||
final dividers = tester.widgetList<Divider>(
|
||||
find.descendant(
|
||||
of: find.byKey(const Key('mine-menu')),
|
||||
matching: find.byType(Divider),
|
||||
),
|
||||
);
|
||||
expect(dividers, hasLength(5));
|
||||
expect(
|
||||
dividers.every((divider) => divider.color == AppColors.contentSurface),
|
||||
isTrue,
|
||||
);
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
await tester.tap(find.byKey(const Key('mine-watchlist')));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.byKey(const Key('favorites-page')), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user