view.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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 '../talk/view.dart';
  21. import '../task/task_item_view.dart';
  22. import 'controller.dart';
  23. class HomePage extends BasePage<HomePageController> {
  24. const HomePage({super.key});
  25. @override
  26. Widget buildBody(BuildContext context) {
  27. return Stack(
  28. children: [
  29. buildBgBox(),
  30. SafeArea(
  31. child: Column(
  32. children: [
  33. Container(
  34. width: 1.sw,
  35. padding: const EdgeInsets.all(12).w,
  36. child: buildOperationBar(),
  37. ),
  38. Expanded(
  39. child: Container(
  40. color: "#F6F5F8".toColor(),
  41. child: PullToRefresh(
  42. enableRefresh: true,
  43. controller: controller.refreshController,
  44. onRefresh: () {
  45. controller.requestHomeData();
  46. },
  47. child: CustomScrollView(
  48. slivers: [
  49. buildHeaderView(),
  50. buildTalkRecordTitle(),
  51. SliverToBoxAdapter(
  52. child: Container(
  53. decoration: BoxDecoration(
  54. gradient: LinearGradient(
  55. begin: Alignment.topCenter,
  56. end: Alignment.bottomCenter,
  57. colors: [
  58. "#FEFEFE".toColor(),
  59. "#FCFBFC".toColor()
  60. ],
  61. ),
  62. ),
  63. height: 0.3472222.sw,
  64. padding: EdgeInsets.only(bottom: 15.h),
  65. child: buildTalkRecord(),
  66. ),
  67. ),
  68. buildTalkTodoTitle(),
  69. Obx(() {
  70. return SliverList.builder(
  71. itemBuilder: _builderAgendaItem,
  72. itemCount: controller.agendaList.length >= 10
  73. ? 10
  74. : controller.agendaList.length);
  75. }),
  76. buildSeeMoreView(),
  77. ],
  78. ),
  79. ),
  80. ))
  81. ],
  82. ),
  83. )
  84. ],
  85. );
  86. }
  87. @override
  88. bool immersive() {
  89. return true;
  90. }
  91. Widget buildHeaderView() {
  92. return SliverToBoxAdapter(
  93. child: Container(
  94. decoration: BoxDecoration(
  95. gradient: LinearGradient(
  96. begin: Alignment.topCenter,
  97. end: Alignment.bottomCenter,
  98. colors: [ColorName.white, "#EEEFFB".toColor()],
  99. ),
  100. ),
  101. padding:
  102. EdgeInsets.only(left: 12.w, right: 12.w, top: 8.h, bottom: 16.h),
  103. child: Row(
  104. children: [
  105. Expanded(
  106. child: _buildHeaderCard(
  107. StringName.homeTalkAudio.tr,
  108. StringName.homeTalkQuickAudio.tr,
  109. Assets.images.iconHomeTalkRecordCard.image().image, [
  110. "#1763F9".toColor(),
  111. "#28B2FF".toColor(),
  112. ], onTap: () {
  113. Get.toNamed(RoutePath.record);
  114. }),
  115. ),
  116. SizedBox(width: 8.w),
  117. Expanded(
  118. child: _buildHeaderCard(
  119. StringName.homeTalkImportAudio.tr,
  120. StringName.homeTalkAnalyzeLocalAudio.tr,
  121. Assets.images.iconHomeTalkSelectCard.image().image,
  122. [
  123. "#5869ED".toColor(),
  124. "#6E8AF7".toColor(),
  125. ], onTap: () {
  126. controller.onPickerAudioFile();
  127. }),
  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: [buildGoLogin(), const Spacer(), buildGoStore()]);
  258. }
  259. GestureDetector buildGoStore() {
  260. return GestureDetector(
  261. child: DecoratedBox(
  262. decoration: BoxDecoration(
  263. color: "#F6F5F8".toColor(),
  264. borderRadius: BorderRadius.circular(16),
  265. ),
  266. child: Padding(
  267. padding:
  268. const EdgeInsets.symmetric(horizontal: 10, vertical: 5).w,
  269. child: Row(
  270. crossAxisAlignment: CrossAxisAlignment.center,
  271. children: [
  272. SizedBox(
  273. width: 20.w,
  274. height: 20.w,
  275. child: Assets.images.iconHomeCharge.image()),
  276. SizedBox(width: 2.w),
  277. Text(StringName.homeChargeTxt.tr,
  278. style: TextStyle(
  279. fontSize: 15.sp, color: ColorName.primaryTextColor)),
  280. ],
  281. ),
  282. )),
  283. onTap: () {
  284. // accountRepository.logout();
  285. // ToastUtil.showToast('GoStore');
  286. Get.toNamed(RoutePath.store);
  287. });
  288. }
  289. Widget buildGoLogin() {
  290. return Obx(() {
  291. return GestureDetector(
  292. onTap: () {
  293. if (controller.isLogin) {
  294. controller.showLoginDrawer();
  295. } else {
  296. Get.toNamed(RoutePath.login);
  297. }
  298. },
  299. child: Row(
  300. children: [
  301. SizedBox(
  302. width: 36.w,
  303. height: 36.w,
  304. child: controller.isLogin
  305. ? Assets.images.iconHomeLogged.image()
  306. : Assets.images.iconHomeNoLogin.image()),
  307. SizedBox(width: 8.w),
  308. Text(controller.loginTxt,
  309. style: TextStyle(
  310. fontWeight: FontWeight.bold,
  311. fontSize: 15.sp,
  312. color: ColorName.primaryTextColor)),
  313. SizedBox(width: 6.w),
  314. controller.isLogin
  315. ? const SizedBox.shrink()
  316. : SizedBox(
  317. height: 16.w, child: Assets.images.iconGoLoginArrow.image())
  318. ],
  319. ),
  320. );
  321. });
  322. }
  323. DecoratedBox buildBgBox() {
  324. return DecoratedBox(
  325. decoration: const BoxDecoration(color: ColorName.white),
  326. child: Container(
  327. height: double.infinity,
  328. ));
  329. }
  330. Widget buildTalkRecord() {
  331. return SizedBox(
  332. width: 1.sw,
  333. child: CustomScrollView(
  334. scrollDirection: Axis.horizontal,
  335. slivers: [
  336. SliverToBoxAdapter(child: SizedBox(width: 12.w)),
  337. Obx(() {
  338. return SliverList.builder(
  339. itemBuilder: _builderTalkItem,
  340. itemCount: controller.talkList.length >= 10
  341. ? 10
  342. : controller.talkList.length);
  343. }),
  344. ],
  345. ),
  346. );
  347. }
  348. Widget _builderTalkItem(BuildContext context, int index) {
  349. return Obx(() {
  350. TalkBean? item = controller.talkList[index];
  351. return _buildTalkView(item, onLongPressStart: (details) {
  352. if (!accountRepository.isLogin.value) {
  353. return;
  354. }
  355. showTalkPopup(details.globalPosition, Alignment.bottomRight,
  356. onRename: () {
  357. showRenameTalkDialog(item);
  358. }, onDelete: () {
  359. showDeleteTalkDialog(item);
  360. });
  361. }, onItemClick: () {
  362. TalkPage.start(item);
  363. });
  364. });
  365. }
  366. Widget _builderAgendaItem(BuildContext context, int index) {
  367. return Obx(() {
  368. Agenda item = controller.agendaList[index];
  369. return taskItemView(
  370. item,
  371. onThinkingClick: () {
  372. ChatPage.startByTalkId(item.talkId, agenda: item);
  373. },
  374. onCheckClick: () {
  375. controller.agendaComplete(item);
  376. },
  377. );
  378. });
  379. }
  380. SliverToBoxAdapter buildGoRecordView() {
  381. return SliverToBoxAdapter(
  382. child: GestureDetector(
  383. onTap: () => Get.toNamed(RoutePath.record),
  384. child: Container(
  385. margin: EdgeInsets.only(right: 8.w),
  386. decoration: BoxDecoration(
  387. color: Colors.white,
  388. border: Border.all(color: '#EBEBFF'.toColor(), width: 1),
  389. borderRadius: BorderRadius.circular(8.0),
  390. ),
  391. child: SizedBox(
  392. width: 100.w,
  393. height: double.infinity,
  394. child: Stack(
  395. children: [
  396. Positioned(
  397. right: 0,
  398. bottom: 0,
  399. child: SizedBox(
  400. width: 48.w,
  401. child: Assets.images.bgHomeQuickAudio.image(),
  402. ),
  403. ),
  404. Positioned.fill(
  405. child: Align(
  406. alignment: Alignment.center,
  407. child: Column(
  408. children: [
  409. SizedBox(height: 20.h),
  410. SizedBox(
  411. width: 32.w,
  412. height: 32.w,
  413. child: Assets.images.iconAddTalk.image()),
  414. SizedBox(height: 6.h),
  415. Text(StringName.homeTalkAudio.tr,
  416. style: TextStyle(
  417. fontSize: 14.sp,
  418. color: ColorName.colorPrimary,
  419. fontWeight: FontWeight.bold)),
  420. Builder(builder: (context) {
  421. controller.todoTargetContext = context;
  422. return Text(StringName.homeTalkQuickAudio.tr,
  423. style: TextStyle(
  424. fontSize: 10.sp,
  425. color: ColorName.secondaryTextColor));
  426. })
  427. ],
  428. ),
  429. )),
  430. ],
  431. ),
  432. ),
  433. ),
  434. ));
  435. }
  436. Widget _buildTalkView(TalkBean item,
  437. {VoidCallback? onItemClick,
  438. GestureLongPressStartCallback? onLongPressStart}) {
  439. return GestureDetector(
  440. onTap: onItemClick,
  441. onLongPressStart: onLongPressStart,
  442. child: Container(
  443. width: 258.w,
  444. margin: EdgeInsets.only(right: 8.w),
  445. decoration: BoxDecoration(
  446. color: Colors.white,
  447. border: Border.all(color: '#F0F0F0'.toColor(), width: 2),
  448. borderRadius: const BorderRadius.only(
  449. topLeft: Radius.circular(12),
  450. topRight: Radius.circular(24),
  451. bottomRight: Radius.circular(12),
  452. bottomLeft: Radius.circular(12)),
  453. ),
  454. padding: EdgeInsets.only(left: 10.w, right: 16.w),
  455. child: Row(
  456. crossAxisAlignment: CrossAxisAlignment.start,
  457. children: [
  458. Padding(
  459. padding: const EdgeInsets.only(top: 14).h,
  460. child: Stack(
  461. children: [
  462. SizedBox(
  463. width: 35.w,
  464. height: 40.w,
  465. child: Assets.images.iconFilesFile.image()),
  466. Visibility(
  467. visible: item.isExample.isTrue,
  468. child: Container(
  469. margin: const EdgeInsets.only(top: 32).w,
  470. decoration: BoxDecoration(
  471. color: "#B2BAC4".toColor(),
  472. borderRadius: BorderRadius.circular(4)),
  473. padding: const EdgeInsets.symmetric(
  474. horizontal: 5.5, vertical: 2)
  475. .w,
  476. child: Text(StringName.homeTalkExample.tr,
  477. style: TextStyle(
  478. height: 1,
  479. fontSize: 12.sp,
  480. color: ColorName.white)),
  481. ),
  482. ),
  483. ],
  484. ),
  485. ),
  486. SizedBox(width: 8.w),
  487. Expanded(
  488. child: Column(
  489. mainAxisAlignment: MainAxisAlignment.center,
  490. crossAxisAlignment: CrossAxisAlignment.start,
  491. children: [
  492. Row(
  493. children: [
  494. Text(item.title.value.orEmpty,
  495. maxLines: 1,
  496. overflow: TextOverflow.ellipsis,
  497. style: TextStyle(
  498. fontSize: 15.sp,
  499. color: ColorName.primaryTextColor,
  500. fontWeight: FontWeight.bold))
  501. ],
  502. ),
  503. SizedBox(height: 5.h),
  504. Text(
  505. item.summary.value.orEmpty,
  506. style: TextStyle(
  507. fontSize: 12.sp, color: ColorName.secondaryTextColor),
  508. overflow: TextOverflow.ellipsis,
  509. maxLines: 2,
  510. ),
  511. SizedBox(height: 8.h),
  512. Row(
  513. crossAxisAlignment: CrossAxisAlignment.center,
  514. children: [
  515. Text(item.duration.toFormattedDuration(),
  516. style: TextStyle(
  517. fontSize: 12.sp,
  518. color: ColorName.tertiaryTextColor)),
  519. SizedBox(width: 6.w),
  520. Container(
  521. width: 1,
  522. height: 9,
  523. color: ColorName.tertiaryTextColor),
  524. SizedBox(width: 6.w),
  525. Text(item.createTime.orEmpty,
  526. style: TextStyle(
  527. fontSize: 12.sp,
  528. color: ColorName.tertiaryTextColor))
  529. ],
  530. )
  531. ],
  532. ),
  533. )
  534. ],
  535. )),
  536. );
  537. }
  538. Widget buildTitle(String titleName, VoidCallback? onTap) {
  539. return Padding(
  540. padding: const EdgeInsets.symmetric(horizontal: 12).w,
  541. child: Row(
  542. crossAxisAlignment: CrossAxisAlignment.center,
  543. children: [
  544. Text(titleName,
  545. style: TextStyle(
  546. fontWeight: FontWeight.bold,
  547. fontSize: 17.sp,
  548. color: ColorName.primaryTextColor)),
  549. const Spacer(),
  550. Visibility(
  551. visible: onTap == null ? false : true,
  552. child: GestureDetector(
  553. onTap: onTap,
  554. child: Padding(
  555. padding: const EdgeInsets.symmetric(vertical: 6).w,
  556. child: Row(
  557. crossAxisAlignment: CrossAxisAlignment.center,
  558. children: [
  559. Text(
  560. StringName.homeTalkSeeAll.tr,
  561. style: TextStyle(
  562. fontSize: 13.sp, color: ColorName.tertiaryTextColor),
  563. ),
  564. Container(
  565. margin: const EdgeInsets.only(bottom: 1),
  566. width: 16.w,
  567. height: 16.w,
  568. child: Assets.images.iconHomeTalkArrow.image()),
  569. ],
  570. ),
  571. ),
  572. ),
  573. )
  574. ],
  575. ),
  576. );
  577. }
  578. void showUnfinishedRecordPopup() {
  579. SmartDialog.showAttach(
  580. targetContext: controller.todoTargetContext,
  581. alignment: Alignment.bottomRight,
  582. animationType: SmartAnimationType.fade,
  583. clickMaskDismiss: true,
  584. maskColor: Colors.transparent,
  585. bindPage: true,
  586. builder: (_) => Padding(
  587. padding: const EdgeInsets.only(top: 7).h,
  588. child: Stack(
  589. alignment: Alignment.topCenter,
  590. children: [
  591. SizedBox(
  592. width: 146.w,
  593. height: 66.w,
  594. child: Assets.images.bgAudioTodoPopup.image()),
  595. Container(
  596. alignment: Alignment.center,
  597. padding: const EdgeInsets.only(top: 17).w,
  598. width: 146.w,
  599. child: Text(StringName.homePopupTipsTxt.tr,
  600. style: TextStyle(fontSize: 14.sp, color: Colors.white)))
  601. ],
  602. ),
  603. ),
  604. );
  605. }
  606. void showRenameTalkDialog(TalkBean item) {
  607. reNameDialog(StringName.talkRenameTitle.tr, item.title.value,
  608. hintTxt: StringName.talkRenameTitleHint.tr,
  609. maxLength: 15, returnBuilder: (newName) {
  610. controller.requestName(newName, item);
  611. });
  612. }
  613. void showDeleteTalkDialog(TalkBean item) {
  614. talkDeleteDialog(item.id, item.title.value, returnBuilder: () {
  615. controller.requestDelete(item);
  616. });
  617. }
  618. }