diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 0fcf1b24..f9698f17 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -1,4 +1,6 @@ import 'dart:math'; +import 'package:dio/dio.dart'; + import '../models/msg/account.dart'; import '../models/msg/session.dart'; import '../utils/wbi_sign.dart'; @@ -6,7 +8,6 @@ import 'api.dart'; import 'init.dart'; class MsgHttp { - static Future msgFeedReplyMe({int cursor = -1, int cursorTime = -1}) async { var res = await Request().get(Api.msgFeedReply, data: { 'id': cursor == -1 ? null : cursor, @@ -25,8 +26,9 @@ class MsgHttp { }; } } + static Future msgFeedAtMe({int cursor = -1, int cursorTime = -1}) async { - var res = await Request().get(Api.msgFeedAt,data: { + var res = await Request().get(Api.msgFeedAt, data: { 'id': cursor == -1 ? null : cursor, 'at_time': cursorTime == -1 ? null : cursorTime, }); @@ -43,8 +45,9 @@ class MsgHttp { }; } } + static Future msgFeedLikeMe({int cursor = -1, int cursorTime = -1}) async { - var res = await Request().get(Api.msgFeedLike,data: { + var res = await Request().get(Api.msgFeedLike, data: { 'id': cursor == -1 ? null : cursor, 'like_time': cursorTime == -1 ? null : cursorTime, }); @@ -61,6 +64,7 @@ class MsgHttp { }; } } + static Future msgFeedSysUserNotify() async { String csrf = await Request.getCsrf(); var res = await Request().get(Api.msgSysUserNotify, data: { @@ -81,6 +85,7 @@ class MsgHttp { }; } } + static Future msgFeedSysUnifiedNotify() async { String csrf = await Request.getCsrf(); var res = await Request().get(Api.msgSysUnifiedNotify, data: { @@ -136,6 +141,7 @@ class MsgHttp { }; } } + // 会话列表 static Future sessionList({int? endTs}) async { Map params = { @@ -271,7 +277,7 @@ class MsgHttp { dynamic content, }) async { String csrf = await Request.getCsrf(); - Map params = await WbiSign().makSign({ + Map base = { 'msg[sender_uid]': senderUid, 'msg[receiver_id]': receiverId, 'msg[receiver_type]': receiverType ?? 1, @@ -286,21 +292,17 @@ class MsgHttp { 'mobi_app': 'web', 'csrf_token': csrf, 'csrf': csrf, - }); - var res = - await Request().post(Api.sendMsg, queryParameters: { - ...params, - 'csrf_token': csrf, - 'csrf': csrf, - }, data: { - 'w_sender_uid': params['msg[sender_uid]'], - 'w_receiver_id': params['msg[receiver_id]'], - 'w_dev_id': params['msg[dev_id]'], - 'w_rid': params['w_rid'], - 'wts': params['wts'], - 'csrf_token': csrf, - 'csrf': csrf, - }); + }; + Map params = await WbiSign().makSign(base); + var res = await Request().post(Api.sendMsg, + queryParameters: { + 'w_sender_uid': params['msg[sender_uid]'], + 'w_receiver_id': params['msg[receiver_id]'], + 'w_dev_id': params['msg[dev_id]'], + 'w_rid': params['w_rid'], + 'wts': params['wts'], + }, + data: FormData.fromMap(base)); if (res.data['code'] == 0) { return { 'status': true, diff --git a/lib/models/msg/session.dart b/lib/models/msg/session.dart index a0c2a048..93f8ba19 100644 --- a/lib/models/msg/session.dart +++ b/lib/models/msg/session.dart @@ -195,6 +195,7 @@ class MessageItem { this.msgStatus, this.notifyCode, this.newFaceVersion, + this.msgSource, }); int? senderUid; @@ -209,6 +210,7 @@ class MessageItem { int? msgStatus; String? notifyCode; int? newFaceVersion; + int? msgSource; MessageItem.fromJson(Map json) { senderUid = json['sender_uid']; @@ -226,5 +228,6 @@ class MessageItem { msgStatus = json['msg_status']; notifyCode = json['notify_code']; newFaceVersion = json['new_face_version']; + msgSource = json['msg_source']; } } diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart index 9e2b7d88..57a12c32 100644 --- a/lib/pages/member/widgets/profile.dart +++ b/lib/pages/member/widgets/profile.dart @@ -202,7 +202,17 @@ class ProfilePanel extends StatelessWidget { const SizedBox(width: 8), Expanded( child: TextButton( - onPressed: () {}, + onPressed: () { + Get.toNamed( + '/whisperDetail', + parameters: { + 'talkerId': ctr.mid.toString(), + 'name': memberInfo.name!, + 'face': memberInfo.face!, + 'mid': ctr.mid.toString(), + }, + ); + }, style: TextButton.styleFrom( backgroundColor: Theme.of(context) .colorScheme diff --git a/lib/pages/video/detail/reply_new/view.dart b/lib/pages/video/detail/reply_new/view.dart index a003eb92..5a0d1dff 100644 --- a/lib/pages/video/detail/reply_new/view.dart +++ b/lib/pages/video/detail/reply_new/view.dart @@ -238,7 +238,7 @@ class _VideoReplyNewDialogState extends State width: double.infinity, height: toolbarType == 'input' ? keyboardHeight : emoteHeight, child: EmotePanel( - onChoose: (package, emote) => onChooseEmote(package, emote), + onChoose: onChooseEmote, ), ), if (toolbarType == 'input' && keyboardHeight == 0.0) diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index d297ae8f..1ab1cff0 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -153,6 +153,17 @@ class _WhisperPageState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (_, int i) { + dynamic content = + sessionList[i].lastMsg.content; + if (content == null || content == "") { + content = '不支持的消息类型'; + } else { + content = content['text'] ?? + content['content'] ?? + content['title'] ?? + content['reply_content'] ?? + content.toString(); + } return ListTile( onTap: () { setState(() { @@ -195,28 +206,7 @@ class _WhisperPageState extends State { ), title: Text(sessionList[i].accountInfo.name), - subtitle: Text( - sessionList[i].lastMsg.content != - null && - sessionList[i] - .lastMsg - .content != - '' - ? (sessionList[i] - .lastMsg - .content['text'] ?? - sessionList[i] - .lastMsg - .content['content'] ?? - sessionList[i] - .lastMsg - .content['title'] ?? - sessionList[i] - .lastMsg - .content[ - 'reply_content']) ?? - sessionList[i].lastMsg.content - : '不支持的消息类型', + subtitle: Text(content, maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context) diff --git a/lib/pages/whisper_detail/controller.dart b/lib/pages/whisper_detail/controller.dart index 551a66d2..10892beb 100644 --- a/lib/pages/whisper_detail/controller.dart +++ b/lib/pages/whisper_detail/controller.dart @@ -32,7 +32,15 @@ class WhisperDetailController extends GetxController { if (res['status']) { messageList.value = res['data'].messages; if (messageList.isNotEmpty) { - ackSessionMsg(); + if (messageList.length == 1 && + messageList.last.msgType == 18 && + messageList.last.msgSource == 18) { + // print(messageList.last); + // print(messageList.last.content); + //{content: [{"text":"对方主动回复或关注你前,最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]} + } else { + ackSessionMsg(); + } if (res['data'].eInfos != null) { eInfos = res['data'].eInfos; } @@ -68,13 +76,20 @@ class WhisperDetailController extends GetxController { SmartDialog.showToast('请输入内容'); return; } + if (mid == null) { + SmartDialog.showToast('这里不能发'); + return; + } var result = await MsgHttp.sendMsg( senderUid: userInfo.mid, receiverId: int.parse(mid), - content: {'content': message}, + content: '{"content":"$message"}', msgType: 1, ); if (result['status']) { + print(result['data']); + querySessionMsg(); + replyContentController.text = ""; SmartDialog.showToast('发送成功'); } else { SmartDialog.showToast(result['msg']); diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index ce701ff4..86e1da1a 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -7,6 +7,7 @@ import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/pages/emote/index.dart'; import 'package:PiliPalaX/pages/whisper_detail/controller.dart'; import 'package:PiliPalaX/utils/feed_back.dart'; +import 'package:PiliPalaX/models/video/reply/emote.dart'; import '../../utils/storage.dart'; import 'widget/chat_item.dart'; @@ -26,7 +27,7 @@ class _WhisperDetailPageState extends State final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间 late double emoteHeight = 0.0; double keyboardHeight = 0.0; // 键盘高度 - String toolbarType = 'input'; + String toolbarType = 'none'; Box userInfoCache = GStrorage.userInfo; @override @@ -35,15 +36,19 @@ class _WhisperDetailPageState extends State WidgetsBinding.instance.addObserver(this); _whisperDetailController.querySessionMsg(); _replyContentController = _whisperDetailController.replyContentController; - _focuslistener(); + _focusListener(); } - _focuslistener() { + _focusListener() { replyContentFocusNode.addListener(() { if (replyContentFocusNode.hasFocus) { setState(() { toolbarType = 'input'; }); + } else if (toolbarType == 'input') { + setState(() { + toolbarType = 'none'; + }); } }); } @@ -51,24 +56,25 @@ class _WhisperDetailPageState extends State @override void didChangeMetrics() { super.didChangeMetrics(); - final String routePath = Get.currentRoute; - if (mounted && routePath.startsWith('/whisper_detail')) { - WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + // 键盘高度 + final viewInsets = EdgeInsets.fromViewPadding( + View.of(context).viewInsets, View.of(context).devicePixelRatio); + _debouncer.run(() { if (!mounted) return; - // 键盘高度 - final viewInsets = EdgeInsets.fromViewPadding( - View.of(context).viewInsets, View.of(context).devicePixelRatio); - _debouncer.run(() { - if (!mounted) return; - if (keyboardHeight == 0) { - setState(() { - emoteHeight = keyboardHeight = - keyboardHeight == 0.0 ? viewInsets.bottom : keyboardHeight; - }); + if (keyboardHeight == 0) { + emoteHeight = keyboardHeight = + keyboardHeight == 0.0 ? viewInsets.bottom : keyboardHeight; + if (emoteHeight == 0 || emoteHeight < keyboardHeight) { + emoteHeight = keyboardHeight; } - }); + if (emoteHeight < 200) emoteHeight = 200; + setState(() {}); + } }); - } + }); } @override @@ -79,6 +85,20 @@ class _WhisperDetailPageState extends State super.dispose(); } + void onChooseEmote(Packages package, Emote emote) { + int cursorPosition = _replyContentController.selection.baseOffset; + if (cursorPosition == -1) cursorPosition = 0; + final String currentText = _replyContentController.text; + final String newText = currentText.substring(0, cursorPosition) + + emote.text! + + currentText.substring(cursorPosition); + _replyContentController.value = TextEditingValue( + text: newText, + selection: + TextSelection.collapsed(offset: cursorPosition + emote.text!.length), + ); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -147,10 +167,10 @@ class _WhisperDetailPageState extends State ), body: GestureDetector( onTap: () { - FocusScope.of(context).unfocus(); setState(() { - keyboardHeight = 0; + toolbarType = 'none'; }); + FocusScope.of(context).unfocus(); }, child: Obx(() { List messageList = _whisperDetailController.messageList; @@ -159,26 +179,33 @@ class _WhisperDetailPageState extends State child: CircularProgressIndicator(), ); } - return ListView.builder( - itemCount: messageList.length, - shrinkWrap: true, - reverse: true, - itemBuilder: (_, int i) { - return ChatItem( - item: messageList[i], - e_infos: _whisperDetailController.eInfos); - }, - ); + return RefreshIndicator( + onRefresh: _whisperDetailController.querySessionMsg, + child: ListView.builder( + itemCount: messageList.length, + shrinkWrap: true, + reverse: true, + itemBuilder: (_, int i) { + return ChatItem( + item: messageList[i], + e_infos: _whisperDetailController.eInfos); + }, + padding: const EdgeInsets.only(bottom: 20), + )); }), ), // resizeToAvoidBottomInset: true, bottomNavigationBar: Container( width: double.infinity, - height: MediaQuery.of(context).padding.bottom + 70 + keyboardHeight, + height: MediaQuery.of(context).padding.bottom + + 70 + + (toolbarType == 'none' + ? 0 + : (toolbarType == 'input' ? keyboardHeight : emoteHeight)), padding: EdgeInsets.only( left: 8, right: 12, - top: 12, + top: 10, bottom: MediaQuery.of(context).padding.bottom, ), decoration: BoxDecoration( @@ -205,16 +232,19 @@ class _WhisperDetailPageState extends State IconButton( tooltip: '表情', onPressed: () { - // if (toolbarType == 'input') { - // setState(() { - // toolbarType = 'emote'; - // }); - // } - // FocusScope.of(context).unfocus(); + if (emoteHeight < 200) emoteHeight = 200; + if (toolbarType != 'emote') { + setState(() { + toolbarType = 'emote'; + }); + } + FocusScope.of(context).unfocus(); }, icon: Icon( - Icons.emoji_emotions_outlined, - color: Theme.of(context).colorScheme.outline, + Icons.emoji_emotions, + color: toolbarType == 'emote' + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, ), ), Expanded( @@ -228,16 +258,15 @@ class _WhisperDetailPageState extends State borderRadius: BorderRadius.circular(40.0), ), child: Semantics( - label: '私信输入框(开发中)', + label: '私信输入框', child: TextField( - readOnly: true, style: Theme.of(context).textTheme.titleMedium, controller: _replyContentController, autofocus: false, focusNode: replyContentFocusNode, decoration: const InputDecoration( border: InputBorder.none, // 移除默认边框 - hintText: '开发中 ...', // 提示文本 + hintText: '发个消息聊聊呗~', // 提示文本 contentPadding: EdgeInsets.symmetric( horizontal: 16.0, vertical: 12.0), // 内边距 ), @@ -246,25 +275,22 @@ class _WhisperDetailPageState extends State ), IconButton( tooltip: '发送', - // onPressed: _whisperDetailController.sendMsg, - onPressed: null, + onPressed: _whisperDetailController.sendMsg, icon: Icon( Icons.send, - color: Theme.of(context).colorScheme.outline, + color: Theme.of(context).colorScheme.primary, ), ), // const SizedBox(width: 16), ], ), - AnimatedSize( - curve: Curves.easeInOut, - duration: const Duration(milliseconds: 300), - child: SizedBox( - width: double.infinity, - height: toolbarType == 'input' ? keyboardHeight : emoteHeight, - child: EmotePanel( - onChoose: (package, emote) => {}, - ), + SizedBox( + width: double.infinity, + height: toolbarType == 'none' + ? 0 + : (toolbarType == 'input' ? keyboardHeight : emoteHeight), + child: EmotePanel( + onChoose: onChooseEmote, ), ), ],