Bläddra i källkod

选择社区选择楼栋单元房号,选择角色,上传文档

liukai 2 veckor sedan
förälder
incheckning
64a934a7b4
25 ändrade filer med 547 tillägg och 25 borttagningar
  1. 2 2
      packages/cpt_auth/lib/modules/select_estate/select_estate_page.dart
  2. 1 1
      packages/cpt_auth/lib/modules/select_role/select_role_page.dart
  3. 3 1
      packages/cpt_auth/lib/modules/select_role/select_role_view_model.dart
  4. 1 1
      packages/cpt_auth/lib/modules/select_role/select_role_view_model.g.dart
  5. 3 3
      packages/cpt_auth/lib/modules/select_unit/select_unit_page.dart
  6. 1 1
      packages/cpt_auth/lib/modules/select_unit/select_unit_view_model.g.dart
  7. 160 0
      packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_page.dart
  8. 22 0
      packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_state.dart
  9. 32 0
      packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_view_model.dart
  10. 27 0
      packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_view_model.g.dart
  11. 2 0
      packages/cpt_auth/lib/router/page/auth_page_router.dart
  12. 37 0
      packages/cpt_auth/lib/router/page/auth_page_router.gr.dart
  13. 137 0
      packages/cs_plugin_platform/lib/engine/image/image_nine_grid.dart
  14. 14 14
      packages/cs_plugin_platform/lib/engine/permission/permission_engine.dart
  15. 2 1
      packages/cs_plugin_platform/lib/platform_export.dart
  16. 0 0
      packages/cs_resources/assets/base_lib/image_add_icon.webp
  17. 1 1
      packages/cs_resources/lib/generated/assets.dart
  18. 9 0
      packages/cs_resources/lib/generated/intl/messages_en.dart
  19. 8 0
      packages/cs_resources/lib/generated/intl/messages_zh_CN.dart
  20. 8 0
      packages/cs_resources/lib/generated/intl/messages_zh_HK.dart
  21. 50 0
      packages/cs_resources/lib/generated/l10n.dart
  22. 5 0
      packages/cs_resources/lib/l10n/intl_en.arb
  23. 5 0
      packages/cs_resources/lib/l10n/intl_zh_CN.arb
  24. 5 0
      packages/cs_resources/lib/l10n/intl_zh_HK.arb
  25. 12 0
      packages/cs_resources/lib/theme/app_colors_theme.dart

+ 2 - 2
packages/cpt_auth/lib/modules/select_estate/select_estate_page.dart

@@ -63,7 +63,7 @@ class SelectEstatePage extends HookConsumerWidget {
         usedHeight += _buttonKey.currentContext?.size?.height ?? 0;
 
         // 计算剩余空间
-        double remainingSpace = screenHeight - statusBarHeight - navigationBarHeight - usedHeight - 38 - 28 - 20 - 20;
+        double remainingSpace = screenHeight - statusBarHeight - navigationBarHeight - usedHeight - 38 - 28 - 20 - 19;
 
         Log.d("计算剩余空间:$remainingSpace");
 
@@ -144,7 +144,7 @@ class SelectEstatePage extends HookConsumerWidget {
                 fontSize: 16,
                 minHeight: 50,
                 radius: 5,
-              ).marginOnly(top: 48, bottom: 32),
+              ).marginOnly(top: 40, bottom: 30),
             ],
           ),
         ),

+ 1 - 1
packages/cpt_auth/lib/modules/select_role/select_role_page.dart

@@ -106,7 +106,7 @@ class SelectRolePage extends HookConsumerWidget {
               fontSize: 16,
               minHeight: 50,
               radius: 5,
-            ).marginOnly(top: 32, bottom: 32, left: 18, right: 18),
+            ).marginOnly(top: 30, bottom: 30, left: 18, right: 18),
           ],
         ),
       ),

+ 3 - 1
packages/cpt_auth/lib/modules/select_role/select_role_view_model.dart

@@ -1,4 +1,5 @@
 import 'package:cpt_auth/modules/select_role/select_role_state.dart';
+import 'package:cpt_auth/modules/tenant_doc/tenant_doc_page.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 
 part 'select_role_view_model.g.dart';
@@ -10,8 +11,9 @@ class SelectRoleViewModel extends _$SelectRoleViewModel {
     return SelectRoleState();
   }
 
+  //进入下一步
   void submitRole() {
-
+    TenantDocPage.startInstance();
   }
 
   //选择角色

+ 1 - 1
packages/cpt_auth/lib/modules/select_role/select_role_view_model.g.dart

@@ -7,7 +7,7 @@ part of 'select_role_view_model.dart';
 // **************************************************************************
 
 String _$selectRoleViewModelHash() =>
