feat(ui): 重做三 Tab 首页与发现页

This commit is contained in:
Zhou Weidong committed 2026-10-19 15:01:45 +08:00
1 parent eae1c533ce
commit e8c1859e70
23 files changed
+1734 -432

No files matched your search

+43 -26
View File
@@ -1,5 +1,7 @@
// Author: fruit.com.cn
import 'dart:ui';
import 'package:flutter/material.dart';
import '../theme/app_colors.dart';
@@ -14,6 +16,7 @@ class AppBottomNavItem {
required this.label,
required this.onTap,
this.selected = false,
this.indicatorKey,
});
final Key tabKey;
@@ -22,9 +25,10 @@ class AppBottomNavItem {
final String label;
final VoidCallback onTap;
final bool selected;
final Key? indicatorKey;
}
/// Shared bottom navigation used by all root tabs and the player fallback.
/// Shared 3-tab navigation used by all root tabs and the player fallback.
class AppBottomNav extends StatelessWidget {
const AppBottomNav({
super.key,
@@ -38,20 +42,23 @@ class AppBottomNav extends StatelessWidget {
final Key? barKey;
@override
Widget build(BuildContext context) => SafeArea(
top: false,
child: Container(
key: barKey,
height: AppDimens.navHeight,
decoration: BoxDecoration(
color: backgroundColor,
border: const Border(
top: BorderSide(color: AppColors.outlineVariantDark),
Widget build(BuildContext context) => ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
child: SafeArea(
top: false,
child: Container(
key: barKey,
height: AppDimens.navHeight,
decoration: BoxDecoration(
color: backgroundColor.withValues(alpha: 0.95),
border: const Border(top: BorderSide(color: AppColors.border)),
),
child: Row(
children: [for (final item in items) _NavDestination(item: item)],
),
),
),
child: Row(
children: [for (final item in items) _NavDestination(item: item)],
),
),
);
}
@@ -71,28 +78,23 @@ class _NavDestination extends StatelessWidget {
key: item.tabKey,
onTap: item.onTap,
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: AppDimens.tapTarget),
constraints: const BoxConstraints(minHeight: 48),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
AnimatedScale(
duration: const Duration(milliseconds: 160),
curve: Curves.easeOut,
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 3,
),
decoration: BoxDecoration(
color: item.selected ? AppColors.blue : Colors.transparent,
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
),
scale: item.selected ? 1 : 0.96,
child: Icon(
item.selected ? item.selectedIcon : item.icon,
size: AppDimens.navIcon,
color: item.selected ? AppColors.onPrimary : AppColors.muted,
color: item.selected
? AppColors.blue
: Colors.white.withValues(alpha: 0.45),
),
),
const SizedBox(height: 2),
const SizedBox(height: 3),
Text(
item.label,
maxLines: 1,
@@ -100,7 +102,22 @@ class _NavDestination extends StatelessWidget {
style: TextStyle(
fontSize: AppDimens.navLabel,
fontWeight: item.selected ? FontWeight.w700 : FontWeight.w500,
color: item.selected ? AppColors.blueSoft : AppColors.muted,
color: item.selected
? AppColors.blue
: Colors.white.withValues(alpha: 0.45),
letterSpacing: 0,
),
),
const SizedBox(height: 3),
AnimatedContainer(
key: item.indicatorKey,
duration: const Duration(milliseconds: 160),
curve: Curves.easeOut,
width: AppDimens.navDot,
height: AppDimens.navDot,
decoration: BoxDecoration(
color: item.selected ? AppColors.blue : Colors.transparent,
shape: BoxShape.circle,
),
),
],