import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/models/common/home_tab_type.dart'; import 'package:PiliPlus/pages/home/controller.dart'; import 'package:PiliPlus/pages/main/controller.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/utils/extension/get_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart'; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State createState() => _HomePageState(); } class _HomePageState extends State with AutomaticKeepAliveClientMixin { final _homeController = Get.putOrFind(HomeController.new); final _mainController = Get.find(); @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { super.build(context); final theme = Theme.of(context); return Column( children: [ if (MediaQuery.sizeOf(context).isPortrait) customAppBar(theme), Padding( padding: const EdgeInsets.only(top: 4), child: SizedBox( height: 42, width: double.infinity, child: TabBar( controller: _homeController.tabController, tabs: HomeTabType.values.map((e) => Tab(text: e.label)).toList(), isScrollable: true, dividerColor: Colors.transparent, dividerHeight: 0, splashBorderRadius: Style.mdRadius, tabAlignment: TabAlignment.center, onTap: (_) { if (!_homeController.tabController.indexIsChanging) { _homeController.animateToTop(); } }, ), ), ), Expanded( child: tabBarView( controller: _homeController.tabController, children: HomeTabType.values.map((e) => e.page).toList(), ), ), ], ); } Widget customAppBar(ThemeData theme) { const padding = EdgeInsets.fromLTRB(14, 6, 14, 0); final child = Row( children: [ searchBar(theme), const SizedBox(width: 4), msgBadge(_mainController), const SizedBox(width: 8), userAvatar(theme: theme, mainController: _mainController), ], ); return Container( height: Style.topBarHeight, padding: padding, child: child, ); } Widget searchBar(ThemeData theme) { const borderRadius = BorderRadius.all(Radius.circular(25)); return Expanded( child: SizedBox( height: 44, child: Material( borderRadius: borderRadius, color: theme.colorScheme.onSecondaryContainer.withValues(alpha: 0.05), child: InkWell( borderRadius: borderRadius, splashColor: theme.colorScheme.primaryContainer.withValues( alpha: 0.3, ), onTap: () => Get.toNamed('/search'), child: Align( alignment: .centerLeft, child: Padding( padding: const .only(left: 14), child: Icon( Icons.search_outlined, color: theme.colorScheme.onSecondaryContainer, semanticLabel: '搜索', ), ), ), ), ), ), ); } } Widget userAvatar({ required ThemeData theme, required MainController mainController, }) { return Semantics( label: "我的", child: Obx( () { if (mainController.accountService.isLogin.value) { return Stack( clipBehavior: .none, children: [ NetworkImgLayer( type: .avatar, width: 34, height: 34, src: mainController.accountService.face.value, ), Positioned.fill( child: Material( type: .transparency, child: InkWell( onTap: mainController.toMinePage, splashColor: theme.colorScheme.primaryContainer.withValues( alpha: 0.3, ), customBorder: const CircleBorder(), ), ), ), Positioned( right: -4, bottom: -4, child: Obx( () => MineController.anonymity.value ? IgnorePointer( child: Container( padding: const .all(2), decoration: BoxDecoration( shape: .circle, color: theme.colorScheme.secondaryContainer, ), child: Icon( size: 14, MdiIcons.incognito, color: theme.colorScheme.onSecondaryContainer, ), ), ) : const SizedBox.shrink(), ), ), ], ); } return SizedBox( width: 38, height: 38, child: IconButton( tooltip: '点击登录', style: IconButton.styleFrom( padding: .zero, backgroundColor: theme.colorScheme.onInverseSurface, ), onPressed: mainController.toMinePage, icon: Icon( Icons.person_rounded, size: 22, color: theme.colorScheme.primary, ), ), ); }, ), ); } Widget msgBadge(MainController mainController) { return Obx( () { if (mainController.accountService.isLogin.value || kDebugMode) { final count = mainController.msgUnReadCount.value; final isNumBadge = mainController.msgBadgeMode == .number; return IconButton( tooltip: '消息', onPressed: () { mainController ..msgUnReadCount.value = '' ..lastCheckUnreadAt = DateTime.now().millisecondsSinceEpoch; Get.toNamed('/whisper'); }, icon: Badge( isLabelVisible: mainController.msgBadgeMode != .hidden && count.isNotEmpty, alignment: isNumBadge ? const Alignment(0.0, -0.85) : const Alignment(1.0, -0.85), label: isNumBadge && count.isNotEmpty ? Text(count) : null, child: const Icon(Icons.notifications_none), ), ); } return const SizedBox.shrink(); }, ); }