merge: 合并 K28-S 四槽导航修正

This commit is contained in:
Zhou Weidong committed 2026-10-20 10:18:18 +08:00
commit 678b976ce1
10 files changed
+21 -139

No files matched your search

-5
View File
@@ -42,11 +42,6 @@ abstract final class AppColors {
/// 底部导航底色。
static const bar = Color(0xFFFFFDFB);
/// 中央操作按钮渐变。
static const navCenterStart = Color(0xFFFF9A3D);
static const navCenterEnd = Color(0xFFFF6A00);
static const navCenterShadow = Color(0x33FF7A1A);
/// 卡片轻阴影。
static const cardShadow = Color(0x14FF8A3D);
-2
View File
@@ -47,8 +47,6 @@ abstract final class AppDimens {
static const double navHeight = 64;
static const double navIcon = 20;
static const double navCenter = 56;
static const double navCenterIcon = 28;
static const double progressHeight = 3;
static const double progressRadius = 2;
static const double progressLineHeight = 3;
+4 -82
View File
@@ -26,37 +26,21 @@ class AppBottomNavItem {
final bool selected;
}
/// 底部导航中央操作按钮。
class AppBottomNavCenterAction {
const AppBottomNavCenterAction({
required this.label,
required this.onTap,
this.key = const Key('nav-center-action'),
});
final Key key;
final String label;
final VoidCallback onTap;
}
/// 全局五槽底部导航。
/// 四槽底部导航,仅做浅色暖橙视觉换肤。
class AppBottomNav extends StatelessWidget {
const AppBottomNav({
super.key,
required this.items,
this.centerAction,
this.backgroundColor = AppColors.bar,
this.barKey,
});
final List<AppBottomNavItem> items;
final AppBottomNavCenterAction? centerAction;
final Color backgroundColor;
final Key? barKey;
@override
Widget build(BuildContext context) {
final action = centerAction;
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
@@ -69,21 +53,9 @@ class AppBottomNav extends StatelessWidget {
color: backgroundColor.withValues(alpha: 0.95),
border: const Border(top: BorderSide(color: AppColors.border)),
),
child: action == null
? Row(
children: [
for (final item in items) _NavDestination(item: item),
],
)
: Row(
children: [
for (final item in items.take(2))
_NavDestination(item: item),
Expanded(child: _CenterDestination(action: action)),
for (final item in items.skip(2))
_NavDestination(item: item),
],
),
child: Row(
children: [for (final item in items) _NavDestination(item: item)],
),
),
),
),
@@ -143,53 +115,3 @@ class _NavDestination extends StatelessWidget {
),
);
}
class _CenterDestination extends StatelessWidget {
const _CenterDestination({required this.action});
final AppBottomNavCenterAction action;
@override
Widget build(BuildContext context) {
return Center(
child: Semantics(
button: true,
label: action.label,
child: Material(
color: Colors.transparent,
shape: const CircleBorder(),
clipBehavior: Clip.antiAlias,
child: Ink(
width: AppDimens.navCenter,
height: AppDimens.navCenter,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [AppColors.navCenterStart, AppColors.navCenterEnd],
),
boxShadow: [
BoxShadow(
color: AppColors.navCenterShadow,
blurRadius: 14,
offset: Offset(0, 5),
),
],
),
child: InkWell(
key: action.key,
customBorder: const CircleBorder(),
onTap: action.onTap,
child: const Icon(
Icons.add_rounded,
color: AppColors.onPrimary,
size: AppDimens.navCenterIcon,
),
),
),
),
),
);
}
}
-4
View File
@@ -340,10 +340,6 @@ class _DiscoverPageState extends State<DiscoverPage> {
}
Widget _bottomNav(AppLocalizations l10n) => AppBottomNav(
centerAction: AppBottomNavCenterAction(
label: l10n.createTab,
onTap: () => _act(DiscoverPageAction.create),
),
items: [
AppBottomNavItem(
tabKey: const Key('discover-nav-home'),
-4
View File
@@ -195,10 +195,6 @@ class _HomeTabsState extends State<_HomeTabs> {
Widget _nav(BuildContext context, AppLocalizations l10n) {
return AppBottomNav(
barKey: const Key('home-tabs-bar'),
centerAction: AppBottomNavCenterAction(
label: l10n.createTab,
onTap: () => _selectTab(context, 2),
),
items: [
_navItem(context, l10n, 0),
_navItem(context, l10n, 1),
-4
View File
@@ -242,10 +242,6 @@ class _MyPageState extends State<MyPage> {
Widget _bottomNav(AppLocalizations l10n) {
return AppBottomNav(
centerAction: AppBottomNavCenterAction(
label: l10n.createTab,
onTap: () => _act(MyPageAction.create),
),
items: [
AppBottomNavItem(
tabKey: const Key('mine-nav-home'),
+16 -27
View File
@@ -7,8 +7,10 @@ import 'package:fruitshorts/core/theme/app_dimens.dart';
import 'package:fruitshorts/core/widgets/app_bottom_nav.dart';
void main() {
testWidgets('should_render_five_slots_with_center_action', (tester) async {
var centerTaps = 0;
testWidgets('should_render_four_slots_with_orange_selected_state', (
tester,
) async {
var theaterTaps = 0;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
@@ -27,7 +29,7 @@ void main() {
icon: Icons.explore_outlined,
selectedIcon: Icons.explore_rounded,
label: 'Theater',
onTap: () {},
onTap: () => theaterTaps++,
),
AppBottomNavItem(
tabKey: const Key('tab-create'),
@@ -44,10 +46,6 @@ void main() {
onTap: () {},
),
],
centerAction: AppBottomNavCenterAction(
label: 'Create',
onTap: () => centerTaps++,
),
),
),
),
@@ -55,14 +53,13 @@ void main() {
expect(find.byKey(const Key('tab-home')), findsOneWidget);
expect(find.byKey(const Key('tab-theater')), findsOneWidget);
expect(find.byKey(const Key('nav-center-action')), findsOneWidget);
expect(find.byKey(const Key('tab-create')), findsOneWidget);
expect(find.byKey(const Key('tab-mine')), findsOneWidget);
expect(find.byKey(const Key('nav-center-action')), findsNothing);
expect(find.text('Home'), findsOneWidget);
final centers = [
Key('tab-home'),
Key('tab-theater'),
Key('nav-center-action'),
Key('tab-create'),
Key('tab-mine'),
].map((key) => tester.getCenter(find.byKey(key)).dx).toList();
@@ -72,25 +69,17 @@ void main() {
AppDimens.navHeight,
);
expect(
tester.getSize(find.byKey(const Key('nav-center-action'))),
const Size.square(AppDimens.navCenter),
);
final ink = tester.widget<Ink>(
find
.ancestor(
of: find.byKey(const Key('nav-center-action')),
matching: find.byType(Ink),
tester
.widget<Icon>(
find.descendant(
of: find.byKey(const Key('tab-home')),
matching: find.byIcon(Icons.movie_rounded),
),
)
.first,
.color,
AppColors.blue,
);
final decoration = ink.decoration! as BoxDecoration;
expect(decoration.shape, BoxShape.circle);
expect((decoration.gradient! as LinearGradient).colors, const [
AppColors.navCenterStart,
AppColors.navCenterEnd,
]);
await tester.tap(find.byKey(const Key('nav-center-action')));
expect(centerTaps, 1);
await tester.tap(find.byKey(const Key('tab-theater')));
expect(theaterTaps, 1);
});
}
-8
View File
@@ -20,7 +20,6 @@ const _keys = [
Key('home-tabs-bar'),
Key('tab-home'),
Key('tab-theater'),
Key('nav-center-action'),
Key('tab-create'),
Key('tab-mine'),
];
@@ -139,7 +138,6 @@ void main() {
expect(find.byKey(const Key('tab-home')), findsOneWidget);
expect(find.byKey(const Key('tab-theater')), findsOneWidget);
expect(find.byKey(const Key('nav-center-action')), findsOneWidget);
expect(find.byKey(const Key('tab-create')), findsOneWidget);
expect(find.byKey(const Key('tab-mine')), findsOneWidget);
expect(find.byKey(const Key('home-browse-page')), findsOneWidget);
@@ -148,12 +146,6 @@ void main() {
await tester.pumpAndSettle();
expect(find.byKey(const Key('home-all-dramas-grid')), findsOneWidget);
await tester.tap(find.byKey(const Key('nav-center-action')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('create-page')), findsOneWidget);
await tester.tap(find.byKey(const Key('tab-home')));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('tab-create')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('create-page')), findsOneWidget);
+1 -2
View File
@@ -33,9 +33,8 @@ void main() {
for (final key in _tabKeys) {
expect(find.byKey(key), findsOneWidget);
}
expect(find.byKey(const Key('nav-center-action')), findsOneWidget);
await tester.tap(find.byKey(const Key('nav-center-action')));
await tester.tap(find.byKey(const Key('tab-create')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('create-page')), findsOneWidget);
-1
View File
@@ -21,7 +21,6 @@ void main() {
expect(AppDimens.primaryButtonHeight, 52);
expect(AppDimens.tapTarget, 44);
expect(AppDimens.navHeight, 64);
expect(AppDimens.navCenter, 56);
expect(AppDimens.progressHeight, 3);
});
}