feat(messenger): incoming typing state + outgoing typing action

This commit is contained in:
simoleo89
2026-06-02 21:11:03 +02:00
parent 7a2dac8759
commit 361ab27853
+44 -2
View File
@@ -1,4 +1,4 @@
import { ConsoleReadReceiptEvent, GetSessionDataManager, MarkConsoleReadComposer, NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer'; import { ConsoleReadReceiptEvent, ConsoleTypingComposer, FriendIsTypingEvent, GetSessionDataManager, MarkConsoleReadComposer, NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { useBetween } from 'use-between'; import { useBetween } from 'use-between';
import { CloneObject, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, PlaySound, SendMessageComposer, SoundNames } from '../../api'; import { CloneObject, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, PlaySound, SendMessageComposer, SoundNames } from '../../api';
@@ -17,6 +17,9 @@ const useMessengerState = () =>
const { simpleAlert = null } = useNotification(); const { simpleAlert = null } = useNotification();
const { settings, translateIncoming } = useTranslation(); const { settings, translateIncoming } = useTranslation();
const [typingUserIds, setTypingUserIds] = useState<number[]>([]);
const typingTimersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());
const messageThreadsRef = useRef(messageThreads); const messageThreadsRef = useRef(messageThreads);
messageThreadsRef.current = messageThreads; messageThreadsRef.current = messageThreads;
@@ -151,6 +154,13 @@ const useMessengerState = () =>
}); });
}; };
const sendTypingStatus = (peerId: number, isTyping: boolean) =>
{
if (!peerId || (peerId <= 0)) return;
SendMessageComposer(new ConsoleTypingComposer(peerId, isTyping));
};
useMessageEvent<NewConsoleMessageEvent>(NewConsoleMessageEvent, event => useMessageEvent<NewConsoleMessageEvent>(NewConsoleMessageEvent, event =>
{ {
const parser = event.getParser(); const parser = event.getParser();
@@ -179,6 +189,38 @@ const useMessengerState = () =>
simpleAlert(`Received room invite error: ${ parser.errorCode },recipients: ${ parser.failedRecipients.join(',') }`, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title')); simpleAlert(`Received room invite error: ${ parser.errorCode },recipients: ${ parser.failedRecipients.join(',') }`, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title'));
}); });
useMessageEvent<FriendIsTypingEvent>(FriendIsTypingEvent, event =>
{
const parser = event.getParser();
const senderId = parser.senderId;
if (senderId <= 0) return;
const timers = typingTimersRef.current;
const existing = timers.get(senderId);
if (existing)
{
clearTimeout(existing);
timers.delete(senderId);
}
if (parser.isTyping)
{
setTypingUserIds(prev => (prev.indexOf(senderId) >= 0) ? prev : [...prev, senderId]);
timers.set(senderId, setTimeout(() =>
{
typingTimersRef.current.delete(senderId);
setTypingUserIds(prev => prev.filter(id => (id !== senderId)));
}, 6000));
}
else
{
setTypingUserIds(prev => prev.filter(id => (id !== senderId)));
}
});
useMessageEvent<ConsoleReadReceiptEvent>(ConsoleReadReceiptEvent, event => useMessageEvent<ConsoleReadReceiptEvent>(ConsoleReadReceiptEvent, event =>
{ {
const parser = event.getParser(); const parser = event.getParser();
@@ -247,7 +289,7 @@ const useMessengerState = () =>
}); });
}, [visibleThreads]); }, [visibleThreads]);
return { messageThreads, activeThread, iconState, visibleThreads, getMessageThread, setActiveThreadId, closeThread, sendMessage }; return { messageThreads, activeThread, iconState, visibleThreads, getMessageThread, setActiveThreadId, closeThread, sendMessage, typingUserIds, sendTypingStatus };
}; };
export const useMessenger = () => useBetween(useMessengerState); export const useMessenger = () => useBetween(useMessengerState);