Browse Source

[new]增加修改头像弹窗

zk 5 months ago
parent
commit
6f8c614f47

BIN
assets/images/icon_avatar_close.webp


BIN
assets/images/icon_avatar_selected.webp


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

@@ -316,4 +316,6 @@
     <string name="account_replace_title">您的账号已在另一台设备登录</string>
     <string name="account_replace_desc">建议重新登录或切换其他账号</string>
     <string name="account_replace_btn_txt">我知道了</string>
+    <string name="account_please_select_avatar">请选择头像</string>
+    <string name="account_select_avatar_btn_txt">立即更换</string>
 </resources>

+ 1 - 0
lib/dialog/user_avatar_dialog.dart

@@ -14,6 +14,7 @@ class UserAvatarDialog {
   static void show(List<String> avatarList, String? selectedAvatarUrl,
       {required AvatarSelectedCallback onAvatarSelected}) {
     SmartDialog.show(
+        alignment: Alignment.bottomCenter,
         builder: (_) =>
             _UserAvatarView(avatarList, onAvatarSelected, selectedAvatarUrl),
         tag: _tag);

+ 45 - 0
lib/module/avatar/user_avatar_controller.dart

@@ -0,0 +1,45 @@
+import 'package:get/get.dart';
+import 'package:location/base/base_controller.dart';
+import 'package:location/data/repositories/account_repository.dart';
+import 'package:location/resource/string.gen.dart';
+import 'package:location/utils/toast_util.dart';
+
+import '../../data/bean/user_info.dart';
+import '../../handler/error_handler.dart';
+
+class UserAvatarController extends BaseController {
+  final List<String> avatarList;
+
+  UserAvatarController(this.avatarList);
+
+  final AccountRepository accountRepository = AccountRepository.getInstance();
+
+  final RxnString _selectedAvatar = RxnString();
+
+  String? get selectedAvatar => _selectedAvatar.value;
+
+  UserInfo? get mineInfo => accountRepository.mineUserInfo.value;
+
+  void onSelectAvatarClick(String url) {
+    _selectedAvatar.value = url;
+  }
+
+  void onSelectedClick() {
+    final avatar =
+        _selectedAvatar.value ?? accountRepository.mineUserInfo.value.avatar;
+    if (avatar == null) {
+      ToastUtil.show(StringName.accountPleaseSelectAvatar);
+      return;
+    }
+    onAvatarSelected(avatar);
+  }
+
+  void onAvatarSelected(String avatar) {
+    accountRepository.userAvatarUpdate(avatar).then((_) {
+      ToastUtil.show(StringName.mineUpdateAvatarSuccess);
+      Get.back();
+    }).catchError((error) {
+      ErrorHandler.toastError(error);
+    });
+  }
+}

+ 159 - 0
lib/module/avatar/user_avatar_view.dart

@@ -0,0 +1,159 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:get/get_core/src/get_main.dart';
+import 'package:location/data/repositories/config_repository.dart';
+import 'package:location/module/avatar/user_avatar_controller.dart';
+import 'package:location/resource/assets.gen.dart';
+import 'package:location/resource/string.gen.dart';
+import 'package:location/utils/common_expand.dart';
+
+import '../../handler/error_handler.dart';
+import '../../resource/colors.gen.dart';
+import '../../utils/common_style.dart';
+
+class UserAvatarView extends GetView<UserAvatarController> {
+  UserAvatarView({super.key, required List<String> avatarList}) {
+    Get.lazyPut(() => UserAvatarController(avatarList));
+  }
+
+  static void show() {
+    ConfigRepository.getInstance().requestUserAvatarList().then((list) {
+      Get.bottomSheet(UserAvatarView(avatarList: list),
+          isScrollControlled: true,
+          barrierColor: ColorName.black55,
+          backgroundColor: ColorName.transparent);
+    }).catchError((error) {
+      ErrorHandler.toastError(error);
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      width: 1.sw,
+      decoration: BoxDecoration(
+        color: Colors.white,
+        borderRadius: BorderRadius.only(
+          topLeft: Radius.circular(10.w),
+          topRight: Radius.circular(10.w),
+        ),
+      ),
+      child: IntrinsicHeight(
+        child: Column(
+          children: [
+            SizedBox(height: 12.w),
+            buildTitleView(),
+            SizedBox(height: 22.w),
+            buildAvatarListView(),
+            SizedBox(height: 30.w),
+            buildSureBtnView(),
+            SizedBox(height: 20.w),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget buildTitleView() {
+    return Row(
+      children: [
+        SizedBox(width: 37.w),
+        Spacer(),
+        Text(
+          StringName.accountPleaseSelectAvatar,
+          style: TextStyle(fontSize: 14.sp, color: '#404040'.color),
+        ),
+        Spacer(),
+        Assets.images.iconAvatarClose.image(width: 25.w, height: 25.w),
+        SizedBox(width: 12.w),
+      ],
+    );
+  }
+
+  Widget buildAvatarListView() {
+    return Container(
+        margin: EdgeInsets.symmetric(horizontal: 20.w),
+        child: Builder(builder: (context) {
+          return Wrap(
+            spacing: 25.w,
+            runSpacing: 30.w,
+            children: controller.avatarList.map((url) {
+              double itemWidth =
+                  (MediaQuery.of(context).size.width - 25.w * 5) / 4;
+              return GestureDetector(
+                onTap: () {
+                  controller.onSelectAvatarClick(url);
+                },
+                child: buildAvatarItem(itemWidth, url),
+              );
+            }).toList(),
+          );
+        }));
+  }
+
+  Widget buildAvatarItem(double itemWidth, String url) {
+    return Stack(
+      children: [
+        Container(
+          width: itemWidth,
+          height: itemWidth,
+          decoration: BoxDecoration(
+              shape: BoxShape.circle,
+              border: Border.all(width: 1.w, color: '#F0F0F0'.color)),
+          child: ClipOval(
+            child: CachedNetworkImage(
+              width: double.infinity,
+              height: double.infinity,
+              imageUrl: url,
+              fit: BoxFit.cover,
+            ),
+          ),
+        ),
+        Obx(() {
+          return Visibility(
+            visible: controller.selectedAvatar == url ||
+                (controller.selectedAvatar == null &&
+                    controller.mineInfo?.avatar == url),
+            child: Container(
+              width: itemWidth,
+              height: itemWidth,
+              decoration: BoxDecoration(
+                  shape: BoxShape.circle,
+                  border:
+                      Border.all(width: 3.w, color: ColorName.colorPrimary)),
+            ),
+          );
+        }),
+        Obx(() {
+          return Visibility(
+            visible: controller.selectedAvatar == url ||
+                (controller.selectedAvatar == null &&
+                    controller.mineInfo?.avatar == url),
+            child: Positioned(
+                bottom: 0,
+                right: 0,
+                child: Assets.images.iconAvatarSelected
+                    .image(width: 20.w, height: 20.w)),
+          );
+        })
+      ],
+    );
+  }
+
+  Widget buildSureBtnView() {
+    return GestureDetector(
+      onTap: controller.onSelectedClick,
+      child: Container(
+        width: 312.w,
+        height: 44.w,
+        decoration: getPrimaryBtnDecoration(100.r),
+        child: Center(
+            child: Text(StringName.accountSelectAvatarBtnTxt,
+                style: TextStyle(fontSize: 15.sp, color: Colors.white))),
+      ),
+    );
+  }
+}

+ 2 - 16
lib/module/mine/mine_controller.dart

@@ -10,6 +10,7 @@ import 'package:location/data/bean/user_info.dart';
 import 'package:location/data/consts/error_code.dart';
 import 'package:location/data/repositories/config_repository.dart';
 import 'package:location/handler/error_handler.dart';
+import 'package:location/module/avatar/user_avatar_view.dart';
 import 'package:location/module/feedback/feed_back_page.dart';
 import 'package:location/module/login/login_page.dart';
 import 'package:location/module/member/member_page.dart';
@@ -119,22 +120,7 @@ class MineController extends BaseController {
   }
 
   void editUserAvatar() {
-    configRepository.requestUserAvatarList().then((list) {
-      UserAvatarDialog.show(
-          list, AccountRepository.getInstance().mineUserInfo.value.avatar,
-          onAvatarSelected: onAvatarSelected);
-    }).catchError((error) {
-      ErrorHandler.toastError(error);
-    });
-  }
-
-  void onAvatarSelected(String avatar) {
-    accountRepository.userAvatarUpdate(avatar).then((_) {
-      ToastUtil.show(StringName.mineUpdateAvatarSuccess);
-      UserAvatarDialog.dismiss();
-    }).catchError((error) {
-      ErrorHandler.toastError(error);
-    });
+    UserAvatarView.show();
   }
 
   onUrgentContactClick() {

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

@@ -84,6 +84,14 @@ class $AssetsImagesGen {
   AssetGenImage get iconAppleRecoverSubscribe =>
       const AssetGenImage('assets/images/icon_apple_recover_subscribe.png');
 
+  /// File path: assets/images/icon_avatar_close.webp
+  AssetGenImage get iconAvatarClose =>
+      const AssetGenImage('assets/images/icon_avatar_close.webp');
+
+  /// File path: assets/images/icon_avatar_selected.webp
+  AssetGenImage get iconAvatarSelected =>
+      const AssetGenImage('assets/images/icon_avatar_selected.webp');
+
   /// File path: assets/images/icon_black_back.webp
   AssetGenImage get iconBlackBack =>
       const AssetGenImage('assets/images/icon_black_back.webp');
@@ -472,6 +480,8 @@ class $AssetsImagesGen {
         iconAlipayPayment,
         iconAlipayScanPayment,
         iconAppleRecoverSubscribe,
+        iconAvatarClose,
+        iconAvatarSelected,
         iconBlackBack,
         iconCbSelected,
         iconCbUnSelect,