intimacy_analyse_report_widget.dart 13 KB

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