mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-22 03:20:09 +08:00
@@ -1,4 +1,4 @@
|
||||
import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart';
|
||||
import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' hide SessionInfo;
|
||||
import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart';
|
||||
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart';
|
||||
import 'package:PiliPlus/grpc/grpc_req.dart';
|
||||
@@ -212,4 +212,16 @@ abstract final class ImGrpc {
|
||||
RspTotalUnread.fromBuffer,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<LoadingState<SessionInfo>> sessionDetail({
|
||||
Int64? talkerId,
|
||||
int? sessionType,
|
||||
Int64? uid,
|
||||
}) {
|
||||
return GrpcReq.request(
|
||||
GrpcUrl.sessionDetail,
|
||||
ReqSessionDetail(talkerId: talkerId, sessionType: sessionType, uid: uid),
|
||||
SessionInfo.fromBuffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ abstract final class GrpcUrl {
|
||||
static const keywordBlockingDelete = '$im2/KeywordBlockingDelete';
|
||||
static const syncFetchSessionMsgs = '$im/SyncFetchSessionMsgs';
|
||||
static const getTotalUnread = '$im/GetTotalUnread';
|
||||
static const sessionDetail = '$im/SessionDetail';
|
||||
|
||||
// view
|
||||
static const viewunite = '/bilibili.app.viewunite.v1.View';
|
||||
|
||||
@@ -7,8 +7,10 @@ import 'package:PiliPlus/common/widgets/dialog/simple_dialog_option.dart';
|
||||
import 'package:PiliPlus/common/widgets/flutter/list_tile.dart';
|
||||
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
|
||||
import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'
|
||||
show Session, SessionId, SessionPageType, SessionType, UnreadStyle;
|
||||
import 'package:PiliPlus/models/common/badge_type.dart';
|
||||
show Session, SessionId, SessionPageType;
|
||||
import 'package:PiliPlus/grpc/im.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/msg.dart';
|
||||
import 'package:PiliPlus/pages/whisper_secondary/view.dart';
|
||||
import 'package:PiliPlus/utils/date_utils.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
@@ -16,6 +18,7 @@ import 'package:PiliPlus/utils/extension/theme_ext.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart' hide ListTile;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -34,6 +37,28 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
final Function(bool isMuted, Int64 talkerUid) onSetMute;
|
||||
final ValueChanged<int> onRemove;
|
||||
|
||||
Future<void> _updateAck(BuildContext context) async {
|
||||
final talkerUid = item.id.privateId.talkerUid;
|
||||
final res = await ImGrpc.sessionDetail(talkerId: talkerUid, sessionType: 1);
|
||||
if (res case Success(:final response)) {
|
||||
final res = await MsgHttp.ackSessionMsg(
|
||||
talkerId: talkerUid.toInt(),
|
||||
ackSeqno: response.ackSeqno.toInt(),
|
||||
);
|
||||
if (res.isSuccess) {
|
||||
SmartDialog.showToast('已标为已读');
|
||||
item.clearUnread();
|
||||
if (context.mounted) {
|
||||
(context as Element).markNeedsBuild();
|
||||
}
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
} else {
|
||||
res.toast();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final resource =
|
||||
@@ -46,7 +71,8 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
Map? vipInfo = item.sessionInfo.hasVipInfo()
|
||||
? jsonDecode(item.sessionInfo.vipInfo)
|
||||
: null;
|
||||
final ThemeData theme = Theme.of(context);
|
||||
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return ListTile(
|
||||
safeArea: true,
|
||||
@@ -57,9 +83,9 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
: null,
|
||||
onLongPress: () => showDialog(
|
||||
context: context,
|
||||
builder: (context) => SimpleDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
builder: (_) => SimpleDialog(
|
||||
clipBehavior: .hardEdge,
|
||||
contentPadding: const .symmetric(vertical: 12),
|
||||
children: [
|
||||
DialogOption(
|
||||
onPressed: () {
|
||||
@@ -68,7 +94,15 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
},
|
||||
child: Text(item.isPinned ? '移除置顶' : '置顶'),
|
||||
),
|
||||
if (item.id.privateId.hasTalkerUid())
|
||||
if (item.id.privateId.hasTalkerUid()) ...[
|
||||
if (kDebugMode || item.hasUnread())
|
||||
DialogOption(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
_updateAck(context);
|
||||
},
|
||||
child: const Text('标为已读'),
|
||||
),
|
||||
DialogOption(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
@@ -76,7 +110,6 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
},
|
||||
child: Text('${item.isMuted ? '关闭' : '开启'}免打扰'),
|
||||
),
|
||||
if (item.id.privateId.hasTalkerUid())
|
||||
DialogOption(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
@@ -89,6 +122,7 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
},
|
||||
child: const Text('删除'),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -96,20 +130,38 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
? (details) => showMenu(
|
||||
context: context,
|
||||
position: PageUtils.menuPosition(details.globalPosition),
|
||||
items: [
|
||||
items: <PopupMenuEntry<Never>>[
|
||||
PopupMenuItem(
|
||||
height: 42,
|
||||
onTap: () => onSetTop(item.isPinned, item.id),
|
||||
child: Text(item.isPinned ? '移除置顶' : '置顶'),
|
||||
),
|
||||
if (item.id.privateId.hasTalkerUid())
|
||||
if (item.id.privateId.hasTalkerUid()) ...[
|
||||
if (kDebugMode || item.hasUnread())
|
||||
PopupMenuItem(
|
||||
height: 42,
|
||||
onTap: () => _updateAck(context),
|
||||
child: const Text('标为已读'),
|
||||
),
|
||||
// if (kDebugMode)
|
||||
// PopupMenuItem(
|
||||
// height: 42,
|
||||
// onTap: () {
|
||||
// item.unread = Unread(
|
||||
// style: .UNREAD_STYLE_NUMBER,
|
||||
// number: .ONE,
|
||||
// );
|
||||
// (context as Element).markNeedsBuild();
|
||||
// },
|
||||
// child: const Text('标为未读'),
|
||||
// ),
|
||||
PopupMenuItem(
|
||||
height: 42,
|
||||
onTap: () =>
|
||||
onSetMute(item.isMuted, item.id.privateId.talkerUid),
|
||||
child: Text('${item.isMuted ? '关闭' : '开启'}免打扰'),
|
||||
),
|
||||
if (item.id.privateId.hasTalkerUid())
|
||||
const PopupMenuDivider(height: 10),
|
||||
PopupMenuItem(
|
||||
height: 42,
|
||||
onTap: () => showConfirmDialog(
|
||||
@@ -118,8 +170,12 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
onConfirm: () =>
|
||||
onRemove(item.id.privateId.talkerUid.toInt()),
|
||||
),
|
||||
child: const Text('删除'),
|
||||
child: Text(
|
||||
'删除',
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
)
|
||||
: null,
|
||||
@@ -147,24 +203,15 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
|
||||
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,
|
||||
.SESSION_TYPE_UNKNOWN => .SESSION_PAGE_TYPE_UNKNOWN,
|
||||
.SESSION_TYPE_GROUP => .SESSION_PAGE_TYPE_GROUP,
|
||||
.SESSION_TYPE_GROUP_FOLD => .SESSION_PAGE_TYPE_GROUP,
|
||||
.SESSION_TYPE_UNFOLLOWED => .SESSION_PAGE_TYPE_UNFOLLOWED,
|
||||
.SESSION_TYPE_STRANGER => .SESSION_PAGE_TYPE_STRANGER,
|
||||
.SESSION_TYPE_DUSTBIN => .SESSION_PAGE_TYPE_DUSTBIN,
|
||||
.SESSION_TYPE_CUSTOMER_FOLD => .SESSION_PAGE_TYPE_CUSTOMER,
|
||||
.SESSION_TYPE_AI_FOLD => .SESSION_PAGE_TYPE_AI,
|
||||
.SESSION_TYPE_CUSTOMER_ACCOUNT => .SESSION_PAGE_TYPE_CUSTOMER,
|
||||
_ => null,
|
||||
};
|
||||
if (sessionPageType != null) {
|
||||
@@ -182,18 +229,18 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
|
||||
if (item.id.hasSystemId()) {
|
||||
switch (item.id.systemId.type) {
|
||||
case SessionType.SESSION_TYPE_SYSTEM:
|
||||
case .SESSION_TYPE_SYSTEM:
|
||||
Get.toNamed('/sysMsg');
|
||||
case SessionType.SESSION_TYPE_AI_FOLD:
|
||||
case SessionType.SESSION_TYPE_CUSTOMER_ACCOUNT:
|
||||
case SessionType.SESSION_TYPE_CUSTOMER_FOLD:
|
||||
case SessionType.SESSION_TYPE_DUSTBIN:
|
||||
case SessionType.SESSION_TYPE_GROUP:
|
||||
case SessionType.SESSION_TYPE_GROUP_FOLD:
|
||||
case SessionType.SESSION_TYPE_PRIVATE:
|
||||
case SessionType.SESSION_TYPE_STRANGER:
|
||||
case SessionType.SESSION_TYPE_UNFOLLOWED:
|
||||
case SessionType.SESSION_TYPE_UNKNOWN:
|
||||
case .SESSION_TYPE_AI_FOLD:
|
||||
case .SESSION_TYPE_CUSTOMER_ACCOUNT:
|
||||
case .SESSION_TYPE_CUSTOMER_FOLD:
|
||||
case .SESSION_TYPE_DUSTBIN:
|
||||
case .SESSION_TYPE_GROUP:
|
||||
case .SESSION_TYPE_GROUP_FOLD:
|
||||
case .SESSION_TYPE_PRIVATE:
|
||||
case .SESSION_TYPE_STRANGER:
|
||||
case .SESSION_TYPE_UNFOLLOWED:
|
||||
case .SESSION_TYPE_UNKNOWN:
|
||||
SmartDialog.showToast(item.id.systemId.type.name);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +295,7 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
child: Text(
|
||||
item.sessionInfo.sessionName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color:
|
||||
@@ -263,8 +310,8 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
if (item.sessionInfo.userLabel.style.borderedLabel.hasText())
|
||||
PBadge(
|
||||
isStack: false,
|
||||
type: PBadgeType.line_secondary,
|
||||
size: PBadgeSize.small,
|
||||
type: .line_secondary,
|
||||
size: .small,
|
||||
fontSize: 10,
|
||||
isBold: false,
|
||||
text: item.sessionInfo.userLabel.style.borderedLabel.text,
|
||||
@@ -274,7 +321,7 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
Assets.livingRect,
|
||||
height: 15,
|
||||
cacheHeight: 15.cacheSize(context),
|
||||
filterQuality: FilterQuality.low,
|
||||
filterQuality: .low,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -295,7 +342,7 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
child: Text(
|
||||
item.msgSummary.rawMsg,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
overflow: .ellipsis,
|
||||
style: theme.textTheme.labelMedium!.copyWith(
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
@@ -307,10 +354,9 @@ class WhisperSessionItem extends StatelessWidget {
|
||||
Icons.notifications_off,
|
||||
color: theme.colorScheme.outline,
|
||||
)
|
||||
else if (item.hasUnread() &&
|
||||
item.unread.style != UnreadStyle.UNREAD_STYLE_NONE)
|
||||
else if (item.hasUnread() && item.unread.style != .UNREAD_STYLE_NONE)
|
||||
Badge(
|
||||
label: item.unread.style == UnreadStyle.UNREAD_STYLE_NUMBER
|
||||
label: item.unread.style == .UNREAD_STYLE_NUMBER
|
||||
? Text(item.unread.number.toString())
|
||||
: null,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user