view.dart 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import 'package:electronic_assistant/base/base_page.dart';
  2. import 'package:electronic_assistant/module/store/view.dart';
  3. import 'package:electronic_assistant/resource/assets.gen.dart';
  4. import 'package:electronic_assistant/resource/colors.gen.dart';
  5. import 'package:electronic_assistant/resource/string.gen.dart';
  6. import 'package:electronic_assistant/utils/expand.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. import '../../utils/fixed_size_tab_indicator.dart';
  11. import 'controller.dart';
  12. class HomePage extends BasePage<HomePageController> {
  13. const HomePage({super.key});
  14. @override
  15. Color backgroundColor() {
  16. return '#F6F5F8'.color;
  17. }
  18. @override
  19. double? pageHeight() {
  20. return double.infinity;
  21. }
  22. @override
  23. Widget buildBody(BuildContext context) {
  24. return Stack(
  25. children: [
  26. buildBgBox(),
  27. Column(
  28. children: [
  29. Obx(() {
  30. return Container(
  31. color: '#EBF0FE'.color.withOpacity(controller.topBgOpacity),
  32. child: Column(
  33. children: [
  34. SizedBox(height: MediaQuery.of(context).padding.top),
  35. Container(
  36. padding: const EdgeInsets.all(12).w,
  37. child: buildOperationBar(),
  38. )
  39. ],
  40. ),
  41. );
  42. }),
  43. Expanded(
  44. child: DefaultTabController(
  45. length: controller.tabList.length,
  46. child: NestedScrollView(
  47. controller: controller.scrollController,
  48. headerSliverBuilder:
  49. (BuildContext context, bool innerBoxIsScrolled) {
  50. return [
  51. SliverToBoxAdapter(child: _buildHeaderView()),
  52. SliverPersistentHeader(
  53. floating: true,
  54. pinned: true,
  55. delegate: CommonSliverHeaderDelegate(
  56. backgroundColor: '#F6F5F8'.color,
  57. child: PreferredSize(
  58. preferredSize:
  59. const Size(double.infinity, 52),
  60. child: _buildTabBar()))),
  61. ];
  62. },
  63. body: _buildHomeTabView())),
  64. ),
  65. ],
  66. ),
  67. ],
  68. );
  69. }
  70. Widget _buildTabBar() {
  71. return TabBar(
  72. padding: EdgeInsets.only(left: 12.w, bottom: 6.h),
  73. tabAlignment: TabAlignment.start,
  74. labelPadding: EdgeInsets.only(right: 32.w),
  75. isScrollable: true,
  76. indicator: FixedSizeTabIndicator(
  77. width: 11.w, height: 4.w, radius: 17, color: ColorName.colorPrimary),
  78. dividerHeight: 0,
  79. unselectedLabelStyle: TextStyle(fontSize: 16.sp, color: '#7C8191'.color),
  80. labelStyle: TextStyle(
  81. fontSize: 16.sp,
  82. color: ColorName.primaryTextColor,
  83. fontWeight: FontWeight.bold),
  84. tabs: controller.tabList.map((bean) => Tab(text: bean.title)).toList(),
  85. );
  86. }
  87. Widget _buildHomeTabView() {
  88. return TabBarView(children: controller.tabList.map((e) => e.view).toList());
  89. }
  90. @override
  91. bool immersive() {
  92. return true;
  93. }
  94. Widget _buildHeaderView() {
  95. return Container(
  96. padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 8.h, bottom: 8.h),
  97. child: getHomeHeadView(
  98. key: controller.headGuideKey,
  99. recordClick: () {
  100. controller.onRecordClick();
  101. },
  102. pickerAudioFileClick: () {
  103. controller.onPickerAudioFile();
  104. },
  105. ),
  106. );
  107. }
  108. Row buildOperationBar() {
  109. return Row(children: [buildGoLogin(), const Spacer(), buildGoStore()]);
  110. }
  111. GestureDetector buildGoStore() {
  112. return GestureDetector(
  113. child: Container(
  114. decoration: BoxDecoration(
  115. gradient: LinearGradient(
  116. colors: ['#FFD3A8'.color, '#FFEDE1'.color, '#FFDBC2'.color],
  117. stops: const [0, 0.5, 1.0],
  118. begin: Alignment.bottomLeft,
  119. end: Alignment.topRight,
  120. ),
  121. borderRadius: BorderRadius.circular(100),
  122. ),
  123. padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).w,
  124. child: Text(StringName.homeChargeTxt.tr,
  125. style: TextStyle(
  126. height: 1,
  127. fontSize: 13.sp,
  128. color: '#773C23'.color,
  129. fontWeight: FontWeight.bold)),
  130. ),
  131. onTap: () {
  132. StorePage.start(fromType: StoreFromType.home);
  133. });
  134. }
  135. Widget buildGoLogin() {
  136. return Obx(() {
  137. return GestureDetector(
  138. onTap: () {
  139. if (controller.isLogin) {
  140. controller.showLoginDrawer();
  141. } else {
  142. controller.onLoginClick();
  143. }
  144. },
  145. child: Container(
  146. color: ColorName.transparent,
  147. child: Row(
  148. children: [
  149. SizedBox(
  150. width: 36.w,
  151. height: 36.w,
  152. child: controller.isLogin
  153. ? Assets.images.iconHomeLogged.image()
  154. : Assets.images.iconHomeNoLogin.image()),
  155. SizedBox(width: 8.w),
  156. Text(controller.loginTxt,
  157. style: TextStyle(
  158. fontWeight: FontWeight.bold,
  159. fontSize: 15.sp,
  160. color: ColorName.primaryTextColor)),
  161. SizedBox(width: 6.w),
  162. controller.isLogin
  163. ? const SizedBox.shrink()
  164. : SizedBox(
  165. height: 16.w,
  166. child: Assets.images.iconGoLoginArrow.image())
  167. ],
  168. ),
  169. ),
  170. );
  171. });
  172. }
  173. Widget buildBgBox() {
  174. return AspectRatio(
  175. aspectRatio: 360 / 188,
  176. child: Container(
  177. decoration: BoxDecoration(
  178. gradient: LinearGradient(
  179. begin: Alignment.topCenter,
  180. end: Alignment.bottomCenter,
  181. colors: ['#CDD1FA'.color, '#FAFFFF'.color, '#F6F5F8'.color],
  182. ),
  183. ),
  184. ),
  185. );
  186. }
  187. }
  188. Widget getHomeHeadView(
  189. {GlobalKey? key,
  190. VoidCallback? recordClick,
  191. VoidCallback? pickerAudioFileClick}) {
  192. return Row(
  193. key: key,
  194. children: [
  195. Expanded(
  196. child: _buildHeaderCard(
  197. StringName.homeTalkAudio.tr,
  198. StringName.homeTalkQuickAudio.tr,
  199. Assets.images.iconHomeTalkRecordCard.image().image, [
  200. "#1763F9".toColor(),
  201. "#28B2FF".toColor(),
  202. ], onTap: () {
  203. recordClick?.call();
  204. }),
  205. ),
  206. SizedBox(width: 8.w),
  207. Expanded(
  208. child: _buildHeaderCard(
  209. StringName.homeTalkImportAudio.tr,
  210. StringName.homeTalkAnalyzeLocalAudio.tr,
  211. Assets.images.iconHomeTalkSelectCard.image().image, [
  212. "#5869ED".toColor(),
  213. "#6E8AF7".toColor(),
  214. ], onTap: () {
  215. pickerAudioFileClick?.call();
  216. }),
  217. ),
  218. ],
  219. );
  220. }
  221. Widget _buildHeaderCard(
  222. String title,
  223. String content,
  224. ImageProvider imageProvider,
  225. List<Color> bgColor, {
  226. VoidCallback? onTap,
  227. }) {
  228. return GestureDetector(
  229. onTap: onTap,
  230. child: AspectRatio(
  231. aspectRatio: 164 / 80,
  232. child: Container(
  233. decoration: BoxDecoration(
  234. gradient: LinearGradient(
  235. begin: Alignment.topLeft,
  236. end: Alignment.bottomRight,
  237. colors: bgColor,
  238. ),
  239. borderRadius: BorderRadius.circular(12),
  240. ),
  241. child: Stack(
  242. children: [
  243. Align(
  244. alignment: Alignment.centerRight,
  245. child: AspectRatio(
  246. aspectRatio: 1,
  247. child: SizedBox(
  248. height: double.infinity,
  249. child: Image(image: imageProvider)),
  250. ),
  251. ),
  252. Align(
  253. alignment: Alignment.centerLeft,
  254. child: IntrinsicHeight(
  255. child: Container(
  256. margin: EdgeInsets.only(left: 12.w),
  257. child: Column(
  258. crossAxisAlignment: CrossAxisAlignment.start,
  259. children: [
  260. Text(title,
  261. style: TextStyle(
  262. fontSize: 16.sp,
  263. color: ColorName.white,
  264. fontWeight: FontWeight.bold)),
  265. SizedBox(height: 4.h),
  266. Text(content,
  267. style: TextStyle(
  268. fontSize: 12.sp, color: ColorName.white80)),
  269. ],
  270. ),
  271. ),
  272. ),
  273. )
  274. ],
  275. ),
  276. ),
  277. ),
  278. );
  279. }
  280. class CommonSliverHeaderDelegate extends SliverPersistentHeaderDelegate {
  281. PreferredSize child; //传入preferredsize组件,因为此组件需要固定高度
  282. Color? backgroundColor; //需要设置的背景色
  283. CommonSliverHeaderDelegate({required this.child, this.backgroundColor});
  284. @override
  285. Widget build(
  286. BuildContext context, double shrinkOffset, bool overlapsContent) {
  287. return Container(
  288. color: backgroundColor,
  289. child: child,
  290. );
  291. }
  292. @override
  293. double get maxExtent => child.preferredSize.height;
  294. @override
  295. double get minExtent => child.preferredSize.height;
  296. @override
  297. bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
  298. return true;
  299. }
  300. }