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:
+10
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'friend_setup_logic.dart';
|
||||
|
||||
class FriendSetupBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => FriendSetupLogic());
|
||||
}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import '../../../../routes/app_navigator.dart';
|
||||
import '../../../chat/chat_logic.dart';
|
||||
import '../../../conversation/conversation_logic.dart';
|
||||
import '../../select_contacts/select_contacts_logic.dart';
|
||||
import '../user_profile _panel_logic.dart';
|
||||
|
||||
class FriendSetupLogic extends GetxController {
|
||||
final conversationLogic = Get.find<ConversationLogic>();
|
||||
final userProfilesLogic = Get.find<UserProfilePanelLogic>(tag: GetTags.userProfile);
|
||||
late String userID;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
userID = Get.arguments['userID'];
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void toggleBlacklist() {
|
||||
if (userProfilesLogic.userInfo.value.isBlacklist == true) {
|
||||
removeBlacklist();
|
||||
} else {
|
||||
addBlacklist();
|
||||
}
|
||||
}
|
||||
|
||||
void addBlacklist() async {
|
||||
var confirm = await Get.dialog(CustomDialog(title: StrRes.areYouSureAddBlacklist));
|
||||
if (confirm == true) {
|
||||
await OpenIM.iMManager.friendshipManager.addBlacklist(
|
||||
userID: userProfilesLogic.userInfo.value.userID!,
|
||||
);
|
||||
userProfilesLogic.userInfo.update((val) {
|
||||
val?.isBlacklist = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void removeBlacklist() async {
|
||||
await OpenIM.iMManager.friendshipManager.removeBlacklist(
|
||||
userID: userProfilesLogic.userInfo.value.userID!,
|
||||
);
|
||||
userProfilesLogic.userInfo.update((val) {
|
||||
val?.isBlacklist = false;
|
||||
});
|
||||
}
|
||||
|
||||
void deleteFromFriendList() async {
|
||||
var confirm = await Get.dialog(CustomDialog(
|
||||
title: StrRes.areYouSureDelFriend,
|
||||
rightText: StrRes.delete,
|
||||
));
|
||||
if (confirm) {
|
||||
await LoadingView.singleton.wrap(asyncFunction: () async {
|
||||
await OpenIM.iMManager.friendshipManager.deleteFriend(
|
||||
userID: userProfilesLogic.userInfo.value.userID!,
|
||||
);
|
||||
userProfilesLogic.userInfo.update((val) {
|
||||
val?.isFriendship = false;
|
||||
});
|
||||
|
||||
final userIDList = [
|
||||
userProfilesLogic.userInfo.value.userID,
|
||||
OpenIM.iMManager.userID,
|
||||
];
|
||||
userIDList.sort();
|
||||
final conversationID = 'si_${userIDList.join('_')}';
|
||||
|
||||
await OpenIM.iMManager.conversationManager.deleteConversationAndDeleteAllMsg(conversationID: conversationID);
|
||||
|
||||
conversationLogic.list.removeWhere((e) => e.conversationID == conversationID);
|
||||
});
|
||||
|
||||
if (userProfilesLogic.offAllWhenDelFriend == true) {
|
||||
AppNavigator.startBackMain();
|
||||
} else {
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recommendToFriend() async {
|
||||
final isRegistered = Get.isRegistered<ChatLogic>(tag: GetTags.chat);
|
||||
if (isRegistered) {
|
||||
final logic = Get.find<ChatLogic>(tag: GetTags.chat);
|
||||
logic.recommendFriendCarte(UserInfo.fromJson(userProfilesLogic.userInfo.value.toJson()));
|
||||
return;
|
||||
}
|
||||
final result = await AppNavigator.startSelectContacts(
|
||||
action: SelAction.recommend,
|
||||
ex: '[${StrRes.carte}]${userProfilesLogic.userInfo.value.nickname}',
|
||||
);
|
||||
if (null != result) {
|
||||
final customEx = result['customEx'];
|
||||
final checkedList = result['checkedList'];
|
||||
for (var info in checkedList) {
|
||||
final userID = IMUtils.convertCheckedToUserID(info);
|
||||
final groupID = IMUtils.convertCheckedToGroupID(info);
|
||||
if (customEx is String && customEx.isNotEmpty) {
|
||||
OpenIM.iMManager.messageManager.sendMessage(
|
||||
message: await OpenIM.iMManager.messageManager.createTextMessage(
|
||||
text: customEx,
|
||||
),
|
||||
userID: userID,
|
||||
groupID: groupID,
|
||||
offlinePushInfo: Config.offlinePushInfo,
|
||||
);
|
||||
}
|
||||
|
||||
OpenIM.iMManager.messageManager.sendMessage(
|
||||
message: await OpenIM.iMManager.messageManager.createCardMessage(
|
||||
userID: userProfilesLogic.userInfo.value.userID!,
|
||||
nickname: userProfilesLogic.userInfo.value.showName,
|
||||
faceURL: userProfilesLogic.userInfo.value.faceURL,
|
||||
),
|
||||
userID: userID,
|
||||
groupID: groupID,
|
||||
offlinePushInfo: Config.offlinePushInfo,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setFriendRemark() => AppNavigator.startSetFriendRemark();
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
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 'friend_setup_logic.dart';
|
||||
|
||||
class FriendSetupPage extends StatelessWidget {
|
||||
final logic = Get.find<FriendSetupLogic>();
|
||||
|
||||
FriendSetupPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: StrRes.friendSetup,
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: Column(
|
||||
children: [
|
||||
10.verticalSpace,
|
||||
_buildItemView(
|
||||
label: StrRes.setupRemark,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(6.r),
|
||||
topLeft: Radius.circular(6.r),
|
||||
),
|
||||
showRightArrow: true,
|
||||
onTap: logic.setFriendRemark,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.recommendToFriend,
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(6.r),
|
||||
bottomRight: Radius.circular(6.r),
|
||||
),
|
||||
showRightArrow: true,
|
||||
onTap: logic.recommendToFriend,
|
||||
),
|
||||
10.verticalSpace,
|
||||
Obx(() => _buildItemView(
|
||||
label: StrRes.addToBlacklist,
|
||||
showSwitchButton: true,
|
||||
switchOn:
|
||||
logic.userProfilesLogic.userInfo.value.isBlacklist == true,
|
||||
onChanged: (_) => logic.toggleBlacklist(),
|
||||
)),
|
||||
10.verticalSpace,
|
||||
_buildItemView(
|
||||
isDelFriendButton: true,
|
||||
onTap: logic.deleteFromFriendList,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildItemView({
|
||||
String? label,
|
||||
bool showRightArrow = false,
|
||||
bool showSwitchButton = false,
|
||||
BorderRadius? borderRadius,
|
||||
bool switchOn = false,
|
||||
bool isDelFriendButton = false,
|
||||
ValueChanged<bool>? onChanged,
|
||||
Function()? onTap,
|
||||
}) =>
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
child: Ink(
|
||||
height: 46.h,
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: borderRadius ?? BorderRadius.circular(6.r),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
alignment: isDelFriendButton ? Alignment.center : null,
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: isDelFriendButton
|
||||
? (StrRes.unfriend.toText..style = Styles.ts_FF381F_17sp)
|
||||
: Row(
|
||||
children: [
|
||||
(label ?? '').toText..style = Styles.ts_0C1C33_17sp,
|
||||
const Spacer(),
|
||||
if (showRightArrow)
|
||||
ImageRes.rightArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
if (showSwitchButton)
|
||||
CupertinoSwitch(
|
||||
value: switchOn,
|
||||
onChanged: onChanged,
|
||||
activeColor: Styles.c_0089FF,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'personal_info_logic.dart';
|
||||
|
||||
class PersonalInfoBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => PersonalInfoLogic());
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../user_profile _panel_logic.dart';
|
||||
|
||||
class PersonalInfoLogic extends GetxController {
|
||||
final userProfilesLogic = Get.find<UserProfilePanelLogic>(tag: GetTags.userProfile);
|
||||
late String userID;
|
||||
final userFullInfo = UserFullInfo().obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
userID = Get.arguments['userID'];
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
_queryUserFullInfo();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
void _queryUserFullInfo() async {
|
||||
final existUser = UserCacheManager().getUserInfo(userID);
|
||||
if (existUser != null) {
|
||||
userFullInfo.update((val) {
|
||||
val?.nickname = existUser.nickname;
|
||||
val?.faceURL = existUser.faceURL;
|
||||
val?.status = existUser.status;
|
||||
val?.level = existUser.level;
|
||||
val?.phoneNumber = existUser.phoneNumber;
|
||||
val?.areaCode = existUser.areaCode;
|
||||
val?.birth = existUser.birth;
|
||||
val?.email = existUser.email;
|
||||
val?.gender = existUser.gender;
|
||||
val?.mobile = existUser.mobile;
|
||||
});
|
||||
}
|
||||
|
||||
final list = await LoadingView.singleton.wrap(
|
||||
asyncFunction: () => Apis.getUserFullInfo(userIDList: [userID]),
|
||||
);
|
||||
final info = list?.firstOrNull;
|
||||
if (null != info) {
|
||||
UserCacheManager().addOrUpdateUserInfo(userID, info);
|
||||
|
||||
userFullInfo.update((val) {
|
||||
val?.nickname = info.nickname;
|
||||
val?.faceURL = info.faceURL;
|
||||
val?.gender = info.gender;
|
||||
val?.englishName = info.englishName;
|
||||
val?.birth = info.birth;
|
||||
val?.telephone = info.telephone;
|
||||
val?.phoneNumber = info.phoneNumber;
|
||||
val?.email = info.email;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String? get nickname => IMUtils.emptyStrToNull(userProfilesLogic.userInfo.value.nickname) ?? IMUtils.emptyStrToNull(userFullInfo.value.nickname);
|
||||
|
||||
String? get faceURL => IMUtils.emptyStrToNull(userProfilesLogic.userInfo.value.faceURL) ?? IMUtils.emptyStrToNull(userFullInfo.value.faceURL);
|
||||
|
||||
bool get isMale => (userProfilesLogic.userInfo.value.gender ?? userFullInfo.value.gender) == 1;
|
||||
|
||||
String? get englishName => IMUtils.emptyStrToNull(userFullInfo.value.englishName) ?? '-';
|
||||
|
||||
int? get _birth => userProfilesLogic.userInfo.value.birth ?? userFullInfo.value.birth;
|
||||
|
||||
String? get birth => _birth == null ? '-' : DateUtil.formatDateMs(_birth!, format: IMUtils.getTimeFormat1());
|
||||
|
||||
String? get telephone => IMUtils.emptyStrToNull(userFullInfo.value.telephone) ?? '-';
|
||||
|
||||
String? get phoneNumber => IMUtils.emptyStrToNull(userFullInfo.value.phoneNumber) ?? '-';
|
||||
|
||||
String? get email => IMUtils.emptyStrToNull(userFullInfo.value.email) ?? '-';
|
||||
|
||||
clickPhoneNumber() => _callSystemPhone(userFullInfo.value.phoneNumber);
|
||||
|
||||
clickTel() => _callSystemPhone(userFullInfo.value.telephone);
|
||||
|
||||
clickEmail() => _callSystemEmail(userFullInfo.value.email);
|
||||
|
||||
_callSystemPhone(String? phone) async {
|
||||
final value = IMUtils.emptyStrToNull(phone);
|
||||
if (null != value) {
|
||||
final uri = Uri.parse('tel:$value');
|
||||
try {
|
||||
launchUrl(uri);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
_callSystemEmail(String? email) {
|
||||
final value = IMUtils.emptyStrToNull(email);
|
||||
if (null != value) {
|
||||
final uri = Uri.parse('mailto:$value');
|
||||
try {
|
||||
launchUrl(uri);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
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 'personal_info_logic.dart';
|
||||
|
||||
class PersonalInfoPage extends StatelessWidget {
|
||||
final logic = Get.find<PersonalInfoLogic>();
|
||||
|
||||
PersonalInfoPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: StrRes.personalInfo,
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: SingleChildScrollView(
|
||||
child: Obx(
|
||||
() => Column(
|
||||
children: [
|
||||
10.verticalSpace,
|
||||
_buildCornerBgView(
|
||||
children: [
|
||||
_buildItemView(
|
||||
label: StrRes.avatar,
|
||||
isAvatar: true,
|
||||
value: logic.nickname,
|
||||
url: logic.faceURL,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.name,
|
||||
value: logic.nickname,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.gender,
|
||||
value: logic.isMale ? StrRes.man : StrRes.woman,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.englishName,
|
||||
value: logic.englishName,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.birthDay,
|
||||
value: logic.birth,
|
||||
),
|
||||
],
|
||||
),
|
||||
10.verticalSpace,
|
||||
_buildCornerBgView(
|
||||
children: [
|
||||
_buildItemView(
|
||||
label: StrRes.mobile,
|
||||
value: logic.phoneNumber,
|
||||
onTap: logic.clickPhoneNumber,
|
||||
),
|
||||
_buildItemView(
|
||||
label: StrRes.email,
|
||||
value: logic.email,
|
||||
onTap: logic.clickEmail,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCornerBgView({required List<Widget> children}) => Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
margin: EdgeInsets.symmetric(horizontal: 10.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_FFFFFF,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(6.r),
|
||||
topRight: Radius.circular(6.r),
|
||||
bottomLeft: Radius.circular(6.r),
|
||||
bottomRight: Radius.circular(6.r),
|
||||
),
|
||||
),
|
||||
child: Column(children: children),
|
||||
);
|
||||
|
||||
Widget _buildItemView({
|
||||
required String label,
|
||||
String? value,
|
||||
String? url,
|
||||
bool isAvatar = false,
|
||||
Function()? onTap,
|
||||
}) =>
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: 46.h,
|
||||
child: Row(
|
||||
children: [
|
||||
label.toText..style = Styles.ts_0C1C33_17sp,
|
||||
const Spacer(),
|
||||
if (null != value && !isAvatar) value.toText..style = Styles.ts_0C1C33_17sp,
|
||||
if (isAvatar)
|
||||
AvatarView(
|
||||
width: 32.w,
|
||||
height: 32.h,
|
||||
url: url,
|
||||
text: value,
|
||||
textStyle: Styles.ts_FFFFFF_10sp,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'set_remark_logic.dart';
|
||||
|
||||
class SetFriendRemarkBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SetFriendRemarkLogic());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import '../user_profile _panel_logic.dart';
|
||||
|
||||
class SetFriendRemarkLogic extends GetxController {
|
||||
final userProfilesLogic =
|
||||
Get.find<UserProfilePanelLogic>(tag: GetTags.userProfile);
|
||||
late TextEditingController inputCtrl;
|
||||
|
||||
void save() async {
|
||||
try {
|
||||
await LoadingView.singleton.wrap(
|
||||
asyncFunction: () => OpenIM.iMManager.friendshipManager.setFriendRemark(
|
||||
userID: userProfilesLogic.userInfo.value.userID!,
|
||||
remark: inputCtrl.text.trim(),
|
||||
),
|
||||
);
|
||||
IMViews.showToast(StrRes.saveSuccessfully);
|
||||
Get.back(result: inputCtrl.text.trim());
|
||||
} catch (_) {
|
||||
IMViews.showToast(StrRes.saveFailed);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
inputCtrl =
|
||||
TextEditingController(text: userProfilesLogic.userInfo.value.remark);
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
inputCtrl.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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 'set_remark_logic.dart';
|
||||
|
||||
class SetFriendRemarkPage extends StatelessWidget {
|
||||
final logic = Get.find<SetFriendRemarkLogic>();
|
||||
|
||||
SetFriendRemarkPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
title: StrRes.remark,
|
||||
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,11 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:openim_common/openim_common.dart';
|
||||
|
||||
import 'user_profile _panel_logic.dart';
|
||||
|
||||
class UserProfilePanelBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => UserProfilePanelLogic(), tag: GetTags.userProfile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
import 'package:extended_image/extended_image.dart';
|
||||
import 'package:flutter/material.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:sprintf/sprintf.dart';
|
||||
import 'package:openim_live/openim_live.dart';
|
||||
|
||||
import '../../../core/controller/app_controller.dart';
|
||||
import '../../../core/controller/im_controller.dart';
|
||||
import '../../conversation/conversation_logic.dart';
|
||||
|
||||
class UserProfilePanelLogic extends GetxController {
|
||||
final appLogic = Get.find<AppController>();
|
||||
final imLogic = Get.find<IMController>();
|
||||
final conversationLogic = Get.find<ConversationLogic>();
|
||||
late Rx<UserFullInfo> userInfo;
|
||||
GroupMembersInfo? groupMembersInfo;
|
||||
GroupInfo? groupInfo;
|
||||
String? groupID;
|
||||
bool? offAllWhenDelFriend = false;
|
||||
bool? forceCanAdd = false;
|
||||
final iHasMutePermissions = false.obs;
|
||||
final iAmOwner = false.obs;
|
||||
final mutedTime = "".obs;
|
||||
final onlineStatus = false.obs;
|
||||
final onlineStatusDesc = ''.obs;
|
||||
final groupUserNickname = "".obs;
|
||||
final joinGroupTime = 0.obs;
|
||||
final joinGroupMethod = ''.obs;
|
||||
final hasAdminPermission = false.obs;
|
||||
final notAllowLookGroupMemberProfiles = true.obs;
|
||||
final notAllowAddGroupMemberFriend = false.obs;
|
||||
final iHaveAdminOrOwnerPermission = false.obs;
|
||||
late StreamSubscription _friendAddedSub;
|
||||
late StreamSubscription _friendDeletedSub;
|
||||
late StreamSubscription _friendInfoChangedSub;
|
||||
late StreamSubscription _memberInfoChangedSub;
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_friendAddedSub.cancel();
|
||||
_friendInfoChangedSub.cancel();
|
||||
_memberInfoChangedSub.cancel();
|
||||
_friendDeletedSub.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
userInfo = (UserFullInfo()
|
||||
..userID = Get.arguments['userID']
|
||||
..nickname = Get.arguments['nickname']
|
||||
..faceURL = Get.arguments['faceURL'])
|
||||
.obs;
|
||||
groupID = Get.arguments['groupID'];
|
||||
offAllWhenDelFriend = Get.arguments['offAllWhenDelFriend'];
|
||||
forceCanAdd = Get.arguments['forceCanAdd'];
|
||||
|
||||
_friendAddedSub = imLogic.friendAddSubject.listen((user) {
|
||||
if (user.userID == userInfo.value.userID) {
|
||||
userInfo.update((val) {
|
||||
val?.isFriendship = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_friendDeletedSub = imLogic.friendDelSubject.listen((user) {
|
||||
if (user.userID == userInfo.value.userID) {
|
||||
UserCacheManager().removeUserInfo(user.userID!);
|
||||
_getUsersInfo();
|
||||
}
|
||||
});
|
||||
|
||||
_friendInfoChangedSub = imLogic.friendInfoChangedSubject.listen((user) {
|
||||
if (user.userID == userInfo.value.userID) {
|
||||
userInfo.update((val) {
|
||||
val?.nickname = user.nickname;
|
||||
val?.remark = user.remark;
|
||||
});
|
||||
|
||||
UserCacheManager().addOrUpdateUserInfo(user.userID!, userInfo.value);
|
||||
}
|
||||
});
|
||||
|
||||
_memberInfoChangedSub = imLogic.memberInfoChangedSubject.listen((value) {
|
||||
if (value.userID == userInfo.value.userID) {
|
||||
if (null != value.muteEndTime) {
|
||||
_calMuteTime(value.muteEndTime!);
|
||||
}
|
||||
groupUserNickname.value = value.nickname ?? '';
|
||||
}
|
||||
});
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
_getUsersInfo();
|
||||
_queryGroupInfo();
|
||||
_queryGroupMemberInfo();
|
||||
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
bool get isMyself => userInfo.value.userID == OpenIM.iMManager.userID;
|
||||
|
||||
bool get isGroupMemberPage => null != groupID && groupID!.isNotEmpty;
|
||||
|
||||
bool get isFriendship => userInfo.value.isFriendship == true;
|
||||
|
||||
bool get isAllowAddFriend => userInfo.value.allowAddFriend == 1;
|
||||
|
||||
bool get allowSendMsgNotFriend {
|
||||
final r = null == appLogic.clientConfigMap['allowSendMsgNotFriend'] ||
|
||||
appLogic.clientConfigMap['allowSendMsgNotFriend'] == '1';
|
||||
return r;
|
||||
}
|
||||
|
||||
void _getUsersInfo() async {
|
||||
final userID = userInfo.value.userID!;
|
||||
final existUser = UserCacheManager().getUserInfo(userID);
|
||||
if (existUser != null) {
|
||||
userInfo.update((val) {
|
||||
val?.nickname = existUser.nickname;
|
||||
val?.faceURL = existUser.faceURL;
|
||||
val?.status = existUser.status;
|
||||
val?.level = existUser.level;
|
||||
val?.phoneNumber = existUser.phoneNumber;
|
||||
val?.areaCode = existUser.areaCode;
|
||||
val?.birth = existUser.birth;
|
||||
val?.email = existUser.email;
|
||||
val?.gender = existUser.gender;
|
||||
val?.mobile = existUser.mobile;
|
||||
});
|
||||
}
|
||||
|
||||
if (userID == OpenIM.iMManager.userID) {
|
||||
final user = await OpenIM.iMManager.userManager.getSelfUserInfo();
|
||||
|
||||
userInfo.update((val) {
|
||||
val?.nickname = user.nickname;
|
||||
val?.faceURL = user.faceURL;
|
||||
});
|
||||
|
||||
UserCacheManager().addOrUpdateUserInfo(userID, userInfo.value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final friendInfo = (await OpenIM.iMManager.friendshipManager.getFriendsInfo(
|
||||
userIDList: [userID],
|
||||
))
|
||||
.firstOrNull;
|
||||
|
||||
final blackList = await OpenIM.iMManager.friendshipManager.getBlacklist();
|
||||
|
||||
final isFriendship = friendInfo != null;
|
||||
final isBlack = blackList.firstWhereOrNull((e) => e.userID == friendInfo?.userID) != null;
|
||||
|
||||
if (friendInfo == null) {
|
||||
final user = (await OpenIM.iMManager.userManager.getUsersInfoWithCache(
|
||||
[userID],
|
||||
))
|
||||
.firstOrNull;
|
||||
if (user != null) {
|
||||
userInfo.update((val) {
|
||||
val?.nickname = user.nickname;
|
||||
val?.faceURL = user.faceURL;
|
||||
val?.remark = friendInfo?.remark;
|
||||
val?.isBlacklist = isBlack;
|
||||
val?.isFriendship = isFriendship;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
userInfo.update((val) {
|
||||
val?.nickname = friendInfo.nickname;
|
||||
val?.faceURL = friendInfo.faceURL;
|
||||
val?.remark = friendInfo.remark;
|
||||
val?.isBlacklist = isBlack;
|
||||
val?.isFriendship = isFriendship;
|
||||
});
|
||||
}
|
||||
UserCacheManager().addOrUpdateUserInfo(userID, userInfo.value);
|
||||
|
||||
final list2 = await Apis.getUserFullInfo(userIDList: [userID]);
|
||||
final fullInfo = list2?.firstOrNull;
|
||||
|
||||
if (null != fullInfo) {
|
||||
userInfo.update((val) {
|
||||
val?.allowAddFriend = fullInfo.allowAddFriend;
|
||||
val?.status = fullInfo.status;
|
||||
val?.level = fullInfo.level;
|
||||
val?.phoneNumber = fullInfo.phoneNumber;
|
||||
val?.areaCode = fullInfo.areaCode;
|
||||
val?.birth = fullInfo.birth;
|
||||
val?.email = fullInfo.email;
|
||||
val?.gender = fullInfo.gender;
|
||||
val?.mobile = fullInfo.mobile;
|
||||
val?.nickname = fullInfo.nickname;
|
||||
val?.faceURL = fullInfo.faceURL;
|
||||
val?.remark = friendInfo?.remark;
|
||||
val?.isBlacklist = isBlack;
|
||||
val?.isFriendship = isFriendship;
|
||||
});
|
||||
|
||||
UserCacheManager().addOrUpdateUserInfo(userID, userInfo.value);
|
||||
}
|
||||
}
|
||||
|
||||
void _resetAvatar(String url) async {
|
||||
clearMemoryImageCache(keyToMd5(url));
|
||||
await clearDiskCachedImage(url);
|
||||
PaintingBinding.instance.imageCache.evict(keyToMd5(url));
|
||||
userInfo.refresh();
|
||||
}
|
||||
|
||||
_queryGroupInfo() async {
|
||||
if (isGroupMemberPage) {
|
||||
var list = await OpenIM.iMManager.groupManager.getGroupsInfo(
|
||||
groupIDList: [groupID!],
|
||||
);
|
||||
groupInfo = list.firstOrNull;
|
||||
|
||||
notAllowLookGroupMemberProfiles.value = groupInfo?.lookMemberInfo == 1;
|
||||
|
||||
notAllowAddGroupMemberFriend.value = groupInfo?.applyMemberFriend == 1;
|
||||
}
|
||||
}
|
||||
|
||||
_queryGroupMemberInfo() async {
|
||||
if (isGroupMemberPage) {
|
||||
final list = await OpenIM.iMManager.groupManager.getGroupMembersInfo(
|
||||
groupID: groupID!,
|
||||
userIDList: [userInfo.value.userID!, if (!isMyself) OpenIM.iMManager.userID],
|
||||
);
|
||||
final other = list.firstWhereOrNull((e) => e.userID == userInfo.value.userID);
|
||||
groupMembersInfo = other;
|
||||
groupUserNickname.value = other?.nickname ?? '';
|
||||
joinGroupTime.value = other?.joinTime ?? 0;
|
||||
|
||||
_getJoinGroupMethod(other);
|
||||
|
||||
hasAdminPermission.value = other?.roleLevel == GroupRoleLevel.admin;
|
||||
|
||||
if (!isMyself) {
|
||||
var me = list.firstWhereOrNull((e) => e.userID == OpenIM.iMManager.userID);
|
||||
|
||||
iAmOwner.value = me?.roleLevel == GroupRoleLevel.owner;
|
||||
|
||||
iHasMutePermissions.value = me?.roleLevel == GroupRoleLevel.owner ||
|
||||
(me?.roleLevel == GroupRoleLevel.admin && other?.roleLevel == GroupRoleLevel.member);
|
||||
|
||||
iHaveAdminOrOwnerPermission.value =
|
||||
me?.roleLevel == GroupRoleLevel.owner || me?.roleLevel == GroupRoleLevel.admin;
|
||||
}
|
||||
|
||||
if (null != other && null != other.muteEndTime && other.muteEndTime! > 0) {
|
||||
_calMuteTime(other.muteEndTime!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getJoinGroupMethod(GroupMembersInfo? other) async {
|
||||
if (other?.joinSource == 2) {
|
||||
if (other!.inviterUserID != null && other.inviterUserID != other.userID) {
|
||||
final list = await OpenIM.iMManager.groupManager.getGroupMembersInfo(
|
||||
groupID: groupID!,
|
||||
userIDList: [other.inviterUserID!],
|
||||
);
|
||||
var inviterUserInfo = list.firstOrNull;
|
||||
joinGroupMethod.value = sprintf(
|
||||
StrRes.byInviteJoinGroup,
|
||||
[inviterUserInfo?.nickname ?? ''],
|
||||
);
|
||||
}
|
||||
} else if (other?.joinSource == 3) {
|
||||
joinGroupMethod.value = StrRes.byIDJoinGroup;
|
||||
} else if (other?.joinSource == 4) {
|
||||
joinGroupMethod.value = StrRes.byQrcodeJoinGroup;
|
||||
}
|
||||
}
|
||||
|
||||
_calMuteTime(int time) {
|
||||
var date = DateUtil.formatDateMs(time, format: IMUtils.getTimeFormat2());
|
||||
var now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
var diff = time - now;
|
||||
if (diff > 0) {
|
||||
mutedTime.value = date;
|
||||
} else {
|
||||
mutedTime.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
String getShowName() {
|
||||
if (isGroupMemberPage) {
|
||||
if (isFriendship) {
|
||||
if (null != IMUtils.emptyStrToNull(userInfo.value.remark)) {
|
||||
return '${groupUserNickname.value}(${IMUtils.emptyStrToNull(userInfo.value.remark)})';
|
||||
}
|
||||
}
|
||||
if (groupUserNickname.value.isEmpty) {
|
||||
return userInfo.value.nickname ??= "";
|
||||
}
|
||||
return groupUserNickname.value;
|
||||
}
|
||||
if (userInfo.value.remark != null && userInfo.value.remark!.isNotEmpty) {
|
||||
return '${userInfo.value.nickname}(${userInfo.value.remark})';
|
||||
}
|
||||
return userInfo.value.nickname ?? '';
|
||||
}
|
||||
|
||||
void toChat() {
|
||||
conversationLogic.toChat(
|
||||
userID: userInfo.value.userID,
|
||||
nickname: userInfo.value.showName,
|
||||
faceURL: userInfo.value.faceURL,
|
||||
);
|
||||
}
|
||||
|
||||
void toCall() {
|
||||
IMViews.openIMCallSheet(userInfo.value.showName, (index) {
|
||||
imLogic.call(
|
||||
callObj: CallObj.single,
|
||||
callType: index == 0 ? CallType.audio : CallType.video,
|
||||
inviteeUserIDList: [userInfo.value.userID!],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void copyID() {
|
||||
IMUtils.copy(text: userInfo.value.userID!);
|
||||
}
|
||||
|
||||
void addFriend() => AppNavigator.startSendVerificationApplication(
|
||||
userID: userInfo.value.userID!,
|
||||
);
|
||||
|
||||
void viewPersonalInfo() => AppNavigator.startPersonalInfo(
|
||||
userID: userInfo.value.userID!,
|
||||
);
|
||||
|
||||
void friendSetup() => AppNavigator.startFriendSetup(
|
||||
userID: userInfo.value.userID!,
|
||||
);
|
||||
}
|
||||
|
||||
class UserCacheManager {
|
||||
static final UserCacheManager _instance = UserCacheManager._();
|
||||
UserCacheManager._();
|
||||
final Map<String, UserFullInfo> _userInfoMap = {};
|
||||
|
||||
void addOrUpdateUserInfo(String userID, UserFullInfo userInfo) {
|
||||
_userInfoMap[userID] = userInfo;
|
||||
}
|
||||
|
||||
UserFullInfo? getUserInfo(String userID) {
|
||||
return _userInfoMap[userID];
|
||||
}
|
||||
|
||||
void removeUserInfo(String userID) {
|
||||
_userInfoMap.remove(userID);
|
||||
}
|
||||
|
||||
factory UserCacheManager() {
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:common_utils/common_utils.dart';
|
||||
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 'user_profile _panel_logic.dart';
|
||||
|
||||
class UserProfilePanelPage extends StatelessWidget {
|
||||
final logic = Get.find<UserProfilePanelLogic>(tag: GetTags.userProfile);
|
||||
|
||||
UserProfilePanelPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(
|
||||
() => Scaffold(
|
||||
appBar: TitleBar.back(
|
||||
right: logic.isFriendship
|
||||
? (ImageRes.moreBlack.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h
|
||||
..onTap = logic.friendSetup)
|
||||
: null,
|
||||
),
|
||||
backgroundColor: Styles.c_F8F9FA,
|
||||
body: SizedBox(
|
||||
height: 1.sh,
|
||||
child: Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
_buildBaseInfoView(),
|
||||
if (logic.isGroupMemberPage) _buildEnterGroupMethodView(),
|
||||
if (logic.isFriendship ||
|
||||
logic.isMyself ||
|
||||
logic.isGroupMemberPage && !logic.notAllowLookGroupMemberProfiles.value)
|
||||
_buildItemView(
|
||||
label: StrRes.personalInfo,
|
||||
showRightArrow: true,
|
||||
onTap: logic.viewPersonalInfo,
|
||||
),
|
||||
SizedBox(height: 108.h),
|
||||
],
|
||||
),
|
||||
),
|
||||
if ((logic.isFriendship || logic.allowSendMsgNotFriend) && !logic.isMyself) _buildButtonGroup(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBaseInfoView() => Container(
|
||||
color: Styles.c_FFFFFF,
|
||||
height: 80.h,
|
||||
margin: EdgeInsets.only(bottom: 10.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Row(
|
||||
children: [
|
||||
AvatarView(
|
||||
url: logic.userInfo.value.faceURL,
|
||||
text: logic.userInfo.value.nickname,
|
||||
width: 48.w,
|
||||
height: 48.h,
|
||||
textStyle: Styles.ts_FFFFFF_14sp,
|
||||
enabledPreview: true,
|
||||
),
|
||||
12.horizontalSpace,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
logic.getShowName().toText
|
||||
..style = Styles.ts_0C1C33_17sp_medium
|
||||
..maxLines = 1
|
||||
..overflow = TextOverflow.ellipsis,
|
||||
if (!logic.isGroupMemberPage || logic.isGroupMemberPage && !logic.notAllowAddGroupMemberFriend.value)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 4.h),
|
||||
child: (logic.userInfo.value.userID ?? '').toText
|
||||
..style = Styles.ts_8E9AB0_14sp
|
||||
..onTap = logic.copyID,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!logic.isMyself &&
|
||||
logic.isAllowAddFriend &&
|
||||
!logic.isFriendship &&
|
||||
(!logic.isGroupMemberPage ||
|
||||
logic.forceCanAdd == true ||
|
||||
logic.isGroupMemberPage && !logic.notAllowAddGroupMemberFriend.value))
|
||||
Material(
|
||||
child: Ink(
|
||||
decoration: BoxDecoration(
|
||||
color: Styles.c_0089FF,
|
||||
borderRadius: BorderRadius.circular(6.r),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: logic.addFriend,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 9.w,
|
||||
vertical: 4.h,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
ImageRes.addContacts.toImage
|
||||
..width = 21.w
|
||||
..height = 21.h
|
||||
..color = Styles.c_FFFFFF,
|
||||
2.horizontalSpace,
|
||||
StrRes.add.toText..style = Styles.ts_FFFFFF_14sp,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildEnterGroupMethodView() {
|
||||
if (logic.joinGroupTime.value == 0 && logic.joinGroupMethod.value.isEmpty) {
|
||||
return Container();
|
||||
}
|
||||
return Container(
|
||||
color: Styles.c_FFFFFF,
|
||||
margin: EdgeInsets.only(bottom: 10.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
|
||||
child: Table(
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.top,
|
||||
columnWidths: {0: FixedColumnWidth(100.w)},
|
||||
children: [
|
||||
if (logic.joinGroupTime.value > 0)
|
||||
_buildTabRowView(
|
||||
label: StrRes.joinGroupDate,
|
||||
value: DateUtil.formatDateMs(
|
||||
logic.joinGroupTime.value,
|
||||
format: DateFormats.zh_y_mo_d,
|
||||
),
|
||||
),
|
||||
if (logic.joinGroupMethod.value.isNotEmpty)
|
||||
_buildTabRowView(
|
||||
label: StrRes.joinGroupMethod,
|
||||
value: logic.joinGroupMethod.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
TableRow _buildTabRowView({
|
||||
required String label,
|
||||
String? value,
|
||||
}) =>
|
||||
TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
child: Container(
|
||||
constraints: BoxConstraints(minHeight: 40.h),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: label.toText..style = Styles.ts_8E9AB0_17sp,
|
||||
),
|
||||
),
|
||||
TableCell(
|
||||
child: Container(
|
||||
constraints: BoxConstraints(minHeight: 40.h),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: (value ?? '').toText..style = Styles.ts_0C1C33_17sp,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _buildItemView({
|
||||
required String label,
|
||||
String? value,
|
||||
bool addMargin = false,
|
||||
bool showSwitchButton = false,
|
||||
bool showRightArrow = false,
|
||||
bool switchOn = false,
|
||||
ValueChanged<bool>? onChanged,
|
||||
Function()? onTap,
|
||||
}) =>
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: addMargin ? 10.h : 0),
|
||||
child: Ink(
|
||||
color: Styles.c_FFFFFF,
|
||||
height: 56.h,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Row(
|
||||
children: [
|
||||
label.toText..style = Styles.ts_0C1C33_17sp,
|
||||
const Spacer(),
|
||||
if (showSwitchButton)
|
||||
CupertinoSwitch(
|
||||
value: switchOn,
|
||||
activeColor: Styles.c_0089FF,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
if (null != value) value.toText..style = Styles.ts_0C1C33_17sp,
|
||||
if (showRightArrow)
|
||||
ImageRes.rightArrow.toImage
|
||||
..width = 24.w
|
||||
..height = 24.h,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildButtonGroup() => Positioned(
|
||||
bottom: 0.h,
|
||||
width: 1.sw,
|
||||
child: ClipRRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
|
||||
child: Container(
|
||||
color: Styles.c_F8F9FA.withOpacity(.3),
|
||||
padding: EdgeInsets.symmetric(horizontal: 9.w),
|
||||
height: 108.h,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ImageTextButton.call(
|
||||
onTap: logic.toCall,
|
||||
),
|
||||
),
|
||||
11.horizontalSpace,
|
||||
Expanded(
|
||||
child: ImageTextButton.message(
|
||||
onTap: logic.toChat,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user