intimacy_analyse_report_widget.dart 13 KB

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