import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:maibu_satabot_v2/features/main_container/presentation/cubit/tab_config_cubit.dart'; import 'package:maibu_satabot_v2/features/main_container/domain/tab_config.dart'; import 'package:maibu_satabot_v2/features/home/presentation/pages/home_page.dart'; import 'package:maibu_satabot_v2/features/v2/home/presentation/pages/home_v2_page.dart'; import 'package:maibu_satabot_v2/features/v2/home/presentation/bloc/home_v2_bloc.dart'; import 'package:maibu_satabot_v2/features/v2/device_list/presentation/pages/device_status_page.dart'; import 'package:maibu_satabot_v2/features/ai/presentation/pages/ai_page.dart'; import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/pages/alarm_center_page.dart'; import 'package:maibu_satabot_v2/features/v2/waring_center/presentation/bloc/alarm_cubit.dart'; import 'package:maibu_satabot_v2/features/my/presentation/pages/my_page.dart'; import 'package:maibu_satabot_v2/features/v2/my/presentation/pages/my_page.dart' as my_v2; import 'package:maibu_satabot_v2/features/v2/workorder/presentation/pages/workorder_page.dart'; import 'package:maibu_satabot_v2/features/v2/report/presentation/pages/report_page.dart'; import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/view/float_bar_widget.dart'; import 'package:maibu_satabot_v2/features/v2/device_list/presentation/float_bar/cubit/float_bar_setting_cubit.dart'; import 'package:maibu_satabot_v2/core/di/injection.dart'; import 'package:maibu_satabot_v2/core/theme/AppTheme.dart'; class MainWrapper extends StatefulWidget { const MainWrapper({super.key}); @override State createState() => _MainWrapperState(); } class _MainWrapperState extends State { int _currentIndex = 0; final PageController _pageController = PageController(); final List _tabKeys = []; double? _circleLeft; @override void initState() { super.initState(); // 🔥 确保 FloatBarSettingService 已初始化 GetIt.I(); WidgetsBinding.instance.addPostFrameCallback((_) { _updateCirclePosition(); }); } void _updateCirclePosition() { if (_tabKeys.isEmpty || _currentIndex >= _tabKeys.length) return; final key = _tabKeys[_currentIndex]; final renderBox = key.currentContext?.findRenderObject() as RenderBox?; if (renderBox != null) { setState(() { _circleLeft = renderBox.localToGlobal(Offset.zero).dx; }); } } @override void dispose() { _pageController.dispose(); super.dispose(); } void _onTabChanged(int index) { setState(() { _currentIndex = index; }); _pageController.jumpToPage(index); WidgetsBinding.instance.addPostFrameCallback((_) { _updateCirclePosition(); }); } IconData _getIconData(String iconName) { switch (iconName) { case 'home_rounded': return Icons.home_rounded; case 'grid_view_rounded': return Icons.grid_view_rounded; case 'devices_rounded': return Icons.devices_rounded; case 'auto_awesome_rounded': return Icons.auto_awesome_rounded; case 'warning_amber_rounded': return Icons.warning_amber_rounded; case 'assignment_rounded': return Icons.assignment_rounded; case 'post_add_rounded': return Icons.post_add_rounded; case 'person_rounded': return Icons.person_rounded; default: return Icons.home_rounded; } } double _getIndicatorPosition(int itemCount, int currentIndex) { final screenWidth = MediaQuery.of(context).size.width; final itemWidth = screenWidth / itemCount; return currentIndex * itemWidth; } double _getCircularLeftPosition(int itemCount, int currentIndex) { final screenWidth = MediaQuery.of(context).size.width; final itemWidth = screenWidth / itemCount; // 圆形应该在每个Tab项的中心 final tabCenterX = 12 + (currentIndex * itemWidth) + (itemWidth / 2); final circularLeft = tabCenterX - 22; // 22 = 44/2,让圆形中心对齐Tab中心 // 边界限制 final maxLeft = screenWidth - 12 - 44; return circularLeft.clamp(12.0, maxLeft); } Widget _buildCurrentPage(TabConfigItem tab) { switch (tab.id) { case 'home_v2': return BlocProvider( create: (_) => sl(), child: const HomeV2Page(), ); case 'home': return const HomePage(); case 'device': return const DeviceStatusPage(); case 'ai': return const AiPage(); case 'warning': return BlocProvider( create: (_) => sl(), child: const AlarmCenterPage(), ); case 'workorder': return const WorkOrderPage(); case 'report': return const ReportPage(); case 'my': return const MyPage(); case 'me': return const my_v2.MyPage(); default: return const HomePage(); } } @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { if (state is! TabConfigLoaded) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } final config = state.config; final enabledItems = config.enabledItems; if (enabledItems.isEmpty) { return const Scaffold(body: Center(child: Text('请至少启用一个 Tab'))); } if (_currentIndex >= enabledItems.length) { _currentIndex = 0; } // 初始化 GlobalKey if (_tabKeys.length != enabledItems.length) { _tabKeys.clear(); for (int i = 0; i < enabledItems.length; i++) { _tabKeys.add(GlobalKey()); } WidgetsBinding.instance.addPostFrameCallback((_) { _updateCirclePosition(); }); } return Scaffold( extendBody: false, body: Stack( children: [ PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), onPageChanged: (index) { setState(() { _currentIndex = index; }); }, children: enabledItems .map((tab) => _buildCurrentPage(tab)) .toList(), ), // 悬浮条 - 可拖动的悬浮按钮 ValueListenableBuilder( valueListenable: FloatBarSettingService.settingNotifier, builder: (context, isEnabled, child) { return Visibility( visible: isEnabled, child: const FloatBarWidget(), ); }, ), ], ), bottomNavigationBar: Container( decoration: BoxDecoration( color: context.appColors.cardBackground, ), child: SafeArea( top: false, child: LayoutBuilder( builder: (context, constraints) { return Container( margin: const EdgeInsets.symmetric( horizontal: 12, vertical: 16, ), padding: const EdgeInsets.symmetric(vertical: 2), decoration: BoxDecoration( color: context.appColors.cardBackground, borderRadius: BorderRadius.circular(25), border: Border.all( color: context.appColors.divider, width: 1, ), boxShadow: [ BoxShadow( color: context.appColors.cardShadow, blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Stack( children: [ // 滑动圆形背景 if (_circleLeft != null) AnimatedPositioned( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, left: _circleLeft! - 8, // 减去外层 margin + 向右偏移 top: 6, child: Container( width: 44, height: 44, decoration: BoxDecoration( color: context.appColors.divider, shape: BoxShape.circle, border: Border.all( color: context.appColors.divider, width: 1, ), ), ), ), // Tab 项 Row( children: enabledItems.asMap().entries.map((entry) { final index = entry.key; final item = entry.value; final isSelected = _currentIndex == index; return Expanded( key: _tabKeys[index], child: InkWell( onTap: () => _onTabChanged(index), child: SizedBox( height: 56, child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( _getIconData(item.icon), size: 24, color: isSelected ? context.appColors.textPrimary : context.appColors.textTertiary, ), const SizedBox(height: 4), Text( item.name, style: TextStyle( fontSize: 11, color: isSelected ? context.appColors.textPrimary : context.appColors.textTertiary, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, ), ), ], ), ), ), ); }).toList(), ), ], ), ); }, ), ), ), ); }, ); } }