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