view.dart 22 KB

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