refa: whisper detail

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-10 11:05:28 +08:00
parent 024e74115e
commit 024a249e6b
6 changed files with 635 additions and 616 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/grpc/bilibili/metadata.pb.dart'; import 'package:PiliPlus/grpc/bilibili/metadata.pb.dart';
import 'package:PiliPlus/grpc/bilibili/metadata/device.pb.dart'; import 'package:PiliPlus/grpc/bilibili/metadata/device.pb.dart';
@@ -60,6 +61,7 @@ class GrpcUrl {
static const keywordBlockingList = '$im2/KeywordBlockingList'; static const keywordBlockingList = '$im2/KeywordBlockingList';
static const keywordBlockingAdd = '$im2/KeywordBlockingAdd'; static const keywordBlockingAdd = '$im2/KeywordBlockingAdd';
static const keywordBlockingDelete = '$im2/KeywordBlockingDelete'; static const keywordBlockingDelete = '$im2/KeywordBlockingDelete';
static const syncFetchSessionMsgs = '$im/SyncFetchSessionMsgs';
} }
class GrpcRepo { class GrpcRepo {
@@ -205,8 +207,11 @@ class GrpcRepo {
try { try {
final grpcMsg = Status.fromBuffer(msgBytes); final grpcMsg = Status.fromBuffer(msgBytes);
// UNKNOWN : -400 : msg // UNKNOWN : -400 : msg
msg = final errMsg =
'${grpcMsg.code} : ${grpcMsg.message} : ${grpcMsg.details.firstOrNull?.status.message}'; grpcMsg.details.map((e) => e.status.message).join('\n');
msg = BuildConfig.isDebug
? 'CODE: ${grpcMsg.code}(${grpcMsg.message})\nMSG: $errMsg'
: errMsg;
} catch (e) { } catch (e) {
msg = utf8 msg = utf8
.decode(msgBytes, allowMalformed: true) .decode(msgBytes, allowMalformed: true)

View File

@@ -41,8 +41,28 @@ class ImGrpc {
); );
} }
static Future<LoadingState<SessionMainReply>> sessionMain( static Future<LoadingState<RspSessionMsg>> syncFetchSessionMsgs({
{PbMap<int, Offset>? offset}) { required int talkerId,
Int64? endSeqno,
Int64? beginSeqno,
}) {
return GrpcRepo.request(
GrpcUrl.syncFetchSessionMsgs,
ReqSessionMsg(
talkerId: Int64(talkerId),
sessionType: 1,
endSeqno: endSeqno,
beginSeqno: beginSeqno,
size: 20,
devId: '1',
),
RspSessionMsg.fromBuffer,
);
}
static Future<LoadingState<SessionMainReply>> sessionMain({
PbMap<int, Offset>? offset,
}) {
return GrpcRepo.request( return GrpcRepo.request(
GrpcUrl.sessionMain, GrpcUrl.sessionMain,
SessionMainReq( SessionMainReq(

View File

@@ -46,9 +46,9 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
widget.replyItem.like = widget.replyItem.like =
$fixnum.Int64(widget.replyItem.like.toInt() - 1); $fixnum.Int64(widget.replyItem.like.toInt() - 1);
} }
widget.replyItem.replyControl.action = $fixnum.Int64(2); widget.replyItem.replyControl.action = $fixnum.Int64.TWO;
} else { } else {
widget.replyItem.replyControl.action = $fixnum.Int64(0); widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
} }
setState(() {}); setState(() {});
} else { } else {
@@ -76,11 +76,11 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
if (action == 1) { if (action == 1) {
widget.replyItem.like = widget.replyItem.like =
$fixnum.Int64(widget.replyItem.like.toInt() + 1); $fixnum.Int64(widget.replyItem.like.toInt() + 1);
widget.replyItem.replyControl.action = $fixnum.Int64(1); widget.replyItem.replyControl.action = $fixnum.Int64.ONE;
} else { } else {
widget.replyItem.like = widget.replyItem.like =
$fixnum.Int64(widget.replyItem.like.toInt() - 1); $fixnum.Int64(widget.replyItem.like.toInt() - 1);
widget.replyItem.replyControl.action = $fixnum.Int64(0); widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
} }
setState(() {}); setState(() {});
} else { } else {

View File

@@ -1,67 +1,70 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart'
show EmotionInfo, RspSessionMsg;
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart' show Msg, MsgType;
import 'package:PiliPlus/grpc/im.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/http/msg.dart';
import 'package:PiliPlus/models/msg/session.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart'; import 'package:PiliPlus/pages/common/common_list_controller.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class WhisperDetailController class WhisperDetailController extends CommonListController<RspSessionMsg, Msg> {
extends CommonListController<SessionMsgDataModel, MessageItem> {
late final ownerMid = Accounts.main.mid; late final ownerMid = Accounts.main.mid;
late int talkerId; late int talkerId;
late String name; late String name;
late String face; late String face;
String? mid; int? mid;
int? msgSeqno; Int64? msgSeqno;
//表情转换图片规则 //表情转换图片规则
List<dynamic>? eInfos; List<EmotionInfo>? eInfos;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
talkerId = int.parse(Get.parameters['talkerId']!); talkerId = int.parse(Get.parameters['talkerId']!);
name = Get.parameters['name']!; name = Get.parameters['name']!;
face = Get.parameters['face']!; face = Get.parameters['face']!;
mid = Get.parameters['mid']; mid = Get.parameters['mid'] != null
? int.parse(Get.parameters['mid']!)
: null;
queryData(); queryData();
} }
@override @override
bool customHandleResponse( bool customHandleResponse(bool isRefresh, Success<RspSessionMsg> response) {
bool isRefresh, Success<SessionMsgDataModel> response) { List<Msg> msgs = response.response.messages;
List<MessageItem>? messageList = response.response.messages; if (msgs.isNotEmpty) {
if (messageList?.isNotEmpty == true) { msgSeqno = msgs.last.msgSeqno;
msgSeqno = messageList!.last.msgSeqno; if (msgs.length == 1 &&
if (messageList.length == 1 && msgs.last.msgType == 18 &&
messageList.last.msgType == 18 && msgs.last.msgSource == 18) {
messageList.last.msgSource == 18) {
// debugPrint(messageList.last); // debugPrint(messageList.last);
// debugPrint(messageList.last.content); // debugPrint(messageList.last.content);
//{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]} //{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]}
} else { } else {
ackSessionMsg(messageList.last.msgSeqno); ackSessionMsg(msgs.last.msgSeqno.toInt());
}
if (response.response.eInfos != null) {
eInfos ??= [];
eInfos!.addAll(response.response.eInfos!);
} }
eInfos ??= <EmotionInfo>[];
eInfos!.addAll(response.response.eInfos);
} }
return false; return false;
} }
// 消息标记已读 // 消息标记已读
Future<void> ackSessionMsg(int? msgSeqno) async { Future<void> ackSessionMsg(int msgSeqno) async {
var res = await MsgHttp.ackSessionMsg( var res = await MsgHttp.ackSessionMsg(
talkerId: talkerId, talkerId: talkerId,
ackSeqno: msgSeqno, ackSeqno: msgSeqno,
@@ -79,37 +82,24 @@ class WhisperDetailController
int? index, int? index,
}) async { }) async {
feedBack(); feedBack();
SmartDialog.dismiss();
if (ownerMid == 0) { if (ownerMid == 0) {
SmartDialog.dismiss();
SmartDialog.showToast('请先登录'); SmartDialog.showToast('请先登录');
return; return;
} }
if (mid == null) { var result = await ImGrpc.sendMsg(
SmartDialog.dismiss();
SmartDialog.showToast('这里不能发');
return;
}
if (picMsg == null && message == '') {
SmartDialog.dismiss();
SmartDialog.showToast('请输入内容');
return;
}
var result = await MsgHttp.sendMsg(
senderUid: ownerMid, senderUid: ownerMid,
receiverId: int.parse(mid!), receiverId: mid!,
content: msgType == 5 content:
? message msgType == 5 ? message : jsonEncode(picMsg ?? {"content": message}),
: jsonEncode( msgType: MsgType.values[msgType ?? (picMsg != null ? 2 : 1)],
picMsg ?? {"content": message},
),
msgType: msgType ?? (picMsg != null ? 2 : 1),
); );
SmartDialog.dismiss(); SmartDialog.dismiss();
if (result['status']) { if (result.isSuccess) {
if (msgType == 5) { if (msgType == 5) {
List<MessageItem> list = (loadingState.value as Success).response; loadingState
list[index!].msgStatus = 1; ..value.data![index!].msgStatus = 1
loadingState.refresh(); ..refresh();
SmartDialog.showToast('撤回成功'); SmartDialog.showToast('撤回成功');
} else { } else {
onRefresh(); onRefresh();
@@ -117,12 +107,12 @@ class WhisperDetailController
SmartDialog.showToast('发送成功'); SmartDialog.showToast('发送成功');
} }
} else { } else {
SmartDialog.showToast(result['msg']); result.toast();
} }
} }
@override @override
List<MessageItem>? getDataList(SessionMsgDataModel response) { List<Msg>? getDataList(RspSessionMsg response) {
if (response.hasMore == 0) { if (response.hasMore == 0) {
isEnd = true; isEnd = true;
} }
@@ -138,10 +128,10 @@ class WhisperDetailController
} }
@override @override
Future<LoadingState<SessionMsgDataModel>> customGetData() => Future<LoadingState<RspSessionMsg>> customGetData() =>
MsgHttp.sessionMsg( ImGrpc.syncFetchSessionMsgs(
talkerId: talkerId, talkerId: talkerId,
beginSeqno: msgSeqno != null ? 0 : null, beginSeqno: msgSeqno != null ? Int64.ZERO : null,
endSeqno: msgSeqno, endSeqno: msgSeqno,
); );
} }

View File

@@ -3,10 +3,10 @@ import 'dart:async';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart' show Msg;
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/http/msg.dart';
import 'package:PiliPlus/models/common/publish_panel_type.dart'; import 'package:PiliPlus/models/common/publish_panel_type.dart';
import 'package:PiliPlus/models/msg/session.dart';
import 'package:PiliPlus/pages/common/common_publish_page.dart'; import 'package:PiliPlus/pages/common/common_publish_page.dart';
import 'package:PiliPlus/pages/emote/view.dart'; import 'package:PiliPlus/pages/emote/view.dart';
import 'package:PiliPlus/pages/whisper_detail/controller.dart'; import 'package:PiliPlus/pages/whisper_detail/controller.dart';
@@ -110,15 +110,17 @@ class _WhisperDetailPageState
_buildBody(_whisperDetailController.loadingState.value)), _buildBody(_whisperDetailController.loadingState.value)),
), ),
), ),
_buildInputView(theme), if (_whisperDetailController.mid != null) ...[
buildPanelContainer(theme.colorScheme.onInverseSurface), _buildInputView(theme),
buildPanelContainer(theme.colorScheme.onInverseSurface),
],
], ],
), ),
), ),
); );
} }
Widget _buildBody(LoadingState<List<MessageItem>?> loadingState) { Widget _buildBody(LoadingState<List<Msg>?> loadingState) {
return switch (loadingState) { return switch (loadingState) {
Loading() => loadingWidget, Loading() => loadingWidget,
Success() => loadingState.response?.isNotEmpty == true Success() => loadingState.response?.isNotEmpty == true

File diff suppressed because it is too large Load Diff