view.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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. SafeArea(
  28. bottom: false,
  29. child: Column(
  30. children: [
  31. Container(
  32. width: 1.sw,
  33. padding: const EdgeInsets.all(12).w,
  34. child: buildOperationBar(),
  35. ),
  36. Expanded(
  37. child: DefaultTabController(
  38. length: controller.tabList.length,
  39. child: NestedScrollView(
  40. headerSliverBuilder:
  41. (BuildContext context, bool innerBoxIsScrolled) {
  42. return [
  43. SliverToBoxAdapter(child: _buildHeaderView()),
  44. SliverPersistentHeader(
  45. floating: true,
  46. pinned: true,
  47. delegate: CommonSliverHeaderDelegate(
  48. backgroundColor: '#F6F5F8'.color,
  49. child: PreferredSize(
  50. preferredSize:
  51. const Size(double.infinity, 52),
  52. child: _buildTabBar()))),
  53. ];
  54. },
  55. body: _buildHomeTabView())),
  56. ),
  57. ],
  58. ),
  59. ),
  60. ],
  61. );
  62. }
  63. Widget _buildTabBar() {
  64. return TabBar(
  65. padding: EdgeInsets.only(left: 12.w, bottom: 6.h),
  66. tabAlignment: TabAlignment.start,
  67. labelPadding: EdgeInsets.only(right: 32.w),
  68. isScrollable: true,
  69. indicator: FixedSizeTabIndicator(
  70. width: 11.w, height: 4.w, radius: 17, color: ColorName.colorPrimary),
  71. dividerHeight: 0,
  72. unselectedLabelStyle: TextStyle(fontSize: 16.sp, color: '#7C8191'.color),
  73. labelStyle: TextStyle(
  74. fontSize: 16.sp,
  75. color: ColorName.primaryTextColor,
  76. fontWeight: FontWeight.bold),
  77. tabs: controller.tabList.map((bean) => Tab(text: bean.title)).toList(),
  78. );
  79. }
  80. Widget _buildHomeTabView() {
  81. return TabBarView(children: controller.tabList.map((e) => e.view).toList());
  82. }
  83. @override
  84. bool immersive() {
  85. return true;
  86. }
  87. Widget _buildHeaderView() {
  88. return Container(
  89. padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 8.h, bottom: 8.h),
  90. child: getHomeHeadView(
  91. key: controller.headGuideKey,
  92. recordClick: () {
  93. controller.onRecordClick();
  94. },
  95. pickerAudioFileClick: () {
  96. controller.onPickerAudioFile();
  97. },
  98. ),
  99. );
  100. }
  101. // SliverToBoxAdapter buildSeeMoreView() {
  102. // return SliverToBoxAdapter(
  103. // child: Obx(() {
  104. // return Visibility(
  105. // visible: controller.agendaList.isNotEmpty,
  106. // child: Container(
  107. // alignment: Alignment.center,
  108. // padding: EdgeInsets.only(
  109. // top: 12.w, bottom: 56.w + Constants.bottomBarHeight),
  110. // child: RichText(
  111. // text: TextSpan(
  112. // text: StringName.homeTalkTodo1.tr,
  113. // style: TextStyle(
  114. // color: ColorName.secondaryTextColor, fontSize: 12.sp),
  115. // children: <TextSpan>[
  116. // TextSpan(
  117. // text: StringName.homeTalkTodo2.tr,
  118. // style: TextStyle(
  119. // color: ColorName.colorPrimary, fontSize: 12.sp),
  120. // recognizer: TapGestureRecognizer()
  121. // ..onTap = () {
  122. // controller.onGoAgendaList();
  123. // }),
  124. // ],
  125. // ),
  126. // ),
  127. // ),
  128. // );
  129. // }),
  130. // );
  131. // }
  132. // SliverToBoxAdapter buildTalkTodoTitle() {
  133. // return SliverToBoxAdapter(
  134. // child: Container(
  135. // decoration: BoxDecoration(
  136. // gradient: LinearGradient(
  137. // begin: Alignment.topCenter,
  138. // end: Alignment.bottomCenter,
  139. // colors: ["#FCFBFC".toColor(), "#F6F5F8".toColor()],
  140. // ),
  141. // ),
  142. // child: Column(
  143. // children: [
  144. // SizedBox(height: 12.w),
  145. // buildTitle(StringName.talkSummaryTodoTitle.tr, () {
  146. // controller.onGoAgendaList();
  147. // }),
  148. // SizedBox(height: 12.w)
  149. // ],
  150. // ),
  151. // ));
  152. // }
  153. //
  154. // SliverToBoxAdapter buildTalkRecordTitle() {
  155. // return SliverToBoxAdapter(
  156. // child: Container(
  157. // decoration: BoxDecoration(
  158. // gradient: LinearGradient(
  159. // begin: Alignment.topCenter,
  160. // end: Alignment.bottomCenter,
  161. // colors: [ColorName.white, "#FEFEFE".toColor()],
  162. // ),
  163. // ),
  164. // padding: const EdgeInsets.symmetric(vertical: 12).w,
  165. // child: buildTitle(StringName.homeTalkRecord.tr, () {
  166. // controller.goTalkRecordPage();
  167. // }),
  168. // ),
  169. // );
  170. // }
  171. Row buildOperationBar() {
  172. return Row(children: [buildGoLogin(), const Spacer(), buildGoStore()]);
  173. }
  174. GestureDetector buildGoStore() {
  175. return GestureDetector(
  176. child: Container(
  177. decoration: BoxDecoration(
  178. gradient: LinearGradient(
  179. colors: ['#FFD3A8'.color, '#FFEDE1'.color, '#FFDBC2'.color],
  180. stops: const [0, 0.5, 1.0],
  181. begin: Alignment.bottomLeft,
  182. end: Alignment.topRight,
  183. ),
  184. borderRadius: BorderRadius.circular(100),
  185. ),
  186. padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8).w,
  187. child: Text(StringName.homeChargeTxt.tr,
  188. style: TextStyle(
  189. height: 1,
  190. fontSize: 13.sp,
  191. color: '#773C23'.color,
  192. fontWeight: FontWeight.bold)),
  193. ),
  194. onTap: () {
  195. // accountRepository.logout();
  196. // ToastUtil.showToast('GoStore');
  197. StorePage.start(fromType: StoreFromType.home);
  198. });
  199. }
  200. Widget buildGoLogin() {
  201. return Obx(() {
  202. return GestureDetector(
  203. onTap: () {
  204. if (controller.isLogin) {
  205. controller.showLoginDrawer();
  206. } else {
  207. controller.onLoginClick();
  208. }
  209. },
  210. child: Container(
  211. color: ColorName.transparent,
  212. child: Row(
  213. children: [
  214. SizedBox(
  215. width: 36.w,
  216. height: 36.w,
  217. child: controller.isLogin
  218. ? Assets.images.iconHomeLogged.image()
  219. : Assets.images.iconHomeNoLogin.image()),
  220. SizedBox(width: 8.w),
  221. Text(controller.loginTxt,
  222. style: TextStyle(
  223. fontWeight: FontWeight.bold,
  224. fontSize: 15.sp,
  225. color: ColorName.primaryTextColor)),
  226. SizedBox(width: 6.w),
  227. controller.isLogin
  228. ? const SizedBox.shrink()
  229. : SizedBox(
  230. height: 16.w,
  231. child: Assets.images.iconGoLoginArrow.image())
  232. ],
  233. ),
  234. ),
  235. );
  236. });
  237. }
  238. Widget buildBgBox() {
  239. return AspectRatio(
  240. aspectRatio: 360 / 188,
  241. child: Container(
  242. decoration: BoxDecoration(
  243. gradient: LinearGradient(
  244. begin: Alignment.topCenter,
  245. end: Alignment.bottomCenter,
  246. colors: ['#CDD1FA'.color, '#FAFFFF'.color, '#F6F5F8'.color],
  247. ),
  248. ),
  249. ),
  250. );
  251. }
  252. // Widget buildTalkRecord() {
  253. // return SizedBox(
  254. // width: 1.sw,
  255. // child: CustomScrollView(
  256. // scrollDirection: Axis.horizontal,
  257. // slivers: [
  258. // SliverToBoxAdapter(child: SizedBox(width: 12.w)),
  259. // Obx(() {
  260. // return SliverList.builder(
  261. // itemBuilder: _builderTalkItem,
  262. // itemCount: controller.talkList.length >= 10
  263. // ? 10
  264. // : controller.talkList.length);
  265. // }),
  266. // ],
  267. // ),
  268. // );
  269. // }
  270. //
  271. // Widget _builderTalkItem(BuildContext context, int index) {
  272. // return Obx(() {
  273. // TalkBean? item = controller.talkList[index];
  274. // return _buildTalkView(item, onLongPressStart: (details) {
  275. // if (!accountRepository.isLogin.value) {
  276. // return;
  277. // }
  278. // showTalkPopup(details.globalPosition, Alignment.bottomRight,
  279. // onRename: () {
  280. // showRenameTalkDialog(item);
  281. // }, onDelete: () {
  282. // showDeleteTalkDialog(item);
  283. // });
  284. // }, onItemClick: () {
  285. // controller.onTalkItemClick(item);
  286. // });
  287. // });
  288. // }
  289. // Widget _builderAgendaItem(BuildContext context, int index) {
  290. // return Obx(() {
  291. // Agenda item = controller.agendaList[index];
  292. // return GestureDetector(
  293. // onTap: () {
  294. // controller.onAgendaItemClick(item);
  295. // },
  296. // child: taskItemView(
  297. // item,
  298. // onThinkingClick: () {
  299. // ChatPage.startByTalkId(
  300. // item.isExample == true
  301. // ? ChatFromType.fromTalkExample
  302. // : ChatFromType.fromAnalysisBtn,
  303. // item.talkId,
  304. // agenda: item);
  305. // },
  306. // onCheckClick: () {
  307. // controller.agendaComplete(item);
  308. // },
  309. // ),
  310. // );
  311. // });
  312. // }
  313. // SliverToBoxAdapter buildGoRecordView() {
  314. // return SliverToBoxAdapter(
  315. // child: GestureDetector(
  316. // onTap: () => Get.toNamed(RoutePath.record),
  317. // child: Container(
  318. // margin: EdgeInsets.only(right: 8.w),
  319. // decoration: BoxDecoration(
  320. // color: Colors.white,
  321. // border: Border.all(color: '#EBEBFF'.toColor(), width: 1),
  322. // borderRadius: BorderRadius.circular(8.0),
  323. // ),
  324. // child: SizedBox(
  325. // width: 100.w,
  326. // height: double.infinity,
  327. // child: Stack(
  328. // children: [
  329. // Positioned(
  330. // right: 0,
  331. // bottom: 0,
  332. // child: SizedBox(
  333. // width: 48.w,
  334. // child: Assets.images.bgHomeQuickAudio.image(),
  335. // ),
  336. // ),
  337. // Positioned.fill(
  338. // child: Align(
  339. // alignment: Alignment.center,
  340. // child: Column(
  341. // children: [
  342. // SizedBox(height: 20.h),
  343. // SizedBox(
  344. // width: 32.w,
  345. // height: 32.w,
  346. // child: Assets.images.iconAddTalk.image()),
  347. // SizedBox(height: 6.h),
  348. // Text(StringName.homeTalkAudio.tr,
  349. // style: TextStyle(
  350. // fontSize: 14.sp,
  351. // color: ColorName.colorPrimary,
  352. // fontWeight: FontWeight.bold)),
  353. // Builder(builder: (context) {
  354. // controller.todoTargetContext = context;
  355. // return Text(StringName.homeTalkQuickAudio.tr,
  356. // style: TextStyle(
  357. // fontSize: 10.sp,
  358. // color: ColorName.secondaryTextColor));
  359. // })
  360. // ],
  361. // ),
  362. // )),
  363. // ],
  364. // ),
  365. // ),
  366. // ),
  367. // ));
  368. // }
  369. // Widget _buildTalkView(TalkBean item,
  370. // {VoidCallback? onItemClick,
  371. // GestureLongPressStartCallback? onLongPressStart}) {
  372. // return GestureDetector(
  373. // onTap: onItemClick,
  374. // onLongPressStart: onLongPressStart,
  375. // child: Container(
  376. // width: 258.w,
  377. // margin: EdgeInsets.only(right: 8.w),
  378. // decoration: BoxDecoration(
  379. // color: Colors.white,
  380. // border: Border.all(color: '#F0F0F0'.toColor(), width: 2),
  381. // borderRadius: const BorderRadius.only(
  382. // topLeft: Radius.circular(12),
  383. // topRight: Radius.circular(24),
  384. // bottomRight: Radius.circular(12),
  385. // bottomLeft: Radius.circular(12)),
  386. // ),
  387. // padding: EdgeInsets.only(left: 10.w, right: 16.w),
  388. // child: Row(
  389. // crossAxisAlignment: CrossAxisAlignment.start,
  390. // children: [
  391. // Padding(
  392. // padding: const EdgeInsets.only(top: 14).h,
  393. // child: Stack(
  394. // children: [
  395. // SizedBox(
  396. // width: 35.w,
  397. // height: 40.w,
  398. // child: Assets.images.iconFilesFile.image()),
  399. // Visibility(
  400. // visible: item.isExample.isTrue,
  401. // child: Container(
  402. // margin: const EdgeInsets.only(top: 32).w,
  403. // decoration: BoxDecoration(
  404. // color: "#B2BAC4".toColor(),
  405. // borderRadius: BorderRadius.circular(4)),
  406. // padding: const EdgeInsets.symmetric(
  407. // horizontal: 5.5, vertical: 2)
  408. // .w,
  409. // child: Text(StringName.homeTalkExample.tr,
  410. // style: TextStyle(
  411. // height: 1,
  412. // fontSize: 12.sp,
  413. // color: ColorName.white)),
  414. // ),
  415. // ),
  416. // ],
  417. // ),
  418. // ),
  419. // SizedBox(width: 8.w),
  420. // Expanded(
  421. // child: Column(
  422. // mainAxisAlignment: MainAxisAlignment.center,
  423. // crossAxisAlignment: CrossAxisAlignment.start,
  424. // children: [
  425. // Text(item.title.value.orEmpty,
  426. // maxLines: 1,
  427. // overflow: TextOverflow.ellipsis,
  428. // style: TextStyle(
  429. // fontSize: 15.sp,
  430. // color: ColorName.primaryTextColor,
  431. // fontWeight: FontWeight.bold)),
  432. // SizedBox(height: 5.h),
  433. // Text(
  434. // item.summary.value.orEmpty,
  435. // style: TextStyle(
  436. // fontSize: 12.sp, color: ColorName.secondaryTextColor),
  437. // overflow: TextOverflow.ellipsis,
  438. // maxLines: 2,
  439. // ),
  440. // SizedBox(height: 8.h),
  441. // Row(
  442. // crossAxisAlignment: CrossAxisAlignment.center,
  443. // children: [
  444. // Text(item.duration.toFormattedDuration(),
  445. // style: TextStyle(
  446. // fontSize: 12.sp,
  447. // color: ColorName.tertiaryTextColor)),
  448. // SizedBox(width: 6.w),
  449. // Container(
  450. // width: 1,
  451. // height: 9,
  452. // color: ColorName.tertiaryTextColor),
  453. // SizedBox(width: 6.w),
  454. // Text(item.createTime.orEmpty,
  455. // style: TextStyle(
  456. // fontSize: 12.sp,
  457. // color: ColorName.tertiaryTextColor))
  458. // ],
  459. // )
  460. // ],
  461. // ),
  462. // )
  463. // ],
  464. // )),
  465. // );
  466. // }
  467. // Widget buildTitle(String titleName, VoidCallback? onTap) {
  468. // return Padding(
  469. // padding: const EdgeInsets.symmetric(horizontal: 12).w,
  470. // child: Row(
  471. // crossAxisAlignment: CrossAxisAlignment.center,
  472. // children: [
  473. // Text(titleName,
  474. // style: TextStyle(
  475. // fontWeight: FontWeight.bold,
  476. // fontSize: 17.sp,
  477. // color: ColorName.primaryTextColor)),
  478. // const Spacer(),
  479. // Visibility(
  480. // visible: onTap == null ? false : true,
  481. // child: GestureDetector(
  482. // onTap: onTap,
  483. // child: Padding(
  484. // padding: const EdgeInsets.symmetric(vertical: 6).w,
  485. // child: Row(
  486. // crossAxisAlignment: CrossAxisAlignment.center,
  487. // children: [
  488. // Text(
  489. // StringName.homeTalkSeeAll.tr,
  490. // style: TextStyle(
  491. // fontSize: 13.sp, color: ColorName.tertiaryTextColor),
  492. // ),
  493. // Container(
  494. // margin: const EdgeInsets.only(bottom: 1),
  495. // width: 16.w,
  496. // height: 16.w,
  497. // child: Assets.images.iconHomeTalkArrow.image()),
  498. // ],
  499. // ),
  500. // ),
  501. // ),
  502. // )
  503. // ],
  504. // ),
  505. // );
  506. // }
  507. }
  508. // Widget buildAgendaEmptyView(double top, {bool isVisible = true}) {
  509. // return Visibility(
  510. // visible: isVisible,
  511. // child: Container(
  512. // width: double.infinity,
  513. // padding: EdgeInsets.symmetric(vertical: top),
  514. // child: Column(
  515. // children: [
  516. // SizedBox(
  517. // width: 100.w,
  518. // height: 100.w,
  519. // child: Assets.images.iconNoTask.image()),
  520. // SizedBox(height: 4.h),
  521. // Text(StringName.agendaNoData.tr,
  522. // style: TextStyle(
  523. // color: ColorName.secondaryTextColor, fontSize: 14.sp)),
  524. // ],
  525. // ),
  526. // ),
  527. // );
  528. // }
  529. Widget getHomeHeadView(
  530. {GlobalKey? key,
  531. VoidCallback? recordClick,
  532. VoidCallback? pickerAudioFileClick}) {
  533. return Row(
  534. key: key,
  535. children: [
  536. Expanded(
  537. child: _buildHeaderCard(
  538. StringName.homeTalkAudio.tr,
  539. StringName.homeTalkQuickAudio.tr,
  540. Assets.images.iconHomeTalkRecordCard.image().image, [
  541. "#1763F9".toColor(),
  542. "#28B2FF".toColor(),
  543. ], onTap: () {
  544. recordClick?.call();
  545. }),
  546. ),
  547. SizedBox(width: 8.w),
  548. Expanded(
  549. child: _buildHeaderCard(
  550. StringName.homeTalkImportAudio.tr,
  551. StringName.homeTalkAnalyzeLocalAudio.tr,
  552. Assets.images.iconHomeTalkSelectCard.image().image, [
  553. "#5869ED".toColor(),
  554. "#6E8AF7".toColor(),
  555. ], onTap: () {
  556. pickerAudioFileClick?.call();
  557. }),
  558. ),
  559. ],
  560. );
  561. }
  562. Widget _buildHeaderCard(
  563. String title,
  564. String content,
  565. ImageProvider imageProvider,
  566. List<Color> bgColor, {
  567. VoidCallback? onTap,
  568. }) {
  569. return GestureDetector(
  570. onTap: onTap,
  571. child: AspectRatio(
  572. aspectRatio: 164 / 80,
  573. child: Container(
  574. decoration: BoxDecoration(
  575. gradient: LinearGradient(
  576. begin: Alignment.topLeft,
  577. end: Alignment.bottomRight,
  578. colors: bgColor,
  579. ),
  580. borderRadius: BorderRadius.circular(12),
  581. ),
  582. child: Stack(
  583. children: [
  584. Align(
  585. alignment: Alignment.centerRight,
  586. child: AspectRatio(
  587. aspectRatio: 1,
  588. child: SizedBox(
  589. height: double.infinity,
  590. child: Image(image: imageProvider)),
  591. ),
  592. ),
  593. Align(
  594. alignment: Alignment.centerLeft,
  595. child: IntrinsicHeight(
  596. child: Container(
  597. margin: EdgeInsets.only(left: 12.w),
  598. child: Column(
  599. crossAxisAlignment: CrossAxisAlignment.start,
  600. children: [
  601. Text(title,
  602. style: TextStyle(
  603. fontSize: 16.sp,
  604. color: ColorName.white,
  605. fontWeight: FontWeight.bold)),
  606. SizedBox(height: 4.h),
  607. Text(content,
  608. style: TextStyle(
  609. fontSize: 12.sp, color: ColorName.white80)),
  610. ],
  611. ),
  612. ),
  613. ),
  614. )
  615. ],
  616. ),
  617. ),
  618. ),
  619. );
  620. }
  621. class CommonSliverHeaderDelegate extends SliverPersistentHeaderDelegate {
  622. PreferredSize child; //传入preferredsize组件,因为此组件需要固定高度
  623. Color? backgroundColor; //需要设置的背景色
  624. CommonSliverHeaderDelegate({required this.child, this.backgroundColor});
  625. @override
  626. Widget build(
  627. BuildContext context, double shrinkOffset, bool overlapsContent) {
  628. return Container(
  629. color: backgroundColor,
  630. child: child,
  631. );
  632. }
  633. @override
  634. double get maxExtent => child.preferredSize.height;
  635. @override
  636. double get minExtent => child.preferredSize.height;
  637. @override
  638. bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
  639. return true;
  640. }
  641. }