import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:keyboard/resource/string.gen.dart'; import 'package:lottie/lottie.dart'; import '../../../data/api/response/intimacy_analyze_response.dart'; import '../../../data/bean/intimacy_analyse_report.dart'; import '../../../resource/assets.gen.dart'; import '../../../resource/colors.gen.dart'; import '../../../utils/string_format_util.dart'; import '../../../widget/animated_progress_bar.dart'; import '../../../widget/markdown/markdown_viewer.dart'; import '../analyse_report/widget/report_item_widget.dart'; /// 亲密度报告组件 class IntimacyAnalyseReportWidget extends StatelessWidget { /// 报告内容,Markdown格式 final String reportContent; /// 分析结果 final IntimacyAnalyzeResponse? intimacyAnalyzeResult; /// 是否已解锁 final bool unlock; /// 是否是预览 final bool isPreview; /// 是否报告生成中 final bool isReportCreating; const IntimacyAnalyseReportWidget({ super.key, this.reportContent = '', this.intimacyAnalyzeResult, this.unlock = false, this.isPreview = false, this.isReportCreating = false, }); @override Widget build(BuildContext context) { if (isPreview) { return PreviewReportCardWidget(previewReportContent: reportContent); } // 报告生成中 if (isReportCreating) { return CreatingReportCardWidget(); } // 未解锁 if (!unlock) { return UnlockReportCardWidget(); } // 已出报告 return ExistReportCardWidget( reportContent: reportContent, intimacyAnalyzeResult: intimacyAnalyzeResult, ); } } /// 预览报告卡片 class PreviewReportCardWidget extends StatelessWidget { final String previewReportContent; const PreviewReportCardWidget({ super.key, required this.previewReportContent, }); @override Widget build(BuildContext context) { return ReportCardFrameWidget( child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: 10.h), Container( // 最小高度 constraints: BoxConstraints(minHeight: 360.h), decoration: ShapeDecoration( color: ColorName.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.r), ), ), child: MarkdownViewer( // 内容 content: previewReportContent, // 不允许滚动 enableContentScroll: false, ), ), ], ), ); } } /// 已有报告组件 class ExistReportCardWidget extends StatelessWidget { /// 报告内容,Markdown格式 final String reportContent; /// 分析结果 final IntimacyAnalyzeResponse? intimacyAnalyzeResult; const ExistReportCardWidget({ super.key, required this.reportContent, this.intimacyAnalyzeResult, }); @override Widget build(BuildContext context) { return ReportCardFrameWidget( child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildReportOverview(), SizedBox(height: 10.h), reportContent.isNotEmpty ? _buildReportDetailByMarkdown() : _buildReportDetail(), ], ), ); } /// 报告概览,包含概览数值和图表 Widget _buildReportOverview() { if (intimacyAnalyzeResult == null) { return SizedBox(); } var analyzeResult = intimacyAnalyzeResult!; // 圆角背景 return Container( padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 12.h), decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.circular(20.r), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 概览数值 Container( padding: EdgeInsets.symmetric(horizontal: 18.w), decoration: BoxDecoration( color: ColorName.bgReportOverview, borderRadius: BorderRadius.all(Radius.circular(10.r)), ), child: Row( children: [ _buildIntimacyOverviewItem( StringFormatUtil.removePercentSymbol( analyzeResult.emotion ?? "", ), ), _buildOverviewDivider(), _buildCurrentStageOverviewItem( analyzeResult.intimacyPhase ?? "", ), ], ), ), SizedBox(height: 36.h), // 图表 _buildChart(analyzeResult), ], ), ); } /// 概览数值的分割线 Widget _buildOverviewDivider() { return Container( height: 44.h, width: 1.w, decoration: BoxDecoration(color: ColorName.black5), margin: EdgeInsets.symmetric(vertical: 10.h), ); } /// 概览亲密度的数值项 Widget _buildIntimacyOverviewItem(String value) { return Expanded( child: Row( // 左对齐 mainAxisAlignment: MainAxisAlignment.start, children: [ // 图标 Assets.images.iconIntimacyAnalyseReportOverviewLove.image( height: 22.w, width: 22.w, ), SizedBox(width: 14.w), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 数值区域 Row( children: [ // 数值 Text( value, maxLines: 1, style: TextStyle( overflow: TextOverflow.ellipsis, color: ColorName.black80, fontSize: 20.sp, fontWeight: FontWeight.w700, ), ), SizedBox(width: 2.w), // 百分比符号 Text( StringName.intimacyValuePercent, style: TextStyle( color: ColorName.black46, fontSize: 13.sp, fontWeight: FontWeight.w700, ), ), ], ), // 描述 Text( StringName.intimacyValue, style: TextStyle( color: ColorName.textReportOverviewValueDesc, fontSize: 12.sp, fontWeight: FontWeight.w400, ), ), ], ), ], ), ); } /// 概览目前阶段的数值项 Widget _buildCurrentStageOverviewItem(String value) { return Expanded( child: Row( // 右对齐 mainAxisAlignment: MainAxisAlignment.end, children: [ // 图标 Assets.images.iconIntimacyAnalyseReportOverviewStage.image( height: 22.w, width: 22.w, ), SizedBox(width: 14.w), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ // 数值 Text( value, style: TextStyle( color: ColorName.black80, fontSize: 14.sp, fontWeight: FontWeight.w700, ), ), // 描述 Text( StringName.intimacyCurrentStage, style: TextStyle( color: ColorName.textReportOverviewValueDesc, fontSize: 12.sp, fontWeight: FontWeight.w400, ), ), ], ), ], ), ); } /// 将百分比转换为进度条需要的数值 double _convertPercentValue2ProgressBar(String percentValue) { if (percentValue.isEmpty) { return 0; } // 去掉%号后的数值 String valueStr = StringFormatUtil.removePercentSymbol(percentValue); double noPercentValue = double.tryParse(valueStr) ?? 0; if (noPercentValue == 0) { return 0; } else { // 除以100,转换为0-1之间的数值,才是进度条需要的数值 double progressValue = noPercentValue / 100; return progressValue; } } /// 报告图表 Widget _buildChart(IntimacyAnalyzeResponse analyzeResult) { return Column( mainAxisSize: MainAxisSize.min, children: [ // 互动好感度 _buildValueItem( iconProvider: Assets.images.iconEmojiLike.provider(), title: StringName.intimacyInteraction, value: _convertPercentValue2ProgressBar( analyzeResult.interaction ?? "", ), progressColors: [ColorName.blueGradient1, ColorName.blueGradient2], ), SizedBox(height: 18.h), // 话题好感度 _buildValueItem( iconProvider: Assets.images.iconEmojiChat.provider(), title: StringName.intimacyTopic, value: _convertPercentValue2ProgressBar(analyzeResult.topic ?? ""), progressColors: [ColorName.greenGradient1, ColorName.greenGradient2], ), SizedBox(height: 18.h), // 情绪回应 _buildValueItem( iconProvider: Assets.images.iconEmojiLike.provider(), title: StringName.intimacyRespond, value: _convertPercentValue2ProgressBar(analyzeResult.respond ?? ""), progressColors: [ ColorName.yellowGradient1, ColorName.yellowGradient2, ], ), SizedBox(height: 18.h), // 亲密词占比 _buildValueItem( iconProvider: Assets.images.iconEmojiPercent.provider(), title: StringName.intimacyintimacyRatio, value: _convertPercentValue2ProgressBar( analyzeResult.intimacyRatio ?? "", ), progressColors: [ColorName.pinkGradient1, ColorName.pinkGradient2], ), SizedBox(height: 18.h), // 预测方向占比 _buildValueItem( iconProvider: Assets.images.iconEmojiLove.provider(), title: analyzeResult.directionName ?? "", value: _convertPercentValue2ProgressBar( analyzeResult.directionRatio ?? "", ), progressColors: [ ColorName.purpleGradient1, ColorName.purpleGradient2, ], ), SizedBox(height: 12, width: double.infinity), ], ); } /// 构建数值Item /// [iconProvider] icon图标的ImageProvider /// [title] 标题 /// [progressColors] 进度条渐变色 /// [value] 进度条的数值,从0到1.0 Widget _buildValueItem({ required ImageProvider iconProvider, required String title, required List progressColors, required double value, }) { return Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 图标 Container( padding: EdgeInsets.all(6.w), decoration: BoxDecoration( // 圆形背景 shape: BoxShape.circle, color: ColorName.bgReportValueIcon, ), child: ClipOval( child: Image( image: iconProvider, width: 15.w, height: 15.w, fit: BoxFit.fill, ), ), ), SizedBox(width: 5.w), // 文字 Text(title), SizedBox(width: 10.w), // 进度条 Expanded( child: AnimatedGradientProgressBar( // 进度值 targetValue: value, // 渐变色 gradient: LinearGradient(colors: progressColors), // 动画时长 duration: const Duration(milliseconds: 1500), ), ), ], ); } /// 报告详情,使用Markdown Widget _buildReportDetailByMarkdown() { return Container( decoration: ShapeDecoration( color: ColorName.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.r), ), ), child: MarkdownViewer( // 内容 content: reportContent, // 不允许滚动 enableContentScroll: false, ), ); } /// 报告详情,使用组件渲染 Widget _buildReportDetail() { if (intimacyAnalyzeResult == null) { return SizedBox(); } // 组装数据 IntimacyAnalyseReport reportPreviewData = IntimacyAnalyseReport( list: [ // 建议调整亲密度 AnalyseItem( title: StringName.intimacyintimacyAdjustintimacy, sections: [intimacyAnalyzeResult?.adjustIntimacy ?? ""], ), // 情感需求 AnalyseItem( title: StringName.intimacyintimacyNeed, sections: [intimacyAnalyzeResult?.need ?? ""], ), // 情感调整方向 AnalyseItem( title: StringName.intimacyintimacyAdjustDirection, sections: [intimacyAnalyzeResult?.adjustDirection ?? ""], ), // 建议使用聊天人设 AnalyseItem( title: StringName.intimacyintimacyChatCharacter, sections: [intimacyAnalyzeResult?.chatCharacter ?? ""], ), // 聊天策略 AnalyseItem( title: StringName.intimacyintimacyChatStrategy, sections: [intimacyAnalyzeResult?.chatStrategy ?? ""], ), // 我的表面行为 AnalyseItem( title: StringName.intimacyintimacyMyBehavior, sections: [intimacyAnalyzeResult?.myBehavior ?? ""], ), // 对方的表面行为 AnalyseItem( title: StringName.intimacyintimacyTargetBehavior, sections: [intimacyAnalyzeResult?.targetBehavior ?? ""], ), // 帮助亲密度提升 AnalyseItem( title: StringName.intimacyintimacyHelpImprove, sections: [intimacyAnalyzeResult?.helpImprove ?? ""], ), // 沟通中我的优势 AnalyseItem( title: StringName.intimacyintimacyMyAdvantage, sections: [intimacyAnalyzeResult?.myAdvantage ?? ""], ), // 沟通中我的劣势 AnalyseItem( title: StringName.intimacyintimacyMyDisadvantage, sections: [intimacyAnalyzeResult?.myDisadvantage ?? ""], ), ], ); return _buildReportContent(reportPreviewData); } /// 构建报告内容 Widget _buildReportContent(IntimacyAnalyseReport report) { return Container( padding: EdgeInsets.all(14.w), decoration: ShapeDecoration( color: ColorName.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.r), ), ), child: Column( children: [ // 报告列表 ...report.list.map((ele) { return ReportItemWidget(item: ele); }), ], ), ); } } /// 报告生成中的卡片 class CreatingReportCardWidget extends StatelessWidget { const CreatingReportCardWidget({super.key}); @override Widget build(BuildContext context) { return ReportCardFrameWidget( child: Container( padding: EdgeInsets.only(top: 33.h, bottom: 52.h), decoration: ShapeDecoration( color: ColorName.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.r), ), ), child: Center( child: Column( // 垂直水平都居中 mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 图标 Lottie.asset( Assets.anim.animIntimacyAnalyseCreatingReportData, repeat: true, width: 82.w, height: 82.w, ), SizedBox(height: 3.h), // 文字 Text( StringName.intimacyAnalyseReportCreating, style: TextStyle( fontSize: 14.sp, color: ColorName.black60, fontWeight: FontWeight.w400, ), ), ], ), ), ), ); } } /// 未解锁时的报告卡片 class UnlockReportCardWidget extends StatelessWidget { const UnlockReportCardWidget({super.key}); @override Widget build(BuildContext context) { return ReportCardFrameWidget( child: Container( padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 6.w), decoration: ShapeDecoration( color: ColorName.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.r), ), ), child: Center( child: Column( // 垂直水平都居中 mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 占位图 Assets.images.iconIntimacyAnalyseReportUnlockPlaceholder.image( width: 300.w, height: 303.h, ), ], ), ), ), ); } } /// 报告卡片框架组件,只定义报告卡片的基本框架,例如卡片背景和顶部的标题,内容由子组件来实现 class ReportCardFrameWidget extends StatelessWidget { /// 内容子组件 final Widget child; const ReportCardFrameWidget({super.key, required this.child}); @override Widget build(BuildContext context) { // 卡片背景 return Container( margin: EdgeInsets.only(left: 12, right: 12, bottom: 0), padding: EdgeInsets.only(bottom: 12), decoration: BoxDecoration( // image: DecorationImage( // image: Assets.images.bgIntimacyAnalyseReportPreview.provider(), // fit: BoxFit.fill, // ), // 渐变背景 gradient: LinearGradient( colors: [Color(0xFFE9E2FF), Color(0xFFF1F5FF)], begin: Alignment.centerLeft, end: Alignment.centerRight, ), borderRadius: BorderRadius.all(Radius.circular(20.r)), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 顶部的图标和标题 _buildReportTopLayout(), // 内容区域 Container( padding: EdgeInsets.only(top: 3, left: 12, right: 12, bottom: 5), child: child, ), ], ), ); } /// 报告的顶部布局-包含:图标和标题 Widget _buildReportTopLayout() { return Container( margin: EdgeInsets.only(left: 12.w, top: 12.h), child: Row( children: [ Assets.images.iconIntimacyAnalyseReportPreviewLove.image( width: 50, height: 48, ), Assets.images.iconIntimacyAnalyseReportPreviewTitle.image( width: 178, height: 24, ), ], ), ); } }