view.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. import 'package:electronic_assistant/base/base_page.dart';
  2. import 'package:electronic_assistant/data/bean/talks.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:electronic_assistant/utils/toast_util.dart';
  8. import 'package:electronic_assistant/widget/pull_to_refresh.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:flutter_screenutil/flutter_screenutil.dart';
  11. import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
  12. import 'package:get/get.dart';
  13. import '../../data/bean/agenda.dart';
  14. import '../../router/app_pages.dart';
  15. import '../task/task_item_view.dart';
  16. import 'controller.dart';
  17. class HomePage extends BasePage<HomePageController> {
  18. HomePage({super.key});
  19. BuildContext? todoTargetContext;
  20. @override
  21. Widget buildBody(BuildContext context) {
  22. return Stack(
  23. children: [
  24. buildBgBox(),
  25. buildTopGradient(),
  26. SafeArea(
  27. child: Column(
  28. children: [
  29. Container(
  30. width: 1.sw,
  31. padding: const EdgeInsets.all(12).w,
  32. child: buildOperationBar(),
  33. ),
  34. Expanded(
  35. child: PullToRefresh(
  36. enableRefresh: true,
  37. controller: controller.refreshController,
  38. onRefresh: () {
  39. controller.requestHomeData();
  40. },
  41. child: CustomScrollView(
  42. slivers: [
  43. buildTalkRecordTitle(),
  44. SliverToBoxAdapter(
  45. child: Container(
  46. height: 0.3111.sw,
  47. margin: EdgeInsets.only(bottom: 15.h),
  48. child: buildTalkRecord(),
  49. ),
  50. ),
  51. buildTalkTodoTitle(),
  52. SliverAnimatedList(
  53. key: controller.agendaList.listKey,
  54. itemBuilder: (context, index, animation) {
  55. return _buildInsertTodoItem(context, index, animation,
  56. controller.agendaList.items[index]);
  57. },
  58. initialItemCount: controller.agendaList.length),
  59. buildSeeMoreView(),
  60. ],
  61. ),
  62. ))
  63. ],
  64. ),
  65. )
  66. ],
  67. );
  68. }
  69. @override
  70. bool immersive() {
  71. return true;
  72. }
  73. SliverToBoxAdapter buildSeeMoreView() {
  74. return SliverToBoxAdapter(
  75. child: Container(
  76. alignment: Alignment.center,
  77. padding: const EdgeInsets.only(top: 12, bottom: 36).w,
  78. // child: RichText(
  79. // text: TextSpan(
  80. // text: StringName.homeTalkTodo1.tr,
  81. // style:
  82. // TextStyle(color: ColorName.secondaryTextColor, fontSize: 12.sp),
  83. // children: <TextSpan>[
  84. // TextSpan(
  85. // text: StringName.homeTalkTodo2.tr,
  86. // style:
  87. // TextStyle(color: ColorName.colorPrimary, fontSize: 12.sp),
  88. // recognizer: TapGestureRecognizer()
  89. // ..onTap = () {
  90. // ToastUtil.showToast('点击了全部');
  91. // }),
  92. // ],
  93. // ),
  94. // ),
  95. ),
  96. );
  97. }
  98. SliverToBoxAdapter buildTalkTodoTitle() {
  99. return SliverToBoxAdapter(
  100. child: Column(
  101. children: [
  102. SizedBox(height: 9.w),
  103. // buildTitle(StringName.homeTalkTodoTitle.tr, () {
  104. // Get.toNamed(RoutePath.task);
  105. // }),
  106. buildTitle(StringName.homeTalkTodoTitle.tr, null),
  107. SizedBox(height: 12.w)
  108. ],
  109. ));
  110. }
  111. SliverToBoxAdapter buildTalkRecordTitle() {
  112. return SliverToBoxAdapter(
  113. child: Column(
  114. children: [
  115. SizedBox(height: 7.w),
  116. buildTitle(StringName.homeTalkRecord.tr, () {
  117. controller.goTalkRecordPage();
  118. }),
  119. SizedBox(height: 12.w)
  120. ],
  121. ),
  122. );
  123. }
  124. Row buildOperationBar() {
  125. return Row(children: [buildGoLogin(), const Spacer(), buildGoStore()]);
  126. }
  127. GestureDetector buildGoStore() {
  128. return GestureDetector(
  129. child: DecoratedBox(
  130. decoration: BoxDecoration(
  131. color: Colors.white,
  132. borderRadius: BorderRadius.circular(16),
  133. ),
  134. child: Padding(
  135. padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2).w,
  136. child: Row(
  137. crossAxisAlignment: CrossAxisAlignment.center,
  138. children: [
  139. SizedBox(
  140. width: 28.w,
  141. height: 28.w,
  142. child: Assets.images.iconCharge.image()),
  143. SizedBox(width: 4.w),
  144. SizedBox(
  145. width: 28.w, child: Assets.images.iconChargeTxt.image()),
  146. SizedBox(
  147. width: 12.w,
  148. height: 12.w,
  149. child: Assets.images.iconChargeArrow.image()),
  150. ],
  151. ),
  152. )),
  153. onTap: () {
  154. ToastUtil.showToast('GoStore');
  155. });
  156. }
  157. Widget buildGoLogin() {
  158. return Obx(() {
  159. return GestureDetector(
  160. onTap: () {
  161. if (controller.isLogin) {
  162. controller.showLoginDrawer();
  163. } else {
  164. Get.toNamed(RoutePath.login);
  165. }
  166. },
  167. child: Row(
  168. children: [
  169. SizedBox(
  170. width: 36.w,
  171. height: 36.w,
  172. child: controller.isLogin
  173. ? Assets.images.iconHomeLogged.image()
  174. : Assets.images.iconHomeNoLogin.image()),
  175. SizedBox(width: 8.w),
  176. Text(controller.loginTxt,
  177. style: TextStyle(
  178. fontWeight: FontWeight.bold,
  179. fontSize: 15.sp,
  180. color: ColorName.primaryTextColor)),
  181. SizedBox(width: 6.w),
  182. controller.isLogin
  183. ? const SizedBox.shrink()
  184. : SizedBox(
  185. height: 16.w, child: Assets.images.iconGoLoginArrow.image())
  186. ],
  187. ),
  188. );
  189. });
  190. }
  191. Container buildTopGradient() {
  192. return Container(
  193. width: 1.sw,
  194. height: 112.h,
  195. decoration: BoxDecoration(
  196. gradient: LinearGradient(
  197. colors: ['#E8EBFF'.toColor(), '#00E8EBFF'.toColor()],
  198. begin: Alignment.topCenter,
  199. end: Alignment.bottomCenter,
  200. stops: const [0.3, 1.0],
  201. ),
  202. ) // 其他子小部件
  203. );
  204. }
  205. DecoratedBox buildBgBox() {
  206. return DecoratedBox(
  207. decoration: BoxDecoration(color: '#F6F6F6'.toColor()),
  208. child: Container(
  209. height: double.infinity,
  210. ));
  211. }
  212. Widget buildTalkRecord() {
  213. return SizedBox(
  214. width: 1.sw,
  215. child: CustomScrollView(
  216. scrollDirection: Axis.horizontal,
  217. slivers: [
  218. SliverToBoxAdapter(child: SizedBox(width: 12.w)),
  219. buildGoRecordView(),
  220. SliverAnimatedList(
  221. key: controller.taskList.listKey,
  222. itemBuilder: (context, index, animation) {
  223. return _buildInsertTalkItem(context, index, animation,
  224. controller.taskList.items[index]);
  225. },
  226. initialItemCount: controller.taskList.length),
  227. ],
  228. ),
  229. );
  230. }
  231. SliverToBoxAdapter buildGoRecordView() {
  232. return SliverToBoxAdapter(
  233. child: GestureDetector(
  234. onTap: () {
  235. showUnfinishedRecordPopup();
  236. },
  237. child: Container(
  238. margin: EdgeInsets.only(right: 8.w),
  239. decoration: BoxDecoration(
  240. color: Colors.white,
  241. border: Border.all(color: '#EBEBFF'.toColor(), width: 1),
  242. borderRadius: BorderRadius.circular(8.0),
  243. ),
  244. child: SizedBox(
  245. width: 100.w,
  246. height: double.infinity,
  247. child: Stack(
  248. children: [
  249. Positioned(
  250. right: 0,
  251. bottom: 0,
  252. child: SizedBox(
  253. width: 48.w,
  254. child: Assets.images.bgHomeQuickAudio.image(),
  255. ),
  256. ),
  257. Positioned.fill(
  258. child: Align(
  259. alignment: Alignment.center,
  260. child: Column(
  261. children: [
  262. SizedBox(height: 20.h),
  263. SizedBox(
  264. width: 32.w,
  265. height: 32.w,
  266. child: Assets.images.iconAddTalk.image()),
  267. SizedBox(height: 6.h),
  268. Text(StringName.homeTalkAudio.tr,
  269. style: TextStyle(
  270. fontSize: 14.sp,
  271. color: ColorName.colorPrimary,
  272. fontWeight: FontWeight.bold)),
  273. Builder(builder: (context) {
  274. todoTargetContext = context;
  275. return Text(StringName.homeTalkQuickAudio.tr,
  276. style: TextStyle(
  277. fontSize: 10.sp,
  278. color: ColorName.secondaryTextColor));
  279. })
  280. ],
  281. ),
  282. )),
  283. ],
  284. ),
  285. ),
  286. ),
  287. ));
  288. }
  289. Widget _buildInsertTalkItem(BuildContext context, int index,
  290. Animation<double> animation, TalkBean item) {
  291. return FadeTransition(
  292. opacity: animation,
  293. child: _buildTalkView(item),
  294. );
  295. }
  296. Widget _buildTalkView(TalkBean item) {
  297. return Container(
  298. width: 258.w,
  299. margin: EdgeInsets.only(right: 8.w),
  300. decoration: BoxDecoration(
  301. color: Colors.white,
  302. border: Border.all(color: '#F0F0F0'.toColor(), width: 1),
  303. borderRadius: BorderRadius.circular(8),
  304. ),
  305. height: double.infinity,
  306. padding: EdgeInsets.symmetric(horizontal: 12.w),
  307. child: Column(
  308. mainAxisAlignment: MainAxisAlignment.center,
  309. crossAxisAlignment: CrossAxisAlignment.start,
  310. children: [
  311. Row(
  312. children: [
  313. Visibility(
  314. visible: item.isExample.isTrue,
  315. child: Container(
  316. padding: const EdgeInsets.symmetric(horizontal: 6).w,
  317. decoration: BoxDecoration(
  318. color: '#DFE4FC'.toColor(),
  319. borderRadius: BorderRadius.circular(4),
  320. ),
  321. child: Text(
  322. StringName.homeTalkExample.tr,
  323. style: TextStyle(
  324. fontSize: 12.sp, color: ColorName.colorPrimary),
  325. )),
  326. ),
  327. SizedBox(width: 6.w),
  328. Text(item.title.orEmpty,
  329. maxLines: 1,
  330. overflow: TextOverflow.ellipsis,
  331. style: TextStyle(
  332. fontSize: 15.sp,
  333. color: ColorName.colorPrimary,
  334. fontWeight: FontWeight.bold))
  335. ],
  336. ),
  337. SizedBox(height: 5.h),
  338. Text(
  339. item.summary.orEmpty,
  340. style: TextStyle(
  341. fontSize: 12.sp, color: ColorName.secondaryTextColor),
  342. overflow: TextOverflow.ellipsis,
  343. maxLines: 2,
  344. ),
  345. SizedBox(height: 8.h),
  346. Row(
  347. crossAxisAlignment: CrossAxisAlignment.center,
  348. children: [
  349. Text(item.duration.toFormattedDuration(),
  350. style: TextStyle(
  351. fontSize: 12.sp, color: ColorName.tertiaryTextColor)),
  352. SizedBox(width: 6.w),
  353. Container(
  354. width: 1, height: 9, color: ColorName.tertiaryTextColor),
  355. SizedBox(width: 6.w),
  356. Text(item.createTime.orEmpty,
  357. style: TextStyle(
  358. fontSize: 12.sp, color: ColorName.tertiaryTextColor))
  359. ],
  360. )
  361. ],
  362. ));
  363. }
  364. Widget _buildInsertTodoItem(BuildContext context, int index,
  365. Animation<double> animation, Agenda item) {
  366. HomePageController controller = Get.find();
  367. return FadeTransition(
  368. opacity: animation,
  369. child: taskItemView(item, onCheckClick: () {
  370. controller.agendaList.remove(
  371. index,
  372. (context, animation, item) =>
  373. _buildRemoveTodoItem(context, index, animation, item));
  374. }),
  375. );
  376. }
  377. Widget _buildRemoveTodoItem(BuildContext context, int index,
  378. Animation<double> animation, Agenda item) {
  379. return SizeTransition(sizeFactor: animation, child: taskItemView(item));
  380. }
  381. Widget buildTitle(String titleName, VoidCallback? onTap) {
  382. return Padding(
  383. padding: const EdgeInsets.symmetric(horizontal: 12).w,
  384. child: Row(
  385. crossAxisAlignment: CrossAxisAlignment.center,
  386. children: [
  387. Text(titleName,
  388. style: TextStyle(
  389. fontWeight: FontWeight.bold,
  390. fontSize: 17.sp,
  391. color: ColorName.primaryTextColor)),
  392. const Spacer(),
  393. Visibility(
  394. visible: onTap == null ? false : true,
  395. child: GestureDetector(
  396. onTap: onTap,
  397. child: Padding(
  398. padding: const EdgeInsets.symmetric(vertical: 6).w,
  399. child: Row(
  400. crossAxisAlignment: CrossAxisAlignment.center,
  401. children: [
  402. Text(
  403. StringName.homeTalkSeeAll.tr,
  404. style: TextStyle(
  405. fontSize: 13.sp, color: ColorName.secondaryTextColor),
  406. ),
  407. SizedBox(
  408. width: 16.w,
  409. height: 16.w,
  410. child: Assets.images.iconHomeTalkArrow.image()),
  411. ],
  412. ),
  413. ),
  414. ),
  415. )
  416. ],
  417. ),
  418. );
  419. }
  420. attachDialog(BuildContext? context, Alignment alignment) {
  421. SmartDialog.showAttach(
  422. targetContext: context,
  423. alignment: alignment,
  424. animationType: SmartAnimationType.fade,
  425. clickMaskDismiss: true,
  426. maskColor: Colors.transparent,
  427. bindPage: true,
  428. builder: (_) => Padding(
  429. padding: const EdgeInsets.only(top: 7).h,
  430. child: Stack(
  431. alignment: Alignment.topCenter,
  432. children: [
  433. SizedBox(
  434. width: 146.w,
  435. height: 66.w,
  436. child: Assets.images.bgAudioTodoPopup.image()),
  437. Container(
  438. alignment: Alignment.center,
  439. padding: const EdgeInsets.only(top: 17).w,
  440. width: 146.w,
  441. child: Text(StringName.homePopupTipsTxt.tr,
  442. style: TextStyle(fontSize: 14.sp, color: Colors.white)))
  443. ],
  444. ),
  445. ),
  446. );
  447. }
  448. void showUnfinishedRecordPopup() {
  449. attachDialog(todoTargetContext, Alignment.bottomRight);
  450. }
  451. }