Sfoglia il codice sorgente

[feat]亲密度分析,封装步骤卡片,方便后面的页面中复用

hezihao 7 mesi fa
parent
commit
1893530ce4

BIN
assets/images/bg_intimacy_analyse_normal_card.webp


+ 2 - 0
assets/string/base/string.xml

@@ -232,6 +232,8 @@
 
     <string name="intimacy_analyse_step_title_select_image">选择你的图片</string>
     <string name="intimacy_analyse_step_title_select_prediction_direction">选择预测方向</string>
+    <string name="intimacy_analyse_prediction_direction_card_tip">选择不同阶段的标签,可以更精准地分析</string>
+    <string name="intimacy_analyse_add_prediction_direction">添加预测方向</string>
 
     <string name="my_self">自己</string>
     <string name="and">与</string>

+ 82 - 92
lib/module/intimacy_analyse/intimacy_analyse_upload/intimacy_analyse_upload_page.dart

@@ -17,6 +17,7 @@ import '../../../router/app_pages.dart';
 import '../../../utils/string_format_util.dart';
 import '../../../widget/gradient_text.dart';
 import '../widget/intimacy_user_widget.dart';
+import '../widget/step_card.dart';
 import 'intimacy_analyse_upload_controller.dart';
 
 /// 亲密度分析上传页
@@ -114,106 +115,88 @@ class IntimacyAnalyseUploadPage
     );
   }
 
