| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- 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 '../../../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';
- /// 亲密度报告组件
- class IntimacyAnalyseReportWidget extends StatelessWidget {
- /// 报告内容,Markdown格式
- final String reportContent;
- /// 分析结果
- final IntimacyAnalyzeResponse? intimacyAnalyzeResult;
- /// 是否已解锁
- final bool unlock;
- /// 是否是预览
- final bool isPreview;
- const IntimacyAnalyseReportWidget({
- super.key,
- required this.reportContent,
- this.intimacyAnalyzeResult,
- this.unlock = false,
- this.isPreview = false,
- });
- @override
- Widget build(BuildContext context) {
- if (isPreview) {
- return PreviewReportCardWidget(previewReportContent: reportContent);
- }
- // 未解锁
- if (!unlock) {
- return UnlockReportCardWidget();
- }
- // 报告生成中
- if (intimacyAnalyzeResult == null || reportContent.isEmpty) {
- return CreatingReportCardWidget();
- }
- // 已出报告
- 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),
- _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,
- style: TextStyle(
- 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.start,
- 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.direction ?? "",
- ),
- 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<Color> 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),
- ),
- ),
- ],
- );
- }
- /// 报告详情
- Widget _buildReportDetail() {
- return Container(
- decoration: ShapeDecoration(
- color: ColorName.white,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(30.r),
- ),
- ),
- child: MarkdownViewer(
- // 内容
- content: reportContent,
- // 不允许滚动
- enableContentScroll: false,
- ),
- );
- }
- }
- /// 报告生成中的卡片
- 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,
- ),
- ],
- ),
- );
- }
- }
|