Compare commits
2 Commits
76d8cd943d
...
ce6e9c185a
Author | SHA1 | Date | |
---|---|---|---|
ce6e9c185a | |||
cdaa8cfe58 |
@ -761,5 +761,7 @@
|
||||
"enrollNewKeyPairDescription": "Generate a new key pair.",
|
||||
"keyPairHasPrivateKey": "With private key",
|
||||
"decrypting": "Decrypting……",
|
||||
"decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online"
|
||||
"decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online",
|
||||
"messageUnablePreview": "Unable preview",
|
||||
"messageUnablePreviewEncrypted": "Unable preview encrypted message"
|
||||
}
|
||||
|
@ -759,5 +759,7 @@
|
||||
"enrollNewKeyPairDescription": "生成一对新密钥对。",
|
||||
"keyPairHasPrivateKey": "有私钥",
|
||||
"decrypting": "解密中……",
|
||||
"decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线"
|
||||
"decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线",
|
||||
"messageUnablePreview": "无法预览消息",
|
||||
"messageUnablePreviewEncrypted": "无法预览加密消息"
|
||||
}
|
||||
|
@ -759,5 +759,7 @@
|
||||
"enrollNewKeyPairDescription": "生成一對新密鑰對。",
|
||||
"keyPairHasPrivateKey": "有私鑰",
|
||||
"decrypting": "解密中……",
|
||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線"
|
||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
||||
"messageUnablePreview": "無法預覽消息",
|
||||
"messageUnablePreviewEncrypted": "無法預覽加密消息"
|
||||
}
|
||||
|
@ -759,5 +759,7 @@
|
||||
"enrollNewKeyPairDescription": "生成一對新密鑰對。",
|
||||
"keyPairHasPrivateKey": "有私鑰",
|
||||
"decrypting": "解密中……",
|
||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線"
|
||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
||||
"messageUnablePreview": "無法預覽消息",
|
||||
"messageUnablePreviewEncrypted": "無法預覽加密消息"
|
||||
}
|
||||
|
@ -357,6 +357,7 @@ class ChatMessageController extends ChangeNotifier {
|
||||
if (mostRecentMessage == null) {
|
||||
// Initial load
|
||||
await loadMessages(take: 20);
|
||||
isAggressiveLoading = false;
|
||||
isCheckedUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
@ -163,7 +163,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ud = context.read<UserDirectoryProvider>();
|
||||
final ua = context.read<UserProvider>();
|
||||
|
||||
if (!ua.isAuthorized) {
|
||||
@ -266,144 +265,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
final channel = _channels![idx];
|
||||
final lastMessage = _lastMessages?[channel.id];
|
||||
|
||||
if (channel.type == 1) {
|
||||
final otherMember =
|
||||
channel.members?.cast<SnChannelMember?>().firstWhere(
|
||||
(ele) => ele?.accountId != ua.user?.id,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
return ListTile(
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(ud
|
||||
.getAccountFromCache(
|
||||
otherMember?.accountId)
|
||||
?.nick ??
|
||||
channel.name),
|
||||
),
|
||||
const Gap(8),
|
||||
if (_unreadCounts?[channel.id] != null &&
|
||||
_unreadCounts![channel.id]! > 0)
|
||||
Badge(
|
||||
label: Text('${_unreadCounts![channel.id]}'),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: lastMessage != null
|
||||
? Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
lastMessage.body['text'] ??
|
||||
'Unable preview',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
Text(
|
||||
DateFormat(
|
||||
lastMessage.createdAt.toLocal().day ==
|
||||
DateTime.now().day
|
||||
? 'HH:mm'
|
||||
: lastMessage.createdAt
|
||||
.toLocal()
|
||||
.year ==
|
||||
DateTime.now().year
|
||||
? 'MM/dd'
|
||||
: 'yy/MM/dd',
|
||||
).format(lastMessage.createdAt.toLocal()),
|
||||
style: GoogleFonts.robotoMono(
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
channel.description,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16),
|
||||
leading: AccountImage(
|
||||
content: ud
|
||||
.getAccountFromCache(otherMember?.accountId)
|
||||
?.avatar,
|
||||
),
|
||||
onTap: () {
|
||||
_onTapChannel(channel);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return ListTile(
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(channel.name)),
|
||||
const Gap(8),
|
||||
if (_unreadCounts?[channel.id] != null &&
|
||||
_unreadCounts![channel.id]! > 0)
|
||||
Badge(
|
||||
label: Text('${_unreadCounts![channel.id]}'),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: lastMessage != null
|
||||
? Row(
|
||||
children: [
|
||||
Badge(
|
||||
label: Text(ud
|
||||
.getAccountFromCache(
|
||||
lastMessage.sender.accountId)
|
||||
?.nick ??
|
||||
'unknown'.tr()),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primary,
|
||||
textColor:
|
||||
Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
const Gap(6),
|
||||
Expanded(
|
||||
child: Text(
|
||||
lastMessage.body['text'] ??
|
||||
'Unable preview',
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
Text(
|
||||
DateFormat(
|
||||
lastMessage.createdAt.toLocal().day ==
|
||||
DateTime.now().day
|
||||
? 'HH:mm'
|
||||
: lastMessage.createdAt
|
||||
.toLocal()
|
||||
.year ==
|
||||
DateTime.now().year
|
||||
? 'MM/dd'
|
||||
: 'yy/MM/dd',
|
||||
).format(lastMessage.createdAt.toLocal()),
|
||||
style: GoogleFonts.robotoMono(
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
channel.description,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 16),
|
||||
leading: AccountImage(
|
||||
content: channel.realm?.avatar,
|
||||
fallbackWidget: const Icon(Symbols.chat, size: 20),
|
||||
),
|
||||
return _ChatChannelEntry(
|
||||
channel: channel,
|
||||
lastMessage: lastMessage,
|
||||
unreadCount: _unreadCounts?[channel.id],
|
||||
onTap: () {
|
||||
if (doExpand) {
|
||||
_unreadCounts?[channel.id] = 0;
|
||||
@ -445,3 +310,101 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
return chatList;
|
||||
}
|
||||
}
|
||||
|
||||
class _ChatChannelEntry extends StatelessWidget {
|
||||
final SnChannel channel;
|
||||
final int? unreadCount;
|
||||
final SnChatMessage? lastMessage;
|
||||
final Function? onTap;
|
||||
const _ChatChannelEntry({
|
||||
required this.channel,
|
||||
this.unreadCount,
|
||||
this.lastMessage,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ud = context.read<UserDirectoryProvider>();
|
||||
final ua = context.read<UserProvider>();
|
||||
|
||||
final otherMember = channel.type == 1
|
||||
? channel.members?.cast<SnChannelMember?>().firstWhere(
|
||||
(ele) => ele?.accountId != ua.user?.id,
|
||||
orElse: () => null,
|
||||
)
|
||||
: null;
|
||||
|
||||
final title = otherMember != null
|
||||
? ud.getAccountFromCache(otherMember.accountId)?.nick ?? channel.name
|
||||
: channel.name;
|
||||
|
||||
return ListTile(
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(title)),
|
||||
const Gap(8),
|
||||
if (unreadCount != null && unreadCount! > 0)
|
||||
Badge(
|
||||
label: Text(unreadCount.toString()),
|
||||
),
|
||||
],
|
||||
),
|
||||
subtitle: lastMessage != null
|
||||
? Row(
|
||||
children: [
|
||||
Badge(
|
||||
label: Text(ud
|
||||
.getAccountFromCache(lastMessage!.sender.accountId)
|
||||
?.nick ??
|
||||
'unknown'.tr()),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
textColor: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
const Gap(6),
|
||||
Expanded(
|
||||
child: Text(
|
||||
lastMessage!.body['algorithm'] == 'plain'
|
||||
? lastMessage!.body['text'] ??
|
||||
'messageUnablePreview'.tr()
|
||||
: 'messageUnablePreviewEncrypted'.tr(),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: lastMessage!.body['algorithm'] != 'plain' ||
|
||||
lastMessage!.body['text'] == null
|
||||
? TextStyle(fontStyle: FontStyle.italic)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
Text(
|
||||
DateFormat(
|
||||
lastMessage!.createdAt.toLocal().day == DateTime.now().day
|
||||
? 'HH:mm'
|
||||
: lastMessage!.createdAt.toLocal().year ==
|
||||
DateTime.now().year
|
||||
? 'MM/dd'
|
||||
: 'yy/MM/dd',
|
||||
).format(lastMessage!.createdAt.toLocal()),
|
||||
style: GoogleFonts.robotoMono(
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Text(
|
||||
channel.description,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
leading: AccountImage(
|
||||
content: otherMember != null
|
||||
? ud.getAccountFromCache(otherMember.accountId)?.avatar
|
||||
: channel.realm?.avatar,
|
||||
fallbackWidget: const Icon(Symbols.chat, size: 20),
|
||||
),
|
||||
onTap: () => onTap?.call(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,9 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
||||
final GlobalKey<ChatMessageInputState> _inputGlobalKey = GlobalKey();
|
||||
late final ChatMessageController _messageController;
|
||||
|
||||
late final NotificationProvider _nty = context.read<NotificationProvider>();
|
||||
late final WebSocketProvider _ws = context.read<WebSocketProvider>();
|
||||
|
||||
bool _isEncrypted = false;
|
||||
|
||||
StreamSubscription? _wsSubscription;
|
||||
@ -91,8 +94,7 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
final nty = context.read<NotificationProvider>();
|
||||
nty.skippableNotifyChannel = _channel!.id;
|
||||
_nty.skippableNotifyChannel = _channel!.id;
|
||||
final ws = context.read<WebSocketProvider>();
|
||||
if (_channel != null) {
|
||||
ws.conn?.sink.add(
|
||||
@ -229,8 +231,7 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
||||
]);
|
||||
});
|
||||
|
||||
final ws = context.read<WebSocketProvider>();
|
||||
_wsSubscription = ws.pk.stream.listen((event) {
|
||||
_wsSubscription = _ws.pk.stream.listen((event) {
|
||||
switch (event.method) {
|
||||
case 'calls.new':
|
||||
final payload = SnChatCall.fromJson(event.payload!);
|
||||
@ -252,11 +253,9 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
||||
void dispose() {
|
||||
_wsSubscription?.cancel();
|
||||
_messageController.dispose();
|
||||
final nty = context.read<NotificationProvider>();
|
||||
nty.skippableNotifyChannel = null;
|
||||
final ws = context.read<WebSocketProvider>();
|
||||
_nty.skippableNotifyChannel = null;
|
||||
if (_channel != null) {
|
||||
ws.conn?.sink.add(
|
||||
_ws.conn?.sink.add(
|
||||
jsonEncode(WebSocketPackage(
|
||||
method: 'events.unsubscribe',
|
||||
endpoint: 'im',
|
||||
|
Loading…
x
Reference in New Issue
Block a user