intimacy_analyse_report_widget.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:keyboard/resource/string.gen.dart';
  4. import 'package:lottie/lottie.dart';
  5. import '../../../resource/assets.gen.dart';
  6. import '../../../resource/colors.gen.dart';
  7. import '../../../widget/animated_progress_bar.dart';
  8. import '../../../widget/markdown/markdown_viewer.dart';
  9. /// 亲密度报告组件
  10. class IntimacyAnalyseReportWidget extends StatelessWidget {
  11. /// 报告内容
  12. final String reportContent;
  13. /// 是否已解锁
  14. final bool unlock;
  15. /// 是否是预览
  16. final bool isPreview;
  17. const IntimacyAnalyseReportWidget({
  18. super.key,
  19. required this.reportContent,
  20. this.unlock = false,
  21. this.isPreview = false,
  22. });
  23. @override
  24. Widget build(BuildContext context) {
  25. if (isPreview) {
  26. return PreviewReportCardWidget(
  27. previewReportContent: reportContent,
  28. );
  29. }
  30. // 未解锁
  31. if (!unlock) {
  32. return UnlockReportCardWidget();
  33. }
  34. return reportContent.isEmpty
  35. // 报告生成中
  36. ? CreatingReportCardWidget()
  37. // 已出报告
  38. : ExistReportCardWidget(reportContent: reportContent);
  39. }
  40. }
  41. /// 预览报告卡片
  42. class PreviewReportCardWidget extends StatelessWidget {
  43. final String previewReportContent;
  44. const PreviewReportCardWidget({
  45. super.key,
  46. required this.previewReportContent,
  47. });
  48. @override
  49. Widget build(BuildContext context) {
  50. return ReportCardFrameWidget(
  51. child: Column(
  52. mainAxisSize: MainAxisSize.min,
  53. children: [
  54. SizedBox(height: 10.h),
  55. Container(
  56. decoration: ShapeDecoration(
  57. color: ColorName.white,
  58. shape: RoundedRectangleBorder(
  59. borderRadius: BorderRadius.circular(30.r),
  60. ),
  61. ),
  62. child: MarkdownViewer(
  63. // 内容
  64. content: previewReportContent,
  65. // 不允许滚动
  66. enableContentScroll: false,
  67. ),
  68. ),
  69. ],
  70. ),
  71. );
  72. }
  73. }
  74. /// 已有报告组件
  75. class ExistReportCardWidget extends StatelessWidget {
  76. /// 报告内容,Markdown格式
  77. final String reportContent;
  78. const ExistReportCardWidget({super.key, required this.reportContent});
  79. @override
  80. Widget build(BuildContext context) {
  81. return ReportCardFrameWidget(
  82. child: Column(
  83. mainAxisSize: MainAxisSize.min,
  84. children: [
  85. _buildReportOverview(),
  86. SizedBox(height: 10.h),
  87. _buildReportDetail(),
  88. ],
  89. ),
  90. );
  91. }
  92. /// 报告概览,包含概览数值和图表
  93. Widget _buildReportOverview() {
  94. // 圆角背景
  95. return Container(
  96. padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 12.h),
  97. decoration: BoxDecoration(
  98. color: ColorName.white,
  99. borderRadius: BorderRadius.circular(20.r),
  100. ),
  101. child: Column(
  102. mainAxisSize: MainAxisSize.min,
  103. children: [
  104. // 概览数值
  105. Container(
  106. padding: EdgeInsets.symmetric(horizontal: 18.w),
  107. decoration: BoxDecoration(
  108. color: ColorName.bgReportOverview,
  109. borderRadius: BorderRadius.all(Radius.circular(10.r)),
  110. ),
  111. child: Row(
  112. children: [
  113. _buildIntimacyOverviewItem("30"),
  114. _buildOverviewDivider(),
  115. _buildCurrentStageOverviewItem("相互了解"),
  116. ],
  117. ),
  118. ),
  119. SizedBox(height: 36.h),
  120. // 图表
  121. _buildChart(),
  122. ],
  123. ),
  124. );
  125. }
  126. /// 概览数值的分割线
  127. Widget _buildOverviewDivider() {
  128. return Container(
  129. height: 44.h,
  130. width: 1.w,
  131. decoration: BoxDecoration(color: ColorName.black5),
  132. margin: EdgeInsets.symmetric(vertical: 10.h),
  133. );
  134. }
  135. /// 概览亲密度的数值项
  136. Widget _buildIntimacyOverviewItem(String value) {
  137. return Expanded(
  138. child: Row(
  139. // 左对齐
  140. mainAxisAlignment: MainAxisAlignment.start,
  141. children: [
  142. // 图表
  143. Assets.images.iconIntimacyAnalyseReportOverviewLove.image(
  144. height: 22.w,
  145. width: 22.w,
  146. ),
  147. SizedBox(width: 14.w),
  148. Column(
  149. crossAxisAlignment: CrossAxisAlignment.start,
  150. children: [
  151. // 数值区域
  152. Row(
  153. children: [
  154. // 数值
  155. Text(
  156. value,
  157. style: TextStyle(
  158. color: ColorName.black80,
  159. fontSize: 20.sp,
  160. fontWeight: FontWeight.w700,
  161. ),
  162. ),
  163. SizedBox(width: 2.w),
  164. // 百分比符号
  165. Text(
  166. StringName.intimacyValuePercent,
  167. style: TextStyle(
  168. color: ColorName.black46,
  169. fontSize: 13.sp,
  170. fontWeight: FontWeight.w700,
  171. ),
  172. ),
  173. ],
  174. ),
  175. // 描述
  176. Text(
  177. StringName.intimacyValue,
  178. style: TextStyle(
  179. color: ColorName.textReportOverviewValueDesc,
  180. fontSize: 12.sp,
  181. fontWeight: FontWeight.w400,
  182. ),
  183. ),
  184. ],
  185. ),
  186. ],
  187. ),
  188. );
  189. }
  190. /// 概览目前阶段的数值项
  191. Widget _buildCurrentStageOverviewItem(String value) {
  192. return Expanded(
  193. child: Row(
  194. // 右对齐
  195. mainAxisAlignment: MainAxisAlignment.end,
  196. children: [
  197. // 图标
  198. Assets.images.iconIntimacyAnalyseReportOverviewStage.image(
  199. height: 22.w,
  200. width: 22.w,
  201. ),
  202. SizedBox(width: 14.w),
  203. Column(
  204. crossAxisAlignment: CrossAxisAlignment.start,
  205. children: [
  206. // 数值
  207. Text(
  208. value,
  209. style: TextStyle(
  210. color: ColorName.black80,
  211. fontSize: 14.sp,
  212. fontWeight: FontWeight.w700,
  213. ),
  214. ),
  215. // 描述
  216. Text(
  217. StringName.intimacyCurrentStage,
  218. style: TextStyle(
  219. color: ColorName.textReportOverviewValueDesc,
  220. fontSize: 12.sp,
  221. fontWeight: FontWeight.w400,
  222. ),
  223. ),
  224. ],
  225. ),
  226. ],
  227. ),
  228. );
  229. }
  230. /// 报告图表
  231. Widget _buildChart() {
  232. return Column(
  233. mainAxisSize: MainAxisSize.min,
  234. children: [
  235. _buildValueItem(
  236. iconProvider: Assets.images.iconEmojiLike.provider(),
  237. title: "互动好感度",
  238. value: 0.5,
  239. progressColors: [ColorName.blueGradient1, ColorName.blueGradient2],
  240. ),
  241. SizedBox(height: 18.h),
  242. _buildValueItem(
  243. iconProvider: Assets.images.iconEmojiChat.provider(),
  244. title: "话题好感度",
  245. value: 0.35,
  246. progressColors: [ColorName.greenGradient1, ColorName.greenGradient2],
  247. ),
  248. SizedBox(height: 18.h),
  249. _buildValueItem(
  250. iconProvider: Assets.images.iconEmojiLike.provider(),
  251. title: "情绪回应",
  252. value: 1.0,
  253. progressColors: [
  254. ColorName.yellowGradient1,
  255. ColorName.yellowGradient2,
  256. ],
  257. ),
  258. SizedBox(height: 18.h),
  259. _buildValueItem(
  260. iconProvider: Assets.images.iconEmojiPercent.provider(),
  261. title: "亲密词占比",
  262. value: 0.4,
  263. progressColors: [ColorName.pinkGradient1, ColorName.pinkGradient2],
  264. ),
  265. SizedBox(height: 18.h),
  266. _buildValueItem(
  267. iconProvider: Assets.images.iconEmojiLove.provider(),
  268. title: "缘分指数",
  269. value: 0.15,
  270. progressColors: [
  271. ColorName.purpleGradient1,
  272. ColorName.purpleGradient2,
  273. ],
  274. ),
  275. SizedBox(height: 12, width: double.infinity),
  276. ],
  277. );
  278. }
  279. /// 构建数值Item
  280. /// [iconProvider] icon图标的ImageProvider
  281. /// [title] 标题
  282. /// [progressColors] 进度条渐变色
  283. /// [value] 进度条的数值,从0到1.0
  284. Widget _buildValueItem({
  285. required ImageProvider iconProvider,
  286. required String title,
  287. required List<Color> progressColors,
  288. required double value,
  289. }) {
  290. return Row(
  291. mainAxisSize: MainAxisSize.min,
  292. crossAxisAlignment: CrossAxisAlignment.center,
  293. children: [
  294. // 图标
  295. Container(
  296. padding: EdgeInsets.all(6.w),
  297. decoration: BoxDecoration(
  298. // 圆形背景
  299. shape: BoxShape.circle,
  300. color: ColorName.bgReportValueIcon,
  301. ),
  302. child: ClipOval(
  303. child: Image(
  304. image: iconProvider,
  305. width: 15.w,
  306. height: 15.w,
  307. fit: BoxFit.fill,
  308. ),
  309. ),
  310. ),
  311. SizedBox(width: 5.w),
  312. // 文字
  313. Text(title),
  314. SizedBox(width: 10.w),
  315. // 进度条
  316. Expanded(
  317. child: AnimatedGradientProgressBar(
  318. // 进度值
  319. targetValue: value,
  320. // 渐变色
  321. gradient: LinearGradient(colors: progressColors),
  322. // 动画时长
  323. duration: const Duration(milliseconds: 1500),
  324. ),
  325. ),
  326. ],
  327. );
  328. }
  329. /// 报告详情
  330. Widget _buildReportDetail() {
  331. return Container(
  332. decoration: ShapeDecoration(
  333. color: ColorName.white,
  334. shape: RoundedRectangleBorder(
  335. borderRadius: BorderRadius.circular(30.r),
  336. ),
  337. ),
  338. child: MarkdownViewer(
  339. // 内容
  340. content: reportContent,
  341. // 不允许滚动
  342. enableContentScroll: false,
  343. ),
  344. );
  345. }
  346. }
  347. /// 报告生成中的卡片
  348. class CreatingReportCardWidget extends StatelessWidget {
  349. const CreatingReportCardWidget({super.key});
  350. @override
  351. Widget build(BuildContext context) {
  352. return ReportCardFrameWidget(
  353. child: Container(
  354. padding: EdgeInsets.only(top: 33.h, bottom: 52.h),
  355. decoration: ShapeDecoration(
  356. color: ColorName.white,
  357. shape: RoundedRectangleBorder(
  358. borderRadius: BorderRadius.circular(30.r),
  359. ),
  360. ),
  361. child: Center(
  362. child: Column(
  363. // 垂直水平都居中
  364. mainAxisAlignment: MainAxisAlignment.center,
  365. crossAxisAlignment: CrossAxisAlignment.center,
  366. children: [
  367. // 图标
  368. Lottie.asset(
  369. Assets.anim.animIntimacyAnalyseCreatingReportData,
  370. repeat: true,
  371. width: 82.w,
  372. height: 82.w,
  373. ),
  374. SizedBox(height: 3.h),
  375. // 文字
  376. Text(
  377. StringName.intimacyAnalyseReportCreating,
  378. style: TextStyle(
  379. fontSize: 14.sp,
  380. color: ColorName.black60,
  381. fontWeight: FontWeight.w400,
  382. ),
  383. ),
  384. ],
  385. ),
  386. ),
  387. ),
  388. );
  389. }
  390. }
  391. /// 未解锁时的报告卡片
  392. class UnlockReportCardWidget extends StatelessWidget {
  393. const UnlockReportCardWidget({super.key});
  394. @override
  395. Widget build(BuildContext context) {
  396. return ReportCardFrameWidget(
  397. child: Container(
  398. padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 6.w),
  399. decoration: ShapeDecoration(
  400. color: ColorName.white,
  401. shape: RoundedRectangleBorder(
  402. borderRadius: BorderRadius.circular(30.r),
  403. ),
  404. ),
  405. child: Center(
  406. child: Column(
  407. // 垂直水平都居中
  408. mainAxisAlignment: MainAxisAlignment.center,
  409. crossAxisAlignment: CrossAxisAlignment.center,
  410. children: [
  411. // 占位图
  412. Assets.images.iconIntimacyAnalyseReportUnlockPlaceholder.image(
  413. width: 300.w,
  414. height: 303.h,
  415. ),
  416. ],
  417. ),
  418. ),
  419. ),
  420. );
  421. }
  422. }
  423. /// 报告卡片框架组件,只定义报告卡片的基本框架,例如卡片背景和顶部的标题,内容由子组件来实现
  424. class ReportCardFrameWidget extends StatelessWidget {
  425. /// 内容子组件
  426. final Widget child;
  427. const ReportCardFrameWidget({super.key, required this.child});
  428. @override
  429. Widget build(BuildContext context) {
  430. // 卡片背景
  431. return Container(
  432. margin: EdgeInsets.only(left: 12, right: 12, bottom: 0),
  433. padding: EdgeInsets.only(bottom: 12),
  434. decoration: BoxDecoration(
  435. // image: DecorationImage(
  436. // image: Assets.images.bgIntimacyAnalyseReportPreview.provider(),
  437. // fit: BoxFit.fill,
  438. // ),
  439. // 渐变背景
  440. gradient: LinearGradient(
  441. colors: [Color(0xFFE9E2FF), Color(0xFFF1F5FF)],
  442. begin: Alignment.centerLeft,
  443. end: Alignment.centerRight,
  444. ),
  445. borderRadius: BorderRadius.all(Radius.circular(20.r)),
  446. ),
  447. child: Column(
  448. mainAxisSize: MainAxisSize.min,
  449. children: [
  450. // 顶部的图标和标题
  451. _buildReportTopLayout(),
  452. // 内容区域
  453. Container(
  454. padding: EdgeInsets.only(top: 3, left: 12, right: 12, bottom: 5),
  455. child: child,
  456. ),
  457. ],
  458. ),
  459. );
  460. }
  461. /// 报告的顶部布局-包含:图标和标题
  462. Widget _buildReportTopLayout() {
  463. return Container(
  464. margin: EdgeInsets.only(left: 12.w, top: 12.h),
  465. child: Row(
  466. children: [
  467. Assets.images.iconIntimacyAnalyseReportPreviewLove.image(
  468. width: 50,
  469. height: 48,
  470. ),
  471. Assets.images.iconIntimacyAnalyseReportPreviewTitle.image(
  472. width: 178,
  473. height: 24,
  474. ),
  475. ],
  476. ),
  477. );
  478. }
  479. }