merge: 对齐四 Tab 底栏布局规格
This commit is contained in:
commit
6dea9d479e
11 files changed
+135
-106
No files matched your search
@@ -831,3 +831,35 @@ $ flutter test --no-pub
|
|||||||
|
|
||||||
解读:静态分析零告警,644 项测试全部通过;追剧与首页/推荐/我的均在同一根页面
|
解读:静态分析零告警,644 项测试全部通过;追剧与首页/推荐/我的均在同一根页面
|
||||||
内切换,无叠加导航或返回栈。`pubspec.lock` 未提交,未启动或停止服务,未操作真机。
|
内切换,无叠加导航或返回栈。`pubspec.lock` 未提交,未启动或停止服务,未操作真机。
|
||||||
|
|
||||||
|
## 2026-10-22 根导航布局规格对齐
|
||||||
|
|
||||||
|
- 分支:`feature/client-bottom-nav-layout`
|
||||||
|
- 基线:`develop` / `origin/develop` = `667fdc5`
|
||||||
|
- 实现提交:`81787dc style(nav): 对齐四 Tab 底栏布局规格`
|
||||||
|
|
||||||
|
### 改动
|
||||||
|
|
||||||
|
- 新增 `AppRootBottomNav` 作为首页、推荐、追剧、我的唯一根导航入口,
|
||||||
|
三个 Shell 页面不再各自拼装 item。
|
||||||
|
- 四列使用 `Expanded` 等分,图标在上、文字在下,间距 4。
|
||||||
|
- 内容高度 56,另由 `SafeArea` 增加底部安全区;图标 26、文字 11、
|
||||||
|
`letterSpacing = 0`,选中 `w600`、未选中 `w400`。
|
||||||
|
- 背景纯黑,取消顶部边框;选中 `#FFFFFF`,未选中 `#8E8E93`。
|
||||||
|
- 首页、推荐、书签、人像继续使用各自的选中实心/未选中描边图标。
|
||||||
|
|
||||||
|
### 门禁命令与原始输出
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ flutter analyze
|
||||||
|
Analyzing reelshort-bottom-nav...
|
||||||
|
No issues found! (ran in 5.2s)
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ flutter test
|
||||||
|
04:43 +645: All tests passed!
|
||||||
|
```
|
||||||
|
|
||||||
|
解读:四等分、56 内容高度、安全区、26 图标、4 间距、精确色值和无分割线
|
||||||
|
均有测试覆盖;645 项测试全部通过。`pubspec.lock` 未提交,未操作真机。
|
||||||
@@ -69,10 +69,9 @@ abstract final class AppColors {
|
|||||||
/// 底部导航底色。
|
/// 底部导航底色。
|
||||||
static const bar = ink;
|
static const bar = ink;
|
||||||
|
|
||||||
/// 底部导航专用:纯黑背景、选中白、未选中灰与轻分割线。
|
/// 底部导航专用:纯黑背景、选中白与未选中灰。
|
||||||
static const navBackground = Color(0xFF000000);
|
static const navBackground = Color(0xFF000000);
|
||||||
static const navSelected = Color(0xFFFFFFFF);
|
static const navSelected = Color(0xFFFFFFFF);
|
||||||
static const navDivider = Color(0xFF1C1C1E);
|
|
||||||
|
|
||||||
/// 卡片阴影(深色几乎不用阴影)。
|
/// 卡片阴影(深色几乎不用阴影)。
|
||||||
static const cardShadow = Color(0x00000000);
|
static const cardShadow = Color(0x00000000);
|
||||||
@@ -126,7 +125,7 @@ abstract final class AppColors {
|
|||||||
static const badgeBeige = raised;
|
static const badgeBeige = raised;
|
||||||
|
|
||||||
/// 导航未选中。
|
/// 导航未选中。
|
||||||
static const navUnselected = Color(0xFF8A8A8E);
|
static const navUnselected = Color(0xFF8E8E93);
|
||||||
|
|
||||||
/// 播放器次要文字。
|
/// 播放器次要文字。
|
||||||
static const playerMuted = Color(0xA3FFFFFF);
|
static const playerMuted = Color(0xA3FFFFFF);
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ abstract final class AppDimens {
|
|||||||
static const double previewSectionTitle = 14;
|
static const double previewSectionTitle = 14;
|
||||||
static const double chipFont = 10;
|
static const double chipFont = 10;
|
||||||
static const double navLabel = 11;
|
static const double navLabel = 11;
|
||||||
|
static const double navLabelGap = 4;
|
||||||
|
|
||||||
static const double buttonHeight = 48;
|
static const double buttonHeight = 48;
|
||||||
static const double primaryButtonHeight = 52;
|
static const double primaryButtonHeight = 52;
|
||||||
@@ -47,8 +48,8 @@ abstract final class AppDimens {
|
|||||||
static const double tapTarget = 44;
|
static const double tapTarget = 44;
|
||||||
static const double contentHeaderHeight = 46;
|
static const double contentHeaderHeight = 46;
|
||||||
|
|
||||||
static const double navHeight = 68;
|
static const double navHeight = 56;
|
||||||
static const double navIcon = 24;
|
static const double navIcon = 26;
|
||||||
static const double progressHeight = 3;
|
static const double progressHeight = 3;
|
||||||
static const double progressRadius = 2;
|
static const double progressRadius = 2;
|
||||||
static const double progressLineHeight = 3;
|
static const double progressLineHeight = 3;
|
||||||
|
|||||||
@@ -26,30 +26,17 @@ class AppBottomNavItem {
|
|||||||
|
|
||||||
/// 四槽底部导航:纯黑背景,白色选中态,灰色未选中态。
|
/// 四槽底部导航:纯黑背景,白色选中态,灰色未选中态。
|
||||||
class AppBottomNav extends StatelessWidget {
|
class AppBottomNav extends StatelessWidget {
|
||||||
const AppBottomNav({
|
const AppBottomNav({super.key, required this.items, this.barKey});
|
||||||
super.key,
|
|
||||||
required this.items,
|
|
||||||
this.backgroundColor = AppColors.navBackground,
|
|
||||||
this.barKey,
|
|
||||||
this.dark = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
final List<AppBottomNavItem> items;
|
final List<AppBottomNavItem> items;
|
||||||
final Color backgroundColor;
|
|
||||||
final Key? barKey;
|
final Key? barKey;
|
||||||
final bool dark;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bar = Container(
|
final bar = Container(
|
||||||
key: barKey,
|
key: barKey,
|
||||||
height: AppDimens.navHeight,
|
height: AppDimens.navHeight,
|
||||||
decoration: BoxDecoration(
|
color: AppColors.navBackground,
|
||||||
color: dark ? AppColors.navBackground : backgroundColor,
|
|
||||||
border: const Border(
|
|
||||||
top: BorderSide(color: AppColors.navDivider, width: 0.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
for (final item in items)
|
for (final item in items)
|
||||||
@@ -99,7 +86,7 @@ class _NavDestination extends StatelessWidget {
|
|||||||
: unselectedColor,
|
: unselectedColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 3),
|
const SizedBox(height: AppDimens.navLabelGap),
|
||||||
Text(
|
Text(
|
||||||
item.label,
|
item.label,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../l10n/app_localizations.dart';
|
import '../../l10n/app_localizations.dart';
|
||||||
|
import 'app_bottom_nav.dart';
|
||||||
|
|
||||||
/// 客户端根导航的固定顺序。
|
/// 客户端根导航的固定顺序。
|
||||||
enum AppRootTab { home, recommend, following, mine }
|
enum AppRootTab { home, recommend, following, mine }
|
||||||
@@ -36,3 +37,36 @@ extension AppRootTabUi on AppRootTab {
|
|||||||
AppRootTab.mine => l10n.myTab,
|
AppRootTab.mine => l10n.myTab,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 根导航唯一入口,确保四个主页面使用完全一致的底栏配置。
|
||||||
|
class AppRootBottomNav extends StatelessWidget {
|
||||||
|
const AppRootBottomNav({
|
||||||
|
super.key,
|
||||||
|
required this.selected,
|
||||||
|
required this.onSelected,
|
||||||
|
this.barKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
final AppRootTab selected;
|
||||||
|
final ValueChanged<AppRootTab> onSelected;
|
||||||
|
final Key? barKey;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = AppLocalizations.of(context)!;
|
||||||
|
return AppBottomNav(
|
||||||
|
barKey: barKey,
|
||||||
|
items: [
|
||||||
|
for (final tab in AppRootTab.values)
|
||||||
|
AppBottomNavItem(
|
||||||
|
tabKey: tab.tabKey,
|
||||||
|
icon: tab.icon,
|
||||||
|
selectedIcon: tab.selectedIcon,
|
||||||
|
label: tab.label(l10n),
|
||||||
|
selected: tab == selected,
|
||||||
|
onTap: () => onSelected(tab),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@ import '../../core/formatting/error_text.dart';
|
|||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/theme/app_dimens.dart';
|
import '../../core/theme/app_dimens.dart';
|
||||||
import '../../core/theme/app_theme.dart';
|
import '../../core/theme/app_theme.dart';
|
||||||
import '../../core/widgets/app_bottom_nav.dart';
|
|
||||||
import '../../core/widgets/app_pull_to_refresh.dart';
|
import '../../core/widgets/app_pull_to_refresh.dart';
|
||||||
import '../../core/widgets/app_root_tab.dart';
|
import '../../core/widgets/app_root_tab.dart';
|
||||||
import '../../core/widgets/catalog_debug_info.dart';
|
import '../../core/widgets/catalog_debug_info.dart';
|
||||||
@@ -160,7 +159,7 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
|||||||
loading: logic.searchLoading,
|
loading: logic.searchLoading,
|
||||||
),
|
),
|
||||||
Expanded(child: _feed(l10n, categories)),
|
Expanded(child: _feed(l10n, categories)),
|
||||||
if (!embedded) _bottomNav(l10n),
|
if (!embedded) _bottomNav(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -612,20 +611,9 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
|||||||
unawaited(playDramaFromCatalog(context, drama));
|
unawaited(playDramaFromCatalog(context, drama));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomNav(AppLocalizations l10n) => AppBottomNav(
|
Widget _bottomNav() => AppRootBottomNav(
|
||||||
items: [
|
selected: AppRootTab.recommend,
|
||||||
for (final tab in AppRootTab.values)
|
onSelected: (tab) => _act(_actionOf(tab)),
|
||||||
AppBottomNavItem(
|
|
||||||
tabKey: tab.tabKey,
|
|
||||||
icon: tab.icon,
|
|
||||||
selectedIcon: tab.selectedIcon,
|
|
||||||
label: tab.label(l10n),
|
|
||||||
selected: tab == AppRootTab.recommend,
|
|
||||||
onTap: tab == AppRootTab.recommend
|
|
||||||
? () {}
|
|
||||||
: () => _act(_actionOf(tab)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
DiscoverPageAction _actionOf(AppRootTab tab) => switch (tab) {
|
DiscoverPageAction _actionOf(AppRootTab tab) => switch (tab) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import '../../core/data/services/category_controller.dart';
|
|||||||
import '../../core/platform/haptics.dart';
|
import '../../core/platform/haptics.dart';
|
||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/theme/app_theme.dart';
|
import '../../core/theme/app_theme.dart';
|
||||||
import '../../core/widgets/app_bottom_nav.dart';
|
|
||||||
import '../../core/widgets/app_root_tab.dart';
|
import '../../core/widgets/app_root_tab.dart';
|
||||||
import '../../core/widgets/catalog_debug_info.dart';
|
import '../../core/widgets/catalog_debug_info.dart';
|
||||||
import '../../core/widgets/catalog_endpoint_editor.dart';
|
import '../../core/widgets/catalog_endpoint_editor.dart';
|
||||||
@@ -262,7 +261,6 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _scaffold(BuildContext context) {
|
Widget _scaffold(BuildContext context) {
|
||||||
final l10n = AppLocalizations.of(context)!;
|
|
||||||
final feed = logic.tab == 0;
|
final feed = logic.tab == 0;
|
||||||
final content = PopScope(
|
final content = PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
@@ -275,7 +273,7 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
backgroundColor: AppColors.transparent,
|
backgroundColor: AppColors.transparent,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
body: _body(context),
|
body: _body(context),
|
||||||
bottomNavigationBar: logic.videoImmersive ? null : _nav(context, l10n),
|
bottomNavigationBar: logic.videoImmersive ? null : _nav(context),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
@@ -451,31 +449,11 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _nav(BuildContext context, AppLocalizations l10n) {
|
Widget _nav(BuildContext context) {
|
||||||
return AppBottomNav(
|
return AppRootBottomNav(
|
||||||
barKey: const Key('home-tabs-bar'),
|
barKey: const Key('home-tabs-bar'),
|
||||||
dark: logic.tab == 0,
|
selected: AppRootTab.values[logic.tab],
|
||||||
items: [
|
onSelected: (tab) => _selectTab(context, tab.index),
|
||||||
_navItem(context, l10n, AppRootTab.home),
|
|
||||||
_navItem(context, l10n, AppRootTab.recommend),
|
|
||||||
_navItem(context, l10n, AppRootTab.following),
|
|
||||||
_navItem(context, l10n, AppRootTab.mine),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppBottomNavItem _navItem(
|
|
||||||
BuildContext context,
|
|
||||||
AppLocalizations l10n,
|
|
||||||
AppRootTab tab,
|
|
||||||
) {
|
|
||||||
return AppBottomNavItem(
|
|
||||||
tabKey: tab.tabKey,
|
|
||||||
icon: tab.icon,
|
|
||||||
selectedIcon: tab.selectedIcon,
|
|
||||||
label: tab.label(l10n),
|
|
||||||
selected: logic.tab == tab.index,
|
|
||||||
onTap: () => _selectTab(context, tab.index),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import '../../core/data/services/wallet_controller.dart';
|
|||||||
import '../../core/theme/app_colors.dart';
|
import '../../core/theme/app_colors.dart';
|
||||||
import '../../core/theme/app_dimens.dart';
|
import '../../core/theme/app_dimens.dart';
|
||||||
import '../../core/theme/app_theme.dart';
|
import '../../core/theme/app_theme.dart';
|
||||||
import '../../core/widgets/app_bottom_nav.dart';
|
|
||||||
import '../../core/widgets/app_root_tab.dart';
|
import '../../core/widgets/app_root_tab.dart';
|
||||||
import '../../core/widgets/auth_gate.dart';
|
import '../../core/widgets/auth_gate.dart';
|
||||||
import '../../core/widgets/plain_page_scaffold.dart';
|
import '../../core/widgets/plain_page_scaffold.dart';
|
||||||
@@ -87,7 +86,7 @@ class _MyPageState extends State<MyPage> {
|
|||||||
children: [
|
children: [
|
||||||
_topBar(l10n),
|
_topBar(l10n),
|
||||||
Expanded(child: _body(context, l10n)),
|
Expanded(child: _body(context, l10n)),
|
||||||
if (!embedded) _bottomNav(l10n),
|
if (!embedded) _bottomNav(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -238,19 +237,10 @@ class _MyPageState extends State<MyPage> {
|
|||||||
_openProtected(RechargePage(onPurchased: () => unawaited(wallet.load())));
|
_openProtected(RechargePage(onPurchased: () => unawaited(wallet.load())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _bottomNav(AppLocalizations l10n) {
|
Widget _bottomNav() {
|
||||||
return AppBottomNav(
|
return AppRootBottomNav(
|
||||||
items: [
|
selected: AppRootTab.mine,
|
||||||
for (final tab in AppRootTab.values)
|
onSelected: (tab) => _act(_actionOf(tab)),
|
||||||
AppBottomNavItem(
|
|
||||||
tabKey: tab.tabKey,
|
|
||||||
icon: tab.icon,
|
|
||||||
selectedIcon: tab.selectedIcon,
|
|
||||||
label: tab.label(l10n),
|
|
||||||
selected: tab == AppRootTab.mine,
|
|
||||||
onTap: tab == AppRootTab.mine ? () {} : () => _act(_actionOf(tab)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,22 @@ import 'package:fruitshorts/core/theme/app_dimens.dart';
|
|||||||
import 'package:fruitshorts/core/widgets/app_bottom_nav.dart';
|
import 'package:fruitshorts/core/widgets/app_bottom_nav.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
test('should_use_exact_root_navigation_colors', () {
|
||||||
|
expect(AppColors.navBackground, const Color(0xFF000000));
|
||||||
|
expect(AppColors.navSelected, const Color(0xFFFFFFFF));
|
||||||
|
expect(AppColors.navUnselected, const Color(0xFF8E8E93));
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('should_render_four_slots_with_white_selected_state', (
|
testWidgets('should_render_four_slots_with_white_selected_state', (
|
||||||
tester,
|
tester,
|
||||||
) async {
|
) async {
|
||||||
var theaterTaps = 0;
|
var theaterTaps = 0;
|
||||||
|
const barKey = Key('nav-bar');
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
MaterialApp(
|
MaterialApp(
|
||||||
home: Scaffold(
|
home: Scaffold(
|
||||||
bottomNavigationBar: AppBottomNav(
|
bottomNavigationBar: AppBottomNav(
|
||||||
|
barKey: barKey,
|
||||||
items: [
|
items: [
|
||||||
AppBottomNavItem(
|
AppBottomNavItem(
|
||||||
tabKey: const Key('tab-home'),
|
tabKey: const Key('tab-home'),
|
||||||
@@ -60,6 +68,8 @@ void main() {
|
|||||||
final selectedLabel = tester.widget<Text>(find.text('Home'));
|
final selectedLabel = tester.widget<Text>(find.text('Home'));
|
||||||
expect(selectedLabel.style?.color, AppColors.navSelected);
|
expect(selectedLabel.style?.color, AppColors.navSelected);
|
||||||
expect(selectedLabel.style?.fontWeight, FontWeight.w600);
|
expect(selectedLabel.style?.fontWeight, FontWeight.w600);
|
||||||
|
expect(selectedLabel.style?.fontSize, AppDimens.navLabel);
|
||||||
|
expect(selectedLabel.style?.letterSpacing, 0);
|
||||||
final unselectedLabel = tester.widget<Text>(find.text('Recommend'));
|
final unselectedLabel = tester.widget<Text>(find.text('Recommend'));
|
||||||
expect(unselectedLabel.style?.color, AppColors.navUnselected);
|
expect(unselectedLabel.style?.color, AppColors.navUnselected);
|
||||||
expect(unselectedLabel.style?.fontWeight, FontWeight.w400);
|
expect(unselectedLabel.style?.fontWeight, FontWeight.w400);
|
||||||
@@ -70,20 +80,35 @@ void main() {
|
|||||||
Key('tab-mine'),
|
Key('tab-mine'),
|
||||||
].map((key) => tester.getCenter(find.byKey(key)).dx).toList();
|
].map((key) => tester.getCenter(find.byKey(key)).dx).toList();
|
||||||
expect(centers, orderedEquals(centers.toList()..sort()));
|
expect(centers, orderedEquals(centers.toList()..sort()));
|
||||||
|
final widths = [
|
||||||
|
Key('tab-home'),
|
||||||
|
Key('tab-recommend'),
|
||||||
|
Key('tab-follow'),
|
||||||
|
Key('tab-mine'),
|
||||||
|
].map((key) => tester.getSize(find.byKey(key)).width).toList();
|
||||||
|
expect(widths.toSet(), hasLength(1));
|
||||||
expect(
|
expect(
|
||||||
tester.getSize(find.byType(AppBottomNav)).height,
|
tester.getSize(find.byType(AppBottomNav)).height,
|
||||||
AppDimens.navHeight,
|
AppDimens.navHeight,
|
||||||
);
|
);
|
||||||
|
final bar = tester.widget<Container>(find.byKey(barKey));
|
||||||
|
expect(bar.color, AppColors.navBackground);
|
||||||
|
expect(bar.decoration, isNull);
|
||||||
|
final selectedIcon = tester.widget<Icon>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byKey(const Key('tab-home')),
|
||||||
|
matching: find.byIcon(Icons.movie_rounded),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(selectedIcon.color, AppColors.navSelected);
|
||||||
expect(
|
expect(
|
||||||
tester
|
tester.getSize(find.byIcon(Icons.movie_rounded)),
|
||||||
.widget<Icon>(
|
const Size(26, 26),
|
||||||
find.descendant(
|
);
|
||||||
of: find.byKey(const Key('tab-home')),
|
expect(
|
||||||
matching: find.byIcon(Icons.movie_rounded),
|
tester.getTopLeft(find.text('Home')).dy -
|
||||||
),
|
tester.getBottomLeft(find.byIcon(Icons.movie_rounded)).dy,
|
||||||
)
|
AppDimens.navLabelGap,
|
||||||
.color,
|
|
||||||
AppColors.navSelected,
|
|
||||||
);
|
);
|
||||||
await tester.tap(find.byKey(const Key('tab-recommend')));
|
await tester.tap(find.byKey(const Key('tab-recommend')));
|
||||||
expect(theaterTaps, 1);
|
expect(theaterTaps, 1);
|
||||||
@@ -99,7 +124,6 @@ void main() {
|
|||||||
data: const MediaQueryData(padding: EdgeInsets.only(bottom: 34)),
|
data: const MediaQueryData(padding: EdgeInsets.only(bottom: 34)),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
bottomNavigationBar: AppBottomNav(
|
bottomNavigationBar: AppBottomNav(
|
||||||
dark: true,
|
|
||||||
barKey: barKey,
|
barKey: barKey,
|
||||||
items: [
|
items: [
|
||||||
AppBottomNavItem(
|
AppBottomNavItem(
|
||||||
@@ -144,12 +168,15 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(tester.getSize(find.byKey(barKey)).height, AppDimens.navHeight);
|
expect(tester.getSize(find.byKey(barKey)).height, AppDimens.navHeight);
|
||||||
|
|
||||||
final coloredBox = tester.widget<ColoredBox>(
|
expect(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
of: find.byType(AppBottomNav),
|
of: find.byType(AppBottomNav),
|
||||||
matching: find.byType(ColoredBox),
|
matching: find.byWidgetPredicate(
|
||||||
|
(widget) =>
|
||||||
|
widget is ColoredBox && widget.color == AppColors.navBackground,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
findsWidgets,
|
||||||
);
|
);
|
||||||
expect(coloredBox.color, AppColors.navBackground);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -85,12 +85,8 @@ void main() {
|
|||||||
|
|
||||||
final barFinder = find.byKey(const Key('home-tabs-bar'));
|
final barFinder = find.byKey(const Key('home-tabs-bar'));
|
||||||
final bar = tester.widget<Container>(barFinder);
|
final bar = tester.widget<Container>(barFinder);
|
||||||
final decoration = bar.decoration as BoxDecoration;
|
expect(bar.color, AppColors.navBackground);
|
||||||
final border = decoration.border as Border;
|
expect(bar.decoration, isNull);
|
||||||
// 所有页面统一深色导航。
|
|
||||||
expect(decoration.color, AppColors.navBackground);
|
|
||||||
expect(border.top.color, AppColors.navDivider);
|
|
||||||
expect(border.top.width, 0.5);
|
|
||||||
expect(
|
expect(
|
||||||
tester
|
tester
|
||||||
.widget<Text>(
|
.widget<Text>(
|
||||||
@@ -158,12 +154,8 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(haptics.selectionClicks, 1);
|
expect(haptics.selectionClicks, 1);
|
||||||
final theaterBar = tester.widget<Container>(barFinder);
|
final theaterBar = tester.widget<Container>(barFinder);
|
||||||
final theaterDecoration = theaterBar.decoration as BoxDecoration;
|
expect(theaterBar.color, AppColors.navBackground);
|
||||||
expect(theaterDecoration.color, AppColors.navBackground);
|
expect(theaterBar.decoration, isNull);
|
||||||
expect(
|
|
||||||
(theaterDecoration.border as Border).top.color,
|
|
||||||
AppColors.navDivider,
|
|
||||||
);
|
|
||||||
await tester.tap(find.byKey(const Key('tab-recommend')));
|
await tester.tap(find.byKey(const Key('tab-recommend')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(haptics.selectionClicks, 1);
|
expect(haptics.selectionClicks, 1);
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ void main() {
|
|||||||
expect(AppDimens.sectionTitle, 16);
|
expect(AppDimens.sectionTitle, 16);
|
||||||
expect(AppDimens.pageTitle, 20);
|
expect(AppDimens.pageTitle, 20);
|
||||||
expect(AppDimens.navLabel, 11);
|
expect(AppDimens.navLabel, 11);
|
||||||
expect(AppDimens.navIcon, 24);
|
expect(AppDimens.navLabelGap, 4);
|
||||||
|
expect(AppDimens.navIcon, 26);
|
||||||
expect(AppDimens.buttonHeight, 48);
|
expect(AppDimens.buttonHeight, 48);
|
||||||
expect(AppDimens.primaryButtonHeight, 52);
|
expect(AppDimens.primaryButtonHeight, 52);
|
||||||
expect(AppDimens.tapTarget, 44);
|
expect(AppDimens.tapTarget, 44);
|
||||||
expect(AppDimens.navHeight, 68);
|
expect(AppDimens.navHeight, 56);
|
||||||
expect(AppDimens.progressHeight, 3);
|
expect(AppDimens.progressHeight, 3);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user