-  /// 步骤标题
-  Widget _buildStepTitle(int step, String title) {
-    return Row(
-      children: [
-        // 步骤标签
-        StepLabelWidget(
-          label: StringFormatUtil.formatStr(
-            StringName.intimacyAnalyseStep,
-            step.toString(),
-          ),
-        ),
-        SizedBox(width: 10.w),
-        // 标题
-        GradientText(
-          // 渐变颜色
-          colors: [ColorName.stepTitleColor1, ColorName.stepTitleColor2],
-          child: Text(
-            title,
-            style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.w700),
+  /// 上传步骤卡片
+  Widget _buildUploadStepCard() {
+    return StepCard(
+      bgImageProvider: Assets.images.bgIntimacyAnalyseUploadCard.provider(),
+      stepLabel: StringFormatUtil.formatStr(
+        StringName.intimacyAnalyseStep,
+        1.toString(),
+      ),
+      stepTitle: StringName.intimacyAnalyseStepTitleSelectImage,
+      stepDesc: StringName.intimacyAnalyseUploadCardTip,
+      topIconWidget: Assets.images.iconIntimacyAnalyseUploadTop.image(
+        height: 63.h,
+        width: 103.w,
+      ),
+      contentWidget: Column(
+        children: [
+          // 九宫格
+          Container(
+            margin: EdgeInsets.only(left: 12.w, right: 12.w),
+            padding: EdgeInsets.only(
+              left: 12.w,
+              top: 12.h,
+              right: 12.w,
+              bottom: 12.h,
+            ),
+            decoration: BoxDecoration(
+              color: ColorName.white,
+              borderRadius: BorderRadius.circular(16.r),
+            ),
+            child: UploadNineGrid(
+              mode: Mode.edit,
+              imageSrcList: ["", "", "", "", "", "", ""],
+              maxCount: 9,
+              spacing: 8.0,
+            ),
           ),
-        ),
-      ],
+          SizedBox(height: 10.h),
+          // 当前的亲密关系
+          _buildRecommendIntimacy(),
+        ],
+      ),
     );
   }
 
-  /// 构建上传卡片
-  Widget _buildUploadCard() {
-    return Container(
-      margin: EdgeInsets.only(left: 12.w, top: 10.h, right: 12.w),
-      child: Stack(
-        // 不裁切超出区域的子组件,例如下面的顶部的图标
-        clipBehavior: Clip.none,
+  /// 预测方向步骤卡片
+  Widget _buildPredictionDirectionStepCard() {
+    return StepCard(
+      bgImageProvider: Assets.images.bgIntimacyAnalyseNormalCard.provider(),
+      stepLabel: StringFormatUtil.formatStr(
+        StringName.intimacyAnalyseStep,
+        2.toString(),
+      ),
+      stepTitle: StringName.intimacyAnalyseStepTitleSelectPredictionDirection,
+      stepDesc: StringName.intimacyAnalysePredictionDirectionCardTip,
+      contentWidget: Column(
         children: [
-          // 顶部的图标
-          Positioned(
-            top: -11.h,
-            right: 0,
-            child: Assets.images.iconIntimacyAnalyseUploadTop.image(
-              height: 63.h,
-              width: 103.w,
-            ),
-          ),
-          // 卡片背景
+          // 九宫格
           Container(
+            margin: EdgeInsets.only(left: 12.w, right: 12.w),
+            padding: EdgeInsets.only(
+              left: 12.w,
+              top: 12.h,
+              right: 12.w,
+              bottom: 12.h,
+            ),
             decoration: BoxDecoration(
-              image: DecorationImage(
-                image: Assets.images.bgIntimacyAnalyseUploadCard.provider(),
-                fit: BoxFit.fill,
-              ),
+              color: ColorName.white,
+              borderRadius: BorderRadius.circular(16.r),
             ),
-            child: Column(
-              // 左对齐
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                // 步骤1
-                Container(
-                  margin: EdgeInsets.only(left: 12.w, top: 16.h),
-                  child: _buildStepTitle(
-                    1,
-                    StringName.intimacyAnalyseStepTitleSelectImage,
-                  ),
-                ),
-                SizedBox(height: 4.h),
-                // 提示文字
-                Container(
-                  margin: EdgeInsets.only(left: 12.w),
-                  child: Text(
-                    StringName.intimacyAnalyseUploadCardTip,
-                    style: TextStyle(
-                      fontSize: 12.sp,
-                      fontWeight: FontWeight.w400,
-                      color: ColorName.black60,
-                    ),
-                  ),
-                ),
-                SizedBox(height: 16.h),
-                // 九宫格
-                Container(
-                  margin: EdgeInsets.only(left: 12.w, right: 12.w),
-                  padding: EdgeInsets.only(
-                    left: 12.w,
-                    top: 12.h,
-                    right: 12.w,
-                    bottom: 12.h,
-                  ),
-                  decoration: BoxDecoration(
-                    color: ColorName.white,
-                    borderRadius: BorderRadius.circular(16.r),
-                  ),
-                  child: UploadNineGrid(
-                    imageUrls: ["", "", "", "", "", "", ""],
-                    maxCount: 9,
-                    spacing: 8.0,
-                  ),
-                ),
-                SizedBox(height: 10.h),
-                // 当前的亲密关系
-                _buildRecommendIntimacy(),
-                SizedBox(height: 18.h),
+            child: UploadNineGrid(
+              mode: Mode.preview,
+              imageSrcList: [
+                "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png",
+                "",
+                "",
+                "",
+                "",
+                "",
+                "",
               ],
+              maxCount: 9,
+              spacing: 8.0,
             ),
           ),
         ],
@@ -327,7 +310,14 @@ class IntimacyAnalyseUploadPage
   Widget _buildContent() {
     return Expanded(
       child: SingleChildScrollView(
-        child: Column(children: [_buildUploadCard()]),
+        child: Column(
+          children: [
+            // 上传卡片
+            _buildUploadStepCard(),
+            // 预测方向卡片
+            _buildPredictionDirectionStepCard(),
+          ],
+        ),
       ),
     );
   }

+ 25 - 8
lib/module/intimacy_analyse/intimacy_analyse_upload/widget/upload_item_widget.dart

@@ -1,5 +1,6 @@
 import 'dart:io';
 
+import 'package:cached_network_image/cached_network_image.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -29,8 +30,8 @@ typedef OnClickDeleteCallback = void Function();
 
 /// 上传项组件,有3种状态,上传成功、上传中、上传失败
 class UploadItemWidget extends StatelessWidget {
-  /// 本地文件路径
-  final String filePath;
+  /// 图片路径
+  final String imageSrc;
 
   /// 上传状态
   final UploadState uploadState;
@@ -43,7 +44,7 @@ class UploadItemWidget extends StatelessWidget {
 
   const UploadItemWidget({
     super.key,
-    required this.filePath,
+    required this.imageSrc,
     required this.uploadState,
     required this.onClickItemCallback,
     required this.onClickDeleteCallback,
@@ -58,11 +59,8 @@ class UploadItemWidget extends StatelessWidget {
         child: Stack(
           alignment: Alignment.center,
           children: [
-            // 本地图片
-            Visibility(
-              visible: filePath.isNotEmpty,
-              child: Image.file(File(filePath), fit: BoxFit.cover),
-            ),
+            // 图片
+            _buildImage(),
             // 上传状态的遮罩层
             _buildMaskByUploadStatus(uploadState),
             // 删除按钮
@@ -73,6 +71,25 @@ class UploadItemWidget extends StatelessWidget {
     );
   }
 
+  /// 判断是否是远程图片
+  bool _isRemoteImage(String imageSrc) {
+    if (imageSrc.isEmpty) {
+      return false;
+    }
+    return imageSrc.startsWith('http') || imageSrc.startsWith('https');
+  }
+
+  /// 图片
+  Widget _buildImage() {
+    // 网络图片
+    if (_isRemoteImage(imageSrc)) {
+      return CachedNetworkImage(imageUrl: imageSrc);
+    } else {
+      // 本地图片
+      return Image.file(File(imageSrc), fit: BoxFit.cover);
+    }
+  }
+
   /// 根据状态,构建遮罩
   Widget _buildMaskByUploadStatus(UploadState uploadState) {
     switch (uploadState) {

+ 29 - 12
lib/module/intimacy_analyse/intimacy_analyse_upload/widget/upload_nine_grid.dart

@@ -2,10 +2,22 @@ import 'package:flutter/cupertino.dart';
 import 'package:keyboard/module/intimacy_analyse/intimacy_analyse_upload/widget/upload_add_widget.dart';
 import 'package:keyboard/module/intimacy_analyse/intimacy_analyse_upload/widget/upload_item_widget.dart';
 
+/// 模式
+enum Mode {
+  /// 编辑模式
+  edit,
+
+  /// 预览模式
+  preview
+}
+
 /// 上传九宫格
 class UploadNineGrid extends StatelessWidget {
-  /// 图片Url列表
-  final List<String> imageUrls;
+  /// 模式
+  final Mode mode;
+
+  /// 图片资源列表
+  final List<String> imageSrcList;
 
   /// 最大显示数量
   final int maxCount;
@@ -15,7 +27,8 @@ class UploadNineGrid extends StatelessWidget {
 
   const UploadNineGrid({
     super.key,
-    required this.imageUrls,
+    required this.mode,
+    required this.imageSrcList,
     this.maxCount = 9,
     this.spacing = 2.0,
   });
@@ -40,17 +53,17 @@ class UploadNineGrid extends StatelessWidget {
       itemCount: _getItemCount(),
       itemBuilder: (context, index) {
         // 添加图片的条目
-        if (index >= imageUrls.length) {
+        if (index >= imageSrcList.length) {
           return UploadAddWidget(
-            residueCount: maxCount - imageUrls.length,
+            residueCount: maxCount - imageSrcList.length,
             onClickAddCallback: () {
               // 上传图片
             },
           );
         } else {
           // 上传项
-          String url = imageUrls[index];
-          return _buildUploadItem(url);
+          String src = imageSrcList[index];
+          return _buildUploadItem(src);
         }
       },
     );
@@ -58,7 +71,11 @@ class UploadNineGrid extends StatelessWidget {
 
   /// 如果图片数量小于最大数量,则总数量,要添加1个添加图片的条目
   bool _isNeedAddItem() {
-    return imageUrls.length < maxCount;
+    // 预览模式,不需要添加
+    if (mode == Mode.preview) {
+      return false;
+    }
+    return imageSrcList.length < maxCount;
   }
 
   /// 获取宫格列表项的数量
@@ -66,18 +83,18 @@ class UploadNineGrid extends StatelessWidget {
     final int itemCount;
     // 如果图片数量小于最大数量,则总数量,要添加1个添加图片的条目
     if (_isNeedAddItem()) {
-      itemCount = imageUrls.length + 1;
+      itemCount = imageSrcList.length + 1;
     } else {
       // 满了最大数量,则直接显示所有图片
-      itemCount = imageUrls.length;
+      itemCount = imageSrcList.length;
     }
     return itemCount;
   }
 
   /// 上传项
-  Widget _buildUploadItem(String url) {
+  Widget _buildUploadItem(String imageSrc) {
     return UploadItemWidget(
-      filePath: url,
+      imageSrc: imageSrc,
       uploadState: UploadState.uploading,
       onClickDeleteCallback: () {
         // 删除图片

+ 121 - 0
lib/module/intimacy_analyse/widget/step_card.dart

@@ -0,0 +1,121 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import '../../../resource/colors.gen.dart';
+import '../../../widget/gradient_text.dart';
+import '../intimacy_analyse_upload/widget/step_label_widget.dart';
+
+/// 步骤卡片,支持设置卡片背景、步骤标题、步骤描述、顶部图标和内容区域
+class StepCard extends StatelessWidget {
+  /// 卡片背景
+  final ImageProvider bgImageProvider;
+
+  /// 步骤标签
+  final String? stepLabel;
+
+  /// 步骤标题
+  final String stepTitle;
+
+  /// 步骤描述
+  final String stepDesc;
+
+  /// 顶部图标
+  final Image? topIconWidget;
+
+  /// 内容组件
+  final Widget contentWidget;
+
+  const StepCard({
+    super.key,
+    required this.bgImageProvider,
+    required this.stepLabel,
+    required this.stepTitle,
+    required this.stepDesc,
+    required this.contentWidget,
+    this.topIconWidget,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: EdgeInsets.only(left: 12.w, top: 10.h, right: 12.w),
+      child: Stack(
+        // 不裁切超出区域的子组件,例如下面的顶部的图标
+        clipBehavior: Clip.none,
+        children: [
+          // 顶部的图标
+          topIconWidget == null
+              ? SizedBox()
+              : Positioned(top: -11.h, right: 0, child: topIconWidget!),
+          // 卡片背景
+          Container(
+            decoration: BoxDecoration(
+              image: DecorationImage(image: bgImageProvider, fit: BoxFit.fill),
+            ),
+            child: Column(
+              // 左对齐
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                // 步骤标题
+                Container(
+                  margin: EdgeInsets.only(left: 12.w, top: 16.h),
+                  child: _buildStepTitle(),
+                ),
+                SizedBox(height: 4.h),
+                // 步骤描述
+                _buildStepDesc(stepDesc),
+                SizedBox(height: 16.h),
+                contentWidget,
+                SizedBox(height: 18.h),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+
+  /// 步骤标题
+  Widget _buildStepTitle() {
+    // 步骤标签
+    String stepLabelStr = stepLabel ?? "";
+    Widget stepLabelWidget;
+    if (stepLabelStr.isBlank == true) {
+      stepLabelWidget = SizedBox();
+    } else {
+      stepLabelWidget = StepLabelWidget(label: stepLabelStr);
+    }
+
+    return Row(
+      children: [
+        // 步骤标签
+        stepLabelWidget,
+        SizedBox(width: 10.w),
+        // 标题
+        GradientText(
+          // 渐变颜色
+          colors: [ColorName.stepTitleColor1, ColorName.stepTitleColor2],
+          child: Text(
+            stepTitle,
+            style: TextStyle(fontSize: 20.sp, fontWeight: FontWeight.w700),
+          ),
+        ),
+      ],
+    );
+  }
+
+  /// 构建步骤描述
+  Widget _buildStepDesc(String desc) {
+    return Container(
+      margin: EdgeInsets.only(left: 12.w),
+      child: Text(
+        desc,
+        style: TextStyle(
+          fontSize: 12.sp,
+          fontWeight: FontWeight.w400,
+          color: ColorName.black60,
+        ),
+      ),
+    );
+  }
+}

+ 5 - 0
lib/resource/assets.gen.dart

@@ -105,6 +105,10 @@ class $AssetsImagesGen {
   AssetGenImage get bgIntimacyAnalyse =>
       const AssetGenImage('assets/images/bg_intimacy_analyse.webp');
 
+  /// File path: assets/images/bg_intimacy_analyse_normal_card.webp
+  AssetGenImage get bgIntimacyAnalyseNormalCard =>
+      const AssetGenImage('assets/images/bg_intimacy_analyse_normal_card.webp');
+
   /// File path: assets/images/bg_intimacy_analyse_report_preview.webp
   AssetGenImage get bgIntimacyAnalyseReportPreview => const AssetGenImage(
     'assets/images/bg_intimacy_analyse_report_preview.webp',
@@ -757,6 +761,7 @@ class $AssetsImagesGen {
     bgDiscountTitle,
     bgGoApp,
     bgIntimacyAnalyse,
+    bgIntimacyAnalyseNormalCard,
     bgIntimacyAnalyseReportPreview,
     bgIntimacyAnalyseReportPreviewBubble,
     bgIntimacyAnalyseReportPreviewMask,

+ 4 - 0
lib/resource/string.gen.dart

@@ -166,6 +166,8 @@ class StringName {
   static final String intimacyAnalyseStep = 'intimacy_analyse_step'.tr; // STEP%s
   static final String intimacyAnalyseStepTitleSelectImage = 'intimacy_analyse_step_title_select_image'.tr; // 选择你的图片
   static final String intimacyAnalyseStepTitleSelectPredictionDirection = 'intimacy_analyse_step_title_select_prediction_direction'.tr; // 选择预测方向
+  static final String intimacyAnalysePredictionDirectionCardTip = 'intimacy_analyse_prediction_direction_card_tip'.tr; // 选择不同阶段的标签,可以更精准地分析
+  static final String intimacyAnalyseAddPredictionDirection = 'intimacy_analyse_add_prediction_direction'.tr; // 添加预测方向
   static final String mySelf = 'my_self'.tr; // 自己
   static final String and = 'and'.tr; // 与
   static final String intimacyRelation = 'intimacy_relation'.tr; // 亲密关系
@@ -340,6 +342,8 @@ class StringMultiSource {
       'intimacy_analyse_step': 'STEP%s',
       'intimacy_analyse_step_title_select_image': '选择你的图片',
       'intimacy_analyse_step_title_select_prediction_direction': '选择预测方向',
+      'intimacy_analyse_prediction_direction_card_tip': '选择不同阶段的标签,可以更精准地分析',
+      'intimacy_analyse_add_prediction_direction': '添加预测方向',
       'my_self': '自己',
       'and': '与',
       'intimacy_relation': '亲密关系',