mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
Merge remote-tracking branch 'fork/main'
# Conflicts: # public/configuration/UITexts_en.json5.example # public/configuration/UITexts_it.json5.example # src/components/MainView.tsx # src/css/friends/FriendsView.css
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { AcceptFriendMessageComposer, DeclineFriendMessageComposer, FollowFriendFailedEvent, FollowFriendMessageComposer, FriendListFragmentEvent, FriendListUpdateComposer, FriendListUpdateEvent, FriendParser, FriendRequestsEvent, GetFriendRequestsComposer, GetSessionDataManager, MessengerInitComposer, MessengerInitEvent, NewFriendRequestEvent, RequestFriendComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||
import { AcceptFriendMessageComposer, AddFriendCategoryComposer, DeclineFriendMessageComposer, FollowFriendFailedEvent, FollowFriendMessageComposer, FriendListFragmentEvent, FriendListUpdateComposer, FriendListUpdateEvent, FriendParser, FriendRequestsEvent, GetFriendRequestsComposer, GetSessionDataManager, MessengerInitComposer, MessengerInitEvent, MoveFriendToCategoryComposer, NewFriendRequestEvent, RemoveFriendCategoryComposer, RenameFriendCategoryComposer, RequestFriendComposer, SetRelationshipStatusComposer } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { CloneObject, LocalizeText, MessengerFriend, MessengerRequest, MessengerSettings, NotificationAlertType, SendMessageComposer } from '../../api';
|
||||
@@ -43,6 +43,38 @@ const useFriendsStore = () =>
|
||||
|
||||
const updateRelationship = (friend: MessengerFriend, type: number) => ((type !== friend.relationshipStatus) && SendMessageComposer(new SetRelationshipStatusComposer(friend.id, type)));
|
||||
|
||||
const addCategory = (name: string) =>
|
||||
{
|
||||
const trimmed = (name ?? '').trim();
|
||||
|
||||
if(!trimmed.length || (trimmed.length > 25)) return;
|
||||
|
||||
SendMessageComposer(new AddFriendCategoryComposer(trimmed));
|
||||
};
|
||||
|
||||
const renameCategory = (categoryId: number, name: string) =>
|
||||
{
|
||||
const trimmed = (name ?? '').trim();
|
||||
|
||||
if(!categoryId || !trimmed.length || (trimmed.length > 25)) return;
|
||||
|
||||
SendMessageComposer(new RenameFriendCategoryComposer(categoryId, trimmed));
|
||||
};
|
||||
|
||||
const removeCategory = (categoryId: number) =>
|
||||
{
|
||||
if(!categoryId) return;
|
||||
|
||||
SendMessageComposer(new RemoveFriendCategoryComposer(categoryId));
|
||||
};
|
||||
|
||||
const moveFriendToCategory = (friendId: number, categoryId: number) =>
|
||||
{
|
||||
if(!friendId) return;
|
||||
|
||||
SendMessageComposer(new MoveFriendToCategoryComposer(friendId, categoryId));
|
||||
};
|
||||
|
||||
const getFriend = (userId: number) =>
|
||||
{
|
||||
for(const friend of friends)
|
||||
@@ -259,7 +291,7 @@ const useFriendsStore = () =>
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { friends, requests, sentRequests, dismissedRequestIds, setDismissedRequestIds, settings, onlineFriends, offlineFriends, getFriend, canRequestFriend, requestFriend, requestResponse, followFriend, updateRelationship };
|
||||
return { friends, requests, sentRequests, dismissedRequestIds, setDismissedRequestIds, settings, onlineFriends, offlineFriends, getFriend, canRequestFriend, requestFriend, requestResponse, followFriend, updateRelationship, addCategory, renameCategory, removeCategory, moveFriendToCategory };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -312,14 +344,22 @@ export const useFriendsActions = () =>
|
||||
requestFriend,
|
||||
requestResponse,
|
||||
followFriend,
|
||||
updateRelationship
|
||||
updateRelationship,
|
||||
addCategory,
|
||||
renameCategory,
|
||||
removeCategory,
|
||||
moveFriendToCategory
|
||||
} = useBetween(useFriendsStore);
|
||||
|
||||
return {
|
||||
requestFriend,
|
||||
requestResponse,
|
||||
followFriend,
|
||||
updateRelationship
|
||||
updateRelationship,
|
||||
addCategory,
|
||||
renameCategory,
|
||||
removeCategory,
|
||||
moveFriendToCategory
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { GetSessionDataManager, NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { ConsoleReadReceiptEvent, ConsoleTypingComposer, FriendIsTypingEvent, GetSessionDataManager, MarkConsoleReadComposer, NewConsoleMessageEvent, RoomInviteErrorEvent, RoomInviteEvent, SendMessageComposer as SendMessageComposerPacket } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { CloneObject, LocalizeText, MessengerIconState, MessengerThread, MessengerThreadChat, NotificationAlertType, PlaySound, SendMessageComposer, SoundNames } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
@@ -17,6 +17,12 @@ const useMessengerState = () =>
|
||||
const { simpleAlert = null } = useNotification();
|
||||
const { settings, translateIncoming } = useTranslation();
|
||||
|
||||
const [typingUserIds, setTypingUserIds] = useState<number[]>([]);
|
||||
const typingTimersRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());
|
||||
|
||||
const messageThreadsRef = useRef(messageThreads);
|
||||
messageThreadsRef.current = messageThreads;
|
||||
|
||||
const visibleThreads = useMemo(() => messageThreads.filter(thread => (hiddenThreadIds.indexOf(thread.threadId) === -1)), [messageThreads, hiddenThreadIds]);
|
||||
const activeThread = useMemo(() => ((activeThreadId > 0) && visibleThreads.find(thread => (thread.threadId === activeThreadId) || null)), [activeThreadId, visibleThreads]);
|
||||
|
||||
@@ -148,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 =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
@@ -156,6 +169,7 @@ const useMessengerState = () =>
|
||||
if (!thread) return;
|
||||
|
||||
sendMessage(thread, parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
|
||||
if ((thread.threadId === activeThreadId) && (parser.senderId > 0)) SendMessageComposer(new MarkConsoleReadComposer(parser.senderId));
|
||||
});
|
||||
|
||||
useMessageEvent<RoomInviteEvent>(RoomInviteEvent, event =>
|
||||
@@ -175,10 +189,65 @@ const useMessengerState = () =>
|
||||
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 =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
const ownUserId = GetSessionDataManager().userId;
|
||||
|
||||
setMessageThreads(prevValue =>
|
||||
{
|
||||
const index = prevValue.findIndex(thread => (thread.participant && (thread.participant.id === parser.readerId)));
|
||||
|
||||
if (index === -1) return prevValue;
|
||||
|
||||
const newValue = [...prevValue];
|
||||
|
||||
newValue[index] = CloneObject(newValue[index]);
|
||||
newValue[index].setMessagesReadFromUser(ownUserId);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if (activeThreadId <= 0) return;
|
||||
|
||||
const activeThreadValue = messageThreadsRef.current.find(thread => (thread.threadId === activeThreadId));
|
||||
const participantId = activeThreadValue?.participant?.id ?? 0;
|
||||
|
||||
setMessageThreads(prevValue =>
|
||||
{
|
||||
const newValue = [...prevValue];
|
||||
@@ -187,12 +256,13 @@ const useMessengerState = () =>
|
||||
if (index >= 0)
|
||||
{
|
||||
newValue[index] = CloneObject(newValue[index]);
|
||||
|
||||
newValue[index].setRead();
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
if (participantId > 0) SendMessageComposer(new MarkConsoleReadComposer(participantId));
|
||||
}, [activeThreadId]);
|
||||
|
||||
useEffect(() =>
|
||||
@@ -219,7 +289,7 @@ const useMessengerState = () =>
|
||||
});
|
||||
}, [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);
|
||||
|
||||
Reference in New Issue
Block a user