-    r'3b03e884e98d9c7186bc5f7871061d91577fef50';
+    r'a42d4ba4dd03754e74e58b1a320793449326bef4';
 
 /// See also [SelectRoleViewModel].
 @ProviderFor(SelectRoleViewModel)

+ 3 - 3
packages/cpt_auth/lib/modules/select_unit/select_unit_page.dart

@@ -66,7 +66,7 @@ class SelectUnitPage extends HookConsumerWidget {
         usedHeight += _buttonKey.currentContext?.size?.height ?? 0;
 
         // 计算剩余空间
-        double remainingSpace = screenHeight - statusBarHeight - navigationBarHeight - usedHeight - 30 - 20 - 25 - 20 - 20;
+        double remainingSpace = screenHeight - statusBarHeight - navigationBarHeight - usedHeight - 28 - 18 - 25 - 20 - 20;
 
         Log.d("计算剩余空间:$remainingSpace");
 
@@ -99,7 +99,7 @@ class SelectUnitPage extends HookConsumerWidget {
                 Assets.authSignUpUnitImg,
                 width: 266.5,
                 height: 162,
-              ).marginOnly(top: 30, bottom: 20),
+              ).marginOnly(top: 28, bottom: 18),
 
               Row(
                 key: _inputKey,
@@ -236,7 +236,7 @@ class SelectUnitPage extends HookConsumerWidget {
                 fontSize: 16,
                 minHeight: 50,
                 radius: 5,
-              ).marginOnly(top: 48, bottom: 32, left: 18, right: 18),
+              ).marginOnly(top: 40, bottom: 30, left: 18, right: 18),
             ],
           ),
         ),

+ 1 - 1
packages/cpt_auth/lib/modules/select_unit/select_unit_view_model.g.dart

@@ -7,7 +7,7 @@ part of 'select_unit_view_model.dart';
 // **************************************************************************
 
 String _$selectUnitViewModelHash() =>
-    r'33be3440f5134f21ce9a9ecae640e97afe250494';
+    r'f31ffde34c823cf1b3ab7477ddcfda312ccce307';
 
 /// See also [SelectUnitViewModel].
 @ProviderFor(SelectUnitViewModel)

+ 160 - 0
packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_page.dart

