diff --git a/lib/routes/user_routes.dart b/lib/routes/user_routes.dart index e431393..fc22159 100644 --- a/lib/routes/user_routes.dart +++ b/lib/routes/user_routes.dart @@ -1,5 +1,6 @@ import 'package:chat/middleware/auth_middleware.dart'; import 'package:chat/views/contact/index/index_page.dart'; +import 'package:chat/views/user/info/avatar_page.dart'; import 'package:chat/views/user/info/index_page.dart'; import 'package:chat/views/user/info/nickname_page.dart'; import 'package:chat/views/user/qr_code/index_page.dart'; @@ -31,6 +32,7 @@ abstract class UserRoutes { static const String share = '/user/share'; static const String info = '/user/info'; + static const String infoAvatar = '/user/info/avatar'; static const String infoNickname = '/user/info/nickname'; static const String serve = '/user/serve'; @@ -87,6 +89,10 @@ abstract class UserRoutes { name: '/info', page: () => const UserInfoPage(), children: [ + GetPage( + name: '/avatar', + page: () => const UserInfoAvatarPage(), + ), GetPage( name: '/nickname', page: () => const UserInfoNicknamePage(), diff --git a/lib/views/moments/index/index_page.dart b/lib/views/moments/index/index_page.dart index e4cd41a..ff62511 100644 --- a/lib/views/moments/index/index_page.dart +++ b/lib/views/moments/index/index_page.dart @@ -76,7 +76,7 @@ class MomentsPage extends GetView { child: MomentListItem(item: item), ), Padding( - padding: const EdgeInsets.only(left: 50), + padding: const EdgeInsets.only(left: 52), child: MomentListItemReplay( index: index, item: item, diff --git a/lib/views/moments/index/widgets/moment_avatar.dart b/lib/views/moments/index/widgets/moment_avatar.dart deleted file mode 100644 index 00b72cf..0000000 --- a/lib/views/moments/index/widgets/moment_avatar.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:cached_network_image/cached_network_image.dart'; -import 'package:chat/configs/app_colors.dart'; -import 'package:flutter/material.dart'; - -class MomentAvatar extends StatelessWidget { - final String imageUrl; - const MomentAvatar({Key? key, String? imageUrl}) - : imageUrl = imageUrl ?? '', - super(key: key); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: 40, - height: 40, - child: DecoratedBox( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(4)), - color: AppColors.white, - image: imageUrl.isNotEmpty - ? DecorationImage( - image: CachedNetworkImageProvider(imageUrl), - fit: BoxFit.cover, - ) - : null, - ), - ), - ); - } -} diff --git a/lib/views/moments/index/widgets/moment_list_item.dart b/lib/views/moments/index/widgets/moment_list_item.dart index 256ba5b..5401bbf 100644 --- a/lib/views/moments/index/widgets/moment_list_item.dart +++ b/lib/views/moments/index/widgets/moment_list_item.dart @@ -5,7 +5,7 @@ import 'package:chat/controllers/moment_controller.dart'; import 'package:chat/models/moment/moment_model.dart'; import 'package:chat/views/moments/index/widgets/future_button.dart'; import 'package:chat/views/moments/index/widgets/grid_media.dart'; -import 'package:chat/views/moments/index/widgets/moment_avatar.dart'; +import 'package:chat/widgets/custom_avatar.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -46,7 +46,7 @@ class MomentListItem extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - MomentAvatar(imageUrl: item.user?.avatar), + CustomAvatar(item.user?.avatar), const SizedBox(width: 10), Expanded( child: Column( diff --git a/lib/views/user/info/avatar_page.dart b/lib/views/user/info/avatar_page.dart new file mode 100644 index 0000000..064b4fc --- /dev/null +++ b/lib/views/user/info/avatar_page.dart @@ -0,0 +1,127 @@ +import 'package:chat/configs/app_colors.dart'; +import 'package:chat/controllers/user_controller.dart'; +import 'package:chat/services/auth_service.dart'; +import 'package:chat/views/home/widgets/pop_menu_item.dart'; +import 'package:chat/widgets/custom_avatar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'package:image_cropper/image_cropper.dart'; +import 'package:wechat_assets_picker/wechat_assets_picker.dart'; + +class UserInfoAvatarPage extends StatelessWidget { + const UserInfoAvatarPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppColors.black, + appBar: AppBar( + title: const Text( + '头像', + style: TextStyle( + color: AppColors.white, + ), + ), + backgroundColor: AppColors.transparent, + foregroundColor: AppColors.white, + systemOverlayStyle: SystemUiOverlayStyle.light, + actions: [ + IconButton( + onPressed: _showMenu, + icon: const Icon(Icons.more_horiz), + ), + ], + ), + body: Center( + child: GetX( + builder: (_) { + return CustomAvatar( + _.userInfo.value.avatar, + size: Get.width, + ); + }, + ), + ), + ); + } + + Future _showMenu() async { + showModalBottomSheet( + context: Get.context!, + isScrollControlled: true, + backgroundColor: AppColors.white, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(8)), + ), + builder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + PopMenuItem( + '从手机相册选择', + onTap: _pickImage, + ), + const Divider(height: 0), + Container( + color: AppColors.page, + height: 8, + ), + const Divider(height: 0), + PopMenuItem( + '取消', + onTap: () { + Get.back(); + }, + ), + ], + ); + }, + ); + } + + Future _pickImage() async { + Get.back(); + final result = await AssetPicker.pickAssets( + Get.context!, + pickerConfig: const AssetPickerConfig( + maxAssets: 1, + textDelegate: AssetPickerTextDelegate(), + requestType: RequestType.image, + ), + ); + + if (result == null) { + return; + } + + _cropImage((await result.first.file)!.path); + } + + Future _cropImage(String imagePath) async { + CroppedFile? croppedFile = await ImageCropper().cropImage( + sourcePath: imagePath, + maxHeight: 512, + maxWidth: 512, + compressQuality: 90, + aspectRatio: const CropAspectRatio( + ratioX: 1, + ratioY: 1, + ), + compressFormat: ImageCompressFormat.jpg, + uiSettings: [ + IOSUiSettings( + title: '头像剪裁', + doneButtonTitle: '完成', + cancelButtonTitle: '取消', + ), + AndroidUiSettings( + toolbarTitle: '头像剪裁', + ), + ], + ); + if (croppedFile != null) { + UserController.to.uploadAvatar(croppedFile.path); + } + } +} diff --git a/lib/views/user/info/index_page.dart b/lib/views/user/info/index_page.dart index 0ea26d4..6d97bbb 100644 --- a/lib/views/user/info/index_page.dart +++ b/lib/views/user/info/index_page.dart @@ -1,12 +1,9 @@ -import 'package:chat/controllers/user_controller.dart'; import 'package:chat/routes/user_routes.dart'; import 'package:chat/services/auth_service.dart'; import 'package:chat/views/user/widgets/link_action_item.dart'; import 'package:chat/widgets/custom_avatar.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:image_cropper/image_cropper.dart'; -import 'package:wechat_assets_picker/wechat_assets_picker.dart'; class UserInfoPage extends StatefulWidget { const UserInfoPage({Key? key}) : super(key: key); @@ -24,79 +21,36 @@ class _UserInfoPageState extends State { ), body: GetX( builder: (_) { - return SafeArea( - child: Column( - children: [ - LinkActionItem( - title: '头像', - onTap: () async { - final result = await AssetPicker.pickAssets( - Get.context!, - pickerConfig: const AssetPickerConfig( - maxAssets: 1, - textDelegate: AssetPickerTextDelegate(), - requestType: RequestType.image, - ), - ); - - if (result == null) { - return; - } - - _cropImage((await result.first.file)!.path); - }, - isLink: true, - trailing: CustomAvatar( - _.userInfo.value.avatar, - size: 52, - ), + return Column( + children: [ + LinkActionItem( + title: '头像', + onTap: () async { + Get.toNamed(UserRoutes.infoAvatar); + }, + isLink: true, + trailing: CustomAvatar( + _.userInfo.value.avatar, + size: 52, ), - LinkActionItem( - title: '昵称', - trailing: Text(_.userInfo.value.nickname!), - isLink: true, - onTap: () { - Get.toNamed( - UserRoutes.infoNickname, - arguments: { - 'nickname': _.userInfo.value.nickname, - }, - ); - }, - ), - Expanded(child: Container()), - ], - ), + ), + LinkActionItem( + title: '昵称', + trailing: Text(_.userInfo.value.nickname!), + isLink: true, + onTap: () { + Get.toNamed( + UserRoutes.infoNickname, + arguments: { + 'nickname': _.userInfo.value.nickname, + }, + ); + }, + ), + ], ); }, ), ); } - - Future _cropImage(String imagePath) async { - CroppedFile? croppedFile = await ImageCropper().cropImage( - sourcePath: imagePath, - maxHeight: 128, - maxWidth: 128, - compressQuality: 100, - aspectRatio: const CropAspectRatio( - ratioX: 1, - ratioY: 1, - ), - compressFormat: ImageCompressFormat.jpg, - uiSettings: [ - IOSUiSettings( - title: '头像剪裁', - doneButtonTitle: '完成', - cancelButtonTitle: '取消', - ), - AndroidUiSettings( - toolbarTitle: '头像剪裁', - ), - ], - ); - if (croppedFile != null) { - UserController.to.uploadAvatar(croppedFile.path); - } - } }