bottom_nav_shell.dart 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import 'package:go_router/go_router.dart';
  4. import '../../../core/l10n/app_localizations.dart';
  5. import '../../../providers/asset_provider.dart'
  6. show assetProvider, currentAssetSubTabProvider;
  7. import '../../../providers/auth_provider.dart';
  8. import '../../../providers/copy_trading_provider.dart';
  9. import '../../../providers/futures_provider.dart'
  10. show activeBottomTabProvider;
  11. import '../../../providers/home_provider.dart';
  12. import '../../../providers/my_copy_trading_provider.dart';
  13. /// 需要登录才能进入的 tab 索引集合(5=资产)
  14. const _authRequiredTabs = {5};
  15. /// 底部导航壳 — 首页 / 行情 / 交易 / 合约 / 跟单 / 资产
  16. class BottomNavShell extends ConsumerWidget {
  17. const BottomNavShell({super.key, required this.navigationShell});
  18. final StatefulNavigationShell navigationShell;
  19. @override
  20. Widget build(BuildContext context, WidgetRef ref) {
  21. final l10n = AppLocalizations.of(context)!;
  22. return Scaffold(
  23. body: navigationShell,
  24. bottomNavigationBar: BottomNavigationBar(
  25. currentIndex: navigationShell.currentIndex,
  26. onTap: (index) {
  27. // 需要登录的 tab:未登录时跳转登录页
  28. if (_authRequiredTabs.contains(index)) {
  29. final isLoggedIn = ref.read(isLoggedInProvider);
  30. if (!isLoggedIn) {
  31. context.push('/login');
  32. return;
  33. }
  34. }
  35. ref.read(activeBottomTabProvider.notifier).state = index;
  36. // 交易 tab:始终回到现货
  37. if (index == 2) {
  38. context.go('/spot/BTCUSDT');
  39. } else {
  40. // 先切换 tab,刷新操作延迟到下一帧执行,避免阻塞切换动画
  41. navigationShell.goBranch(
  42. index,
  43. initialLocation: index == navigationShell.currentIndex,
  44. );
  45. }
  46. // 延迟执行数据刷新,不阻塞 tab 切换的首帧渲染
  47. Future.microtask(() {
  48. if (index == 0) {
  49. ref.read(homeProvider.notifier).refreshAsset();
  50. }
  51. if (index == 4) {
  52. ref.read(copyTradingProvider.notifier).refresh();
  53. }
  54. if (index == 5) {
  55. final subTab = ref.read(currentAssetSubTabProvider);
  56. ref.read(assetProvider.notifier).silentRefresh();
  57. if (subTab == 4) {
  58. ref.read(myCopyTradingProvider.notifier).silentRefresh();
  59. } else if (subTab == 5) {
  60. ref.read(assetProvider.notifier).loadStakingOrders();
  61. }
  62. }
  63. });
  64. },
  65. items: [
  66. BottomNavigationBarItem(
  67. icon: const Icon(Icons.home_outlined),
  68. activeIcon: const Icon(Icons.home),
  69. label: l10n.home,
  70. ),
  71. BottomNavigationBarItem(
  72. icon: const Icon(Icons.bar_chart_outlined),
  73. activeIcon: const Icon(Icons.bar_chart),
  74. label: l10n.market,
  75. ),
  76. BottomNavigationBarItem(
  77. icon: const Icon(Icons.swap_horiz_outlined),
  78. activeIcon: const Icon(Icons.swap_horiz),
  79. label: l10n.bottomNavTrade,
  80. ),
  81. BottomNavigationBarItem(
  82. icon: const Icon(Icons.layers_outlined),
  83. activeIcon: const Icon(Icons.layers),
  84. label: l10n.futures,
  85. ),
  86. BottomNavigationBarItem(
  87. icon: const Icon(Icons.people_alt_outlined),
  88. activeIcon: const Icon(Icons.people_alt),
  89. label: l10n.copyTrading,
  90. ),
  91. BottomNavigationBarItem(
  92. icon: const Icon(Icons.account_balance_wallet_outlined),
  93. activeIcon: const Icon(Icons.account_balance_wallet),
  94. label: l10n.assets,
  95. ),
  96. ],
  97. ),
  98. );
  99. }
  100. }