import 'package:flutter/material.dart'; import 'package:patbond_flutter/analytics/analytics_page_name.dart'; import 'package:patbond_flutter/analytics/page_view_tracker.dart'; import 'package:patbond_flutter/core/theme/app_theme.dart'; import 'package:patbond_flutter/features/community/community_controller.dart'; import 'package:patbond_flutter/features/community/feed_analytics.dart'; import 'package:patbond_flutter/features/create/create_page.dart'; import 'package:patbond_flutter/features/home/home_page.dart'; import 'package:patbond_flutter/features/pets/health_record_analytics.dart'; import 'package:patbond_flutter/features/pets/pet_analytics.dart'; import 'package:patbond_flutter/features/pets/pets_controller.dart'; import 'package:patbond_flutter/features/pets/pets_page.dart'; import 'package:patbond_flutter/features/post/post_detail_page.dart'; import 'package:patbond_flutter/features/profile/profile_page.dart'; import 'package:patbond_flutter/features/services/services_page.dart'; import 'package:patbond_flutter/models/models.dart'; import 'package:patbond_flutter/state/app_state.dart'; import 'package:patbond_flutter/widgets/common.dart'; class MainShellPage extends StatefulWidget { const MainShellPage({ required this.appState, required this.petsController, required this.communityController, super.key, this.petAnalytics, this.healthRecordAnalytics, this.feedAnalytics, this.pageViewTracker, this.onLogout, }); final AppState appState; /// 宠物档案状态(T2-11 拆出的独立 pets feature;档案 Tab 数据源)。 final PetsController petsController; /// 社区状态(T3-12 数据层;首页 Feed segment 数据源,T3-14 接线)。 final CommunityController communityController; /// pet 域埋点强类型封装(建宠漏斗三事件)。 final PetAnalytics? petAnalytics; /// health_record 域埋点强类型封装(T2-13 创建漏斗三事件 + viewed)。 final HealthRecordAnalytics? healthRecordAnalytics; /// feed 域埋点(T3-14 聚合曝光 + 加载失败)。 final FeedAnalytics? feedAnalytics; /// Tab 曝光补点(IndexedStack 切换不产生路由事件,03 号评估 §3.2)。 final PageViewTracker? pageViewTracker; /// 退出登录:调 logout 接口并清会话,认证状态机自动回登录页。 final Future Function()? onLogout; @override State createState() => _MainShellPageState(); } class _MainShellPageState extends State { int currentIndex = 0; bool showPersonalServices = false; static const titles = ['首页', '创作中心', '健康档案', '本地服务', '我的资料']; /// Tab 索引 → pageName 枚举(03 号评估 §3.2 映射表;档案 Tab 自 T2-12 /// 起为真实宠物列表,页名由 pet_archive 改报 pet_list,06 §5.2 字典 v2)。 static const _tabPages = [ AnalyticsPageName.home, AnalyticsPageName.create, AnalyticsPageName.petList, AnalyticsPageName.services, AnalyticsPageName.profile, ]; @override void initState() { super.initState(); // 初始 Tab 曝光补一次(03 号评估 §3.2 手动补点 1)。 widget.pageViewTracker?.reportTab(_tabPages[currentIndex]); } void selectTab(int index) { setState(() => currentIndex = index); widget.pageViewTracker?.reportTab(_tabPages[index]); } void openServices(bool personal) { setState(() { showPersonalServices = personal; currentIndex = 3; }); widget.pageViewTracker?.reportTab(_tabPages[3]); } void openPost(PostModel post) { Navigator.of(context).push( MaterialPageRoute( settings: RouteSettings(name: AnalyticsPageName.postDetail.pageName), builder: (context) => PostDetailPage(appState: widget.appState, postId: post.id), ), ); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: widget.appState, builder: (context, _) { if (!widget.appState.isReady) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } final pages = [ HomePage( appState: widget.appState, communityController: widget.communityController, feedAnalytics: widget.feedAnalytics, isActive: currentIndex == 0, onOpenServices: openServices, onOpenCreate: () => selectTab(1), ), CreatePage( appState: widget.appState, onPublished: (post) { selectTab(0); WidgetsBinding.instance.addPostFrameCallback( (_) => openPost(post), ); }, ), PetsPage( controller: widget.petsController, analytics: widget.petAnalytics, healthAnalytics: widget.healthRecordAnalytics, ), ServicesPage( showPersonal: showPersonalServices, locationWeather: widget.appState.locationWeather, ), ProfilePage(appState: widget.appState, onLogout: widget.onLogout), ]; return Scaffold( appBar: AppBar( backgroundColor: Colors.white.withAlpha(245), surfaceTintColor: Colors.transparent, scrolledUnderElevation: 1, centerTitle: true, title: Text( titles[currentIndex], style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w800), ), leadingWidth: 118, leading: InkWell( onTap: () => selectTab(2), borderRadius: BorderRadius.circular(24), child: Padding( padding: const EdgeInsets.only(left: 14), child: Row( children: [ RemoteImage( url: widget.appState.pet.avatarUrl, width: 36, height: 36, borderRadius: BorderRadius.circular(18), ), const SizedBox(width: 7), const Expanded( child: Text( 'Patbond', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: AppColors.primary, fontSize: 13, fontWeight: FontWeight.w800, ), ), ), ], ), ), ), actions: [ IconButton.filledTonal( tooltip: '通知', onPressed: () { ScaffoldMessenger.of( context, ).showSnackBar(const SnackBar(content: Text('暂无新通知 🐾'))); }, icon: const Icon(Icons.notifications_outlined, size: 21), ), const SizedBox(width: 10), ], ), body: SafeArea( top: false, child: IndexedStack(index: currentIndex, children: pages), ), bottomNavigationBar: NavigationBar( selectedIndex: currentIndex, onDestinationSelected: selectTab, destinations: const [ NavigationDestination( icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home_rounded), label: '首页', ), NavigationDestination( icon: Icon(Icons.auto_awesome_outlined), selectedIcon: Icon(Icons.auto_awesome), label: '创作', ), NavigationDestination( icon: Icon(Icons.pets_outlined), selectedIcon: Icon(Icons.pets), label: '档案', ), NavigationDestination( icon: Icon(Icons.storefront_outlined), selectedIcon: Icon(Icons.storefront), label: '服务', ), NavigationDestination( icon: Icon(Icons.person_outline), selectedIcon: Icon(Icons.person), label: '我的', ), ], ), ); }, ); } }