bottom_nav_shell.dart 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. }
  60. }
  61. });
  62. },
  63. items: [
  64. BottomNavigationBarItem(
  65. icon: const Icon(Icons.home_outlined),
  66. activeIcon: const Icon(Icons.home),
  67. label: l10n.home,
  68. ),
  69. BottomNavigationBarItem(
  70. icon: const Icon(Icons.bar_chart_outlined),
  71. activeIcon: const Icon(Icons.bar_chart),
  72. label: l10n.market,
  73. ),
  74. BottomNavigationBarItem(
  75. icon: const Icon(Icons.swap_horiz_outlined),
  76. activeIcon: const Icon(Icons.swap_horiz),
  77. label: l10n.bottomNavTrade,
  78. ),
  79. BottomNavigationBarItem(
  80. icon: const Icon(Icons.layers_outlined),
  81. activeIcon: const Icon(Icons.layers),
  82. label: l10n.futures,
  83. ),
  84. BottomNavigationBarItem(
  85. icon: const Icon(Icons.people_alt_outlined),
  86. activeIcon: const Icon(Icons.people_alt),
  87. label: l10n.copyTrading,
  88. ),
  89. BottomNavigationBarItem(
  90. icon: const Icon(Icons.account_balance_wallet_outlined),
  91. activeIcon: const Icon(Icons.account_balance_wallet),
  92. label: l10n.assets,
  93. ),
  94. ],
  95. ),
  96. );
  97. }
  98. }