diff --git a/lib/grpc/dm.dart b/lib/grpc/dm.dart new file mode 100644 index 000000000..102e8b9dc --- /dev/null +++ b/lib/grpc/dm.dart @@ -0,0 +1,27 @@ +import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; +import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:fixnum/fixnum.dart'; + +class DmGrpc { + static Future> dmSegMobile({ + required int cid, + required int segmentIndex, + int type = 1, + }) async { + final res = await GrpcRepo.request( + GrpcUrl.dmSegMobile, + DmSegMobileReq( + oid: Int64(cid), + segmentIndex: Int64(segmentIndex), + type: type, + ), + DmSegMobileReply.fromBuffer, + ); + if (res['status']) { + return LoadingState.success(res['data']); + } else { + return const Error(''); + } + } +} diff --git a/lib/grpc/dyn.dart b/lib/grpc/dyn.dart new file mode 100644 index 000000000..4ed6e3166 --- /dev/null +++ b/lib/grpc/dyn.dart @@ -0,0 +1,29 @@ +import 'package:PiliPlus/grpc/bilibili/app/dynamic/v1.pb.dart'; +import 'package:PiliPlus/grpc/grpc_repo.dart'; + +class DynGrpc { + // static Future dynSpace({ + // required int uid, + // required int page, + // }) { + // return _request( + // GrpcUrl.dynSpace, + // DynSpaceReq( + // hostUid: Int64(uid), + // localTime: 8, + // page: Int64(page), + // from: 'space', + // ), + // DynSpaceRsp.fromBuffer, + // ); + // } + + static Future dynRed() { + return GrpcRepo.request( + GrpcUrl.dynRed, + DynRedReq(tabOffset: [TabOffset(tab: 1)]), + DynRedReply.fromBuffer, + onSuccess: (response) => response.dynRedItem.count.toInt(), + ); + } +} diff --git a/lib/grpc/grpc_repo.dart b/lib/grpc/grpc_repo.dart index 4cdcc4e43..c884f0e9e 100644 --- a/lib/grpc/grpc_repo.dart +++ b/lib/grpc/grpc_repo.dart @@ -2,20 +2,12 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/grpc/bilibili/app/dynamic/v1.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/app/dynamic/v2.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.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/fawkes.pb.dart'; import 'package:PiliPlus/grpc/bilibili/metadata/locale.pb.dart'; import 'package:PiliPlus/grpc/bilibili/metadata/network.pb.dart' as network; import 'package:PiliPlus/grpc/bilibili/metadata/restriction.pb.dart'; -import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart'; import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/utils/login_utils.dart'; @@ -24,8 +16,7 @@ import 'package:PiliPlus/utils/utils.dart'; import 'package:archive/archive.dart'; import 'package:dio/dio.dart'; import 'package:fixnum/fixnum.dart'; -import 'package:protobuf/protobuf.dart' show GeneratedMessage, PbMap; -import 'package:uuid/uuid.dart'; +import 'package:protobuf/protobuf.dart' show GeneratedMessage; class GrpcUrl { // static const playerOnline = @@ -56,7 +47,12 @@ class GrpcUrl { static const sendMsg = '$im/SendMsg'; static const shareList = '$im/ShareList'; static const sessionMain = '$im2/SessionMain'; + static const sessionSecondary = '$im2/SessionSecondary'; static const clearUnread = '$im2/ClearUnread'; + static const sessionUpdate = '$im2/SessionUpdate'; + static const pinSession = '$im2/PinSession'; + static const unpinSession = '$im2/UnpinSession'; + static const deleteSessionList = '$im2/DeleteSessionList'; } class GrpcRepo { @@ -172,7 +168,7 @@ class GrpcRepo { } } - static Future> _request( + static Future> request( url, GeneratedMessage request, Function grpcParser, {Function? onSuccess}) async { final response = await Request().post(HttpString.appBaseUrl + url, @@ -231,194 +227,4 @@ class GrpcRepo { // return {'status': true, 'data': response.items}; // }); // } - - // static Future replyInfo({required int rpid}) { - // return _request( - // GrpcUrl.replyInfo, - // ReplyInfoReq(rpid: Int64(rpid)), - // ReplyInfoReply.fromBuffer, - // onSuccess: (response) => response.reply, - // ); - // } - - // static Future dynSpace({ - // required int uid, - // required int page, - // }) { - // return _request( - // GrpcUrl.dynSpace, - // DynSpaceReq( - // hostUid: Int64(uid), - // localTime: 8, - // page: Int64(page), - // from: 'space', - // ), - // DynSpaceRsp.fromBuffer, - // ); - // } - - static Future mainList({ - int type = 1, - required int oid, - required Mode mode, - required String? offset, - required Int64? cursorNext, - }) { - return _request( - GrpcUrl.mainList, - MainListReq( - oid: Int64(oid), - type: Int64(type), - rpid: Int64(0), - cursor: CursorReq( - mode: mode, - next: cursorNext, - ), - // pagination: FeedPagination(offset: offset ?? ''), - ), - MainListReply.fromBuffer, - ); - } - - static Future detailList({ - int type = 1, - required int oid, - required int root, - required int rpid, - required Mode mode, - required String? offset, - }) { - return _request( - GrpcUrl.detailList, - DetailListReq( - oid: Int64(oid), - type: Int64(type), - root: Int64(root), - rpid: Int64(rpid), - scene: DetailListScene.REPLY, - mode: mode, - pagination: FeedPagination(offset: offset ?? ''), - ), - DetailListReply.fromBuffer, - ); - } - - static Future dialogList({ - int type = 1, - required int oid, - required int root, - required int dialog, - required String? offset, - }) { - return _request( - GrpcUrl.dialogList, - DialogListReq( - oid: Int64(oid), - type: Int64(type), - root: Int64(root), - dialog: Int64(dialog), - pagination: FeedPagination(offset: offset ?? ''), - ), - DialogListReply.fromBuffer, - ); - } - - static Future dynRed() { - return _request( - GrpcUrl.dynRed, - DynRedReq(tabOffset: [TabOffset(tab: 1)]), - DynRedReply.fromBuffer, - onSuccess: (response) => response.dynRedItem.count.toInt(), - ); - } - - static Future dmSegMobile( - {required int cid, required int segmentIndex, int type = 1}) { - return _request( - GrpcUrl.dmSegMobile, - DmSegMobileReq( - oid: Int64(cid), - segmentIndex: Int64(segmentIndex), - type: type, - ), - DmSegMobileReply.fromBuffer, - ); - } - - static Future sendMsg({ - required int senderUid, - required int receiverId, - required String content, - MsgType msgType = MsgType.EN_MSG_TYPE_TEXT, - }) { - final devId = const Uuid().v4(); - return _request( - GrpcUrl.sendMsg, - ReqSendMsg( - msg: Msg( - senderUid: Int64(senderUid), - receiverType: 1, - receiverId: Int64(receiverId), - msgType: msgType.value, - content: content, - timestamp: Int64(DateTime.now().millisecondsSinceEpoch ~/ 1000), - msgStatus: 0, - newFaceVersion: 1, - ), - devId: devId, - ), - RspSendMsg.fromBuffer, - ); - } - - static Future shareList({int size = 10}) { - return _request( - GrpcUrl.shareList, - ReqShareList(size: size), - RspShareList.fromBuffer, - ); - } - - static Future sessionMain({PbMap? offset}) { - return _request( - GrpcUrl.sessionMain, - SessionMainReq( - paginationParams: PaginationParams(offsets: offset), - ), - SessionMainReply.fromBuffer, - ); - } - - static Future clearUnread({ - SessionPageType? pageType, - SessionId? sessionId, - }) { - return _request( - GrpcUrl.clearUnread, - ClearUnreadReq( - pageType: pageType, - sessionId: sessionId, - ), - ClearUnreadReply.fromBuffer, - ); - } - - static Future opusSpaceFlow({ - required int hostMid, - String? next, - required String filterType, - }) { - return _request( - GrpcUrl.opusSpaceFlow, - OpusSpaceFlowReq( - hostMid: Int64(hostMid), - pagination: Pagination( - pageSize: 20, - next: next, - ), - filterType: filterType, - ), - OpusSpaceFlowResp.fromBuffer, - ); - } } diff --git a/lib/grpc/im.dart b/lib/grpc/im.dart new file mode 100644 index 000000000..d61639816 --- /dev/null +++ b/lib/grpc/im.dart @@ -0,0 +1,146 @@ +import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; +import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart'; +import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart'; +import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:fixnum/fixnum.dart'; +import 'package:protobuf/protobuf.dart' show PbMap; +import 'package:uuid/uuid.dart'; + +class ImGrpc { + static Future sendMsg({ + required int senderUid, + required int receiverId, + required String content, + MsgType msgType = MsgType.EN_MSG_TYPE_TEXT, + }) { + final devId = const Uuid().v4(); + return GrpcRepo.request( + GrpcUrl.sendMsg, + ReqSendMsg( + msg: Msg( + senderUid: Int64(senderUid), + receiverType: 1, + receiverId: Int64(receiverId), + msgType: msgType.value, + content: content, + timestamp: Int64(DateTime.now().millisecondsSinceEpoch ~/ 1000), + msgStatus: 0, + newFaceVersion: 1, + ), + devId: devId, + ), + RspSendMsg.fromBuffer, + ); + } + + static Future shareList({int size = 10}) { + return GrpcRepo.request( + GrpcUrl.shareList, + ReqShareList(size: size), + RspShareList.fromBuffer, + ); + } + + static Future> sessionMain({ + PbMap? offset, + }) async { + final res = await GrpcRepo.request( + GrpcUrl.sessionMain, + SessionMainReq( + paginationParams: PaginationParams(offsets: offset), + ), + SessionMainReply.fromBuffer, + ); + if (res['status']) { + return LoadingState.success(res['data']); + } else { + return LoadingState.error(res['msg']); + } + } + + static Future> sessionSecondary({ + PbMap? offset, + SessionPageType? pageType, + }) async { + final res = await GrpcRepo.request( + GrpcUrl.sessionSecondary, + SessionSecondaryReq( + paginationParams: PaginationParams(offsets: offset), + pageType: pageType, + ), + SessionSecondaryReply.fromBuffer, + ); + if (res['status']) { + return LoadingState.success(res['data']); + } else { + return LoadingState.error(res['msg']); + } + } + + static Future clearUnread({ + SessionPageType? pageType, + SessionId? sessionId, + }) { + return GrpcRepo.request( + GrpcUrl.clearUnread, + ClearUnreadReq( + pageType: pageType, + sessionId: sessionId, + ), + ClearUnreadReply.fromBuffer, + ); + } + + static Future sessionUpdate({ + SessionPageType? pageType, + SessionId? sessionId, + }) { + return GrpcRepo.request( + GrpcUrl.sessionUpdate, + SessionUpdateReq( + pageType: pageType, + sessionId: sessionId, + ), + SessionUpdateReply.fromBuffer, + ); + } + + static Future pinSession({ + SessionId? sessionId, + Int64? topTimeMicros, + }) { + return GrpcRepo.request( + GrpcUrl.pinSession, + PinSessionReq( + sessionId: sessionId, + topTimeMicros: topTimeMicros, + ), + PinSessionReply.fromBuffer, + ); + } + + static Future unpinSession({ + SessionId? sessionId, + }) { + return GrpcRepo.request( + GrpcUrl.unpinSession, + UnPinSessionReq( + sessionId: sessionId, + ), + UnPinSessionReply.fromBuffer, + ); + } + + static Future deleteSessionList({ + SessionPageType? pageType, + }) { + return GrpcRepo.request( + GrpcUrl.deleteSessionList, + DeleteSessionListReq( + pageType: pageType, + ), + DeleteSessionListReply.fromBuffer, + ); + } +} diff --git a/lib/grpc/reply.dart b/lib/grpc/reply.dart new file mode 100644 index 000000000..c87be3ca5 --- /dev/null +++ b/lib/grpc/reply.dart @@ -0,0 +1,189 @@ +import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'; +import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart'; +import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/reply.dart'; +import 'package:fixnum/fixnum.dart'; + +class ReplyGrpc { + // static Future replyInfo({required int rpid}) { + // return _request( + // GrpcUrl.replyInfo, + // ReplyInfoReq(rpid: Int64(rpid)), + // ReplyInfoReply.fromBuffer, + // onSuccess: (response) => response.reply, + // ); + // } + + // ref BiliRoamingX + static bool needRemoveGrpc(ReplyInfo reply) { + if ((reply.content.urls.isNotEmpty && + reply.content.urls.values.any((url) { + return url.hasExtra() && + (url.extra.goodsCmControl == 1 || + url.extra.goodsItemId != 0 || + url.extra.goodsPrefetchedCache.isNotEmpty); + })) || + reply.content.message.contains(Constants.goodsUrlPrefix)) { + return true; + } + return false; + } + + static Future> mainList({ + int type = 1, + required int oid, + required Mode mode, + required String? offset, + required Int64? cursorNext, + required bool antiGoodsReply, + }) async { + dynamic res = await GrpcRepo.request( + GrpcUrl.mainList, + MainListReq( + oid: Int64(oid), + type: Int64(type), + rpid: Int64(0), + cursor: CursorReq( + mode: mode, + next: cursorNext, + ), + // pagination: FeedPagination(offset: offset ?? ''), + ), + MainListReply.fromBuffer, + ); + if (res['status']) { + MainListReply mainListReply = res['data']; + // keyword filter + if (ReplyHttp.replyRegExp.pattern.isNotEmpty) { + // upTop + if (mainListReply.hasUpTop() && + ReplyHttp.replyRegExp + .hasMatch(mainListReply.upTop.content.message)) { + mainListReply.clearUpTop(); + } + + // replies + if (mainListReply.replies.isNotEmpty) { + mainListReply.replies.removeWhere((item) { + bool hasMatch = + ReplyHttp.replyRegExp.hasMatch(item.content.message); + // remove subreplies + if (!hasMatch) { + if (item.replies.isNotEmpty) { + item.replies.removeWhere((item) => + ReplyHttp.replyRegExp.hasMatch(item.content.message)); + } + } + return hasMatch; + }); + } + } + + // antiGoodsReply + if (antiGoodsReply) { + // upTop + if (mainListReply.hasUpTop() && needRemoveGrpc(mainListReply.upTop)) { + mainListReply.clearUpTop(); + } + + // replies + if (mainListReply.replies.isNotEmpty) { + mainListReply.replies.removeWhere((item) { + bool hasMatch = needRemoveGrpc(item); + // remove subreplies + if (!hasMatch) { + if (item.replies.isNotEmpty) { + item.replies.removeWhere(needRemoveGrpc); + } + } + return hasMatch; + }); + } + } + return LoadingState.success(mainListReply); + } else { + return LoadingState.error(res['msg']); + } + } + + static Future> detailList({ + int type = 1, + required int oid, + required int root, + required int rpid, + required Mode mode, + required String? offset, + required bool antiGoodsReply, + }) async { + dynamic res = await GrpcRepo.request( + GrpcUrl.detailList, + DetailListReq( + oid: Int64(oid), + type: Int64(type), + root: Int64(root), + rpid: Int64(rpid), + scene: DetailListScene.REPLY, + mode: mode, + pagination: FeedPagination(offset: offset ?? ''), + ), + DetailListReply.fromBuffer, + ); + if (res['status']) { + DetailListReply detailListReply = res['data']; + if (ReplyHttp.replyRegExp.pattern.isNotEmpty) { + if (detailListReply.root.replies.isNotEmpty) { + detailListReply.root.replies.removeWhere( + (item) => ReplyHttp.replyRegExp.hasMatch(item.content.message)); + } + } + if (antiGoodsReply) { + if (detailListReply.root.replies.isNotEmpty) { + detailListReply.root.replies.removeWhere(needRemoveGrpc); + } + } + return LoadingState.success(detailListReply); + } else { + return LoadingState.error(res['msg']); + } + } + + static Future> dialogList({ + int type = 1, + required int oid, + required int root, + required int dialog, + required String? offset, + required bool antiGoodsReply, + }) async { + dynamic res = await GrpcRepo.request( + GrpcUrl.dialogList, + DialogListReq( + oid: Int64(oid), + type: Int64(type), + root: Int64(root), + dialog: Int64(dialog), + pagination: FeedPagination(offset: offset ?? ''), + ), + DialogListReply.fromBuffer, + ); + if (res['status']) { + DialogListReply dialogListReply = res['data']; + if (ReplyHttp.replyRegExp.pattern.isNotEmpty) { + if (dialogListReply.replies.isNotEmpty) { + dialogListReply.replies.removeWhere( + (item) => ReplyHttp.replyRegExp.hasMatch(item.content.message)); + } + } + if (antiGoodsReply) { + if (dialogListReply.replies.isNotEmpty) { + dialogListReply.replies.removeWhere(needRemoveGrpc); + } + } + return LoadingState.success(dialogListReply); + } else { + return LoadingState.error(res['msg']); + } + } +} diff --git a/lib/grpc/space.dart b/lib/grpc/space.dart new file mode 100644 index 000000000..5b1b87f7b --- /dev/null +++ b/lib/grpc/space.dart @@ -0,0 +1,31 @@ +import 'package:PiliPlus/grpc/bilibili/app/dynamic/v2.pb.dart'; +import 'package:PiliPlus/grpc/bilibili/pagination.pb.dart'; +import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:fixnum/fixnum.dart'; + +class SpaceGrpc { + static Future> opusSpaceFlow({ + required int hostMid, + String? next, + required String filterType, + }) async { + final res = await GrpcRepo.request( + GrpcUrl.opusSpaceFlow, + OpusSpaceFlowReq( + hostMid: Int64(hostMid), + pagination: Pagination( + pageSize: 20, + next: next, + ), + filterType: filterType, + ), + OpusSpaceFlowResp.fromBuffer, + ); + if (res['status']) { + return LoadingState.success(res['data']); + } else { + return LoadingState.error(res['msg']); + } + } +} diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart index d1eff0f50..fbaa7779c 100644 --- a/lib/http/danmaku.dart +++ b/lib/http/danmaku.dart @@ -1,37 +1,9 @@ -import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; -import 'package:PiliPlus/grpc/grpc_repo.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/init.dart'; -import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:dio/dio.dart'; class DanmakuHttp { - // 获取视频弹幕 - static Future> queryDanmaku({ - required int cid, - required int segmentIndex, - int queryCount = 1, - }) async { - // 构建参数对象 - final response = - await GrpcRepo.dmSegMobile(cid: cid, segmentIndex: segmentIndex); - if (!response['status']) { - if (queryCount >= 3) { - return const Error(''); - } else { - await Future.delayed(const Duration(seconds: 1)); - return await queryDanmaku( - cid: cid, - segmentIndex: segmentIndex, - queryCount: ++queryCount, - ); - } - } - DmSegMobileReply data = response['data']; - return LoadingState.success(data); - } - static Future shootDanmaku({ int type = 1, //弹幕类选择(1:视频弹幕 2:漫画弹幕) required int oid, // 视频cid diff --git a/lib/http/member.dart b/lib/http/member.dart index 2e521b48b..4c660fcaa 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -2,9 +2,6 @@ import 'dart:convert'; import 'dart:io'; import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/grpc/bilibili/app/dynamic/v2.pb.dart' - show OpusSpaceFlowResp; -import 'package:PiliPlus/grpc/grpc_repo.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/init.dart'; @@ -52,18 +49,6 @@ class MemberHttp { }; } - // static Future spaceDynamic({ - // required int mid, - // required int page, - // }) async { - // dynamic result = await GrpcRepo.dynSpace(uid: mid, page: page); - // if (result['status']) { - // return LoadingState.success(result['data']); - // } else { - // return LoadingState.error(result['msg']); - // } - // } - static Future> spaceArticle({ required int mid, required int page, @@ -848,23 +833,6 @@ class MemberHttp { } } - static Future> opusSpaceFlow({ - required int hostMid, - String? next, - required String filterType, - }) async { - var res = await GrpcRepo.opusSpaceFlow( - hostMid: hostMid, - next: next, - filterType: filterType, - ); - if (res['status']) { - return LoadingState.success(res['data']); - } else { - return LoadingState.error(res['msg']); - } - } - static Future> spaceOpus({ required int hostMid, required int page, diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 0b3408705..5b8e56246 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -1,7 +1,5 @@ import 'dart:math'; -import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; -import 'package:PiliPlus/grpc/grpc_repo.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/init.dart'; @@ -17,7 +15,6 @@ import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/wbi_sign.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:protobuf/protobuf.dart' show PbMap; import 'package:uuid/uuid.dart'; class MsgHttp { @@ -433,16 +430,6 @@ class MsgHttp { } } - static Future> sessionMain( - {PbMap? offset}) async { - final res = await GrpcRepo.sessionMain(offset: offset); - if (res['status']) { - return LoadingState.success(res['data']); - } else { - return LoadingState.error(res['msg']); - } - } - static Future accountList(uids) async { var res = await Request().get(Api.sessionAccountList, queryParameters: { 'uids': uids, diff --git a/lib/http/reply.dart b/lib/http/reply.dart index dc1521a58..004502e17 100644 --- a/lib/http/reply.dart +++ b/lib/http/reply.dart @@ -1,6 +1,4 @@ import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'; -import 'package:PiliPlus/grpc/grpc_repo.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -11,7 +9,6 @@ import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:dio/dio.dart'; -import 'package:fixnum/fixnum.dart'; class ReplyHttp { static Options get _options => @@ -124,89 +121,6 @@ class ReplyHttp { } } - static Future> mainList({ - int type = 1, - required int oid, - required Mode mode, - required String? offset, - required Int64? cursorNext, - required bool antiGoodsReply, - }) async { - dynamic res = await GrpcRepo.mainList( - type: type, - oid: oid, - mode: mode, - offset: offset, - cursorNext: cursorNext, - ); - if (res['status']) { - MainListReply mainListReply = res['data']; - // keyword filter - if (replyRegExp.pattern.isNotEmpty) { - // upTop - if (mainListReply.hasUpTop() && - replyRegExp.hasMatch(mainListReply.upTop.content.message)) { - mainListReply.clearUpTop(); - } - - // replies - if (mainListReply.replies.isNotEmpty) { - mainListReply.replies.removeWhere((item) { - bool hasMatch = replyRegExp.hasMatch(item.content.message); - // remove subreplies - if (hasMatch.not) { - if (item.replies.isNotEmpty) { - item.replies.removeWhere( - (item) => replyRegExp.hasMatch(item.content.message)); - } - } - return hasMatch; - }); - } - } - - // antiGoodsReply - if (antiGoodsReply) { - // upTop - if (mainListReply.hasUpTop() && needRemoveGrpc(mainListReply.upTop)) { - mainListReply.clearUpTop(); - } - - // replies - if (mainListReply.replies.isNotEmpty) { - mainListReply.replies.removeWhere((item) { - bool hasMatch = needRemoveGrpc(item); - // remove subreplies - if (hasMatch.not) { - if (item.replies.isNotEmpty) { - item.replies.removeWhere(needRemoveGrpc); - } - } - return hasMatch; - }); - } - } - return LoadingState.success(mainListReply); - } else { - return LoadingState.error(res['msg']); - } - } - - // ref BiliRoamingX - static bool needRemoveGrpc(ReplyInfo reply) { - if ((reply.content.urls.isNotEmpty && - reply.content.urls.values.any((url) { - return url.hasExtra() && - (url.extra.goodsCmControl == 1 || - url.extra.goodsItemId != 0 || - url.extra.goodsPrefetchedCache.isNotEmpty); - })) || - reply.content.message.contains(Constants.goodsUrlPrefix)) { - return true; - } - return false; - } - static bool needRemove(ReplyItemModel reply) { try { if ((reply.content?.jumpUrl?.isNotEmpty == true && @@ -269,76 +183,6 @@ class ReplyHttp { } } - static Future detailList({ - int type = 1, - required int oid, - required int root, - required int rpid, - required Mode mode, - required String? offset, - required bool antiGoodsReply, - }) async { - dynamic res = await GrpcRepo.detailList( - type: type, - oid: oid, - root: root, - rpid: rpid, - mode: mode, - offset: offset, - ); - if (res['status']) { - DetailListReply detailListReply = res['data']; - if (replyRegExp.pattern.isNotEmpty) { - if (detailListReply.root.replies.isNotEmpty) { - detailListReply.root.replies.removeWhere( - (item) => replyRegExp.hasMatch(item.content.message)); - } - } - if (antiGoodsReply) { - if (detailListReply.root.replies.isNotEmpty) { - detailListReply.root.replies.removeWhere(needRemoveGrpc); - } - } - return LoadingState.success(detailListReply); - } else { - return LoadingState.error(res['msg']); - } - } - - static Future dialogList({ - int type = 1, - required int oid, - required int root, - required int dialog, - required String? offset, - required bool antiGoodsReply, - }) async { - dynamic res = await GrpcRepo.dialogList( - type: type, - oid: oid, - root: root, - dialog: dialog, - offset: offset, - ); - if (res['status']) { - DialogListReply dialogListReply = res['data']; - if (replyRegExp.pattern.isNotEmpty) { - if (dialogListReply.replies.isNotEmpty) { - dialogListReply.replies.removeWhere( - (item) => replyRegExp.hasMatch(item.content.message)); - } - } - if (antiGoodsReply) { - if (dialogListReply.replies.isNotEmpty) { - dialogListReply.replies.removeWhere(needRemoveGrpc); - } - } - return LoadingState.success(dialogListReply); - } else { - return LoadingState.error(res['msg']); - } - } - static Future hateReply({ required int type, required int action, diff --git a/lib/http/video.dart b/lib/http/video.dart index d9a1b52ac..4f91e394d 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -172,22 +172,6 @@ class VideoHttp { } } - // static Future hotVideoListGrpc({required int idx}) async { - // dynamic res = await GrpcRepo.popular(idx); - // if (res['status']) { - // List list = []; - // Set blackMids = GStorage.blackMids; - // for (card.Card item in res['data']) { - // if (!blackMids.contains(item.smallCoverV5.up.id.toInt())) { - // list.add(item); - // } - // } - // return LoadingState.success(list); - // } else { - // return LoadingState.error(res['msg']); - // } - // } - // 视频流 static Future videoUrl({ int? avid, diff --git a/lib/pages/article/controller.dart b/lib/pages/article/controller.dart index 357e63274..a05512e8b 100644 --- a/lib/pages/article/controller.dart +++ b/lib/pages/article/controller.dart @@ -1,8 +1,8 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show MainListReply, ReplyInfo; +import 'package:PiliPlus/grpc/reply.dart'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/models/dynamics/article_content_model.dart' @@ -172,7 +172,7 @@ class ArticleController extends ReplyController { @override Future> customGetData() { - return ReplyHttp.mainList( + return ReplyGrpc.mainList( type: commentType, oid: commentId, mode: mode.value, diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index 03e6ba86b..650c7bf20 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -1,5 +1,5 @@ import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; -import 'package:PiliPlus/http/danmaku.dart'; +import 'package:PiliPlus/grpc/dm.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; class PlDanmakuController { @@ -31,7 +31,7 @@ class PlDanmakuController { return; } requestedSeg.add(segmentIndex); - final result = await DanmakuHttp.queryDanmaku( + final result = await DmGrpc.dmSegMobile( cid: cid, segmentIndex: segmentIndex + 1, ); diff --git a/lib/pages/dynamics_detail/controller.dart b/lib/pages/dynamics_detail/controller.dart index 8faef1ddf..531c96d96 100644 --- a/lib/pages/dynamics_detail/controller.dart +++ b/lib/pages/dynamics_detail/controller.dart @@ -1,8 +1,8 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show MainListReply, ReplyInfo; +import 'package:PiliPlus/grpc/reply.dart'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/models/common/reply/reply_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; @@ -54,7 +54,7 @@ class DynamicDetailController extends ReplyController { } @override - Future> customGetData() => ReplyHttp.mainList( + Future> customGetData() => ReplyGrpc.mainList( type: type, oid: oid, mode: mode.value, diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index ffa5dab66..0e188a108 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -35,23 +35,20 @@ class _DynTopicPageState extends State { Obx(() { if (_controller.topicSortByConf.value?.allSortBy?.isNotEmpty == true) { - return Padding( - padding: const EdgeInsets.only(right: 16), - child: PopupMenuButton( - initialValue: _controller.sortBy, - itemBuilder: (context) { - return _controller.topicSortByConf.value!.allSortBy! - .map((e) { - return PopupMenuItem( - value: e.sortBy, - child: Text(e.sortName!), - onTap: () { - _controller.onSort(e.sortBy!); - }, - ); - }).toList(); - }, - ), + return PopupMenuButton( + initialValue: _controller.sortBy, + itemBuilder: (context) { + return _controller.topicSortByConf.value!.allSortBy! + .map((e) { + return PopupMenuItem( + value: e.sortBy, + child: Text(e.sortName!), + onTap: () { + _controller.onSort(e.sortBy!); + }, + ); + }).toList(); + }, ); } return const SizedBox.shrink(); diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index 81c05a027..ed40753ed 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/grpc/dyn.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart'; @@ -175,7 +175,7 @@ class MainController extends GetxController { if (!isLogin.value || dynIndex == -1) { return; } - GrpcRepo.dynRed().then((res) { + DynGrpc.dynRed().then((res) { if (res['status']) { setCount(res['data']); } diff --git a/lib/pages/video/reply/controller.dart b/lib/pages/video/reply/controller.dart index e18a2680d..63952e523 100644 --- a/lib/pages/video/reply/controller.dart +++ b/lib/pages/video/reply/controller.dart @@ -1,7 +1,7 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show MainListReply, ReplyInfo; +import 'package:PiliPlus/grpc/reply.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; import 'package:PiliPlus/utils/id_utils.dart'; import 'package:flutter/material.dart'; @@ -41,7 +41,7 @@ class VideoReplyController extends ReplyController } @override - Future> customGetData() => ReplyHttp.mainList( + Future> customGetData() => ReplyGrpc.mainList( oid: aid, mode: mode.value, cursorNext: cursorNext, diff --git a/lib/pages/video/reply_reply/controller.dart b/lib/pages/video/reply_reply/controller.dart index 7a4f882b9..a0aaca9af 100644 --- a/lib/pages/video/reply_reply/controller.dart +++ b/lib/pages/video/reply_reply/controller.dart @@ -1,7 +1,7 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show ReplyInfo, DetailListReply, Mode; +import 'package:PiliPlus/grpc/reply.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/models/common/reply/reply_type.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; import 'package:PiliPlus/utils/id_utils.dart'; @@ -107,7 +107,7 @@ class VideoReplyReplyController extends ReplyController @override Future customGetData() => isDialogue - ? ReplyHttp.dialogList( + ? ReplyGrpc.dialogList( type: replyType.index, oid: oid, root: rpid, @@ -115,7 +115,7 @@ class VideoReplyReplyController extends ReplyController offset: paginationReply?.nextOffset, antiGoodsReply: antiGoodsReply, ) - : ReplyHttp.detailList( + : ReplyGrpc.detailList( type: replyType.index, oid: oid, root: rpid, diff --git a/lib/pages/whisper/controller.dart b/lib/pages/whisper/controller.dart index f899117c6..3804f19a3 100644 --- a/lib/pages/whisper/controller.dart +++ b/lib/pages/whisper/controller.dart @@ -1,6 +1,6 @@ import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' - show SessionMainReply, Session, Offset, SessionPageType; -import 'package:PiliPlus/grpc/grpc_repo.dart'; + show Offset, Session, SessionId, SessionMainReply, SessionPageType; +import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/models/msg/msgfeed_unread.dart'; @@ -74,7 +74,7 @@ class WhisperController @override Future> customGetData() => - MsgHttp.sessionMain(offset: offset); + ImGrpc.sessionMain(offset: offset); @override Future onRefresh() { @@ -94,13 +94,13 @@ class WhisperController } } - Future onSetTop(int index, bool isTop, int? talkerId) async { - var res = await MsgHttp.setTop( - talkerId: talkerId, - opType: isTop ? 1 : 0, - ); + Future onSetTop(int index, bool isTop, SessionId sessionId) async { + var res = isTop + ? await ImGrpc.unpinSession(sessionId: sessionId) + : await ImGrpc.pinSession(sessionId: sessionId); + if (res['status']) { - List list = (loadingState.value as Success).response; + List list = loadingState.value.data!; list[index].isPinned = isTop ? false : true; if (!isTop) { list.insert(0, list.removeAt(index)); @@ -121,7 +121,7 @@ class WhisperController } Future onClearUnread() async { - final res = await GrpcRepo.clearUnread( + final res = await ImGrpc.clearUnread( pageType: SessionPageType.SESSION_PAGE_TYPE_HOME); if (res['status']) { if (loadingState.value is Success) { diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index 6a63b0fcc..0827e9653 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -50,7 +50,13 @@ class _WhisperPageState extends State { physics: const AlwaysScrollableScrollPhysics(), slivers: [ _buildTopItems, - Obx(() => _buildBody(_whisperController.loadingState.value)), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 100, + ), + sliver: + Obx(() => _buildBody(_whisperController.loadingState.value)), + ), ], ), ), @@ -66,31 +72,26 @@ class _WhisperPageState extends State { }, ), Success() => loadingState.response?.isNotEmpty == true - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 100, - ), - sliver: SliverList.separated( - itemCount: loadingState.response!.length, - itemBuilder: (context, index) { - if (index == loadingState.response!.length - 1) { - _whisperController.onLoadMore(); - } - return WhisperSessionItem( - item: loadingState.response![index], - onSetTop: (isTop, talkerId) => - _whisperController.onSetTop(index, isTop, talkerId), - onRemove: (talkerId) => - _whisperController.onRemove(index, talkerId), - onTap: () => _whisperController.onTap(index), - ); - }, - separatorBuilder: (context, index) => Divider( - indent: 72, - endIndent: 20, - height: 1, - color: Colors.grey.withOpacity(0.1), - ), + ? SliverList.separated( + itemCount: loadingState.response!.length, + itemBuilder: (context, index) { + if (index == loadingState.response!.length - 1) { + _whisperController.onLoadMore(); + } + return WhisperSessionItem( + item: loadingState.response![index], + onSetTop: (isTop, id) => + _whisperController.onSetTop(index, isTop, id), + onRemove: (talkerId) => + _whisperController.onRemove(index, talkerId), + onTap: () => _whisperController.onTap(index), + ); + }, + separatorBuilder: (context, index) => Divider( + indent: 72, + endIndent: 20, + height: 1, + color: Colors.grey.withOpacity(0.1), ), ) : HttpError( diff --git a/lib/pages/whisper/widgets/item.dart b/lib/pages/whisper/widgets/item.dart index 8227893b4..24c0f56d8 100644 --- a/lib/pages/whisper/widgets/item.dart +++ b/lib/pages/whisper/widgets/item.dart @@ -3,11 +3,13 @@ import 'dart:convert'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' - show Session, UnreadStyle; + show Session, SessionId, SessionPageType, SessionType, UnreadStyle; import 'package:PiliPlus/models/common/badge_type.dart'; +import 'package:PiliPlus/pages/whisper_secondary/view.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; class WhisperSessionItem extends StatelessWidget { @@ -20,7 +22,7 @@ class WhisperSessionItem extends StatelessWidget { }); final Session item; - final Function(bool isTop, int? talkerId) onSetTop; + final Function(bool isTop, SessionId id) onSetTop; final ValueChanged onRemove; final VoidCallback onTap; @@ -49,27 +51,25 @@ class WhisperSessionItem extends StatelessWidget { dense: true, onTap: () { Get.back(); - onSetTop( - item.isPinned, - item.id.privateId.talkerUid.toInt(), - ); + onSetTop(item.isPinned, item.id); }, title: Text( item.isPinned ? '移除置顶' : '置顶', style: const TextStyle(fontSize: 14), ), ), - ListTile( - dense: true, - onTap: () { - Get.back(); - onRemove(item.id.privateId.talkerUid.toInt()); - }, - title: const Text( - '删除', - style: TextStyle(fontSize: 14), + if (item.id.privateId.hasTalkerUid()) + ListTile( + dense: true, + onTap: () { + Get.back(); + onRemove(item.id.privateId.talkerUid.toInt()); + }, + title: const Text( + '删除', + style: TextStyle(fontSize: 14), + ), ), - ), ], ), ); @@ -78,17 +78,54 @@ class WhisperSessionItem extends StatelessWidget { }, onTap: () { onTap(); - Get.toNamed( - '/whisperDetail', - parameters: { - 'talkerId': item.id.privateId.talkerUid.toString(), - 'name': item.sessionInfo.sessionName, - 'face': item.sessionInfo.avatar.fallbackLayers.layers.first.resource - .resImage.imageSrc.remote.url, - if (item.sessionInfo.avatar.hasMid()) - 'mid': item.sessionInfo.avatar.mid.toString(), - }, - ); + if (item.id.privateId.hasTalkerUid()) { + Get.toNamed( + '/whisperDetail', + parameters: { + 'talkerId': item.id.privateId.talkerUid.toString(), + 'name': item.sessionInfo.sessionName, + 'face': item.sessionInfo.avatar.fallbackLayers.layers.first + .resource.resImage.imageSrc.remote.url, + if (item.sessionInfo.avatar.hasMid()) + 'mid': item.sessionInfo.avatar.mid.toString(), + }, + ); + return; + } + + if (item.id.foldId.hasType()) { + SessionPageType? sessionPageType = switch (item.id.foldId.type) { + SessionType.SESSION_TYPE_UNKNOWN => + SessionPageType.SESSION_PAGE_TYPE_UNKNOWN, + SessionType.SESSION_TYPE_GROUP => + SessionPageType.SESSION_PAGE_TYPE_GROUP, + SessionType.SESSION_TYPE_GROUP_FOLD => + SessionPageType.SESSION_PAGE_TYPE_GROUP, + SessionType.SESSION_TYPE_UNFOLLOWED => + SessionPageType.SESSION_PAGE_TYPE_UNFOLLOWED, + SessionType.SESSION_TYPE_STRANGER => + SessionPageType.SESSION_PAGE_TYPE_STRANGER, + SessionType.SESSION_TYPE_DUSTBIN => + SessionPageType.SESSION_PAGE_TYPE_DUSTBIN, + SessionType.SESSION_TYPE_CUSTOMER_FOLD => + SessionPageType.SESSION_PAGE_TYPE_CUSTOMER, + SessionType.SESSION_TYPE_AI_FOLD => + SessionPageType.SESSION_PAGE_TYPE_AI, + SessionType.SESSION_TYPE_CUSTOMER_ACCOUNT => + SessionPageType.SESSION_PAGE_TYPE_CUSTOMER, + _ => null, + }; + if (sessionPageType != null) { + Get.to( + WhisperSecPage( + name: item.sessionInfo.sessionName, + sessionPageType: sessionPageType, + ), + ); + } else { + SmartDialog.showToast(item.id.foldId.type.name); + } + } }, leading: Builder( builder: (context) { diff --git a/lib/pages/whisper_secondary/controller.dart b/lib/pages/whisper_secondary/controller.dart new file mode 100644 index 000000000..b413be189 --- /dev/null +++ b/lib/pages/whisper_secondary/controller.dart @@ -0,0 +1,114 @@ +import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' + show Offset, Session, SessionId, SessionPageType, SessionSecondaryReply; +import 'package:PiliPlus/grpc/im.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/msg.dart'; +import 'package:PiliPlus/pages/common/common_list_controller.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:protobuf/protobuf.dart' show PbMap; + +class WhisperSecController + extends CommonListController { + WhisperSecController({ + required this.sessionPageType, + }); + + PbMap? offset; + final SessionPageType sessionPageType; + + @override + void onInit() { + super.onInit(); + queryData(); + } + + @override + Future onRefresh() { + offset = null; + return super.onRefresh(); + } + + @override + List? getDataList(SessionSecondaryReply response) { + if (response.paginationParams.hasMore == false) { + isEnd = true; + } + return response.sessions; + } + + @override + Future> customGetData() => + ImGrpc.sessionSecondary( + offset: offset, + pageType: sessionPageType, + ); + + Future onRemove(int index, int? talkerId) async { + var res = await MsgHttp.removeMsg(talkerId); + if (res['status']) { + loadingState + ..value.data!.removeAt(index) + ..refresh(); + SmartDialog.showToast('删除成功'); + } else { + SmartDialog.showToast(res['msg']); + } + } + + Future onSetTop(int index, bool isTop, SessionId sessionId) async { + var res = isTop + ? await ImGrpc.unpinSession(sessionId: sessionId) + : await ImGrpc.pinSession(sessionId: sessionId); + + if (res['status']) { + List list = loadingState.value.data!; + list[index].isPinned = isTop ? false : true; + if (!isTop) { + list.insert(0, list.removeAt(index)); + } + loadingState.refresh(); + SmartDialog.showToast('${isTop ? '移除' : ''}置顶成功'); + } else { + SmartDialog.showToast(res['msg']); + } + } + + void onTap(int index) { + Session item = loadingState.value.data![index]; + if (item.hasUnread()) { + item.clearUnread(); + loadingState.refresh(); + } + } + + Future onClearUnread() async { + final res = await ImGrpc.clearUnread( + pageType: SessionPageType.SESSION_PAGE_TYPE_UNFOLLOWED); + if (res['status']) { + if (loadingState.value is Success) { + List? list = loadingState.value.data; + if (list?.isNotEmpty == true) { + for (var item in list!) { + if (item.hasUnread()) { + item.clearUnread(); + } + } + loadingState.refresh(); + } + } + SmartDialog.showToast('已标记为已读'); + } else { + SmartDialog.showToast(res['msg']); + } + } + + Future onDeleteList() async { + var res = await ImGrpc.deleteSessionList( + pageType: SessionPageType.SESSION_PAGE_TYPE_UNFOLLOWED); + if (res['status']) { + loadingState.value = LoadingState.success(null); + } else { + SmartDialog.showToast(res['msg']); + } + } +} diff --git a/lib/pages/whisper_secondary/view.dart b/lib/pages/whisper_secondary/view.dart new file mode 100644 index 000000000..1e624be9c --- /dev/null +++ b/lib/pages/whisper_secondary/view.dart @@ -0,0 +1,139 @@ +import 'package:PiliPlus/common/skeleton/whisper_item.dart'; +import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; +import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/pages/whisper/widgets/item.dart'; +import 'package:PiliPlus/pages/whisper_secondary/controller.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class WhisperSecPage extends StatefulWidget { + const WhisperSecPage({ + super.key, + required this.name, + required this.sessionPageType, + }); + + final String name; + final SessionPageType sessionPageType; + + @override + State createState() => _WhisperSecPageState(); +} + +class _WhisperSecPageState extends State { + late final WhisperSecController _controller = Get.put( + WhisperSecController(sessionPageType: widget.sessionPageType), + tag: widget.sessionPageType.name, + ); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.name), + actions: [ + PopupMenuButton( + itemBuilder: (context) { + return [ + PopupMenuItem( + onTap: () { + showConfirmDialog( + context: context, + title: '一键已读', + content: '是否清除全部新消息提醒?', + onConfirm: _controller.onClearUnread, + ); + }, + child: const Row( + children: [ + Icon( + size: 17, + Icons.cleaning_services, + ), + Text(' 一键已读'), + ], + ), + ), + PopupMenuItem( + onTap: () { + showConfirmDialog( + context: context, + title: '清空列表', + content: '清空后所有消息将被删除,无法恢复', + onConfirm: _controller.onDeleteList, + ); + }, + child: const Row( + children: [ + Icon( + size: 19, + Icons.delete_forever_outlined, + ), + Text(' 清空列表'), + ], + ), + ), + ]; + }, + ), + ], + ), + body: refreshIndicator( + onRefresh: _controller.onRefresh, + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80), + sliver: Obx(() => _buildBody(_controller.loadingState.value)), + ) + ], + ), + ), + ); + } + + Widget _buildBody(LoadingState?> loadingState) { + return switch (loadingState) { + Loading() => SliverList.builder( + itemCount: 12, + itemBuilder: (context, index) { + return const WhisperItemSkeleton(); + }, + ), + Success() => loadingState.response?.isNotEmpty == true + ? SliverList.separated( + itemCount: loadingState.response!.length, + itemBuilder: (context, index) { + if (index == loadingState.response!.length - 1) { + _controller.onLoadMore(); + } + return WhisperSessionItem( + item: loadingState.response![index], + onSetTop: (isTop, talkerId) => + _controller.onSetTop(index, isTop, talkerId), + onRemove: (talkerId) => _controller.onRemove(index, talkerId), + onTap: () => _controller.onTap(index), + ); + }, + separatorBuilder: (context, index) => Divider( + indent: 72, + endIndent: 20, + height: 1, + color: Colors.grey.withOpacity(0.1), + ), + ) + : HttpError( + onReload: _controller.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + onReload: _controller.onReload, + ), + }; + } +} diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index e0cf54c16..6761ff477 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; -import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/search.dart'; import 'package:PiliPlus/models/bangumi/info.dart'; @@ -36,7 +36,7 @@ class PageUtils { int? selectedIndex; List userList = []; - final shareListRes = await GrpcRepo.shareList(size: 3); + final shareListRes = await ImGrpc.shareList(size: 3); if (shareListRes['status'] && shareListRes['data'].sessionList.isNotEmpty) { userList.addAll(shareListRes['data'] .sessionList diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart index eaec11873..2c7d6da3c 100644 --- a/lib/utils/request_utils.dart +++ b/lib/utils/request_utils.dart @@ -7,7 +7,7 @@ import 'package:PiliPlus/common/widgets/radio_widget.dart'; import 'package:PiliPlus/grpc/bilibili/im/type.pbenum.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show ReplyInfo; -import 'package:PiliPlus/grpc/grpc_repo.dart'; +import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/member.dart'; @@ -53,7 +53,7 @@ class RequestUtils { SmartDialog.showLoading(); final ownerMid = Accounts.main.mid; - final contentRes = await GrpcRepo.sendMsg( + final contentRes = await ImGrpc.sendMsg( senderUid: ownerMid, receiverId: receiverId, content: jsonEncode(content),