import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:loopin/IM/controller/chat_detail_controller.dart'; import 'package:loopin/IM/im_service.dart'; import 'package:loopin/api/common_api.dart'; import 'package:loopin/components/my_confirm.dart'; import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/pages/groupChat/components/invite_action_sheet.dart'; import 'package:loopin/pages/groupChat/components/member_action_sheet.dart'; import 'package:loopin/pages/groupChat/components/set_group_info.dart'; import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart'; import 'package:loopin/service/http.dart'; import 'package:loopin/utils/index.dart'; import 'package:loopin/utils/permissions.dart'; import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:tencent_cloud_chat_sdk/enum/group_type.dart'; import 'package:tencent_cloud_chat_sdk/enum/receive_message_opt.dart'; import 'package:tencent_cloud_chat_sdk/enum/receive_message_opt_enum.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_info.dart'; import 'package:wechat_assets_picker/wechat_assets_picker.dart'; class Groupdetail extends StatefulWidget { const Groupdetail({super.key}); // final String groupID; // const Groupdetail({super.key, required this.groupID}); @override State createState() => GroupdetailState(); } class GroupdetailState extends State { late final GroupDetailController controller; @override void initState() { super.initState(); // 跳转前先put controller = Get.find(); // controller = Get.put(GroupDetailController(groupID: widget.groupID)); } ///设置群头像 void pickFaceUrl(BuildContext context) async { final hasPer = await Permissions.requestPhotoPermission(); if (!hasPer) { Permissions.showPermissionDialog(); return; } final pickedAssets = await AssetPicker.pickAssets( context, pickerConfig: AssetPickerConfig( textDelegate: const AssetPickerTextDelegate(), pathNameBuilder: (AssetPathEntity album) { return Utils.translateAlbumName(album); }, maxAssets: 1, requestType: RequestType.image, filterOptions: FilterOptionGroup( imageOption: const FilterOption(), ), ), ); if (pickedAssets != null && pickedAssets.isNotEmpty) { final asset = pickedAssets.first; final file = await asset.file; // 获取实际文件 if (file != null) { final fileSizeInBytes = await file.length(); final sizeInMB = fileSizeInBytes / (1024 * 1024); if (sizeInMB > 20) { MyDialog.toast('图片大小不能超过20MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200))); } else { logger.w("图片合法,大小:$sizeInMB MB"); //走upload(file)上传图片拿到url地址 final istance = MyDialog.loading('上传中', duration: Duration(minutes: 1)); final res = await Http.upload(CommonApi.uploadFile, filePath: file.path); final imgUrl = res['data']['url']; logger.e(imgUrl); // 设置群头像 await controller.setGroupInfo( changedInfo: V2TimGroupInfo( groupID: controller.info.value!.groupID, groupType: GroupType.Work, faceUrl: imgUrl, ), ); istance.close(); } } } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( centerTitle: true, forceMaterialTransparency: true, title: const Text( "群资料", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { Get.back(result: controller.info.value?.groupName ?? ''); }, ), bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Container(height: 1, color: Colors.grey[300]), ), ), body: ListView( children: [ // 介绍 ListTile( // 群头像 leading: Obx( () => GestureDetector( onTap: () { // 编辑头像 if (controller.isOwner.value) { // pickFaceUrl(context); } }, child: ClipOval( child: NetworkOrAssetImage( imageUrl: controller.info.value?.faceUrl ?? '', placeholderAsset: 'assets/images/group.png', height: 60, width: 60, ), ), ), ), // 群名称 title: Obx( () => GestureDetector( onTap: () { // 去setinfo页 logger.w('点了名称'); if (controller.isOwner.value) { Get.to( () => SetGroupInfoPage( appBarTitle: "修改群名称", fieldLabel: "群名称", maxLines: 1, maxLength: 20, initialValue: controller.info.value?.groupName ?? "", onSubmit: (value) async { // 修改群名称 await controller.setGroupInfo( changedInfo: V2TimGroupInfo( groupID: controller.info.value!.groupID, groupType: GroupType.Work, groupName: value, ), ); }, ), ); } }, child: Text( Utils.handleText(controller.info.value?.groupName, '', "未命名群聊"), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ), // 群简介 subtitle: Obx( () => GestureDetector( onTap: () { // 去setinfo页 logger.w('点了简介绍'); if (controller.isOwner.value) { Get.to( () => SetGroupInfoPage( appBarTitle: "修改群简介", fieldLabel: "群简介", maxLines: 5, maxLength: 100, initialValue: controller.info.value?.introduction ?? "", onSubmit: (value) async { // 修改群名称 await controller.setGroupInfo( changedInfo: V2TimGroupInfo( groupID: controller.info.value!.groupID, groupType: GroupType.Work, introduction: value, ), ); }, ), ); } }, child: Text( Utils.handleText(controller.info.value?.introduction, '', "暂无群介绍"), maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.grey), ), ), ), trailing: const Icon(Icons.chevron_right), ), const Divider(height: 1), // 群成员 ListTile( title: Obx( () => Text("群成员(${controller.info.value?.memberCount ?? 0}/${controller.info.value?.memberMaxCount ?? 0})"), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Obx( () => Text("查看${controller.info.value?.memberCount ?? 0}个群成员", style: const TextStyle(color: Colors.grey, fontSize: 14)), ), const Icon(Icons.chevron_right), ], ), onTap: () { // 群成员列表 showModalBottomSheet( context: context, barrierColor: Colors.white, isScrollControlled: true, useSafeArea: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return MemberActionSheet( showButton: false, groupID: controller.groupID, title: '群成员', showSelf: true, onAction: (userIDs) { // }, ); }, ); }, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Wrap( spacing: 16, runSpacing: 12, children: [ Obx( () { return Wrap( spacing: 16, runSpacing: 12, children: controller.memberList.take(8).map((m) { // 点击成员头像 return GestureDetector( onTap: () { final currentUserID = controller.selfInfo.value?.userID ?? ''; if (m.userID != currentUserID) { Get.toNamed('/vloger', arguments: {'memberId': m.userID}); } }, child: Column( mainAxisSize: MainAxisSize.min, children: [ ClipOval( child: NetworkOrAssetImage( imageUrl: m.faceUrl, height: 50, width: 50, ), ), const SizedBox(height: 4), SizedBox( width: 50, child: Text( m.nickName ?? '未知昵称', maxLines: 1, softWrap: false, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12), ), ), ], ), ); }).toList(), ); }, ), // 邀请 + GestureDetector( onTap: () { //检测群人数上限, logger.w('当前人数${controller.info.value?.memberCount ?? 0}---上限人数${controller.info.value?.memberMaxCount ?? 0}'); if ((controller.info.value?.memberCount ?? 0) < (controller.info.value?.memberMaxCount ?? 0)) { // 群人数未达到上限,可以继续加人 showModalBottomSheet( context: context, barrierColor: Colors.white, isScrollControlled: true, useSafeArea: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return InviteActionSheet( groupID: controller.groupID, title: '邀请新成员', onAction: (userIDs) { logger.w("准备添加群成员: $userIDs"); controller.inviteUserToGroup(userList: userIDs); }, ); }, ); } else { MyToast().tip(title: '群人数已达上限', position: 'top'); } }, child: Column( children: [ CircleAvatar( radius: 25, child: const Icon(Icons.add), ), const SizedBox(height: 4), const Text("邀请", style: TextStyle(fontSize: 12)), ], ), ), // 移除 - Obx( () => controller.isOwner.value ? GestureDetector( onTap: () { showModalBottomSheet( context: context, barrierColor: Colors.white, isScrollControlled: true, useSafeArea: true, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return MemberActionSheet( groupID: controller.groupID, title: '移出成员', onAction: (userIDs) { logger.w("准备移除群成员: $userIDs"); controller.kickGroupMember(userIDs); }, ); }, ); }, child: Column( children: [ const CircleAvatar( radius: 25, child: Icon(Icons.remove), ), const SizedBox(height: 4), const Text("移除", style: TextStyle(fontSize: 12)), ], ), ) : SizedBox.shrink(), ) ], ), ), const Divider(height: 1), // 群公告 ListTile( title: const Text("群公告"), subtitle: Obx( () => Text( Utils.handleText(controller.info.value?.notification, '', "暂无公告"), maxLines: 3, overflow: TextOverflow.ellipsis, ), ), trailing: const Icon(Icons.chevron_right), onTap: () { logger.w('点击了群公告'); if (controller.isOwner.value) { Get.to( () => SetGroupInfoPage( appBarTitle: "修改群公告", fieldLabel: "群公告", maxLines: 8, maxLength: 200, initialValue: controller.info.value?.notification ?? "", onSubmit: (value) async { // 修改群公告 await controller.setGroupInfo( changedInfo: V2TimGroupInfo( groupID: controller.info.value!.groupID, groupType: GroupType.Work, notification: value, ), ); }, ), ); } }, ), const Divider(height: 1), // 我的本群昵称 ListTile( title: const Text("我的本群昵称"), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Obx( () { return Text( Utils.handleText(controller.selfInfo.value?.nameCard, controller.selfInfo.value?.nickName, '未设置昵称'), style: TextStyle(fontSize: 14), ); }, ), const Icon(Icons.chevron_right), ], ), onTap: () async { Get.to( () => SetGroupInfoPage( appBarTitle: "修改群昵称", fieldLabel: "群昵称", maxLines: 1, maxLength: 12, initialValue: controller.selfInfo.value?.nameCard ?? "", onSubmit: (value) { // 修改自己的群昵称 controller.setSelfInfo(nameCard: value); }, ), ); }, ), const Divider(height: 1), // 消息免打扰 Obx( () => SwitchListTile( title: Text("消息免打扰"), value: controller.info.value?.recvOpt == ReceiveMsgOptType.kTIMRecvMsgOpt_Not_Notify_Except_At, // 暂时只提供0和3 activeColor: Colors.green, inactiveThumbColor: Colors.grey, inactiveTrackColor: Colors.white, onChanged: (v) async { if (controller.info.value != null) { logger.w(v); logger.e(controller.info.value?.recvOpt); // v=true -> 开启免打扰 = 3 final res = await ImService.instance.setGroupReceiveMessageOpt( groupID: controller.groupID, opt: v ? ReceiveMsgOptEnum.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE_EXCEPT_AT : ReceiveMsgOptEnum.V2TIM_RECEIVE_MESSAGE, // 关闭免打扰 = 0 ); if (res.success) { controller.info.value!.recvOpt = v ? ReceiveMsgOptType.kTIMRecvMsgOpt_Not_Notify_Except_At : ReceiveMsgOptType.kTIMRecvMsgOpt_Receive; // 关闭免打扰 = 0 开启=3 controller.info.refresh(); } else { MyToast().tip(title: '网络繁忙,请稍后再试', position: 'top'); } } // class ReceiveMsgOptType { // 在线正常接收消息,离线时会进行 APNs 推送 // static const int kTIMRecvMsgOpt_Receive = 0; // 不会接收到消息,离线不会有推送通知 // static const int kTIMRecvMsgOpt_Not_Receive = 1; // 在线正常接收消息,离线不会有推送通知 // static const int kTIMRecvMsgOpt_Not_Notify = 2; // 在线接收消息,离线只接收 at 消息的推送 // static const int kTIMRecvMsgOpt_Not_Notify_Except_At = 3; // 在线和离线都只接收@消息 // static const int kTIMRecvMsgOpt_Not_Receive_Except_At = 4; // } }, ), ), const Divider(height: 1), // 举报 // ListTile( // title: const Text("举报"), // trailing: const Icon(Icons.chevron_right), // onTap: () { // // // }, // ), // 退出群聊 const SizedBox(height: 20), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.red, minimumSize: const Size(double.infinity, 48), ), onPressed: () async { // 二次确认 final confirmed = await ConfirmDialog.show( title: "提示", content: "确认要退出群聊吗?", ); if (confirmed == true) { await controller.quitGroup(); Get.find().toolFlag.value = false; // 禁用工具栏 Get.back(); // 返回上一个页面 } }, child: const Text("退出群聊", style: TextStyle(color: Colors.white)), ), ), const SizedBox(height: 30), ], ), ); } }