From f9a1f2ff9fae232f5a5d74986edea460c55cda56 Mon Sep 17 00:00:00 2001 From: abu <3109389044@qq.com> Date: Wed, 1 Oct 2025 12:29:09 +0800 Subject: [PATCH] 4.1.1 --- assets/images/svg/more.svg | 1 + ios/Runner/Info.plist | 7 + lib/IM/im_message.dart | 12 +- lib/IM/im_service.dart | 24 +- lib/IM/push_service.dart | 8 +- lib/components/image_viewer.dart | 122 +++--- lib/pages/chat/chat.dart | 10 +- lib/pages/chat/chat_group.dart | 8 +- lib/pages/chat/chat_no_friend.dart | 4 +- lib/pages/chat/index.dart | 3 + lib/pages/chat/notify/interaction.dart | 116 +++--- lib/pages/chat/notify/newFoucs.dart | 16 +- lib/pages/goods/detail.dart | 10 +- .../components/invite_action_sheet.dart | 15 +- .../components/member_action_sheet.dart | 42 +- lib/pages/groupChat/groupDetail.dart | 365 +++++++++++------- lib/pages/index/index.dart | 34 +- lib/pages/my/user_info.dart | 1 - lib/pages/my/vloger.dart | 137 +++---- lib/pages/order/seller_detail.dart | 13 +- .../upload_video_page/upload_video_page.dart | 1 + lib/pages/video/commonVideo.dart | 24 +- lib/pages/video/module/attention.dart | 22 +- lib/pages/video/module/friend.dart | 22 +- lib/pages/video/module/recommend.dart | 11 +- lib/update/upgrade_service.dart | 2 +- lib/utils/notification_banner.dart | 28 +- lib/utils/parse_message_summary.dart | 2 + pubspec.yaml | 7 +- 29 files changed, 626 insertions(+), 441 deletions(-) create mode 100644 assets/images/svg/more.svg diff --git a/assets/images/svg/more.svg b/assets/images/svg/more.svg new file mode 100644 index 0000000..463bb0e --- /dev/null +++ b/assets/images/svg/more.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index ee8fd3b..20d7262 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -72,6 +72,13 @@ App需要访问您的相册用于选择图片或视频 UIApplicationSupportsIndirectInputEvents + CFBundleLocalizations + + en + zh-Hans + + ITSAppUsesNonExemptEncryption + UIBackgroundModes remote-notification diff --git a/lib/IM/im_message.dart b/lib/IM/im_message.dart index 6747703..368174c 100644 --- a/lib/IM/im_message.dart +++ b/lib/IM/im_message.dart @@ -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, diff --git a/lib/IM/im_service.dart b/lib/IM/im_service.dart index 83c4684..c2d6772 100644 --- a/lib/IM/im_service.dart +++ b/lib/IM/im_service.dart @@ -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; } diff --git a/lib/IM/push_service.dart b/lib/IM/push_service.dart index c877549..445a8ad 100644 --- a/lib/IM/push_service.dart +++ b/lib/IM/push_service.dart @@ -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) { // 聊天 diff --git a/lib/components/image_viewer.dart b/lib/components/image_viewer.dart index b28b056..fa1f9d3 100644 --- a/lib/components/image_viewer.dart +++ b/lib/components/image_viewer.dart @@ -50,68 +50,70 @@ class _ImageViewerState extends State { 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'), + ), + )), + ), + ], + ), ), ); } diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index a3e2601..2308df7 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -502,6 +502,7 @@ class _ChatState extends State 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 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 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 with SingleTickerProviderStateMixin { title: Obx(() { return Text( // '${arguments['title']}', - '${arguments.value.showName}', + arguments.value.showName ?? '神秘人', style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'), ); }), diff --git a/lib/pages/chat/chat_group.dart b/lib/pages/chat/chat_group.dart index 68bda48..13ebde0 100644 --- a/lib/pages/chat/chat_group.dart +++ b/lib/pages/chat/chat_group.dart @@ -383,6 +383,7 @@ class _ChatGroupState extends State 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 with SingleTickerProviderStateMix children: [ NetworkOrAssetImage( imageUrl: url, + placeholderAsset: 'assets/images/bk.jpg', width: 160.0, ), Container( @@ -1568,7 +1570,7 @@ class _ChatGroupState extends State 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 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 with SingleTickerProviderStateMix ), titleSpacing: 1.0, title: Text( - '${arguments.showName}', + arguments.showName ?? '群聊', style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'), maxLines: 1, overflow: TextOverflow.ellipsis, diff --git a/lib/pages/chat/chat_no_friend.dart b/lib/pages/chat/chat_no_friend.dart index d780ece..03633e0 100644 --- a/lib/pages/chat/chat_no_friend.dart +++ b/lib/pages/chat/chat_no_friend.dart @@ -441,6 +441,7 @@ class _ChatNoFriendState extends State 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 with SingleTickerProviderSt children: [ NetworkOrAssetImage( imageUrl: url, + placeholderAsset: 'assets/images/bk.jpg', width: 160.0, ), Container( @@ -1515,7 +1517,7 @@ class _ChatNoFriendState extends State with SingleTickerProviderSt title: Obx(() { return Text( // '${arguments['title']}', - '${arguments.value.showName}', + arguments.value.showName ?? '陌生人', style: const TextStyle(fontSize: 18.0, fontFamily: 'Arial'), ); }), diff --git a/lib/pages/chat/index.dart b/lib/pages/chat/index.dart index f33bb29..53b7aa5 100644 --- a/lib/pages/chat/index.dart +++ b/lib/pages/chat/index.dart @@ -103,6 +103,7 @@ class ChatPageState extends State { final controller = Get.find(); 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 { ), ), onTap: () { + // logger.e(chatList[index].isCustomAdmin); + if (conversationTypeFromString(chatList[index].isCustomAdmin) != null) { // 跳转对应的通知消息页 notify下的内容 logger.e(chatList[index].isCustomAdmin); diff --git a/lib/pages/chat/notify/interaction.dart b/lib/pages/chat/notify/interaction.dart index 498081e..e767148 100644 --- a/lib/pages/chat/notify/interaction.dart +++ b/lib/pages/chat/notify/interaction.dart @@ -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 with SingleTickerProviderState Future 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 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 with SingleTickerProviderState msgList.addAll(item.messageList ?? []); } } else { + msgList.clear(); logger.e('数据为空${res.desc}'); } } @@ -244,15 +264,15 @@ class InteractionState extends State 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 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 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 with SingleTickerProviderState spacing: 10.0, children: [ // 头像 - InkWell( + GestureDetector( onTap: () async { // 点击头像转到对方主页 // 先获取视频详情 // 如果cloudCustomData是interactionComment,interactionAt,interactionReply,传参时带上评论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 with SingleTickerProviderState // 消息 Expanded( - child: InkWell( + child: GestureDetector( onTap: () async { // 点击头像转到对方主页 // 先获取视频详情 // 如果cloudCustomData是interactionComment,interactionAt,interactionReply,传参时带上评论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 with SingleTickerProviderState ), // 右侧 - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - 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: [ + 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), + ), + ], + ), ), ], ), diff --git a/lib/pages/chat/notify/newFoucs.dart b/lib/pages/chat/notify/newFoucs.dart index 128ecab..965b29e 100644 --- a/lib/pages/chat/notify/newFoucs.dart +++ b/lib/pages/chat/notify/newFoucs.dart @@ -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 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 with SingleTickerProviderStateMixin // 先获取视频详情 // 如果cloudCustomData是interactionComment,interactionAt,interactionReply,传参时带上评论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 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( diff --git a/lib/pages/goods/detail.dart b/lib/pages/goods/detail.dart index 96c272b..98c17be 100644 --- a/lib/pages/goods/detail.dart +++ b/lib/pages/goods/detail.dart @@ -190,7 +190,8 @@ class _GoodsState extends State { 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 { 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: '分享成功', diff --git a/lib/pages/groupChat/components/invite_action_sheet.dart b/lib/pages/groupChat/components/invite_action_sheet.dart index 3528dea..556bebe 100644 --- a/lib/pages/groupChat/components/invite_action_sheet.dart +++ b/lib/pages/groupChat/components/invite_action_sheet.dart @@ -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 { 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 { 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), // 用户名 diff --git a/lib/pages/groupChat/components/member_action_sheet.dart b/lib/pages/groupChat/components/member_action_sheet.dart index 50138b2..76f1557 100644 --- a/lib/pages/groupChat/components/member_action_sheet.dart +++ b/lib/pages/groupChat/components/member_action_sheet.dart @@ -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 { final self = Get.find().selfInfo.value!; members.insert(0, self); } + getMemberData(); } @@ -59,7 +61,7 @@ class _MemberActionSheetState extends State { 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 { 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 { @override Widget build(BuildContext context) { - List filteredMembers; + List filteredMembers; if (_query.isEmpty) { filteredMembers = members; } else { @@ -223,11 +230,22 @@ class _MemberActionSheetState extends State { 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().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 { 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), diff --git a/lib/pages/groupChat/groupDetail.dart b/lib/pages/groupChat/groupDetail.dart index c05e8dd..1ea221a 100644 --- a/lib/pages/groupChat/groupDetail.dart +++ b/lib/pages/groupChat/groupDetail.dart @@ -166,51 +166,116 @@ class GroupdetailState extends State { ); } }, - 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 { ); }, ), + // 群成员头像区域 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 = [ + ...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), diff --git a/lib/pages/index/index.dart b/lib/pages/index/index.dart index c298917..3a291dc 100644 --- a/lib/pages/index/index.dart +++ b/lib/pages/index/index.dart @@ -167,6 +167,7 @@ class _IndexPageState extends State with TickerProviderStateMixin { /// 切换数据 Future 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 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 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 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(); } diff --git a/lib/pages/my/user_info.dart b/lib/pages/my/user_info.dart index 94f1d20..dae9df0 100644 --- a/lib/pages/my/user_info.dart +++ b/lib/pages/my/user_info.dart @@ -291,7 +291,6 @@ class _UserInfoState extends State { } else { print("图片合法,大小:$sizeInMB MB"); //走upload(file)上传图片拿到url地址 - final croppedFile = await ImageCropper().cropImage( sourcePath: file.path, maxWidth: 1024, diff --git a/lib/pages/my/vloger.dart b/lib/pages/my/vloger.dart index f4167e7..5f72cd8 100644 --- a/lib/pages/my/vloger.dart +++ b/lib/pages/my/vloger.dart @@ -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 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 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( - 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( + 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), diff --git a/lib/pages/order/seller_detail.dart b/lib/pages/order/seller_detail.dart index 2b1fffb..d4d8fa8 100644 --- a/lib/pages/order/seller_detail.dart +++ b/lib/pages/order/seller_detail.dart @@ -84,6 +84,9 @@ class _SellerOrderDetailState extends State 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 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 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 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 with SingleTicker } Widget _buildOrderInfoRow(String label, String value) { + // logger.e(orderGoodsInfo); return Padding( padding: const EdgeInsets.symmetric(vertical: 6.0), child: Row( diff --git a/lib/pages/upload_video_page/upload_video_page.dart b/lib/pages/upload_video_page/upload_video_page.dart index bab3a02..de0a9ee 100644 --- a/lib/pages/upload_video_page/upload_video_page.dart +++ b/lib/pages/upload_video_page/upload_video_page.dart @@ -90,6 +90,7 @@ class _UploadVideoPageState extends State { 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 { diff --git a/lib/pages/video/commonVideo.dart b/lib/pages/video/commonVideo.dart index c0794f3..2fd25aa 100644 --- a/lib/pages/video/commonVideo.dart +++ b/lib/pages/video/commonVideo.dart @@ -683,7 +683,7 @@ class _VideoDetailPageState extends State { ), child: ClipOval( child: NetworkOrAssetImage( - imageUrl: videoData['vlogerFace'] ?? videoData['commentUserFace'], + imageUrl: videoData['vlogerFace'] ?? videoData['avatar'], ), ), ), @@ -808,7 +808,7 @@ class _VideoDetailPageState extends State { 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 { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = comment['commentUserNickname'] ?? '未知用户'; }); }, @@ -1239,10 +1239,10 @@ class _CommentBottomSheetState extends State { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = reply['commentUserNickname'] ?? '未知用户'; }); }, @@ -1337,8 +1337,8 @@ class _CommentBottomSheetState extends State { 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('加载更多回复'), ), ), ], diff --git a/lib/pages/video/module/attention.dart b/lib/pages/video/module/attention.dart index 92a1f99..48b6725 100644 --- a/lib/pages/video/module/attention.dart +++ b/lib/pages/video/module/attention.dart @@ -295,8 +295,8 @@ class _CommentBottomSheetState extends State { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = comment['commentUserNickname'] ?? '未知用户'; }); }, @@ -355,10 +355,10 @@ class _CommentBottomSheetState extends State { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = reply['commentUserNickname'] ?? '未知用户'; }); }, @@ -453,8 +453,8 @@ class _CommentBottomSheetState extends State { 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 { ), child: ClipOval( child: NetworkOrAssetImage( - imageUrl: videoList[index]['commentUserFace'], + imageUrl: videoList[index]['avatar'], ), ), ), diff --git a/lib/pages/video/module/friend.dart b/lib/pages/video/module/friend.dart index 96cf1b2..e175266 100644 --- a/lib/pages/video/module/friend.dart +++ b/lib/pages/video/module/friend.dart @@ -296,8 +296,8 @@ class _CommentBottomSheetState extends State { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = comment['commentUserNickname'] ?? '未知用户'; }); }, @@ -356,10 +356,10 @@ class _CommentBottomSheetState extends State { 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 { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = reply['commentUserNickname'] ?? '未知用户'; }); }, @@ -454,8 +454,8 @@ class _CommentBottomSheetState extends State { 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 { ), child: ClipOval( child: NetworkOrAssetImage( - imageUrl: videoList[index]['commentUserFace'], + imageUrl: videoList[index]['avatar'], ), ), ), diff --git a/lib/pages/video/module/recommend.dart b/lib/pages/video/module/recommend.dart index 1239fae..6a8b7ea 100644 --- a/lib/pages/video/module/recommend.dart +++ b/lib/pages/video/module/recommend.dart @@ -332,7 +332,7 @@ class _CommentBottomSheetState extends State { onTap: () { setState(() { logger.e(comment); - // replyingCommentId = comment['id']; //null + replyingCommentId = comment['commentId']; replyingCommentUser = comment['commentUserNickname'] ?? '未知用户'; }); @@ -427,7 +427,7 @@ class _CommentBottomSheetState extends State { GestureDetector( onTap: () { setState(() { - replyingCommentId = comment['id']; + replyingCommentId = comment['commentId']; replyingCommentUser = reply['commentUserNickname'] ?? '未知用户'; }); }, @@ -461,8 +461,8 @@ class _CommentBottomSheetState extends State { 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 { ), child: ClipOval( child: NetworkOrAssetImage( - imageUrl: videoList[index]['commentUserFace'], + imageUrl: videoList[index]['avatar'], ), ), ), ), ), ), + // 关注区域 Positioned( bottom: 0, left: 15.0, diff --git a/lib/update/upgrade_service.dart b/lib/update/upgrade_service.dart index 115ec6c..18e58cf 100644 --- a/lib/update/upgrade_service.dart +++ b/lib/update/upgrade_service.dart @@ -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; diff --git a/lib/utils/notification_banner.dart b/lib/utils/notification_banner.dart index 9fdea4b..5f9f045 100644 --- a/lib/utils/notification_banner.dart +++ b/lib/utils/notification_banner.dart @@ -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( diff --git a/lib/utils/parse_message_summary.dart b/lib/utils/parse_message_summary.dart index 2fd5247..4b8c5e3 100644 --- a/lib/utils/parse_message_summary.dart +++ b/lib/utils/parse_message_summary.dart @@ -233,6 +233,8 @@ String _parseCustomMessage(V2TimMessage? msg) { ///系统推广类的先不管了 return elment!.desc!; + + // interaction required key={type} value={interactionComment} 对应类型的枚举值 case NotifyMessageTypeConstants.interactionComment: // 评论视频 diff --git a/pubspec.yaml b/pubspec.yaml index 04b768f..987bf95 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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"