feat(mobile-next): 导入官方 openim-flutter-demo 固定基线 3.8.3-patch.3 并完成双构建
- 上游: github.com/OpenIMSDK/openim-flutter-demo tag 3.8.3-patch.3 commit b3dfdb1e8aaeaaf6f0793e10cadd20d5c184a31f - 并行目录 mobile-next/ 原样导入(含 LICENSE),不覆盖现网 mobile/ - 锁定 Flutter 3.24.5 / Dart 3.5.4 / JDK 17 / Gradle 7.6.3 / AGP 7.3.1 - 实测 Android debug 与 release 构建均成功(见 docs/mobile-next-baseline-import.md) - 本提交可单独回退:git revert 1db1229(重写前) Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'edit_name_logic.dart';
|
||||
|
||||
class EditGroupNameBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => EditGroupNameLogic());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim/pages/chat/group_setup/group_setup_logic.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
enum EditNameType {
|
||||
myGroupMemberNickname,
|
||||
groupNickname,
|
||||
}
|
||||
|
||||
class EditGroupNameLogic extends GetxController {
|
||||
final groupSetupLogic = Get.find<GroupSetupLogic>();
|
||||
late TextEditingController inputCtrl;
|
||||
late EditNameType type;
|
||||
String? faceUrl;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
type = Get.arguments['type'];
|
||||
faceUrl = Get.arguments['faceUrl'];
|
||||
inputCtrl = TextEditingController(
|
||||
text: type == EditNameType.groupNickname ? groupSetupLogic.groupInfo.value.groupName : groupSetupLogic.myGroupMembersInfo.value.nickname,
|
||||
);
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
inputCtrl.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
String? get title => type == EditNameType.myGroupMemberNickname ? StrRes.myGroupMemberNickname : StrRes.groupName;
|
||||
|
||||
void save() async {
|
||||
if (inputCtrl.text.trim().length > 16) {
|
||||
return IMViews.showToast(StrRes.createGroupTips);
|
||||
}
|
||||
await LoadingView.singleton.wrap(asyncFunction: () async {
|
||||
if (type == EditNameType.groupNickname) {
|
||||
await OpenIM.iMManager.groupManager
|
||||
.setGroupInfo(GroupInfo(groupID: groupSetupLogic.groupInfo.value.groupID, groupName: inputCtrl.text.trim()));
|
||||
} else if (type == EditNameType.myGroupMemberNickname) {
|
||||
await OpenIM.iMManager.groupManager.setGroupMemberNickname(
|
||||
groupID: groupSetupLogic.groupInfo.value.groupID,
|
||||
userID: OpenIM.iMManager.userID,
|
||||
groupNickname: inputCtrl.text.trim(),
|
||||
);
|
||||
}
|
||||
});
|
||||
IMViews.showToast(StrRes.setSuccessfully);
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import 'edit_name_logic.dart';
|
||||
|
||||
class EditGroupNamePage extends StatelessWidget {
|
||||
final logic = Get.find<EditGroupNameLogic>();
|
||||
|
||||
EditGroupNamePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (logic.type == EditNameType.groupNickname) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: TitleBar.back(),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
67.verticalSpace,
|
||||
StrRes.editGroupName.toText..style = Styles.ts_0C1C33_20sp,
|
||||
10.verticalSpace,
|
||||
StrRes.editGroupTips.toText..style = Styles.ts_8E9AB0_15sp,
|
||||
37.verticalSpace,
|
||||
Row(
|
||||
children: [
|
||||
50.horizontalSpace,
|
||||
AvatarView(
|
||||
url: logic.faceUrl,
|
||||
isGroup: true,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: logic.inputCtrl,
|
||||
style: Styles.ts_0C1C33_17sp,
|
||||
autofocus: true,
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(16)],
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: 10.h,
|
||||
horizontal: 12.w,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
40.horizontalSpace,
|
||||
],
|
||||
),
|
||||
const Expanded(child: SizedBox.shrink()),
|
||||
Button(
|
||||
margin: EdgeInsets.symmetric(horizontal: 100.w),
|
||||
text: StrRes.save,
|
||||
onTap: logic.save,
|
||||
),
|
||||
const Expanded(child: SizedBox.shrink()),
|
||||
],
|
||||
));
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: logic.title,
|
||||
right: StrRes.save.toText
|
||||
..style = Styles.ts_0C1C33_17sp
|
||||
..onTap = logic.save,
|
||||
),
|
||||
backgroundColor: Styles.c_FFFFFF,
|
||||
body: Column(
|
||||
children: [
|
||||
22.verticalSpace,
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_E8EAEF,
|
||||
borderRadius: BorderRadius.circular(4.r),
|
||||
),
|
||||
child: TextField(
|
||||
controller: logic.inputCtrl,
|
||||
style: Styles.ts_0C1C33_17sp,
|
||||
autofocus: true,
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(16)],
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: 10.h,
|
||||
horizontal: 12.w,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'group_manage_logic.dart';
|
||||
|
||||
class GroupManageBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => GroupManageLogic());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim/pages/chat/group_setup/group_setup_logic.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import '../../../../routes/app_navigator.dart';
|
||||
import '../group_member_list/group_member_list_logic.dart';
|
||||
|
||||
class GroupManageLogic extends GetxController {
|
||||
final groupSetupLogic = Get.find<GroupSetupLogic>();
|
||||
|
||||
Rx<GroupInfo> get groupInfo => groupSetupLogic.groupInfo;
|
||||
|
||||
void transferGroupOwnerRight() async {
|
||||
var result = await AppNavigator.startGroupMemberList(
|
||||
groupInfo: groupInfo.value,
|
||||
opType: GroupMemberOpType.transferRight,
|
||||
);
|
||||
if (result is GroupMembersInfo) {
|
||||
await LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.groupManager.transferGroupOwner(
|
||||
groupID: groupInfo.value.groupID,
|
||||
userID: result.userID!,
|
||||
),
|
||||
);
|
||||
groupInfo.update((val) {
|
||||
val?.ownerUserID = result.userID;
|
||||
});
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import 'group_manage_logic.dart';
|
||||
|
||||
class GroupManagePage extends StatelessWidget {
|
||||
final logic = Get.find<GroupManageLogic>();
|
||||
|
||||
GroupManagePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: StrRes.groupManage,
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Column(
|
||||
children: [
|
||||
_buildItemView(
|
||||
text: StrRes.transferGroupOwnerRight,
|
||||
onTap: logic.transferGroupOwnerRight,
|
||||
showRightArrow: true,
|
||||
isTopRadius: true,
|
||||
isBottomRadius: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemView({
|
||||
required String text,
|
||||
TextStyle? textStyle,
|
||||
String? value,
|
||||
bool switchOn = false,
|
||||
bool isTopRadius = false,
|
||||
bool isBottomRadius = false,
|
||||
bool showRightArrow = false,
|
||||
bool showSwitchButton = false,
|
||||
ValueChanged<bool>? onChanged,
|
||||
Function()? onTap,
|
||||
}) =>
|
||||
GestureDetector(
|
||||
onTap: onTap,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Container(
|
||||
height: 46.h,
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(isTopRadius ? 6.r : 0),
|
||||
topLeft: Radius.circular(isTopRadius ? 6.r : 0),
|
||||
bottomLeft: Radius.circular(isBottomRadius ? 6.r : 0),
|
||||
bottomRight: Radius.circular(isBottomRadius ? 6.r : 0),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: text.toText..style = textStyle ?? Styles.ts_0C1C33_17sp,
|
||||
),
|
||||
if (null != value)
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 150.w),
|
||||
child: value.toText
|
||||
..style = Styles.ts_8E9AB0_14sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
),
|
||||
if (showSwitchButton)
|
||||
CupertinoSwitch(
|
||||
value: switchOn,
|
||||
activeColor: Styles.c_0089FF,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
if (showRightArrow)
|
||||
ImageRes.rightArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../group_setup_logic.dart';
|
||||
import 'group_member_list_logic.dart';
|
||||
|
||||
class GroupMemberListBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
GroupMemberOpType opType = Get.arguments['opType'];
|
||||
Get.lazyPut(() => GroupMemberListLogic(), tag: opType.name);
|
||||
Get.lazyPut(() => GroupSetupLogic());
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim/routes/app_navigator.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:pull_to_refresh_new/pull_to_refresh.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
import '../../../../core/controller/im_controller.dart';
|
||||
import '../group_setup_logic.dart';
|
||||
|
||||
enum GroupMemberOpType {
|
||||
view,
|
||||
transferRight,
|
||||
call,
|
||||
at,
|
||||
del,
|
||||
}
|
||||
|
||||
class GroupMemberListLogic extends GetxController {
|
||||
final imLogic = Get.find<IMController>();
|
||||
final groupSetupLogic = Get.find<GroupSetupLogic>();
|
||||
final controller = RefreshController();
|
||||
final memberList = <GroupMembersInfo>[].obs;
|
||||
final checkedList = <GroupMembersInfo>[].obs;
|
||||
final poController = CustomPopupMenuController();
|
||||
int count = 500;
|
||||
final myGroupMemberLevel = 1.obs;
|
||||
late GroupInfo groupInfo;
|
||||
late GroupMemberOpType opType;
|
||||
late StreamSubscription mISub;
|
||||
|
||||
bool get isMultiSelMode =>
|
||||
opType == GroupMemberOpType.call || opType == GroupMemberOpType.at || opType == GroupMemberOpType.del;
|
||||
|
||||
bool get excludeSelfFromList =>
|
||||
opType == GroupMemberOpType.call || opType == GroupMemberOpType.at || opType == GroupMemberOpType.transferRight;
|
||||
|
||||
bool get isDelMember => opType == GroupMemberOpType.del;
|
||||
|
||||
bool get isAdmin => myGroupMemberLevel.value == GroupRoleLevel.admin;
|
||||
|
||||
bool get isOwner => myGroupMemberLevel.value == GroupRoleLevel.owner;
|
||||
|
||||
bool get isOwnerOrAdmin => isAdmin || isOwner;
|
||||
|
||||
int get maxLength => min(groupInfo.memberCount!, 10);
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
mISub.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
groupInfo = Get.arguments['groupInfo'];
|
||||
opType = Get.arguments['opType'];
|
||||
mISub = imLogic.memberInfoChangedSubject.listen(_updateMemberLevel);
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
_queryMyGroupMemberLevel();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
void _updateMemberLevel(GroupMembersInfo e) {
|
||||
if (e.groupID == groupInfo.groupID) {
|
||||
equal(GroupMembersInfo el) => el.userID == e.userID;
|
||||
final member = memberList.firstWhereOrNull(equal);
|
||||
if (null != member && e.roleLevel != member.roleLevel) {
|
||||
member.roleLevel = e.roleLevel;
|
||||
}
|
||||
memberList.sort((a, b) {
|
||||
if (b.roleLevel != a.roleLevel) {
|
||||
return b.roleLevel!.compareTo(a.roleLevel!);
|
||||
} else {
|
||||
return b.joinTime!.compareTo(a.joinTime!);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _queryMyGroupMemberLevel() async {
|
||||
LoadingView.singleton.wrap(asyncFunction: () async {
|
||||
final list = await OpenIM.iMManager.groupManager.getGroupMembersInfo(
|
||||
groupID: groupInfo.groupID,
|
||||
userIDList: [OpenIM.iMManager.userID],
|
||||
);
|
||||
final myInfo = list.firstOrNull;
|
||||
if (null != myInfo) {
|
||||
myGroupMemberLevel.value = myInfo.roleLevel ?? 1;
|
||||
}
|
||||
await onLoad();
|
||||
});
|
||||
}
|
||||
|
||||
Future<List<GroupMembersInfo>> _getGroupMembers() {
|
||||
final result = OpenIM.iMManager.groupManager.getGroupMemberList(
|
||||
groupID: groupInfo.groupID,
|
||||
count: count,
|
||||
offset: memberList.length,
|
||||
filter: isDelMember ? (isOwner ? 4 : (isAdmin ? 3 : 0)) : 0,
|
||||
);
|
||||
|
||||
count = 100;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
onLoad() async {
|
||||
final list = await _getGroupMembers();
|
||||
memberList.addAll(list);
|
||||
|
||||
if (list.length < count) {
|
||||
controller.loadNoData();
|
||||
} else {
|
||||
controller.loadComplete();
|
||||
}
|
||||
}
|
||||
|
||||
bool isChecked(GroupMembersInfo membersInfo) => checkedList.contains(membersInfo);
|
||||
|
||||
clickMember(GroupMembersInfo membersInfo) async {
|
||||
if (opType == GroupMemberOpType.transferRight) {
|
||||
_transferGroupRight(membersInfo);
|
||||
return;
|
||||
}
|
||||
if (isMultiSelMode) {
|
||||
if (isChecked(membersInfo)) {
|
||||
checkedList.remove(membersInfo);
|
||||
} else if (checkedList.length < maxLength) {
|
||||
checkedList.add(membersInfo);
|
||||
}
|
||||
} else {
|
||||
viewMemberInfo(membersInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static _transferGroupRight(GroupMembersInfo membersInfo) async {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: sprintf(StrRes.confirmTransferGroupToUser, [membersInfo.nickname]),
|
||||
));
|
||||
if (confirm == true) {
|
||||
Get.back(result: membersInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void removeSelectedMember(GroupMembersInfo membersInfo) {
|
||||
checkedList.remove(membersInfo);
|
||||
}
|
||||
|
||||
viewMemberInfo(GroupMembersInfo membersInfo) => AppNavigator.startUserProfilePane(
|
||||
userID: membersInfo.userID!,
|
||||
groupID: membersInfo.groupID,
|
||||
nickname: membersInfo.nickname,
|
||||
faceURL: membersInfo.faceURL,
|
||||
);
|
||||
|
||||
void addMember() async {
|
||||
poController.hideMenu();
|
||||
await groupSetupLogic.addMember();
|
||||
refreshData();
|
||||
}
|
||||
|
||||
void refreshData() {
|
||||
LoadingView.singleton.wrap(asyncFunction: () async {
|
||||
memberList.clear();
|
||||
await onLoad();
|
||||
});
|
||||
}
|
||||
|
||||
void delMember() async {
|
||||
poController.hideMenu();
|
||||
await groupSetupLogic.removeMember();
|
||||
refreshData();
|
||||
}
|
||||
|
||||
void search() async {
|
||||
final memberInfo = await AppNavigator.startSearchGroupMember(
|
||||
groupInfo: groupInfo,
|
||||
opType: opType,
|
||||
);
|
||||
if (opType == GroupMemberOpType.transferRight) {
|
||||
Get.back(result: memberInfo);
|
||||
} else if (isMultiSelMode) {
|
||||
clickMember(memberInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static _buildEveryoneMemberInfo() => GroupMembersInfo(
|
||||
userID: OpenIM.iMManager.conversationManager.atAllTag,
|
||||
nickname: StrRes.everyone,
|
||||
);
|
||||
|
||||
void selectEveryone() {
|
||||
Get.back(result: <GroupMembersInfo>[_buildEveryoneMemberInfo()]);
|
||||
}
|
||||
|
||||
void confirmSelectedMember() {
|
||||
Get.back(result: checkedList.value);
|
||||
}
|
||||
|
||||
bool hiddenMember(GroupMembersInfo membersInfo) =>
|
||||
excludeSelfFromList && membersInfo.userID == OpenIM.iMManager.userID;
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:pull_to_refresh_new/pull_to_refresh.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
import 'group_member_list_logic.dart';
|
||||
|
||||
class GroupMemberListPage extends StatelessWidget {
|
||||
final logic = Get.find<GroupMemberListLogic>(tag: (Get.arguments['opType'] as GroupMemberOpType).name);
|
||||
|
||||
GroupMemberListPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(() => Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: logic.opType == GroupMemberOpType.del ? StrRes.removeGroupMember : StrRes.groupMember,
|
||||
right: logic.opType == GroupMemberOpType.view
|
||||
? PopButton(
|
||||
popCtrl: logic.poController,
|
||||
horizontalMargin: 1.w,
|
||||
menus: [
|
||||
PopMenuInfo(text: StrRes.addMember, onTap: logic.addMember),
|
||||
if (logic.isOwnerOrAdmin) PopMenuInfo(text: StrRes.delMember, onTap: logic.delMember),
|
||||
],
|
||||
child: ImageRes.moreBlack.toImage
|
||||
..width = 28.w
|
||||
..height = 28.h)
|
||||
: null,
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: logic.search,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.h),
|
||||
color: Styles.c_FFFFFF,
|
||||
child: const SearchBox(),
|
||||
),
|
||||
),
|
||||
if (logic.opType == GroupMemberOpType.at && logic.isOwnerOrAdmin)
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: logic.selectEveryone,
|
||||
child: Container(
|
||||
height: 64.h,
|
||||
color: Styles.c_FFFFFF,
|
||||
margin: EdgeInsets.symmetric(vertical: 10.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarView(
|
||||
width: 44.w,
|
||||
height: 44.h,
|
||||
text: '@',
|
||||
textStyle: Styles.ts_FFFFFF_21sp,
|
||||
),
|
||||
10.horizontalSpace,
|
||||
StrRes.everyone.toText..style = Styles.ts_0C1C33_17sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: SmartRefresher(
|
||||
controller: logic.controller,
|
||||
onLoading: logic.onLoad,
|
||||
enablePullDown: false,
|
||||
enablePullUp: true,
|
||||
header: IMViews.buildHeader(),
|
||||
footer: IMViews.buildFooter(),
|
||||
child: ListView.builder(
|
||||
itemCount: logic.memberList.length,
|
||||
itemBuilder: (_, index) => Obx(() => _buildItemView(logic.memberList[index])),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (logic.isMultiSelMode) _buildCheckedConfirmView(),
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildItemView(GroupMembersInfo membersInfo) => logic.hiddenMember(membersInfo)
|
||||
? const SizedBox()
|
||||
: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => logic.clickMember(membersInfo),
|
||||
child: Container(
|
||||
height: 64.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
color: Styles.c_FFFFFF,
|
||||
child: Row(
|
||||
children: [
|
||||
if (logic.isMultiSelMode)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 15.w),
|
||||
child: ChatRadio(checked: logic.isChecked(membersInfo)),
|
||||
),
|
||||
AvatarView(
|
||||
url: membersInfo.faceURL,
|
||||
text: membersInfo.nickname,
|
||||
),
|
||||
10.horizontalSpace,
|
||||
Expanded(
|
||||
child: (membersInfo.nickname ?? '').toText
|
||||
..style = Styles.ts_0C1C33_17sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
),
|
||||
if (membersInfo.roleLevel == GroupRoleLevel.owner)
|
||||
StrRes.groupOwner.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
if (membersInfo.roleLevel == GroupRoleLevel.admin)
|
||||
StrRes.groupAdmin.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildCheckedConfirmView() => Container(
|
||||
height: 66.h,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
offset: Offset(0, -1.h),
|
||||
blurRadius: 4.r,
|
||||
spreadRadius: 1.r,
|
||||
color: Styles.c_000000_opacity4,
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => Get.bottomSheet(
|
||||
SelectedMemberListView(),
|
||||
isScrollControlled: true,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
sprintf(StrRes.selectedPeopleCount, [logic.checkedList.length]).toText
|
||||
..style = Styles.ts_0089FF_14sp,
|
||||
ImageRes.expandUpArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
],
|
||||
),
|
||||
if (logic.checkedList.isNotEmpty) 4.verticalSpace,
|
||||
logic.checkedList.map((e) => e.nickname ?? '').join('、').toText
|
||||
..style = Styles.ts_8E9AB0_14sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Button(
|
||||
height: 40.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 14.w),
|
||||
text: sprintf(StrRes.confirmSelectedPeople, [
|
||||
logic.checkedList.length,
|
||||
logic.maxLength,
|
||||
]),
|
||||
textStyle: Styles.ts_FFFFFF_14sp,
|
||||
onTap: logic.confirmSelectedMember,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class SelectedMemberListView extends StatelessWidget {
|
||||
SelectedMemberListView({Key? key}) : super(key: key);
|
||||
final logic = Get.find<GroupMemberListLogic>(tag: (Get.arguments['opType'] as GroupMemberOpType).name);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
constraints: BoxConstraints(maxHeight: 548.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(6.r),
|
||||
topRight: Radius.circular(6.r),
|
||||
),
|
||||
),
|
||||
child: Obx(() => Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
decoration: BoxDecoration(
|
||||
border: BorderDirectional(
|
||||
bottom: BorderSide(color: Styles.c_E8EAEF, width: 1),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
sprintf(StrRes.selectedPeopleCount, [logic.checkedList.length]).toText
|
||||
..style = Styles.ts_0C1C33_17sp_medium,
|
||||
const Spacer(),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => Get.back(),
|
||||
child: Container(
|
||||
height: 52.h,
|
||||
alignment: Alignment.center,
|
||||
child: StrRes.confirm.toText..style = Styles.ts_0089FF_17sp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: logic.checkedList.length,
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (_, index) => _buildItemView(logic.checkedList[index]),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemView(GroupMembersInfo membersInfo) => Container(
|
||||
height: 64.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
color: Styles.c_FFFFFF,
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarView(
|
||||
url: membersInfo.faceURL,
|
||||
text: membersInfo.nickname,
|
||||
),
|
||||
10.horizontalSpace,
|
||||
Expanded(
|
||||
child: (membersInfo.nickname ?? '').toText
|
||||
..style = Styles.ts_0C1C33_17sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => logic.removeSelectedMember(membersInfo),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 13.w, vertical: 4.h),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(2.r),
|
||||
border: Border.all(
|
||||
color: Styles.c_E8EAEF,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: StrRes.remove.toText..style = Styles.ts_0089FF_17sp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'search_group_member_logic.dart';
|
||||
|
||||
class SearchGroupMemberBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SearchGroupMemberLogic());
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim/pages/chat/group_setup/group_setup_logic.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:pull_to_refresh_new/pull_to_refresh.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
import '../../../../../core/controller/im_controller.dart';
|
||||
import '../../../../../routes/app_navigator.dart';
|
||||
import '../group_member_list_logic.dart';
|
||||
|
||||
class SearchGroupMemberLogic extends GetxController {
|
||||
final imLogic = Get.find<IMController>();
|
||||
final controller = RefreshController();
|
||||
final focusNode = FocusNode();
|
||||
final searchCtrl = TextEditingController();
|
||||
final memberList = <GroupMembersInfo>[].obs;
|
||||
final count = 100;
|
||||
late GroupInfo groupInfo;
|
||||
late GroupMemberOpType opType;
|
||||
late StreamSubscription mISub;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
groupInfo = Get.arguments['groupInfo'];
|
||||
opType = Get.arguments['opType'];
|
||||
searchCtrl.addListener(_clearInput);
|
||||
mISub = imLogic.memberInfoChangedSubject.listen((e) {
|
||||
if (e.groupID == groupInfo.groupID) {
|
||||
final member = memberList.firstWhereOrNull((el) => el.userID == e.userID);
|
||||
if (null != member && e.roleLevel != member.roleLevel) {
|
||||
member.roleLevel = e.roleLevel;
|
||||
memberList.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
focusNode.dispose();
|
||||
searchCtrl.dispose();
|
||||
mISub.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
bool get isSearchNotResult => searchCtrl.text.trim().isNotEmpty && memberList.isEmpty;
|
||||
|
||||
_clearInput() {
|
||||
final key = searchCtrl.text.trim();
|
||||
if (key.isEmpty) {
|
||||
memberList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<GroupMembersInfo>> _request(int offset) => LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.groupManager.searchGroupMembers(
|
||||
groupID: groupInfo.groupID,
|
||||
isSearchMemberNickname: true,
|
||||
isSearchUserID: true,
|
||||
keywordList: [searchCtrl.text.trim()],
|
||||
offset: offset,
|
||||
count: count,
|
||||
),
|
||||
);
|
||||
|
||||
search() async {
|
||||
final key = searchCtrl.text.trim();
|
||||
if (key.isNotEmpty) {
|
||||
final list = await _request(0);
|
||||
memberList.assignAll(list);
|
||||
if (list.length < count) {
|
||||
controller.loadNoData();
|
||||
} else {
|
||||
controller.loadComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load() async {
|
||||
final key = searchCtrl.text.trim();
|
||||
if (key.isNotEmpty) {
|
||||
final list = await _request(memberList.length);
|
||||
memberList.addAll(list);
|
||||
if (list.length < count) {
|
||||
controller.loadNoData();
|
||||
} else {
|
||||
controller.loadComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hiddenMembers(GroupMembersInfo info) {
|
||||
if (opType == GroupMemberOpType.transferRight || opType == GroupMemberOpType.at || opType == GroupMemberOpType.call) {
|
||||
return info.userID == OpenIM.iMManager.userID;
|
||||
} else if (opType == GroupMemberOpType.del) {
|
||||
final logic = Get.find<GroupSetupLogic>();
|
||||
return logic.isAdmin && info.roleLevel != GroupRoleLevel.member || logic.isOwner && info.roleLevel == GroupRoleLevel.owner;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clickMember(GroupMembersInfo membersInfo) {
|
||||
if (opType == GroupMemberOpType.transferRight) {
|
||||
_transferGroupRight(membersInfo);
|
||||
} else if (opType == GroupMemberOpType.at || opType == GroupMemberOpType.call || opType == GroupMemberOpType.del) {
|
||||
Get.back(result: membersInfo);
|
||||
} else {
|
||||
viewMemberInfo(membersInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static _transferGroupRight(GroupMembersInfo membersInfo) async {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: sprintf(StrRes.confirmTransferGroupToUser, [membersInfo.nickname]),
|
||||
));
|
||||
if (confirm == true) {
|
||||
Get.back(result: membersInfo);
|
||||
}
|
||||
}
|
||||
|
||||
viewMemberInfo(GroupMembersInfo membersInfo) => AppNavigator.startUserProfilePane(
|
||||
userID: membersInfo.userID!,
|
||||
groupID: membersInfo.groupID,
|
||||
nickname: membersInfo.nickname,
|
||||
faceURL: membersInfo.faceURL,
|
||||
);
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:pull_to_refresh_new/pull_to_refresh.dart';
|
||||
import 'package:search_keyword_text/search_keyword_text.dart';
|
||||
|
||||
import 'search_group_member_logic.dart';
|
||||
|
||||
class SearchGroupMemberPage extends StatelessWidget {
|
||||
final logic = Get.find<SearchGroupMemberLogic>();
|
||||
|
||||
SearchGroupMemberPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TouchCloseSoftKeyboard(
|
||||
child: Scaffold(
|
||||
appBar: TitleBar.search(
|
||||
focusNode: logic.focusNode,
|
||||
controller: logic.searchCtrl,
|
||||
onSubmitted: (_) => logic.search(),
|
||||
onCleared: () => logic.focusNode.requestFocus(),
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Obx(() => logic.isSearchNotResult
|
||||
? _emptyListView
|
||||
: SmartRefresher(
|
||||
controller: logic.controller,
|
||||
enablePullUp: true,
|
||||
enablePullDown: false,
|
||||
footer: IMViews.buildFooter(),
|
||||
onLoading: logic.load,
|
||||
child: ListView.builder(
|
||||
itemCount: logic.memberList.length,
|
||||
itemBuilder: (_, index) {
|
||||
final info = logic.memberList.elementAt(index);
|
||||
if (logic.hiddenMembers(info)) {
|
||||
return const SizedBox();
|
||||
} else {
|
||||
return _buildItemView(info);
|
||||
}
|
||||
},
|
||||
),
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemView(GroupMembersInfo membersInfo) => GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () => logic.clickMember(membersInfo),
|
||||
child: Container(
|
||||
height: 64.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
color: Styles.c_FFFFFF,
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarView(
|
||||
url: membersInfo.faceURL,
|
||||
text: membersInfo.nickname,
|
||||
),
|
||||
10.horizontalSpace,
|
||||
Expanded(
|
||||
child: SearchKeywordText(
|
||||
text: membersInfo.nickname ?? '',
|
||||
keyText: logic.searchCtrl.text.trim(),
|
||||
style: Styles.ts_0C1C33_17sp,
|
||||
keyStyle: Styles.ts_0089FF_17sp,
|
||||
),
|
||||
),
|
||||
if (membersInfo.roleLevel == GroupRoleLevel.owner)
|
||||
StrRes.groupOwner.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
if (membersInfo.roleLevel == GroupRoleLevel.admin)
|
||||
StrRes.groupAdmin.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _emptyListView => SizedBox(
|
||||
width: 1.sw,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
44.verticalSpace,
|
||||
StrRes.searchNotFound.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'group_qrcode_logic.dart';
|
||||
|
||||
class GroupQrcodeBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => GroupQrcodeLogic());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim/pages/chat/group_setup/group_setup_logic.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
class GroupQrcodeLogic extends GetxController {
|
||||
final groupSetupLogic = Get.find<GroupSetupLogic>();
|
||||
|
||||
String buildQRContent() {
|
||||
return '${Config.groupScheme}${groupSetupLogic.groupInfo.value.groupID}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
import 'group_qrcode_logic.dart';
|
||||
|
||||
class GroupQrcodePage extends StatelessWidget {
|
||||
final logic = Get.find<GroupQrcodeLogic>();
|
||||
|
||||
GroupQrcodePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(
|
||||
() => Scaffold(
|
||||
appBar: TitleBar.back(title: StrRes.groupQrcode),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 22.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 30.w),
|
||||
width: 331.w,
|
||||
height: 460.h,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 7.r,
|
||||
spreadRadius: 1.r,
|
||||
color: Styles.c_000000.withOpacity(.08),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
top: 30.h,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
AvatarView(
|
||||
width: 48.w,
|
||||
height: 48.h,
|
||||
url: logic.groupSetupLogic.groupInfo.value.faceURL,
|
||||
text: logic.groupSetupLogic.groupInfo.value.groupName,
|
||||
textStyle: Styles.ts_FFFFFF_14sp,
|
||||
),
|
||||
12.horizontalSpace,
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 180.w),
|
||||
child: (logic.groupSetupLogic.groupInfo.value.groupName ?? '').toText
|
||||
..style = Styles.ts_0C1C33_20sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 140.h,
|
||||
width: 272.w,
|
||||
child: StrRes.groupQrcodeHint.toText
|
||||
..style = Styles.ts_8E9AB0_15sp
|
||||
..textAlign = TextAlign.center,
|
||||
),
|
||||
Positioned(
|
||||
top: 183.h,
|
||||
width: 272.w,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
child: Container(
|
||||
width: 180.w,
|
||||
height: 180.w,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
border: Border.all(color: Styles.c_E8EAEF, width: 4.w),
|
||||
),
|
||||
child: QrImageView(
|
||||
data: logic.buildQRContent(),
|
||||
size: 140.w,
|
||||
backgroundColor: Styles.c_FFFFFF,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'group_setup_logic.dart';
|
||||
|
||||
class GroupSetupBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => GroupSetupLogic());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
||||
|
||||
import '../../../core/controller/app_controller.dart';
|
||||
import '../../../core/controller/im_controller.dart';
|
||||
import '../../../routes/app_navigator.dart';
|
||||
import '../../contacts/select_contacts/select_contacts_logic.dart';
|
||||
import '../../conversation/conversation_logic.dart';
|
||||
import '../chat_logic.dart';
|
||||
import 'edit_name/edit_name_logic.dart';
|
||||
import 'group_member_list/group_member_list_logic.dart';
|
||||
|
||||
class GroupSetupLogic extends GetxController {
|
||||
final imLogic = Get.find<IMController>();
|
||||
|
||||
final chatLogic = Get.find<ChatLogic>(tag: GetTags.chat);
|
||||
final appLogic = Get.find<AppController>();
|
||||
final conversationLogic = Get.find<ConversationLogic>();
|
||||
final memberList = <GroupMembersInfo>[].obs;
|
||||
late Rx<ConversationInfo> conversationInfo;
|
||||
late Rx<GroupInfo> groupInfo;
|
||||
late Rx<GroupMembersInfo> myGroupMembersInfo;
|
||||
late StreamSubscription _guSub;
|
||||
late StreamSubscription _mASub;
|
||||
late StreamSubscription _mISub;
|
||||
late StreamSubscription _mDSub;
|
||||
late StreamSubscription _ccSub;
|
||||
late StreamSubscription _jasSub;
|
||||
late StreamSubscription _jdsSub;
|
||||
final lock = Lock();
|
||||
final isJoinedGroup = false.obs;
|
||||
final avatar = Rx<File?>(null);
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
if (Get.arguments['conversationInfo'] != null) {
|
||||
conversationInfo = Rx(Get.arguments['conversationInfo']);
|
||||
} else {
|
||||
final temp = await OpenIM.iMManager.conversationManager.getOneConversation(
|
||||
sourceID: chatLogic.conversationInfo.isGroupChat
|
||||
? chatLogic.conversationInfo.groupID!
|
||||
: chatLogic.conversationInfo.userID!,
|
||||
sessionType: chatLogic.conversationInfo.conversationType!);
|
||||
conversationInfo = Rx(temp);
|
||||
}
|
||||
groupInfo = Rx(_defaultGroupInfo);
|
||||
myGroupMembersInfo = Rx(_defaultMemberInfo);
|
||||
|
||||
_ccSub = imLogic.conversationChangedSubject.listen((newList) {
|
||||
final newValue =
|
||||
newList.firstWhereOrNull((element) => element.conversationID == conversationInfo.value.conversationID);
|
||||
if (newValue != null) {
|
||||
conversationInfo.update((val) {
|
||||
val?.isPinned = newValue.isPinned;
|
||||
|
||||
val?.recvMsgOpt = newValue.recvMsgOpt;
|
||||
val?.isMsgDestruct = newValue.isMsgDestruct;
|
||||
val?.msgDestructTime = newValue.msgDestructTime;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_guSub = imLogic.groupInfoUpdatedSubject.listen((value) {
|
||||
if (value.groupID == groupInfo.value.groupID) {
|
||||
_updateGroupInfo(value);
|
||||
}
|
||||
});
|
||||
|
||||
_jasSub = imLogic.joinedGroupAddedSubject.listen((value) {
|
||||
if (value.groupID == groupInfo.value.groupID) {
|
||||
isJoinedGroup.value = true;
|
||||
_queryAllInfo();
|
||||
}
|
||||
});
|
||||
|
||||
_jdsSub = imLogic.joinedGroupDeletedSubject.listen((value) {
|
||||
if (value.groupID == groupInfo.value.groupID) {
|
||||
isJoinedGroup.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
_mISub = imLogic.memberInfoChangedSubject.listen((e) {
|
||||
if (e.groupID == groupInfo.value.groupID && e.userID == myGroupMembersInfo.value.userID) {
|
||||
myGroupMembersInfo.update((val) {
|
||||
val?.nickname = e.nickname;
|
||||
val?.roleLevel = e.roleLevel;
|
||||
});
|
||||
}
|
||||
if (e.groupID == groupInfo.value.groupID && e.userID == groupInfo.value.ownerUserID) {
|
||||
var index = memberList.indexWhere((element) => element.userID == groupInfo.value.ownerUserID);
|
||||
if (index == -1) {
|
||||
memberList.insert(0, e);
|
||||
} else if (index != 0) {
|
||||
memberList.insert(0, memberList.removeAt(index));
|
||||
}
|
||||
}
|
||||
memberList.sort((a, b) {
|
||||
if (b.roleLevel != a.roleLevel) {
|
||||
return b.roleLevel!.compareTo(a.roleLevel!);
|
||||
} else {
|
||||
return b.joinTime!.compareTo(a.joinTime!);
|
||||
}
|
||||
});
|
||||
});
|
||||
_mASub = imLogic.memberAddedSubject.listen((e) async {
|
||||
if (e.groupID == groupInfo.value.groupID) {
|
||||
if (e.userID == OpenIM.iMManager.userID) {
|
||||
isJoinedGroup.value = true;
|
||||
_queryAllInfo();
|
||||
} else {
|
||||
memberList.add(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
_mDSub = imLogic.memberDeletedSubject.listen((e) {
|
||||
if (e.groupID == groupInfo.value.groupID) {
|
||||
if (e.userID == OpenIM.iMManager.userID) {
|
||||
isJoinedGroup.value = false;
|
||||
} else {
|
||||
memberList.removeWhere((element) => element.userID == e.userID);
|
||||
}
|
||||
}
|
||||
});
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
_checkIsJoinedGroup();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_guSub.cancel();
|
||||
_mASub.cancel();
|
||||
_mDSub.cancel();
|
||||
_ccSub.cancel();
|
||||
_mISub.cancel();
|
||||
_jdsSub.cancel();
|
||||
_jasSub.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
get _defaultGroupInfo => GroupInfo(
|
||||
groupID: conversationInfo.value.groupID!,
|
||||
groupName: conversationInfo.value.showName,
|
||||
faceURL: conversationInfo.value.faceURL,
|
||||
memberCount: 0,
|
||||
);
|
||||
|
||||
get _defaultMemberInfo => GroupMembersInfo(
|
||||
userID: OpenIM.iMManager.userID,
|
||||
nickname: OpenIM.iMManager.userInfo.nickname,
|
||||
);
|
||||
|
||||
bool get isOwnerOrAdmin => isOwner || isAdmin;
|
||||
|
||||
bool get isAdmin => myGroupMembersInfo.value.roleLevel == GroupRoleLevel.admin;
|
||||
|
||||
bool get isNotDisturb => conversationInfo.value.recvMsgOpt != 0;
|
||||
|
||||
bool get isOwner => groupInfo.value.ownerUserID == OpenIM.iMManager.userID;
|
||||
|
||||
String get conversationID => conversationInfo.value.conversationID;
|
||||
|
||||
void _checkIsJoinedGroup() async {
|
||||
isJoinedGroup.value = await OpenIM.iMManager.groupManager.isJoinedGroup(
|
||||
groupID: groupInfo.value.groupID,
|
||||
);
|
||||
_queryAllInfo();
|
||||
}
|
||||
|
||||
void _queryAllInfo() {
|
||||
if (isJoinedGroup.value) {
|
||||
getGroupInfo();
|
||||
getGroupMembers();
|
||||
getMyGroupMemberInfo();
|
||||
}
|
||||
}
|
||||
|
||||
getGroupMembers() async {
|
||||
var list = await OpenIM.iMManager.groupManager.getGroupMemberList(
|
||||
groupID: groupInfo.value.groupID,
|
||||
count: 10,
|
||||
);
|
||||
memberList.assignAll(list);
|
||||
}
|
||||
|
||||
getGroupInfo() async {
|
||||
var list = await OpenIM.iMManager.groupManager.getGroupsInfo(
|
||||
groupIDList: [groupInfo.value.groupID],
|
||||
);
|
||||
var value = list.firstOrNull;
|
||||
if (null != value) {
|
||||
_updateGroupInfo(value);
|
||||
}
|
||||
}
|
||||
|
||||
getMyGroupMemberInfo() async {
|
||||
final list = await OpenIM.iMManager.groupManager.getGroupMembersInfo(
|
||||
groupID: groupInfo.value.groupID,
|
||||
userIDList: [OpenIM.iMManager.userID],
|
||||
);
|
||||
final info = list.firstOrNull;
|
||||
if (null != info) {
|
||||
myGroupMembersInfo.update((val) {
|
||||
val?.nickname = info.nickname;
|
||||
val?.roleLevel = info.roleLevel;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _updateGroupInfo(GroupInfo value) {
|
||||
groupInfo.update((val) {
|
||||
val?.groupName = value.groupName;
|
||||
val?.faceURL = value.faceURL;
|
||||
val?.notification = value.notification;
|
||||
val?.introduction = value.introduction;
|
||||
val?.memberCount = value.memberCount;
|
||||
val?.ownerUserID = value.ownerUserID;
|
||||
val?.status = value.status;
|
||||
val?.needVerification = value.needVerification;
|
||||
val?.groupType = value.groupType;
|
||||
val?.lookMemberInfo = value.lookMemberInfo;
|
||||
val?.applyMemberFriend = value.applyMemberFriend;
|
||||
val?.notificationUserID = value.notificationUserID;
|
||||
val?.notificationUpdateTime = value.notificationUpdateTime;
|
||||
val?.ex = value.ex;
|
||||
});
|
||||
}
|
||||
|
||||
void modifyGroupAvatar() async {
|
||||
final List<AssetEntity>? assets = await AssetPicker.pickAssets(
|
||||
Get.context!,
|
||||
pickerConfig: const AssetPickerConfig(maxAssets: 1, requestType: RequestType.image),
|
||||
);
|
||||
if (assets != null) {
|
||||
final file = await assets.first.file;
|
||||
final result = await IMViews.uCropPic(file!.path);
|
||||
|
||||
final path = result['path'];
|
||||
final url = result['url'];
|
||||
|
||||
if (url != null) {
|
||||
avatar.value = File(path);
|
||||
await _modifyGroupInfo(faceUrl: url);
|
||||
groupInfo.update((val) {
|
||||
val?.faceURL = url;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void modifyGroupName(String? faceUrl) => AppNavigator.startEditGroupName(
|
||||
type: EditNameType.groupNickname,
|
||||
faceUrl: faceUrl,
|
||||
);
|
||||
|
||||
_modifyGroupInfo({
|
||||
String? groupName,
|
||||
String? notification,
|
||||
String? introduction,
|
||||
String? faceUrl,
|
||||
}) =>
|
||||
OpenIM.iMManager.groupManager.setGroupInfo(GroupInfo(
|
||||
groupID: groupInfo.value.groupID,
|
||||
groupName: groupName,
|
||||
notification: notification,
|
||||
introduction: introduction,
|
||||
faceURL: faceUrl,
|
||||
));
|
||||
|
||||
void viewGroupQrcode() => AppNavigator.startGroupQrcode();
|
||||
|
||||
void viewGroupMembers() => AppNavigator.startGroupMemberList(
|
||||
groupInfo: groupInfo.value,
|
||||
);
|
||||
|
||||
void groupManage() => AppNavigator.startGroupManage(
|
||||
groupInfo: groupInfo.value,
|
||||
);
|
||||
|
||||
void _removeConversation() async {
|
||||
await OpenIM.iMManager.conversationManager.deleteConversationAndDeleteAllMsg(
|
||||
conversationID: conversationInfo.value.conversationID,
|
||||
);
|
||||
|
||||
conversationLogic.removeConversation(conversationInfo.value.conversationID);
|
||||
}
|
||||
|
||||
void quitGroup() async {
|
||||
if (isJoinedGroup.value) {
|
||||
if (isOwner) {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: StrRes.dismissGroupHint,
|
||||
));
|
||||
if (confirm == true) {
|
||||
await OpenIM.iMManager.groupManager.dismissGroup(
|
||||
groupID: groupInfo.value.groupID,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: StrRes.quitGroupHint,
|
||||
));
|
||||
if (confirm == true) {
|
||||
await OpenIM.iMManager.groupManager.quitGroup(
|
||||
groupID: groupInfo.value.groupID,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_removeConversation();
|
||||
}
|
||||
|
||||
AppNavigator.startBackMain();
|
||||
}
|
||||
|
||||
void copyGroupID() {
|
||||
IMUtils.copy(text: groupInfo.value.groupID);
|
||||
}
|
||||
|
||||
int length() {
|
||||
int buttons = isOwnerOrAdmin ? 2 : 1;
|
||||
return (memberList.length + buttons) > 10 ? 10 : (memberList.length + buttons);
|
||||
}
|
||||
|
||||
Widget itemBuilder({
|
||||
required int index,
|
||||
required Widget Function(GroupMembersInfo info) builder,
|
||||
required Widget Function() addButton,
|
||||
required Widget Function() delButton,
|
||||
}) {
|
||||
var length = isOwnerOrAdmin ? 8 : 9;
|
||||
if (memberList.length > length) {
|
||||
if (index < length) {
|
||||
var info = memberList.elementAt(index);
|
||||
return builder(info);
|
||||
} else if (index == length) {
|
||||
return addButton();
|
||||
} else {
|
||||
return delButton();
|
||||
}
|
||||
} else {
|
||||
if (index < memberList.length) {
|
||||
var info = memberList.elementAt(index);
|
||||
return builder(info);
|
||||
} else if (index == memberList.length) {
|
||||
return addButton();
|
||||
} else {
|
||||
return delButton();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void toggleNotDisturb() {
|
||||
LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.conversationManager.setConversationRecvMessageOpt(
|
||||
conversationID: conversationID,
|
||||
status: !isNotDisturb ? 2 : 0,
|
||||
));
|
||||
}
|
||||
|
||||
void clearChatHistory() async {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: StrRes.confirmClearChatHistory,
|
||||
rightText: StrRes.clearAll,
|
||||
));
|
||||
if (confirm == true) {
|
||||
await OpenIM.iMManager.conversationManager.clearConversationAndDeleteAllMsg(
|
||||
conversationID: conversationID,
|
||||
);
|
||||
chatLogic.clearAllMessage();
|
||||
IMViews.showToast(StrRes.clearSuccessfully);
|
||||
}
|
||||
}
|
||||
|
||||
addMember() async {
|
||||
final result = await AppNavigator.startSelectContacts(
|
||||
action: SelAction.addMember,
|
||||
groupID: groupInfo.value.groupID,
|
||||
);
|
||||
|
||||
final list = IMUtils.convertSelectContactsResultToUserID(result);
|
||||
if (list is List<String>) {
|
||||
try {
|
||||
await LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.groupManager.inviteUserToGroup(
|
||||
groupID: groupInfo.value.groupID,
|
||||
userIDList: list,
|
||||
reason: 'Come on baby',
|
||||
),
|
||||
);
|
||||
} catch (_) {}
|
||||
getGroupMembers();
|
||||
}
|
||||
}
|
||||
|
||||
removeMember() async {
|
||||
final list = await AppNavigator.startGroupMemberList(
|
||||
groupInfo: groupInfo.value,
|
||||
opType: GroupMemberOpType.del,
|
||||
);
|
||||
if (list is List<GroupMembersInfo>) {
|
||||
var removeUidList = list.map((e) => e.userID!).toList();
|
||||
try {
|
||||
await LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.groupManager.kickGroupMember(
|
||||
groupID: groupInfo.value.groupID,
|
||||
userIDList: removeUidList,
|
||||
reason: 'Get out baby',
|
||||
),
|
||||
);
|
||||
} catch (_) {}
|
||||
getGroupMembers();
|
||||
}
|
||||
}
|
||||
|
||||
void viewMemberInfo(GroupMembersInfo membersInfo) => AppNavigator.startUserProfilePane(
|
||||
userID: membersInfo.userID!,
|
||||
nickname: membersInfo.nickname,
|
||||
faceURL: membersInfo.faceURL,
|
||||
groupID: membersInfo.groupID,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:sprintf/sprintf.dart';
|
||||
|
||||
import 'group_setup_logic.dart';
|
||||
|
||||
class GroupSetupPage extends StatelessWidget {
|
||||
final logic = Get.find<GroupSetupLogic>();
|
||||
|
||||
GroupSetupPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(title: StrRes.groupChatSetup),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Obx(() => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
if (logic.isJoinedGroup.value) _buildBaseInfoView(),
|
||||
if (logic.isJoinedGroup.value) _buildMemberView(),
|
||||
if (logic.isOwner)
|
||||
_buildItemView(
|
||||
text: StrRes.groupManage,
|
||||
showRightArrow: true,
|
||||
isBottomRadius: true,
|
||||
onTap: logic.groupManage,
|
||||
),
|
||||
10.verticalSpace,
|
||||
|
||||
_buildItemView(
|
||||
text: StrRes.messageNotDisturb,
|
||||
switchOn: logic.isNotDisturb,
|
||||
showSwitchButton: true,
|
||||
isBottomRadius: true,
|
||||
onChanged: (_) => logic.toggleNotDisturb(),
|
||||
),
|
||||
10.verticalSpace,
|
||||
_buildItemView(
|
||||
text: StrRes.clearChatHistory,
|
||||
textStyle: Styles.ts_FF381F_17sp,
|
||||
isTopRadius: true,
|
||||
showRightArrow: true,
|
||||
onTap: logic.clearChatHistory,
|
||||
),
|
||||
if (!logic.isOwner)
|
||||
_buildItemView(
|
||||
text: logic.isJoinedGroup.value ? StrRes.exitGroup : StrRes.delete,
|
||||
textStyle: Styles.ts_FF381F_17sp,
|
||||
showRightArrow: true,
|
||||
onTap: logic.quitGroup,
|
||||
),
|
||||
if (logic.isOwner)
|
||||
_buildItemView(
|
||||
text: StrRes.dismissGroup,
|
||||
textStyle: Styles.ts_FF381F_17sp,
|
||||
isBottomRadius: true,
|
||||
showRightArrow: true,
|
||||
onTap: logic.quitGroup,
|
||||
),
|
||||
40.verticalSpace,
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBaseInfoView() => Container(
|
||||
height: 80.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 50.h,
|
||||
height: 50.h,
|
||||
child: Stack(
|
||||
children: [
|
||||
AvatarView(
|
||||
width: 48.w,
|
||||
height: 48.h,
|
||||
url: logic.groupInfo.value.faceURL,
|
||||
file: logic.avatar.value,
|
||||
text: logic.groupInfo.value.groupName,
|
||||
textStyle: Styles.ts_FFFFFF_14sp,
|
||||
isGroup: true,
|
||||
onTap: logic.isOwnerOrAdmin ? logic.modifyGroupAvatar : null,
|
||||
),
|
||||
if (logic.isOwnerOrAdmin)
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: ImageRes.editAvatar.toImage
|
||||
..width = 14.w
|
||||
..height = 14.h)
|
||||
],
|
||||
),
|
||||
),
|
||||
10.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: logic.isOwnerOrAdmin ? () => logic.modifyGroupName(logic.conversationInfo.value.faceURL) : null,
|
||||
child: Row(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 200.w),
|
||||
child: (logic.groupInfo.value.groupName ?? '').toText..style = Styles.ts_0C1C33_17sp),
|
||||
'(${logic.groupInfo.value.memberCount ?? 0})'.toText..style = Styles.ts_0C1C33_17sp,
|
||||
6.horizontalSpace,
|
||||
if (logic.isOwnerOrAdmin)
|
||||
ImageRes.editName.toImage
|
||||
..width = 12.w
|
||||
..height = 12.h,
|
||||
],
|
||||
),
|
||||
),
|
||||
4.verticalSpace,
|
||||
logic.groupInfo.value.groupID.toText
|
||||
..style = Styles.ts_8E9AB0_14sp
|
||||
..onTap = logic.copyGroupID,
|
||||
],
|
||||
),
|
||||
),
|
||||
ImageRes.mineQr.toImage
|
||||
..width = 18.w
|
||||
..height = 18.h
|
||||
..onTap = logic.viewGroupQrcode,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildMemberView() => Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: Column(
|
||||
children: [
|
||||
GridView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: logic.length(),
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 8.h),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 5,
|
||||
crossAxisSpacing: 3.w,
|
||||
mainAxisSpacing: 2.h,
|
||||
childAspectRatio: 68.w / 78.h,
|
||||
),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return logic.itemBuilder(
|
||||
index: index,
|
||||
builder: (info) => Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 58.w,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AvatarView(
|
||||
width: 48.w,
|
||||
height: 48.h,
|
||||
url: info.faceURL,
|
||||
text: info.nickname,
|
||||
textStyle: Styles.ts_FFFFFF_14sp,
|
||||
onTap: () => logic.viewMemberInfo(info),
|
||||
),
|
||||
if (logic.groupInfo.value.ownerUserID == info.userID)
|
||||
Positioned(
|
||||
bottom: 0.h,
|
||||
child: Container(
|
||||
width: 52.h,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_E8EAEF,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
child: StrRes.groupOwner.toText
|
||||
..style = Styles.ts_8E9AB0_10sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
2.verticalSpace,
|
||||
(info.nickname ?? '').toText
|
||||
..style = Styles.ts_8E9AB0_10sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
],
|
||||
),
|
||||
addButton: () => GestureDetector(
|
||||
onTap: logic.addMember,
|
||||
child: Column(
|
||||
children: [
|
||||
ImageRes.addMember.toImage
|
||||
..width = 48.w
|
||||
..height = 48.h,
|
||||
StrRes.addMember.toText..style = Styles.ts_8E9AB0_10sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
delButton: () => GestureDetector(
|
||||
onTap: logic.removeMember,
|
||||
child: Column(
|
||||
children: [
|
||||
ImageRes.delMember.toImage
|
||||
..width = 48.w
|
||||
..height = 48.h,
|
||||
StrRes.delMember.toText..style = Styles.ts_8E9AB0_10sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Container(
|
||||
color: Styles.c_E8EAEF,
|
||||
height: 1,
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
),
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: logic.viewGroupMembers,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 12.w, right: 16.w),
|
||||
height: 46.h,
|
||||
child: Row(
|
||||
children: [
|
||||
sprintf(StrRes.viewAllGroupMembers, [logic.groupInfo.value.memberCount]).toText
|
||||
..style = Styles.ts_0C1C33_17sp,
|
||||
const Spacer(),
|
||||
ImageRes.rightArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildItemView({
|
||||
required String text,
|
||||
TextStyle? textStyle,
|
||||
String? value,
|
||||
bool switchOn = false,
|
||||
bool isTopRadius = false,
|
||||
bool isBottomRadius = false,
|
||||
bool showRightArrow = false,
|
||||
bool showSwitchButton = false,
|
||||
ValueChanged<bool>? onChanged,
|
||||
Function()? onTap,
|
||||
}) =>
|
||||
GestureDetector(
|
||||
onTap: onTap,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Container(
|
||||
height: 46.h,
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(isTopRadius ? 6.r : 0),
|
||||
topLeft: Radius.circular(isTopRadius ? 6.r : 0),
|
||||
bottomLeft: Radius.circular(isBottomRadius ? 6.r : 0),
|
||||
bottomRight: Radius.circular(isBottomRadius ? 6.r : 0),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: text.toText
|
||||
..style = textStyle ?? Styles.ts_0C1C33_17sp
|
||||
..maxLines = 1),
|
||||
if (null != value)
|
||||
value.toText
|
||||
..style = Styles.ts_8E9AB0_14sp
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
if (showSwitchButton)
|
||||
CupertinoSwitch(
|
||||
value: switchOn,
|
||||
activeColor: Styles.c_0089FF,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
if (showRightArrow)
|
||||
ImageRes.rightArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user