import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../../core/theme/app_color_scheme.dart'; import '../../../core/theme/app_spacing.dart'; import '../../../core/theme/app_theme.dart'; import '../../../providers/asset_provider.dart'; import '../../../providers/market_provider.dart'; import '../home/home_page.dart'; import '../market/market_page.dart'; import '../trade/trade_page.dart'; import '../asset/asset_page.dart'; import '../mine/mine_page.dart'; /// 底部导航项 class _NavItem { final String label; final IconData icon; const _NavItem({required this.label, required this.icon}); } /// 主页面 - "The Kinetic Vault" 设计风格 class MainPage extends StatefulWidget { const MainPage({super.key}); @override State createState() => MainPageState(); } class MainPageState extends State { int _currentIndex = 0; final Set _loadedPages = {0}; String? _tradeCoinCode; // 交易页面选中的币种代码 late final List _pages; // 防抖:记录上次刷新时间,同一 Tab 500ms 内不重复刷新 final Map _lastRefreshTime = {}; @override void initState() { super.initState(); _pages = [ const HomePage(), const MarketPage(), TradePage(initialCoinCode: _tradeCoinCode), const AssetPage(), const MinePage(), ]; } void _onTabChanged(int index) { final wasLoaded = _loadedPages.contains(index); setState(() { _currentIndex = index; _loadedPages.add(index); }); // 切换到已加载的 Tab 时刷新数据 if (wasLoaded) { _refreshTab(index); } } /// 刷新对应 Tab 的数据(带防抖) void _refreshTab(int index) { final now = DateTime.now(); final last = _lastRefreshTime[index]; if (last != null && now.difference(last).inMilliseconds < 500) return; _lastRefreshTime[index] = now; switch (index) { case 0: // 首页 - 刷新资产概览 context.read().loadOverview(force: true); break; case 1: // 行情 - 刷新币种列表 context.read().loadCoins(force: true); break; case 3: // 资产 - 刷新全部资产 context.read().refreshAll(force: true); break; } } /// 切换到交易页面并选中指定币种 void switchToTrade(String coinCode) { setState(() { _tradeCoinCode = coinCode; _currentIndex = 2; // 交易页面索引 _loadedPages.add(2); // 重新构建交易页面 _pages[2] = TradePage(initialCoinCode: _tradeCoinCode); }); } /// 切换到指定 tab void switchToTab(int index) { setState(() { _currentIndex = index; _loadedPages.add(index); }); } static const _navItems = [ _NavItem(label: '首页', icon: LucideIcons.house), _NavItem(label: '行情', icon: LucideIcons.trendingUp), _NavItem(label: '交易', icon: LucideIcons.arrowLeftRight), _NavItem(label: '资产', icon: LucideIcons.wallet), _NavItem(label: '我的', icon: LucideIcons.user), ]; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Scaffold( backgroundColor: colorScheme.background, body: LazyIndexedStack( index: _currentIndex, loadedIndexes: _loadedPages, children: _pages, ), bottomNavigationBar: _BottomNavBar( items: _navItems, currentIndex: _currentIndex, onTap: _onTabChanged, ), ); } } /// 底部导航栏 - 专业信任主题 class _BottomNavBar extends StatelessWidget { final List<_NavItem> items; final int currentIndex; final ValueChanged onTap; const _BottomNavBar({ required this.items, required this.currentIndex, required this.onTap, }); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; // Light: #FFFFFF, Dark: #0F172A final backgroundColor = isDark ? const Color(0xFF0F172A) : const Color(0xFFFFFFFF); return Container( decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.vertical(top: Radius.circular(AppRadius.xxl + AppSpacing.sm)), border: Border( top: BorderSide( color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.15), ), ), ), child: SafeArea( child: Padding( padding: EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.sm, AppSpacing.md, AppSpacing.lg), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: items.asMap().entries.map((entry) { return _NavItemWidget( item: entry.value, isSelected: entry.key == currentIndex, onTap: () => onTap(entry.key), ); }).toList(), ), ), ), ); } } /// 导航项组件 class _NavItemWidget extends StatelessWidget { final _NavItem item; final bool isSelected; final VoidCallback onTap; const _NavItemWidget({ required this.item, required this.isSelected, required this.onTap, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final color = isSelected ? colorScheme.primary : colorScheme.onSurfaceVariant; return GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: Padding( padding: EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: AppSpacing.sm), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( item.icon, color: color, size: 24, ), SizedBox(height: AppSpacing.xs), Text( item.label, style: AppTextStyles.bodyMedium(context).copyWith( color: color, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), ], ), ), ); } } /// 懒加载 IndexedStack - 只渲染已访问过的页面 class LazyIndexedStack extends StatefulWidget { final int index; final Set loadedIndexes; final List children; const LazyIndexedStack({ super.key, required this.index, required this.loadedIndexes, required this.children, }); @override State createState() => _LazyIndexedStackState(); } class _LazyIndexedStackState extends State { @override Widget build(BuildContext context) { return Stack( children: widget.children.asMap().entries.map((entry) { final isVisible = entry.key == widget.index; final isLoaded = widget.loadedIndexes.contains(entry.key); return Positioned.fill( child: Offstage( offstage: !isVisible, child: TickerMode( enabled: isVisible, child: isLoaded ? entry.value : const SizedBox.shrink(), ), ), ); }).toList(), ); } }