@@ -0,0 +1,160 @@
+import 'package:cs_resources/generated/l10n.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:router/ext/auto_router_extensions.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:plugin_platform/platform_export.dart';
+
+import '../../router/page/auth_page_router.dart';
+import 'tenant_doc_view_model.dart';
+
+@RoutePage()
+class TenantDocPage extends HookConsumerWidget {
+  TenantDocPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({BuildContext? context}) {
+    if (context != null) {
+      context.router.push(TenantDocPageRoute());
+    } else {
+      appRouter.push(TenantDocPageRoute());
+    }
+  }
+
+  // 为需要测量的控件创建 GlobalKey
+  final GlobalKey _appbarKey = GlobalKey();
+  final GlobalKey _titleKey = GlobalKey();
+  final GlobalKey _descriptionKey = GlobalKey();
+  final GlobalKey _description1Key = GlobalKey();
+  final GlobalKey _description2Key = GlobalKey();
+  final GlobalKey _nineGridKey = GlobalKey();
+  final GlobalKey _buttonKey = GlobalKey();
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final viewModel = ref.read(tenantDocViewModelProvider.notifier);
+    final state = ref.watch(tenantDocViewModelProvider);
+
+    // 获取屏幕高度
+    final screenHeight = MediaQuery.of(context).size.height;
+    final statusBarHeight = MediaQuery.of(context).padding.top;
+    final navigationBarHeight = MediaQuery.of(context).padding.bottom;
+
+    useEffect(() {
+      double usedHeight = 0;
+      // 组件挂载时执行,获取控件高度
+      WidgetsBinding.instance.addPostFrameCallback((_) {
+        // 获取各个控件的高度
+        usedHeight += _appbarKey.currentContext?.size?.height ?? 0;
+        usedHeight += _titleKey.currentContext?.size?.height ?? 0;
+        usedHeight += _descriptionKey.currentContext?.size?.height ?? 0;
+        usedHeight += _description1Key.currentContext?.size?.height ?? 0;
+        usedHeight += _description2Key.currentContext?.size?.height ?? 0;
+        usedHeight += _nineGridKey.currentContext?.size?.height ?? 0;
+        usedHeight += _buttonKey.currentContext?.size?.height ?? 0;
+
+        // 计算剩余空间
+        double remainingSpace = screenHeight - statusBarHeight - navigationBarHeight - usedHeight - 23 - 21;
+
+        Log.d("计算剩余空间:$remainingSpace");
+
+        if (remainingSpace > 0) {
+          // 设置一个状态来存储剩余空间的高度
+          viewModel.setRemainingSpace(remainingSpace);
+        }
+      });
+      return () {
+        // 组件卸载时执行
+      };
+    }, []);
+
+    return Scaffold(
+      appBar: MyAppBar.appBar(context, "", key: _appbarKey),
+      backgroundColor: context.appColors.backgroundDefault,
+      body: Container(
+        padding: const EdgeInsets.symmetric(horizontal: 15),
+        width: double.infinity,
+        child: Column(
+          mainAxisSize: MainAxisSize.max,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            MyTextView(
+              key: _titleKey,
+              S.current.upload_documents,
+              fontSize: 23.5,
+              marginTop: 23,
+              marginBottom: 21,
+              textAlign: TextAlign.center,
+              isFontMedium: true,
+              textColor: context.appColors.textBlack,
+            ),
+
+            MyTextView(
+              key: _descriptionKey,
+              S.current.upload_doc_desc,
+              fontSize: 15,
+              isFontMedium: true,
+              textColor: context.appColors.textBlack,
+            ),
+
+            MyTextView(
+              key: _description1Key,
+              S.current.upload_doc_desc1,
+              fontSize: 15,
+              marginTop: 22,
+              isFontMedium: true,
+              textColor: context.appColors.textBlack,
+            ),
+
+            MyTextView(
+              key: _description2Key,
+              S.current.upload_doc_desc2,
+              fontSize: 15,
+              marginTop: 22,
+              marginBottom: 24,
+              isFontMedium: true,
+              textColor: context.appColors.textBlack,
+            ),
+
+            ImageNineGrid(
+              key: _nineGridKey,
+              isSelectEnable: true,
+              maxImages: 3,
+              spacing: 10,
+              aspectRatio: 108 / 80,
+              initialImages: [],
+              onImagesChanged: (list) {
+                viewModel.setDocList(list);
+              },
+            ),
+
+            SizedBox(
+              height: state.remainingSpace, // 使用剩余空间的值
+            ),
+
+            //底部的按钮
+            MyButton(
+              key: _buttonKey,
+              onPressed: viewModel.submitDoc,
+              text: S.current.next,
+              textColor: Colors.white,
+              backgroundColor: context.appColors.btnBgDefault,
+              fontWeight: FontWeight.w500,
+              type: ClickType.throttle,
+              fontSize: 16,
+              minHeight: 50,
+              radius: 5,
+            ).marginOnly(top: 30, bottom: 30, left: 18, right: 18),
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 22 - 0
packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_state.dart

@@ -0,0 +1,22 @@
+class TenantDocState {
+
+  final List<String> docList;
+
+  final double remainingSpace;
+
+  const TenantDocState({
+    required this.docList,
+    this.remainingSpace = 0,
+  });
+
+  TenantDocState copyWith({
+    List<String>? docList,
+    double? remainingSpace,
+  }) {
+    return TenantDocState(
+      docList: docList ?? this.docList,
+      remainingSpace: remainingSpace ?? this.remainingSpace,
+    );
+  }
+
+}

+ 32 - 0
packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_view_model.dart

@@ -0,0 +1,32 @@
+
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+
+import 'tenant_doc_state.dart';
+
+part 'tenant_doc_view_model.g.dart';
+
+@riverpod
+class TenantDocViewModel extends _$TenantDocViewModel {
+
+  @override
+  TenantDocState build(){
+    return const TenantDocState(docList: []);
+  }
+
+  //设置已选中的文件数组
+  void setDocList(List<String> list){
+    state = state.copyWith(docList: list);
+  }
+
+  //提交文件
+  void submitDoc() {
+
+    ToastEngine.show("请求接口上传文件:${state.docList}");
+  }
+
+  void setRemainingSpace(double remainingSpace) {
+    state = state.copyWith(remainingSpace: remainingSpace);
+  }
+
+}

+ 27 - 0
packages/cpt_auth/lib/modules/tenant_doc/tenant_doc_view_model.g.dart

@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'tenant_doc_view_model.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+String _$tenantDocViewModelHash() =>
+    r'8283e1970743d66a871e1145e15ffd3177d3a42b';
+
+/// See also [TenantDocViewModel].
+@ProviderFor(TenantDocViewModel)
+final tenantDocViewModelProvider =
+    AutoDisposeNotifierProvider<TenantDocViewModel, TenantDocState>.internal(
+  TenantDocViewModel.new,
+  name: r'tenantDocViewModelProvider',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$tenantDocViewModelHash,
+  dependencies: null,
+  allTransitiveDependencies: null,
+);
+
+typedef _$TenantDocViewModel = AutoDisposeNotifier<TenantDocState>;
+// ignore_for_file: type=lint
+// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

+ 2 - 0
packages/cpt_auth/lib/router/page/auth_page_router.dart

@@ -12,6 +12,7 @@ import '../../modules/sing_up_success/sign_up_success_page.dart';
 import '../../modules/select_estate/select_estate_page.dart';
 import '../../modules/select_unit/select_unit_page.dart';
 import '../../modules/select_role/select_role_page.dart';
+import '../../modules/tenant_doc/tenant_doc_page.dart';
 
 
 
@@ -33,5 +34,6 @@ class AuthPageRouter extends _$AuthPageRouter {
     CustomRoute(page: SelectEstatePageRoute.page, path: RouterPath.authSelectEstate, transitionsBuilder: applySlideTransition),
     CustomRoute(page: SelectUnitPageRoute.page, path: RouterPath.authSelectUnit, transitionsBuilder: applySlideTransition),
     CustomRoute(page: SelectRolePageRoute.page, path: RouterPath.authSelectRole, transitionsBuilder: applySlideTransition),
+    CustomRoute(page: TenantDocPageRoute.page, path: RouterPath.authTenantDoc, transitionsBuilder: applySlideTransition),
   ];
 }

+ 37 - 0
packages/cpt_auth/lib/router/page/auth_page_router.gr.dart

@@ -73,6 +73,14 @@ abstract class _$AuthPageRouter extends RootStackRouter {
         child: const SignUpVerifyPage(),
       );
     },
+    TenantDocPageRoute.name: (routeData) {
+      final args = routeData.argsAs<TenantDocPageRouteArgs>(
+          orElse: () => const TenantDocPageRouteArgs());
+      return AutoRoutePage<dynamic>(
+        routeData: routeData,
+        child: TenantDocPage(key: args.key),
+      );
+    },
   };
 }
 
