import 'package:electronic_assistant/base/base_page.dart'; import 'package:electronic_assistant/module/store/view.dart'; import 'package:electronic_assistant/resource/assets.gen.dart'; import 'package:electronic_assistant/resource/colors.gen.dart'; import 'package:electronic_assistant/resource/string.gen.dart'; import 'package:electronic_assistant/utils/expand.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../../utils/fixed_size_tab_indicator.dart'; import 'controller.dart'; class HomePage extends BasePage { const HomePage({super.key}); @override Color backgroundColor() { return '#F6F5F8'.color; } @override double? pageHeight() { return double.infinity; } @override Widget buildBody(BuildContext context) { return Stack( children: [ buildBgBox(), Column( children: [ Obx(() { return Container( color: '#EBF0FE'.color.withOpacity(controller.topBgOpacity), child: Column( children: [ SizedBox(height: MediaQuery.of(context).padding.top), Container( padding: const EdgeInsets.all(12).w, child: buildOperationBar(), ) ], ), ); }), Expanded( child: DefaultTabController( length: controller.tabList.length, child: NestedScrollView( controller: controller.scrollController, headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ SliverToBoxAdapter(child: _buildHeaderView()), SliverPersistentHeader( floating: true, pinned: true, delegate: CommonSliverHeaderDelegate( backgroundColor: '#F6F5F8'.color, child: PreferredSize( preferredSize: const Size(double.infinity, 52), child: _buildTabBar()))), ]; }, body: _buildHomeTabView())), ), ], ), ], ); } Widget _buildTabBar() { return TabBar( padding: EdgeInsets.only(left: 12.w, bottom: 6.h), tabAlignment: TabAlignment.start, labelPadding: EdgeInsets.only(right: 32.w), isScrollable: true, indicator: FixedSizeTabIndicator( width: 11.w, height: 4.w, radius: 17, color: ColorName.colorPrimary), dividerHeight: 0, unselectedLabelStyle: TextStyle(fontSize: 16.sp, color: '#7C8191'.color), labelStyle: TextStyle( fontSize: 16.sp, color: ColorName.primaryTextColor, fontWeight: FontWeight.bold), tabs: controller.tabList.map((bean) => Tab(text: bean.title)).toList(), ); } Widget _buildHomeTabView() { return TabBarView(children: controller.tabList.map((e) => e.view).toList()); } @override bool immersive() { return true; } Widget _buildHeaderView() { return Container( padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 8.h, bottom: 8.h), child: getHomeHeadView( key: controller.headGuideKey, recordClick: () { controller.onRecordClick(); }, pickerAudioFileClick: () { controller.onPickerAudioFile(); }, ), ); } Row buildOperationBar() { return Row(children: [buildGoLogin(), const Spacer(), buildGoStore()]); } GestureDetector buildGoStore() { return GestureDetector( child: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: ['#FFD3A8'.color, '#FFEDE1'.color, '#FFDBC2'.color], stops: const [0, 0.5, 1.0], begin: Alignment.bottomLeft, end: Alignment.topRight, ), borderRadius: BorderRadius.circular(100), ), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).w, child: Text(StringName.homeChargeTxt.tr, style: TextStyle( height: 1, fontSize: 13.sp, color: '#773C23'.color, fontWeight: FontWeight.bold)), ), onTap: () { StorePage.start(fromType: StoreFromType.home); }); } Widget buildGoLogin() { return Obx(() { return GestureDetector( onTap: () { if (controller.isLogin) { controller.showLoginDrawer(); } else { controller.onLoginClick(); } }, child: Container( color: ColorName.transparent, child: Row( children: [ SizedBox( width: 36.w, height: 36.w, child: controller.isLogin ? Assets.images.iconHomeLogged.image() : Assets.images.iconHomeNoLogin.image()), SizedBox(width: 8.w), Text(controller.loginTxt, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15.sp, color: ColorName.primaryTextColor)), SizedBox(width: 6.w), controller.isLogin ? const SizedBox.shrink() : SizedBox( height: 16.w, child: Assets.images.iconGoLoginArrow.image()) ], ), ), ); }); } Widget buildBgBox() { return AspectRatio( aspectRatio: 360 / 188, child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: ['#CDD1FA'.color, '#FAFFFF'.color, '#F6F5F8'.color], ), ), ), ); } } Widget getHomeHeadView( {GlobalKey? key, VoidCallback? recordClick, VoidCallback? pickerAudioFileClick}) { return Row( key: key, children: [ Expanded( child: _buildHeaderCard( StringName.homeTalkAudio.tr, StringName.homeTalkQuickAudio.tr, Assets.images.iconHomeTalkRecordCard.image().image, [ "#1763F9".toColor(), "#28B2FF".toColor(), ], onTap: () { recordClick?.call(); }), ), SizedBox(width: 8.w), Expanded( child: _buildHeaderCard( StringName.homeTalkImportAudio.tr, StringName.homeTalkAnalyzeLocalAudio.tr, Assets.images.iconHomeTalkSelectCard.image().image, [ "#5869ED".toColor(), "#6E8AF7".toColor(), ], onTap: () { pickerAudioFileClick?.call(); }), ), ], ); } Widget _buildHeaderCard( String title, String content, ImageProvider imageProvider, List bgColor, { VoidCallback? onTap, }) { return GestureDetector( onTap: onTap, child: AspectRatio( aspectRatio: 164 / 80, child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: bgColor, ), borderRadius: BorderRadius.circular(12), ), child: Stack( children: [ Align( alignment: Alignment.centerRight, child: AspectRatio( aspectRatio: 1, child: SizedBox( height: double.infinity, child: Image(image: imageProvider)), ), ), Align( alignment: Alignment.centerLeft, child: IntrinsicHeight( child: Container( margin: EdgeInsets.only(left: 12.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle( fontSize: 16.sp, color: ColorName.white, fontWeight: FontWeight.bold)), SizedBox(height: 4.h), Text(content, style: TextStyle( fontSize: 12.sp, color: ColorName.white80)), ], ), ), ), ) ], ), ), ), ); } class CommonSliverHeaderDelegate extends SliverPersistentHeaderDelegate { PreferredSize child; //传入preferredsize组件,因为此组件需要固定高度 Color? backgroundColor; //需要设置的背景色 CommonSliverHeaderDelegate({required this.child, this.backgroundColor}); @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( color: backgroundColor, child: child, ); } @override double get maxExtent => child.preferredSize.height; @override double get minExtent => child.preferredSize.height; @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { return true; } }