This commit is contained in:
abu 2025-10-01 12:29:09 +08:00
parent 57fb6f7de9
commit 9bb7aea8ab
29 changed files with 626 additions and 441 deletions

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1759238468389" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5738" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M256 512m-74.666667 0a74.666667 74.666667 0 1 0 149.333334 0 74.666667 74.666667 0 1 0-149.333334 0Z" fill="#111111" p-id="5739"></path><path d="M512 512m-74.666667 0a74.666667 74.666667 0 1 0 149.333334 0 74.666667 74.666667 0 1 0-149.333334 0Z" fill="#111111" p-id="5740"></path><path d="M768 512m-74.666667 0a74.666667 74.666667 0 1 0 149.333334 0 74.666667 74.666667 0 1 0-149.333334 0Z" fill="#111111" p-id="5741"></path></svg>

After

Width:  |  Height:  |  Size: 765 B

View File

@ -72,6 +72,13 @@
<string>App需要访问您的相册用于选择图片或视频</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>zh-Hans</string>
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>

View File

@ -47,6 +47,11 @@ class IMMessage {
title: myInfo.nickname.value,
desc: parseMessageSummary(msg),
ext: jsonEncode({"userID": myInfo.userID.value, "title": myInfo.nickname.value}),
//ios ios>18
iOSPushType: 0, //0= 1=/
iOSSound: 'default', // kIOSOfflinePushDefaultSound
ignoreIOSBadge: false, //
iOSInterruptionLevel: 'active', // active // time-sensitive
);
sendRes = await TencentImSDKPlugin.v2TIMManager.getMessageManager().sendMessage(
message: msg,
@ -75,7 +80,12 @@ class IMMessage {
OfflinePushInfo offlinePushInfo = OfflinePushInfo(
title: groupName,
desc: parseMessageSummary(msg),
ext: jsonEncode({"groupID": groupID, "title": groupName ?? ''}),
ext: jsonEncode({"groupID": groupID, "title": groupName ?? '群聊'}),
//ios ios>18
iOSPushType: 0, //0= 1=/
iOSSound: 'default', // kIOSOfflinePushDefaultSound
ignoreIOSBadge: false, //
iOSInterruptionLevel: 'active', //
);
sendRes = await TencentImSDKPlugin.v2TIMManager.getMessageManager().sendMessage(
message: msg,

View File

@ -124,13 +124,23 @@ class ImService {
);
} else {
logger.i("IM 登录失败:${result.code} - ${result.desc}");
Get.snackbar(
'登录失败',
'${result.code} - ${result.desc}',
backgroundColor: Colors.red.withAlpha(230),
colorText: Colors.white,
icon: const Icon(Icons.error_outline, color: Colors.white),
);
if (result.code == 70013) {
Get.snackbar(
'登录失败',
'请求的 Identifier 与生成 UserSig 的 Identifier 不匹配',
backgroundColor: Colors.red.withAlpha(230),
colorText: Colors.white,
icon: const Icon(Icons.error_outline, color: Colors.white),
);
} else {
Get.snackbar(
'登录失败',
'${result.code} - ${result.desc}',
backgroundColor: Colors.red.withAlpha(230),
colorText: Colors.white,
icon: const Icon(Icons.error_outline, color: Colors.white),
);
}
}
return result;
}

View File

@ -136,12 +136,14 @@ class PushService {
// "userID": "123456",
// "groupID": "654321",
// });
final isGroup = groupID != null && groupID.isNotEmpty;
final data = jsonDecode(ext);
logger.i(data);
String extGroupID = data['groupID'] ?? '';
final isGroup = extGroupID.isNotEmpty;
// final type = data['type'];
final router = conversationTypeFromString(userID); //userID
final router = conversationTypeFromString(data['userID']); //userID
logger.w(router);
if (router == null) {
//

View File

@ -50,68 +50,70 @@ class _ImageViewerState extends State<ImageViewer> {
Widget build(BuildContext context) {
var imgCount = widget.images?.length;
return Scaffold(
body: Stack(
children: [
Positioned(
top: 0,
left: 0,
bottom: 0,
right: 0,
child: GestureDetector(
child: imgCount == 1
? PhotoView(
// imageProvider: Utils.isUrl(widget.images![0]) ? NetworkImage(widget.images![0]) : AssetImage(widget.images![0]),
imageProvider: getImageProvider(widget.images![0]),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
return SafeArea(
child: Scaffold(
body: Stack(
children: [
Positioned(
top: 0,
left: 0,
bottom: 0,
right: 0,
child: GestureDetector(
child: imgCount == 1
? PhotoView(
// imageProvider: Utils.isUrl(widget.images![0]) ? NetworkImage(widget.images![0]) : AssetImage(widget.images![0]),
imageProvider: getImageProvider(widget.images![0]),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![0]),
enableRotation: true,
)
: PhotoViewGallery.builder(
itemCount: widget.images?.length,
builder: (context, index) {
return PhotoViewGalleryPageOptions(
imageProvider: Utils.isUrl(widget.images![index]) ? NetworkImage(widget.images![index]) : AssetImage(widget.images![index]),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![index]),
);
},
scrollPhysics: const BouncingScrollPhysics(),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
),
pageController: PageController(initialPage: widget.index),
enableRotation: true,
onPageChanged: (index) {
setState(() {
currentIndex = index;
});
},
),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![0]),
enableRotation: true,
)
: PhotoViewGallery.builder(
itemCount: widget.images?.length,
builder: (context, index) {
return PhotoViewGalleryPageOptions(
imageProvider: Utils.isUrl(widget.images![index]) ? NetworkImage(widget.images![index]) : AssetImage(widget.images![index]),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 2,
heroAttributes: PhotoViewHeroAttributes(tag: widget.images![index]),
);
},
scrollPhysics: const BouncingScrollPhysics(),
backgroundDecoration: const BoxDecoration(
color: Colors.black,
),
pageController: PageController(initialPage: widget.index),
enableRotation: true,
onPageChanged: (index) {
setState(() {
currentIndex = index;
});
},
),
onTap: () {
Get.back();
},
),
),
// index
Positioned(
top: MediaQuery.of(context).padding.top + 15,
width: MediaQuery.of(context).size.width,
child: Center(
child: Visibility(
visible: imgCount! > 1 ? true : false,
child: Text(
'${currentIndex + 1} / ${widget.images?.length}',
style: const TextStyle(color: Colors.white, fontSize: 16, fontFamily: 'arial'),
onTap: () {
Get.back();
},
),
)),
),
],
),
// index
Positioned(
top: MediaQuery.of(context).padding.top + 15,
width: MediaQuery.of(context).size.width,
child: Center(
child: Visibility(
visible: imgCount! > 1 ? true : false,
child: Text(
'${currentIndex + 1} / ${widget.images?.length}',
style: const TextStyle(color: Colors.white, fontSize: 16, fontFamily: 'arial'),
),
)),
),
],
),
),
);
}

View File

@ -502,6 +502,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
child: NetworkOrAssetImage(
imageUrl: item.videoElem?.snapshotUrl ?? '',
width: 120,
placeholderAsset: 'assets/images/bk.jpg',
),
),
const Align(
@ -701,6 +702,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
NetworkOrAssetImage(
imageUrl: url,
width: 160.0,
placeholderAsset: 'assets/images/bk.jpg',
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
@ -1606,10 +1608,10 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
if (file != null) {
var fileSizeInBytes = await file.length();
var sizeInMB = fileSizeInBytes / (1024 * 1024);
if (sizeInMB > 28) {
MyDialog.toast('图片大小不能超过28MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
if (sizeInMB > 100) {
MyDialog.toast('文件大小不能超过100MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
} else {
print("图片合法,大小:$sizeInMB MB");
print("视频合法,大小:$sizeInMB MB");
//
var snapshot = await generateVideoThumbnail(file.path);
String? mimeType = await asset.mimeTypeAsync;
@ -1875,7 +1877,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
title: Obx(() {
return Text(
// '${arguments['title']}',
'${arguments.value.showName}',
arguments.value.showName ?? '神秘人',
style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'),
);
}),

View File

@ -383,6 +383,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
borderRadius: BorderRadius.circular(10.0),
child: NetworkOrAssetImage(
imageUrl: item.videoElem?.snapshotUrl ?? '',
placeholderAsset: 'assets/images/bk.jpg',
width: 120,
),
),
@ -541,6 +542,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
children: [
NetworkOrAssetImage(
imageUrl: url,
placeholderAsset: 'assets/images/bk.jpg',
width: 160.0,
),
Container(
@ -1568,7 +1570,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
obj['ids'] = ids.join(',');
data.customElem!.data = jsonEncode(obj);
//
ImService.instance.modifyMessage(message: data);
await ImService.instance.modifyMessage(message: data);
// 1
Future.delayed(Duration(seconds: 1), () {
animController.stop();
@ -1585,7 +1587,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
obj['totalCount'] = 0;
obj['open'] = true; //true
data.customElem!.data = jsonEncode(obj);
ImService.instance.modifyMessage(message: data);
await ImService.instance.modifyMessage(message: data);
Future.delayed(Duration(seconds: 1), () {
animController.stop();
@ -1748,7 +1750,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
),
titleSpacing: 1.0,
title: Text(
'${arguments.showName}',
arguments.showName ?? '群聊',
style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'),
maxLines: 1,
overflow: TextOverflow.ellipsis,

View File

@ -441,6 +441,7 @@ class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderSt
child: NetworkOrAssetImage(
imageUrl: item.videoElem?.snapshotUrl ?? '',
width: 120,
placeholderAsset: 'assets/images/bk.jpg',
),
),
const Align(
@ -605,6 +606,7 @@ class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderSt
children: [
NetworkOrAssetImage(
imageUrl: url,
placeholderAsset: 'assets/images/bk.jpg',
width: 160.0,
),
Container(
@ -1515,7 +1517,7 @@ class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderSt
title: Obx(() {
return Text(
// '${arguments['title']}',
'${arguments.value.showName}',
arguments.value.showName ?? '陌生人',
style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'),
);
}),

View File

@ -103,6 +103,7 @@ class ChatPageState extends State<ChatPage> {
final controller = Get.find<ImUserInfoController>();
final role = controller.role.value;
final isSeller = Utils.hasRole(role, 2);
// writeOffCodeId
if (isSeller) {
//
Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value});
@ -638,6 +639,8 @@ class ChatPageState extends State<ChatPage> {
),
),
onTap: () {
// logger.e(chatList[index].isCustomAdmin);
if (conversationTypeFromString(chatList[index].isCustomAdmin) != null) {
// notify下的内容
logger.e(chatList[index].isCustomAdmin);

View File

@ -7,13 +7,11 @@ import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/notify_message.type.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
@ -93,7 +91,7 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
Future<void> getMsgData() async {
//
V2TimMessage? lastRealMsg;
lastRealMsg = msgList.last;
lastRealMsg = msgList.isEmpty ? null : msgList.last;
final res = await ImService.instance.getHistoryMessageList(
userID: ConversationType.interaction.name, // userID为固定的interaction
lastMsg: lastRealMsg,
@ -118,13 +116,34 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
//
void _filterMessages(String filterType) async {
logger.e(filterType);
if (filterType == 'all') {
getMsgData();
return;
}
//
String keyword;
// interactionComment, //->
// interactionAt, //->@
// interactionLike, //->
// interactionReply, //->
if (filterType == 'interactionComment') {
keyword = '评论';
} else if (filterType == 'interactionLike') {
keyword = '点赞';
} else if (filterType == 'interactionReply') {
keyword = '回复';
} else {
keyword = '视频'; //
}
final res = await ImService.instance.searchLocalMessages(
page: page,
conversationID: 'c2c_${ConversationType.interaction.name}',
keywordList: ['action', filterType],
keywordList: [keyword],
// keywordList: ['action', filterType], //interactionLike
);
logger.e(res.data!.toLogString());
logger.e(res.data!.toJson());
if (res.success && res.data != null) {
msgList.clear();
final resultList = res.data?.messageSearchResultItems ?? [];
if (resultList.isNotEmpty) {
for (var item in resultList) {
@ -132,6 +151,7 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
msgList.addAll(item.messageList ?? []);
}
} else {
msgList.clear();
logger.e('数据为空${res.desc}');
}
}
@ -244,15 +264,15 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
child: EasyRefresh.builder(
callLoadOverOffset: 20, //
callRefreshOverOffset: 20, //
header: ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
// header: ClassicHeader(
// dragText: '下拉刷新',
// armedText: '释放刷新',
// readyText: '加载中...',
// processingText: '加载中...',
// processedText: '加载完成',
// failedText: '加载失败,请重试',
// messageText: '最后更新于 %T',
// ),
footer: ClassicFooter(
dragText: '加载更多',
armedText: '释放加载',
@ -263,11 +283,11 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
onRefresh: () async {
await handleRefresh();
},
// onRefresh: () async {
// await handleRefresh();
// },
onLoad: () async {
if (hasMore.value) {
if (selectedMessageType.value != 'all' && hasMore.value) {
await getMsgData();
return hasMore.value ? IndicatorResult.success : IndicatorResult.noMore;
}
@ -297,6 +317,8 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
final desc = msgList[index].customElem!.desc!;
final jsonData = msgList[index].customElem!.data ?? '{"faceUrl":"","nickName":"data为null","userID":"213213"}';
final item = jsonDecode(jsonData); //
logger.e(item);
// ----
// final jsonData = '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}';
// final item = jsonDecode(jsonData); //
@ -310,15 +332,14 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
spacing: 10.0,
children: <Widget>[
//
InkWell(
GestureDetector(
onTap: () async {
//
//
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id
//
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
//
Get.toNamed('/vloger', arguments: res['data']);
// final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
Get.toNamed('/vloger', arguments: {'memberId': item['userID']});
},
child: ClipOval(
child: NetworkOrAssetImage(
@ -331,15 +352,13 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
//
Expanded(
child: InkWell(
child: GestureDetector(
onTap: () async {
//
//
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id
//
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
Get.toNamed('/vloger', arguments: res['data']);
// Get.toNamed('/vloger');
logger.e(item);
Get.toNamed('/videoDetail', arguments: {'videoId': item['vlogID']});
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -373,26 +392,31 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
),
//
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Visibility(
visible: true,
//
child: NetworkOrAssetImage(
imageUrl: item['firstFrameImg'],
placeholderAsset: 'assets/images/bk.jpg',
width: 40,
height: 60,
GestureDetector(
onTap: () {
Get.toNamed('/videoDetail', arguments: {'videoId': item['vlogID']});
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Visibility(
visible: true,
//
child: NetworkOrAssetImage(
imageUrl: item['firstFrameImg'],
placeholderAsset: 'assets/images/bk.jpg',
width: 40,
height: 60,
),
),
),
const SizedBox(width: 5.0),
//
Visibility(
visible: !(element.isRead ?? true),
child: FStyle.badge(0, isdot: true),
),
],
const SizedBox(width: 5.0),
//
Visibility(
visible: !(element.isRead ?? true),
child: FStyle.badge(0, isdot: true),
),
],
),
),
],
),

View File

@ -7,13 +7,10 @@ import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
@ -187,6 +184,7 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
jsonData = (jsonData == null || jsonData.isEmpty) ? '{"faceUrl":"","nickName":"data为空","userID":"213213"}' : jsonData;
final item = jsonDecode(jsonData);
logger.e(item);
logger.w(element.toJson());
@ -210,13 +208,7 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
//
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id
//
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
if (res['data'] == null) {
MyToast().tip(title: '视频数据不存在', position: 'top');
} else {
//
Get.toNamed('/vloger', arguments: res['data']);
}
Get.toNamed('/vloger', arguments: {'memberId': item['userID']});
},
child: ClipOval(
child: NetworkOrAssetImage(
@ -232,8 +224,8 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
child: InkWell(
onTap: () async {
// ,
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
Get.toNamed('/vloger', arguments: res['data']);
Get.toNamed('/vloger', arguments: {'memberId': item['userID']});
// Get.toNamed('/vloger');
},
child: Column(

View File

@ -190,7 +190,8 @@ class _GoodsState extends State<Goods> {
void handlCoverClick(V2TimConversation conv) async {
//
final userId = conv.userID;
final isGroup = conv.groupID != null && (conv.groupID ?? '').isNotEmpty;
final id = isGroup ? conv.groupID : conv.userID;
//price,title,url,sell
logger.w(shopObj['name']);
final makeJson = jsonEncode({
@ -205,7 +206,12 @@ class _GoodsState extends State<Goods> {
data: makeJson,
);
if (res.success) {
final sendRes = await IMMessage().sendMessage(msg: res.data!.messageInfo!, toUserID: userId, cloudCustomData: SummaryType.shareTuangou);
final sendRes = await IMMessage().sendMessage(
msg: res.data!.messageInfo!,
groupID: isGroup ? id : null,
toUserID: isGroup ? null : id,
cloudCustomData: SummaryType.shareTuangou,
);
if (sendRes.success) {
MyToast().tip(
title: '分享成功',

View File

@ -1,6 +1,7 @@
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/styles/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_full_info.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
@ -184,6 +185,7 @@ class _MemberActionSheetState extends State<InviteActionSheet> {
final showName = uname.isEmpty ? nickname : uname;
return InkWell(
onTap: () {
FocusScope.of(context).unfocus();
setState(() {
if (_selectedIDs.contains(id)) {
_selectedIDs.remove(id);
@ -196,12 +198,15 @@ class _MemberActionSheetState extends State<InviteActionSheet> {
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
children: [
//
CircleAvatar(
radius: 20,
backgroundImage: m.faceUrl != null ? NetworkImage(m.faceUrl!) : null,
child: m.faceUrl == null ? const Icon(Icons.person) : null,
//
ClipOval(
child: NetworkOrAssetImage(
imageUrl: m.faceUrl ?? '',
width: 40.0,
height: 40.0,
),
),
const SizedBox(width: 12),
//

View File

@ -2,6 +2,7 @@ import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart';
import 'package:loopin/styles/index.dart';
import 'package:tencent_cloud_chat_sdk/enum/group_member_filter_enum.dart';
@ -50,6 +51,7 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
final self = Get.find<GroupDetailController>().selfInfo.value!;
members.insert(0, self);
}
getMemberData();
}
@ -59,7 +61,7 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
loading = true;
final res = await ImService.instance.getGroupMemberList(
groupID: widget.groupID,
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_COMMON,
filter: GroupMemberFilterTypeEnum.V2TIM_GROUP_MEMBER_FILTER_ALL,
nextSeq: nextSeq,
count: 100,
);
@ -67,8 +69,13 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
logger.e(res.data!.nextSeq);
nextSeq = res.data!.nextSeq ?? '0';
final mem = res.data!.memberInfoList ?? [];
setState(() {
//
if (widget.showSelf) {
members.addAll(mem);
members = {for (var m in members) m.userID: m}.values.toList();
}
setState(() {
hasMore = res.data!.nextSeq == '0' ? false : true;
loading = false;
});
@ -131,7 +138,7 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
@override
Widget build(BuildContext context) {
List filteredMembers;
List<V2TimGroupMemberFullInfo> filteredMembers;
if (_query.isEmpty) {
filteredMembers = members;
} else {
@ -223,11 +230,22 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
final showName = uname.isEmpty ? nickname : uname;
return InkWell(
onTap: () {
FocusScope.of(context).unfocus();
setState(() {
if (_selectedIDs.contains(id)) {
_selectedIDs.remove(id);
if (widget.showSelf) {
// =,
final selfInfo = Get.find<GroupDetailController>().selfInfo.value ?? V2TimGroupMemberFullInfo(userID: '');
final currentUserID = selfInfo.userID;
if (m.userID != currentUserID) {
Get.toNamed('/vloger', arguments: {'memberId': m.userID});
}
} else {
_selectedIDs.add(id);
// false=
if (_selectedIDs.contains(id)) {
_selectedIDs.remove(id);
} else {
_selectedIDs.add(id);
}
}
});
},
@ -235,11 +253,13 @@ class _MemberActionSheetState extends State<MemberActionSheet> {
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: Row(
children: [
//
CircleAvatar(
radius: 20,
backgroundImage: m.faceUrl != null ? NetworkImage(m.faceUrl!) : null,
child: m.faceUrl == null ? const Icon(Icons.person) : null,
//
ClipOval(
child: NetworkOrAssetImage(
imageUrl: m.faceUrl ?? '',
width: 40.0,
height: 40.0,
),
),
const SizedBox(width: 12),

View File

@ -166,51 +166,116 @@ class GroupdetailState extends State<Groupdetail> {
);
}
},
child: Text(
Utils.handleText(controller.info.value?.groupName, '', "未命名群聊"),
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
child: Text(
Utils.handleText(controller.info.value?.groupName, '', "未命名群聊"),
// '很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长',
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(
width: 10,
),
if (controller.isOwner.value)
Icon(
Icons.edit,
size: 14,
)
],
),
),
),
//
subtitle: Obx(
() => GestureDetector(
onTap: () {
// setinfo页
logger.w('点了简介绍');
if (controller.isOwner.value) {
Get.to(
() => SetGroupInfoPage(
appBarTitle: "修改群简介",
fieldLabel: "群简介",
maxLines: 5,
maxLength: 100,
initialValue: controller.info.value?.introduction ?? "",
onSubmit: (value) async {
//
await controller.setGroupInfo(
changedInfo: V2TimGroupInfo(
groupID: controller.info.value!.groupID,
groupType: GroupType.Work,
introduction: value,
subtitle: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Obx(
() => GestureDetector(
onTap: () {
// setinfo页
logger.w('点了简介绍');
if (controller.isOwner.value) {
Get.to(
() => SetGroupInfoPage(
appBarTitle: "修改群简介",
fieldLabel: "群简介",
maxLines: 5,
maxLength: 100,
initialValue: controller.info.value?.introduction ?? "",
onSubmit: (value) async {
//
await controller.setGroupInfo(
changedInfo: V2TimGroupInfo(
groupID: controller.info.value!.groupID,
groupType: GroupType.Work,
introduction: value,
),
);
},
),
);
} else {
//
showModalBottomSheet(
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
isScrollControlled: true, //
builder: (ctx) => SafeArea(
child: Container(
width: double.infinity, // 👈
padding: const EdgeInsets.all(16),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min, //
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"群简介",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Text(
Utils.handleText(controller.info.value?.introduction, '', "暂无群介绍"),
style: const TextStyle(fontSize: 14),
),
const SizedBox(height: 16),
],
),
),
);
},
),
),
);
}
},
child: Row(mainAxisSize: MainAxisSize.max, children: [
Flexible(
child: Text(
Utils.handleText(controller.info.value?.introduction, '', "暂无群介绍"),
// '非常长的内容非常长的内容非常长的内容非常长的内容非常长的内容非常长的内容',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.grey),
),
);
}
},
child: Text(
Utils.handleText(controller.info.value?.introduction, '', "暂无群介绍"),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.grey),
),
SizedBox(
width: 10,
),
if (controller.isOwner.value)
Icon(
Icons.edit,
size: 14,
)
]),
),
),
),
trailing: const Icon(Icons.chevron_right),
// trailing: const Icon(Icons.chevron_right),
),
const Divider(height: 1),
@ -252,135 +317,135 @@ class GroupdetailState extends State<Groupdetail> {
);
},
),
//
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Wrap(
spacing: 16,
runSpacing: 12,
children: [
Obx(
() {
return Wrap(
spacing: 16,
runSpacing: 12,
children: controller.memberList.take(8).map((m) {
//
return GestureDetector(
onTap: () {
final currentUserID = controller.selfInfo.value?.userID ?? '';
if (m.userID != currentUserID) {
Get.toNamed('/vloger', arguments: {'memberId': m.userID});
}
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ClipOval(
child: NetworkOrAssetImage(
imageUrl: m.faceUrl,
height: 50,
width: 50,
),
),
const SizedBox(height: 4),
SizedBox(
width: 50,
child: Text(
m.nickName ?? '未知昵称',
maxLines: 1,
softWrap: false,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 12),
),
),
],
),
);
}).toList(),
);
},
),
// +
GestureDetector(
child: Obx(() {
//
final memberWidgets = controller.memberList.take(8).map((m) {
return GestureDetector(
onTap: () {
//,
logger.w('当前人数${controller.info.value?.memberCount ?? 0}---上限人数${controller.info.value?.memberMaxCount ?? 0}');
if ((controller.info.value?.memberCount ?? 0) < (controller.info.value?.memberMaxCount ?? 0)) {
//
showModalBottomSheet(
context: context,
barrierColor: Colors.white,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return InviteActionSheet(
groupID: controller.groupID,
title: '邀请新成员',
onAction: (userIDs) {
logger.w("准备添加群成员: $userIDs");
controller.inviteUserToGroup(userList: userIDs);
},
);
},
);
} else {
MyToast().tip(title: '群人数已达上限', position: 'top');
final currentUserID = controller.selfInfo.value?.userID ?? '';
if (m.userID != currentUserID) {
Get.toNamed('/vloger', arguments: {'memberId': m.userID});
}
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircleAvatar(
radius: 25,
child: const Icon(Icons.add),
ClipOval(
child: NetworkOrAssetImage(
imageUrl: m.faceUrl,
height: 50,
width: 50,
),
),
const SizedBox(height: 4),
const Text("邀请", style: TextStyle(fontSize: 12)),
SizedBox(
width: 50,
child: Text(
m.nickName ?? '未知昵称',
maxLines: 1,
overflow: TextOverflow.ellipsis,
softWrap: false,
style: const TextStyle(fontSize: 12),
textAlign: TextAlign.center,
),
),
],
),
);
}).toList();
//
final inviteWidget = GestureDetector(
onTap: () {
logger.w('当前人数${controller.info.value?.memberCount ?? 0}---上限人数${controller.info.value?.memberMaxCount ?? 0}');
if ((controller.info.value?.memberCount ?? 0) < (controller.info.value?.memberMaxCount ?? 0)) {
showModalBottomSheet(
context: context,
barrierColor: Colors.white,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return InviteActionSheet(
groupID: controller.groupID,
title: '邀请新成员',
onAction: (userIDs) {
logger.w("准备添加群成员: $userIDs");
controller.inviteUserToGroup(userList: userIDs);
},
);
},
);
} else {
MyToast().tip(title: '群人数已达上限', position: 'top');
}
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
CircleAvatar(radius: 25, child: Icon(Icons.add)),
SizedBox(height: 4),
Text("邀请", style: TextStyle(fontSize: 12)),
],
),
// -
Obx(
() => controller.isOwner.value
? GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
barrierColor: Colors.white,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return MemberActionSheet(
groupID: controller.groupID,
title: '移出成员',
onAction: (userIDs) {
logger.w("准备移除群成员: $userIDs");
controller.kickGroupMember(userIDs);
},
);
);
//
final removeWidget = controller.isOwner.value
? GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
barrierColor: Colors.white,
isScrollControlled: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return MemberActionSheet(
groupID: controller.groupID,
title: '移出成员',
onAction: (userIDs) {
logger.w("准备移除群成员: $userIDs");
controller.kickGroupMember(userIDs);
},
);
},
child: Column(
children: [
const CircleAvatar(
radius: 25,
child: Icon(Icons.remove),
),
const SizedBox(height: 4),
const Text("移除", style: TextStyle(fontSize: 12)),
],
),
)
: SizedBox.shrink(),
)
],
),
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
CircleAvatar(radius: 25, child: Icon(Icons.remove)),
SizedBox(height: 4),
Text("移除", style: TextStyle(fontSize: 12)),
],
),
)
: const SizedBox.shrink();
final allWidgets = <Widget>[
...memberWidgets,
inviteWidget,
];
if (controller.isOwner.value) allWidgets.add(removeWidget);
return GridView.count(
shrinkWrap: true, //
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 4, // 4
mainAxisSpacing: 0, //
crossAxisSpacing: 16, //
childAspectRatio: 1, //
children: allWidgets,
);
}),
),
const Divider(height: 1),

View File

@ -167,6 +167,7 @@ class _IndexPageState extends State<IndexPage> with TickerProviderStateMixin {
///
Future<void> changeData(int index) async {
dataList.clear();
if (isLoading.value) return;
isLoading.value = true;
final res = await Http.post(ShopApi.shopList, data: {
@ -178,12 +179,12 @@ class _IndexPageState extends State<IndexPage> with TickerProviderStateMixin {
final data = res['data']['records'];
final total = res['data']['total'];
logger.w(res);
dataList.value = data;
if (dataList.length >= total) {
hasMore.value = false;
isLoading.value = false;
return;
}
// logger.w(res);
dataList.value = data;
page += 1;
isLoading.value = false;
isInitLoading.value = false;
@ -202,13 +203,14 @@ class _IndexPageState extends State<IndexPage> with TickerProviderStateMixin {
final data = res['data']['records'];
final total = res['data']['total'];
logger.w(res);
dataList.addAll(data);
if (dataList.length >= total) {
hasMore.value = false;
isLoading.value = false;
return;
}
// logger.w(res);
dataList.addAll(data);
page += 1;
logger.e(page);
isLoading.value = false;
isInitLoading.value = false;
}
@ -528,16 +530,16 @@ class _IndexPageState extends State<IndexPage> with TickerProviderStateMixin {
SliverToBoxAdapter(
child: Obx(
() {
if (isInitLoading.value) {
return Column(
children: [
RefreshProgressIndicator(
backgroundColor: Colors.white,
color: Color(0xFFFF5000),
),
],
);
}
// if (isInitLoading.value) {
// return Column(
// children: [
// RefreshProgressIndicator(
// backgroundColor: Colors.white,
// color: Color(0xFFFF5000),
// ),
// ],
// );
// }
if (dataList.isEmpty) {
return EmptyTip();
}

View File

@ -291,7 +291,6 @@ class _UserInfoState extends State<UserInfo> {
} else {
print("图片合法,大小:$sizeInMB MB");
//upload(file)url地址
final croppedFile = await ImageCropper().cropImage(
sourcePath: file.path,
maxWidth: 1024,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_typedefs/rx_typedefs.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
@ -271,6 +272,17 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
}
}
Widget _buildIcon(String assetPath, VoidCallback onTap) {
return InkWell(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
decoration: BoxDecoration(color: Colors.black.withAlpha((0.3 * 255).round()), borderRadius: BorderRadius.circular(20.0)),
child: SvgPicture.asset(assetPath, height: 20.0, width: 20.0, colorFilter: const ColorFilter.mode(Colors.white70, BlendMode.srcIn)),
),
);
}
@override
Widget build(BuildContext context) {
return PopScope(
@ -297,75 +309,70 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
pinned: true,
stretch: true,
actions: [
IconButton(
icon: const Icon(
Icons.more_horiz,
color: Colors.black,
),
onPressed: () async {
final paddingTop = MediaQuery.of(Get.context!).padding.top;
_buildIcon('assets/images/svg/more.svg', () async {
final paddingTop = MediaQuery.of(Get.context!).padding.top;
final selected = await showMenu(
context: Get.context!,
position: RelativeRect.fromLTRB(
double.infinity,
kToolbarHeight + paddingTop - 12,
8,
double.infinity,
),
color: FStyle.primaryColor,
elevation: 8,
items: [
PopupMenuItem<String>(
value: 'block',
child: Row(
children: [
Icon(Icons.block, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
blackTxt,
style: TextStyle(color: Colors.white),
),
],
),
final selected = await showMenu(
context: Get.context!,
position: RelativeRect.fromLTRB(
double.infinity,
kToolbarHeight + paddingTop - 12,
8,
double.infinity,
),
color: FStyle.primaryColor,
elevation: 8,
items: [
PopupMenuItem<String>(
value: 'block',
child: Row(
children: [
Icon(Icons.block, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
blackTxt,
style: TextStyle(color: Colors.white),
),
],
),
],
);
),
],
);
if (selected != null) {
switch (selected) {
case 'block':
// print('点击了拉黑');
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('确认要$blackTxt对方吗', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(
onPressed: () {
Get.back();
},
child: const Text('取消', style: TextStyle(color: Colors.black54)),
),
TextButton(onPressed: _handleBlack, child: const Text('确认', style: TextStyle(color: Colors.red))),
],
);
},
);
break;
// case 'foucs':
// print('点击了取关');
// break;
}
if (selected != null) {
switch (selected) {
case 'block':
// print('点击了拉黑');
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('确认要$blackTxt对方吗', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(
onPressed: () {
Get.back();
},
child: const Text('取消', style: TextStyle(color: Colors.black54)),
),
TextButton(onPressed: _handleBlack, child: const Text('确认', style: TextStyle(color: Colors.red))),
],
);
},
);
break;
// case 'foucs':
// print('点击了取关');
// break;
}
},
),
}
}),
const SizedBox(width: 10.0),
],
leading: IconButton(
icon: const Icon(Icons.arrow_back),

View File

@ -84,6 +84,9 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
logger.e('code=$code');
final res = await Http.get('${ShopApi.getWriteOffDetail}?code=$code');
logger.w('订单详情-------------->${res['data']}');
if (res == null) {
return;
}
setState(() {
orderGoodsInfo = res['data'];
_isLoading = false;
@ -428,7 +431,9 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
body: _isLoading
? Center(child: CircularProgressIndicator())
: orderGoodsInfo == null
? emptyTip()
? Center(
child: emptyTip(),
)
: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: ListView(
@ -494,7 +499,8 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
Row(
children: [
Spacer(),
orderGoodsInfo['items'][0]['status'] == 1
// orderGoodsInfo['items'][0]['status'] == 1
orderGoodsInfo['verificationCodeStatus'] == 1
? Text(
'已核销',
style: TextStyle(
@ -557,7 +563,7 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
SizedBox(height: 10),
Column(
children: [
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderId']?.toString() ?? ''),
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderSn']?.toString() ?? ''),
_buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime']?.toString() ?? ''),
_buildOrderInfoRow('购买数量', _calculateTotalQuantity().toString()),
_orderId.isNotEmpty
@ -607,6 +613,7 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
}
Widget _buildOrderInfoRow(String label, String value) {
// logger.e(orderGoodsInfo);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: Row(

View File

@ -90,6 +90,7 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
if (file != null) {
final fileSizeInBytes = await file.length();
final sizeInMB = fileSizeInBytes / (1024 * 1024);
//
if (sizeInMB > 200) {
MyDialog.toast('文件大小不能超过200MB', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
} else {

View File

@ -683,7 +683,7 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
),
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: videoData['vlogerFace'] ?? videoData['commentUserFace'],
imageUrl: videoData['vlogerFace'] ?? videoData['avatar'],
),
),
),
@ -808,7 +808,7 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'@${videoData['vlogerNickname'] ?? videoData['commentUserNickname'] ?? '未知用户'}',
'@${videoData['nickname'] ?? '未知用户'}',
style: const TextStyle(color: Colors.white, fontSize: 16.0),
),
LayoutBuilder(
@ -1179,8 +1179,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
final comment = commentList[index];
final hasReplies = comment['childCount'] > 0;
final isExpanded = expandedReplies[comment['id']] == true;
final replies = replyData[comment['id']] ?? [];
final isExpanded = expandedReplies[comment['commentId']] == true;
final replies = replyData[comment['commentId']] ?? [];
return Column(
children: [
@ -1211,7 +1211,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
},
@ -1239,10 +1239,10 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
expandedReplies[comment['id']] = !isExpanded;
if (expandedReplies[comment['id']] == true &&
(replyData[comment['id']] == null || replyData[comment['id']]!.isEmpty)) {
fetchReplies(comment['id'], false);
expandedReplies[comment['commentId']] = !isExpanded;
if (expandedReplies[comment['commentId']] == true &&
(replyData[comment['commentId']] == null || replyData[comment['commentId']]!.isEmpty)) {
fetchReplies(comment['commentId'], false);
}
});
},
@ -1303,7 +1303,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = reply['commentUserNickname'] ?? '未知用户';
});
},
@ -1337,8 +1337,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
if (replies.length < comment['childCount'])
Center(
child: TextButton(
onPressed: () => fetchReplies(comment['id'], true),
child: isLoadingReplies[comment['id']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
onPressed: () => fetchReplies(comment['commentId'], true),
child: isLoadingReplies[comment['commentId']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
),
),
],

View File

@ -295,8 +295,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
final comment = commentList[index];
final hasReplies = comment['childCount'] > 0;
final isExpanded = expandedReplies[comment['id']] == true;
final replies = replyData[comment['id']] ?? [];
final isExpanded = expandedReplies[comment['commentId']] == true;
final replies = replyData[comment['commentId']] ?? [];
return Column(
children: [
@ -327,7 +327,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
},
@ -355,10 +355,10 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
expandedReplies[comment['id']] = !isExpanded;
if (expandedReplies[comment['id']] == true &&
(replyData[comment['id']] == null || replyData[comment['id']]!.isEmpty)) {
fetchReplies(comment['id'], false);
expandedReplies[comment['commentId']] = !isExpanded;
if (expandedReplies[comment['commentId']] == true &&
(replyData[comment['commentId']] == null || replyData[comment['commentId']]!.isEmpty)) {
fetchReplies(comment['commentId'], false);
}
});
},
@ -419,7 +419,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = reply['commentUserNickname'] ?? '未知用户';
});
},
@ -453,8 +453,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
if (replies.length < comment['childCount'])
Center(
child: TextButton(
onPressed: () => fetchReplies(comment['id'], true),
child: isLoadingReplies[comment['id']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
onPressed: () => fetchReplies(comment['commentId'], true),
child: isLoadingReplies[comment['commentId']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
),
),
],
@ -1164,7 +1164,7 @@ class _AttentionModuleState extends State<AttentionModule> {
),
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: videoList[index]['commentUserFace'],
imageUrl: videoList[index]['avatar'],
),
),
),

View File

@ -296,8 +296,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
final comment = commentList[index];
final hasReplies = comment['childCount'] > 0;
final isExpanded = expandedReplies[comment['id']] == true;
final replies = replyData[comment['id']] ?? [];
final isExpanded = expandedReplies[comment['commentId']] == true;
final replies = replyData[comment['commentId']] ?? [];
return Column(
children: [
@ -328,7 +328,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
},
@ -356,10 +356,10 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
expandedReplies[comment['id']] = !isExpanded;
if (expandedReplies[comment['id']] == true &&
(replyData[comment['id']] == null || replyData[comment['id']]!.isEmpty)) {
fetchReplies(comment['id'], false);
expandedReplies[comment['commentId']] = !isExpanded;
if (expandedReplies[comment['commentId']] == true &&
(replyData[comment['commentId']] == null || replyData[comment['commentId']]!.isEmpty)) {
fetchReplies(comment['commentId'], false);
}
});
},
@ -420,7 +420,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = reply['commentUserNickname'] ?? '未知用户';
});
},
@ -454,8 +454,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
if (replies.length < comment['childCount'])
Center(
child: TextButton(
onPressed: () => fetchReplies(comment['id'], true),
child: isLoadingReplies[comment['id']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
onPressed: () => fetchReplies(comment['commentId'], true),
child: isLoadingReplies[comment['commentId']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
),
),
],
@ -1169,7 +1169,7 @@ class _FriendModuleState extends State<FriendModule> {
),
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: videoList[index]['commentUserFace'],
imageUrl: videoList[index]['avatar'],
),
),
),

View File

@ -332,7 +332,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
onTap: () {
setState(() {
logger.e(comment);
// replyingCommentId = comment['id']; //null
replyingCommentId = comment['commentId'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
});
@ -427,7 +427,7 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
GestureDetector(
onTap: () {
setState(() {
replyingCommentId = comment['id'];
replyingCommentId = comment['commentId'];
replyingCommentUser = reply['commentUserNickname'] ?? '未知用户';
});
},
@ -461,8 +461,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
if (replies.length < comment['childCount'])
Center(
child: TextButton(
onPressed: () => fetchReplies(comment['id'], true),
child: isLoadingReplies[comment['id']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
onPressed: () => fetchReplies(comment['commentId'], true),
child: isLoadingReplies[comment['commentId']] == true ? CircularProgressIndicator() : Text('加载更多回复'),
),
),
],
@ -1169,13 +1169,14 @@ class _RecommendModuleState extends State<RecommendModule> {
),
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: videoList[index]['commentUserFace'],
imageUrl: videoList[index]['avatar'],
),
),
),
),
),
),
//
Positioned(
bottom: 0,
left: 15.0,

View File

@ -22,7 +22,7 @@ class UpgradeService {
});
if (!state.mounted) return;
logger.w(res);
logger.e(res);
final result = res['data']['records'] as List;
if (result.isEmpty) return;
final data = result.first;

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/parse_message_summary.dart';
import 'package:shirne_dialog/shirne_dialog.dart';
@ -20,6 +21,8 @@ class NotificationBanner {
name = gpInfo?.groupName ?? "未知群名";
avatar = gpInfo?.faceUrl ?? "";
} else {
logger.e('获取群名称失败');
logger.e(msg.toJson());
name = '获取群名称失败';
}
} else {
@ -71,18 +74,25 @@ class NotificationBanner {
),
onTap: (_) async {
Get.closeCurrentSnackbar();
String? conversationID;
if (msg.groupID != null && msg.groupID!.isNotEmpty) {
conversationID = 'group_${msg.groupID}';
} else if (msg.userID != null && msg.userID!.isNotEmpty) {
conversationID = 'c2c_${msg.userID}';
//
bool isGroup = msg.groupID != null && msg.groupID!.isNotEmpty;
String id = isGroup ? (msg.groupID ?? '') : (msg.userID ?? '');
String conversationID = isGroup ? 'group_$id' : 'c2c_$id';
String? router;
//
final cRes = await ImService.instance.getConversation(conversationID: conversationID);
if (!isGroup) {
// ,
router = conversationTypeFromString(msg.userID); //userID
}
final cRes = await ImService.instance.getConversation(conversationID: conversationID!);
if (cRes.success) {
if (msg.userID != null) {
Get.toNamed('/chat', arguments: cRes.data);
} else if (msg.groupID != null) {
if (router != null) {
//
Get.toNamed('/$router', arguments: cRes.data);
} else if (isGroup) {
Get.toNamed('/chatGroup', arguments: cRes.data);
} else {
Get.toNamed('/chat', arguments: cRes.data);
}
} else {
MyDialog.toast(

View File

@ -233,6 +233,8 @@ String _parseCustomMessage(V2TimMessage? msg) {
///广
return elment!.desc!;
// interaction required key={type} value={interactionComment}
case NotifyMessageTypeConstants.interactionComment:
//

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 4.1.0+407
version: 4.1.1+413
environment:
sdk: ^3.6.0
@ -205,7 +205,10 @@ flutter_native_splash:
android_gravity: fill
fullscreen: true #隐藏通知栏
android_12:
android_12:
color: "#000000"
color_dark: "#000000"
image: assets/images/logo/androidlogo.png
icon_background_color: "#000000"