@@ -231,3 +239,32 @@ class SignUpVerifyPageRoute extends PageRouteInfo<void> {
 
   static const PageInfo<void> page = PageInfo<void>(name);
 }
+
+/// generated route for
+/// [TenantDocPage]
+class TenantDocPageRoute extends PageRouteInfo<TenantDocPageRouteArgs> {
+  TenantDocPageRoute({
+    Key? key,
+    List<PageRouteInfo>? children,
+  }) : super(
+          TenantDocPageRoute.name,
+          args: TenantDocPageRouteArgs(key: key),
+          initialChildren: children,
+        );
+
+  static const String name = 'TenantDocPageRoute';
+
+  static const PageInfo<TenantDocPageRouteArgs> page =
+      PageInfo<TenantDocPageRouteArgs>(name);
+}
+
+class TenantDocPageRouteArgs {
+  const TenantDocPageRouteArgs({this.key});
+
+  final Key? key;
+
+  @override
+  String toString() {
+    return 'TenantDocPageRouteArgs{key: $key}';
+  }
+}

+ 137 - 0
packages/cs_plugin_platform/lib/engine/image/image_nine_grid.dart

@@ -0,0 +1,137 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_platform/engine/media/image_picker_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:widgets/my_text_view.dart';
+import 'image_preview.dart';
+import 'package:cs_resources/generated/l10n.dart';
+
+class ImageNineGrid extends StatefulWidget {
+  final bool isSelectEnable; // 是否能选择
+  final List<String> initialImages; // 初始化图片集合
+  final int maxImages; // 最多选择的图片
+  final double aspectRatio; // 宽高比
+  final double spacing; // 横向竖向的间距
+  final double borderRadius; //整体边框圆角
+  final Function(List<String>) onImagesChanged;
+
+  const ImageNineGrid({
+    Key? key,
+    this.isSelectEnable = true,
+    this.maxImages = 9,
+    this.aspectRatio = 1.0,
+    this.spacing = 8,
+    this.borderRadius = 5.0,
+    required this.initialImages,
+    required this.onImagesChanged,
+  }) : super(key: key);
+
+  @override
+  _ImageNineGridState createState() => _ImageNineGridState();
+}
+
+class _ImageNineGridState extends State<ImageNineGrid> {
+  late List<String> _images;
+
+  @override
+  void initState() {
+    super.initState();
+    _images = List.from(widget.initialImages);
+  }
+
+  // 选择图片
+  Future<void> _pickImage() async {
+    ImagePickerUtils().show(context, (filePath) {
+      if (Utils.isNotEmpty(filePath)) {
+        setState(() {
+          _images.add(filePath);
+        });
+        widget.onImagesChanged(_images);
+      }
+    });
+  }
+
+  // 删除图片
+  void _removeImage(int index) {
+    setState(() {
+      _images.removeAt(index);
+    });
+    widget.onImagesChanged(_images);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final gridChildren = List<Widget>.generate(
+      _images.length,
+      (index) => Stack(
+        children: [
+          ClipRRect(
+            borderRadius: BorderRadius.circular(widget.borderRadius), // 圆角半径
+            child: Hero(
+              tag: _images[index],
+              child: MyLoadImage(
+                _images[index],
+                width: double.infinity,
+                height: double.infinity,
+                fit: BoxFit.cover,
+              ).onTap(() {
+                //预览图片
+                ImagePreviewEngine.singleImagePreview(context, _images[index], heroTag: _images[index]);
+              }),
+            ),
+          ),
+          Positioned(
+            top: 0,
+            right: 0,
+            child: Visibility(
+              visible: widget.isSelectEnable,
+              child: const MyAssetImage(Assets.baseLibDialogDeleteIcon, width: 24, height: 24).onTap(() {
+                if (widget.isSelectEnable) {
+                  _removeImage(index);
+                }
+              }, padding: 5),
+            ),
+          ),
+        ],
+      ),
+    );
+
+    if (widget.isSelectEnable && _images.length < widget.maxImages) {
+      gridChildren.add(
+        GestureDetector(
+          onTap: _pickImage,
+          child: Container(
+            decoration: BoxDecoration(
+              color: context.appColors.imgGrayBg,
+              borderRadius: BorderRadius.circular(widget.borderRadius), // 圆角半径
+            ),
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                const MyAssetImage(Assets.baseLibImageAddIcon, width: 211.5, height: 21.5),
+                MyTextView(S.current.upload, fontSize: 10, isFontMedium: true, marginTop: 3, textColor: context.appColors.textDarkGray999),
+              ],
+            ),
+          ),
+        ),
+      );
+    }
+
+    return GridView.builder(
+      shrinkWrap: true,
+      physics: const NeverScrollableScrollPhysics(),
+      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+        crossAxisCount: 3,
+        childAspectRatio: widget.aspectRatio,
+        mainAxisSpacing: widget.spacing,
+        crossAxisSpacing: widget.spacing,
+      ),
+      itemCount: gridChildren.length,
+      itemBuilder: (context, index) => gridChildren[index],
+    );
+  }
+}

+ 14 - 14
packages/cs_plugin_platform/lib/engine/permission/permission_engine.dart

@@ -40,8 +40,8 @@ class PermissionEngine {
         Log.d("相册无授权,去设置");
         DialogEngine.show(
           widget: AppDefaultDialog(
-            title: "提示",
-            message: '无相册权限,前往设置',
+            title: "Alert",
+            message: 'No album permission, go to settings?',
             confirmAction: () {
               PhotoManager.openSetting();
             },
@@ -60,7 +60,7 @@ class PermissionEngine {
         var permissionRequestFuture = PhotoManager.requestPermissionExtend();
 
         // 延迟500毫秒的Future
-        var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
+        var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
 
         // 使用Future.any等待上述两个Future中的任何一个完成
         var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
@@ -69,7 +69,7 @@ class PermissionEngine {
         if (firstCompleted == 'delay') {
           Log.d("判断响应结果:1");
           // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-          _showPermissionDialog("“YYBusiness”想访问你的多媒体相册 用于图片上传,图片保存等功能,请允许我获取您的权限");
+          _showPermissionDialog("“YYHome” would like to access your multimedia album for functions such as image uploading and saving. Please allow me to obtain your permission");
           // 再次等待权限请求结果
           ps = await permissionRequestFuture;
           DialogEngine.dismiss(tag: "permission");
@@ -87,8 +87,8 @@ class PermissionEngine {
           // 权限被拒绝
           await DialogEngine.show(
             widget: AppDefaultDialog(
-                message: "请到您的手机设置打开相册的权限",
-                title: "提醒",
+                message: "Please set the permission to open the photo album on your phone",
+                title: "Alert",
                 confirmAction: () {
                   openAppSettings();
                 }),
@@ -110,7 +110,7 @@ class PermissionEngine {
       var permissionRequestFuture = Permission.camera.request();
 
       // 延迟500毫秒的Future
-      var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
+      var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
 
       // 使用Future.any等待上述两个Future中的任何一个完成
       var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
@@ -118,7 +118,7 @@ class PermissionEngine {
       // 判断响应结果
       if (firstCompleted == 'delay') {
         // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-        _showPermissionDialog("“YYBusiness”申请调用您的相机权限 用于使用拍摄头像,图片上传保存等功能,请允许我获取您的权限");
+        _showPermissionDialog("“YYHome” requests to use your camera permission for functions such as taking avatars, uploading and saving images. Please allow me to obtain your permission");
         // 再次等待权限请求结果
         status = await permissionRequestFuture;
         DialogEngine.dismiss(tag: "permission");
@@ -135,8 +135,8 @@ class PermissionEngine {
         // 权限被拒绝
         await DialogEngine.show(
           widget: AppDefaultDialog(
-              message: "请到您的手机设置打开相机的权限",
-              title: "提醒",
+              message: "Please set the permission to open the camera on your phone",
+              title: "Alert",
               confirmAction: () {
                 openAppSettings();
               }),
@@ -157,7 +157,7 @@ class PermissionEngine {
       var permissionRequestFuture = Permission.location.request();
 
       // 延迟500毫秒的Future
-      var delayFuture = Future.delayed(Duration(milliseconds: 500), () => 'delay');
+      var delayFuture = Future.delayed(const Duration(milliseconds: 500), () => 'delay');
 
       // 使用Future.any等待上述两个Future中的任何一个完成
       var firstCompleted = await Future.any([permissionRequestFuture, delayFuture]);
@@ -165,7 +165,7 @@ class PermissionEngine {
       // 判断响应结果
       if (firstCompleted == 'delay') {
         // 如果是延迟Future完成了,表示500毫秒内没有获得权限响应,显示对话框
-        _showPermissionDialog("“YYBusiness”想访问您的定位权限获取您的位置来推荐附近的工作");
+        _showPermissionDialog("“YYHome” want to access your location permission to obtain your location and recommend nearby information");
         // 再次等待权限请求结果
         status = await permissionRequestFuture;
         DialogEngine.dismiss(tag: "permission");
@@ -183,8 +183,8 @@ class PermissionEngine {
         // 权限被拒绝
         await DialogEngine.show(
           widget: AppDefaultDialog(
-              message: "请到您的手机设置打开定位的权限",
-              title: "提醒",
+              message: "Please go to your phone settings to enable location permission",
+              title: "Alert",
               confirmAction: () {
                 openAppSettings();
               }),

+ 2 - 1
packages/cs_plugin_platform/lib/platform_export.dart

@@ -1,2 +1,3 @@
 export 'package:dio/dio.dart';
-export 'package:permission_handler/permission_handler.dart';
+export 'package:permission_handler/permission_handler.dart';
+export 'engine/image/image_nine_grid.dart';

packages/cs_resources/assets/auth/image_add_icon.webp → packages/cs_resources/assets/base_lib/image_add_icon.webp


+ 1 - 1
packages/cs_resources/lib/generated/assets.dart

@@ -8,7 +8,6 @@ class Assets {
   static const String authCountrySg = 'assets/auth/country_sg.webp';
   static const String authForgotInputEmailPhoneImg = 'assets/auth/forgot_input_email_phone_img.webp';
   static const String authForgotResetPasswordImg = 'assets/auth/forgot_reset_password_img.webp';
-  static const String authImageAddIcon = 'assets/auth/image_add_icon.webp';
   static const String authPasswordHide = 'assets/auth/password_hide.webp';
   static const String authPasswordShow = 'assets/auth/password_show.webp';
   static const String authSignUpInputImg = 'assets/auth/sign_up_input_img.webp';
@@ -19,6 +18,7 @@ class Assets {
   static const String baseLibBlackBack = 'assets/base_lib/black_back.webp';
   static const String baseLibDialogBlueDeleteIcon = 'assets/base_lib/dialog_blue_delete_icon.webp';
   static const String baseLibDialogDeleteIcon = 'assets/base_lib/dialog_delete_icon.webp';
+  static const String baseLibImageAddIcon = 'assets/base_lib/image_add_icon.webp';
   static const String baseLibImageDefaultPlaceholder = 'assets/base_lib/image_default_placeholder.png';
   static const String baseLibItemMoreIcon = 'assets/base_lib/item_more_icon.webp';
   static const String baseLibSearchIcon = 'assets/base_lib/search_icon.webp';

+ 9 - 0
packages/cs_resources/lib/generated/intl/messages_en.dart

@@ -104,6 +104,15 @@ class MessageLookup extends MessageLookupByLibrary {
         "tries_left": MessageLookupByLibrary.simpleMessage("Tries Left"),
         "type_here": MessageLookupByLibrary.simpleMessage("Type Here"),
         "unit_number": MessageLookupByLibrary.simpleMessage("Unit Number"),
+        "upload": MessageLookupByLibrary.simpleMessage("Upload"),
+        "upload_doc_desc": MessageLookupByLibrary.simpleMessage(
+            "The Management requires that you upload the following documents to verify your tenancy. You may redact sensitive financia information"),
+        "upload_doc_desc1": MessageLookupByLibrary.simpleMessage(
+            "(1)A valid tenancy agreement showing your name,unit numper,tenancy expiration date and a list of occupants (if applicable)"),
+        "upload_doc_desc2": MessageLookupByLibrary.simpleMessage(
+            "(2)Tenancy Agreement Stamp Duty receipt"),
+        "upload_documents":
+            MessageLookupByLibrary.simpleMessage("Upload Documents"),
         "verification_code":
             MessageLookupByLibrary.simpleMessage("Verification Code"),
         "welcome_name": m0,

+ 8 - 0
packages/cs_resources/lib/generated/intl/messages_zh_CN.dart

@@ -86,6 +86,14 @@ class MessageLookup extends MessageLookupByLibrary {
         "tries_left": MessageLookupByLibrary.simpleMessage("次尝试机会"),
         "type_here": MessageLookupByLibrary.simpleMessage("在此输入"),
         "unit_number": MessageLookupByLibrary.simpleMessage("单元"),
+        "upload": MessageLookupByLibrary.simpleMessage("上传"),
+        "upload_doc_desc": MessageLookupByLibrary.simpleMessage(
+            "管理员要求您上传以下文件以验证您的租约。您可以编辑敏感的财务信息"),
+        "upload_doc_desc1": MessageLookupByLibrary.simpleMessage(
+            "(1)一份有效的租赁协议,显示您的姓名、单位编号、租赁到期日期和居住者名单(如果适用)"),
+        "upload_doc_desc2":
+            MessageLookupByLibrary.simpleMessage("(2)租赁协议印花税收据"),
+        "upload_documents": MessageLookupByLibrary.simpleMessage("上传文档"),
         "verification_code": MessageLookupByLibrary.simpleMessage("验证码"),
         "welcome_name": m0,
         "who_are_owners": MessageLookupByLibrary.simpleMessage("怎样才算业主?"),

+ 8 - 0
packages/cs_resources/lib/generated/intl/messages_zh_HK.dart

@@ -73,6 +73,14 @@ class MessageLookup extends MessageLookupByLibrary {
         "tries_left": MessageLookupByLibrary.simpleMessage("次尝试机会"),
         "type_here": MessageLookupByLibrary.simpleMessage("在此输入"),
         "unit_number": MessageLookupByLibrary.simpleMessage("单元"),
+        "upload": MessageLookupByLibrary.simpleMessage("上传"),
+        "upload_doc_desc": MessageLookupByLibrary.simpleMessage(
+            "管理员要求您上传以下文件以验证您的租约。您可以编辑敏感的财务信息"),
+        "upload_doc_desc1": MessageLookupByLibrary.simpleMessage(
+            "(1)一份有效的租赁协议,显示您的姓名、单位编号、租赁到期日期和居住者名单(如果适用)"),
+        "upload_doc_desc2":
+            MessageLookupByLibrary.simpleMessage("(2)租赁协议印花税收据"),
+        "upload_documents": MessageLookupByLibrary.simpleMessage("上传文档"),
         "verification_code": MessageLookupByLibrary.simpleMessage("验证码"),
         "welcome_name": m0,
         "you_have": MessageLookupByLibrary.simpleMessage("你还有"),

+ 50 - 0
packages/cs_resources/lib/generated/l10n.dart

@@ -620,6 +620,56 @@ class S {
     );
   }
 
+  /// `Upload Documents`
+  String get upload_documents {
+    return Intl.message(
+      'Upload Documents',
+      name: 'upload_documents',
+      desc: '',
+      args: [],
+    );
+  }
+
+  /// `The Management requires that you upload the following documents to verify your tenancy. You may redact sensitive financia information`
+  String get upload_doc_desc {
+    return Intl.message(
+      'The Management requires that you upload the following documents to verify your tenancy. You may redact sensitive financia information',
+      name: 'upload_doc_desc',
+      desc: '',
+      args: [],
+    );
+  }
+
+  /// `(1)A valid tenancy agreement showing your name,unit numper,tenancy expiration date and a list of occupants (if applicable)`
+  String get upload_doc_desc1 {
+    return Intl.message(
+      '(1)A valid tenancy agreement showing your name,unit numper,tenancy expiration date and a list of occupants (if applicable)',
+      name: 'upload_doc_desc1',
+      desc: '',
+      args: [],
+    );
+  }
+
+  /// `(2)Tenancy Agreement Stamp Duty receipt`
+  String get upload_doc_desc2 {
+    return Intl.message(
+      '(2)Tenancy Agreement Stamp Duty receipt',
+      name: 'upload_doc_desc2',
+      desc: '',
+      args: [],
+    );
+  }
+
+  /// `Upload`
+  String get upload {
+    return Intl.message(
+      'Upload',
+      name: 'upload',
+      desc: '',
+      args: [],
+    );
+  }
+
   /// `Other`
   String get other {
     return Intl.message(

+ 5 - 0
packages/cs_resources/lib/l10n/intl_en.arb

@@ -56,5 +56,10 @@
   "tenants_desc2": "I live in the same household as the named tenant",
   "tenants_desc3": "I am the tenant of the company that rented the unit",
   "tenants_desc4": "The Management will verify your application accordingly",
+  "upload_documents": "Upload Documents",
+  "upload_doc_desc": "The Management requires that you upload the following documents to verify your tenancy. You may redact sensitive financia information",
+  "upload_doc_desc1": "(1)A valid tenancy agreement showing your name,unit numper,tenancy expiration date and a list of occupants (if applicable)",
+  "upload_doc_desc2": "(2)Tenancy Agreement Stamp Duty receipt",
+  "upload": "Upload",
   "other": "Other"
 }

+ 5 - 0
packages/cs_resources/lib/l10n/intl_zh_CN.arb

@@ -56,5 +56,10 @@
   "tenants_desc2": "我和指定的租户住在同一个家庭",
   "tenants_desc3": "我是租用该单元的公司的租户",
   "tenants_desc4": "管理员将相应地验证您的申请",
+  "upload_documents": "上传文档",
+  "upload_doc_desc": "管理员要求您上传以下文件以验证您的租约。您可以编辑敏感的财务信息",
+  "upload_doc_desc1": "(1)一份有效的租赁协议,显示您的姓名、单位编号、租赁到期日期和居住者名单(如果适用)",
+  "upload_doc_desc2": "(2)租赁协议印花税收据",
+  "upload": "上传",
   "other": "其他"
 }

+ 5 - 0
packages/cs_resources/lib/l10n/intl_zh_HK.arb

@@ -42,5 +42,10 @@
   "estate_or_building_name": "房产或建筑名称?",
   "type_here": "在此输入",
   "estate_name_desc": "告诉我们您申请的公寓楼的名称",
+  "upload_documents": "上传文档",
+  "upload_doc_desc": "管理员要求您上传以下文件以验证您的租约。您可以编辑敏感的财务信息",
+  "upload_doc_desc1": "(1)一份有效的租赁协议,显示您的姓名、单位编号、租赁到期日期和居住者名单(如果适用)",
+  "upload_doc_desc2": "(2)租赁协议印花税收据",
+  "upload": "上传",
   "other": "其他"
 }

+ 12 - 0
packages/cs_resources/lib/theme/app_colors_theme.dart

@@ -21,6 +21,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
   static const _colorFE6C00 = Color(0xFFFE6C00);
   static const _colorD3D3D3 = Color(0xFFD3D3D3);
   static const _color333333 = Color(0xFF333333);
+  static const _colorF3F3F3 = Color(0xFFF3F3F3);
+  static const _color999999 = Color(0xFF999999);
 
   //暗色主题的一些自定义颜色值
   static const _darkBlackBg = Color(0xFF0F0F0F);
@@ -44,6 +46,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
   final Color tabBgUnSelectedPrimary; //Tab的未选中主题色背景
   final Color tabTextSelectedPrimary; //Tab的未选中主题色文本
   final Color tabTextUnSelectedPrimary; //Tab的未选中主题色文本
+  final Color imgGrayBg; //灰色的图片底色背景
+  final Color textDarkGray999; //文本深灰色
 
   // 私有的构造函数
   const AppColorsTheme._internal({
@@ -61,6 +65,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
     required this.tabBgUnSelectedPrimary,
     required this.tabTextSelectedPrimary,
     required this.tabTextUnSelectedPrimary,
+    required this.imgGrayBg,
+    required this.textDarkGray999,
   });
 
   // 浅色主题工厂方法
@@ -80,6 +86,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
       tabBgUnSelectedPrimary: _colorD3D3D3,
       tabTextSelectedPrimary: Colors.white,
       tabTextUnSelectedPrimary: _color333333,
+      imgGrayBg: _colorF3F3F3,
+      textDarkGray999: _color999999,
     );
   }
 
@@ -100,6 +108,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
       tabBgUnSelectedPrimary: _darkBlackItem,
       tabTextSelectedPrimary: Colors.black,
       tabTextUnSelectedPrimary: Colors.white,
+      imgGrayBg: _darkBlackItem,
+      textDarkGray999: Colors.white,
     );
   }
 
@@ -129,6 +139,8 @@ class AppColorsTheme extends ThemeExtension<AppColorsTheme> {
       tabBgUnSelectedPrimary: Color.lerp(tabBgUnSelectedPrimary, other.tabBgUnSelectedPrimary, t)!,
       tabTextSelectedPrimary: Color.lerp(tabTextSelectedPrimary, other.tabTextSelectedPrimary, t)!,
       tabTextUnSelectedPrimary: Color.lerp(tabTextUnSelectedPrimary, other.tabTextUnSelectedPrimary, t)!,
+      imgGrayBg: Color.lerp(imgGrayBg, other.imgGrayBg, t)!,
+      textDarkGray999: Color.lerp(textDarkGray999, other.textDarkGray999, t)!,
     );
   }
 }