From 1a8bf75a0de642470267a05a3ca356c7666cdf98 Mon Sep 17 00:00:00 2001 From: Bill Date: Sun, 13 Nov 2022 20:59:55 -0500 Subject: [PATCH] Update chat --- src/api/room/widgets/ChatBubbleMessage.ts | 1 - .../widgets/chat/ChatWidgetMessageView.tsx | 30 ++++--- .../room/widgets/chat/ChatWidgetView.tsx | 78 +++++++++++++++---- src/hooks/rooms/widgets/useChatWidget.ts | 10 ++- 4 files changed, 90 insertions(+), 29 deletions(-) diff --git a/src/api/room/widgets/ChatBubbleMessage.ts b/src/api/room/widgets/ChatBubbleMessage.ts index cef0ff27..c9cede33 100644 --- a/src/api/room/widgets/ChatBubbleMessage.ts +++ b/src/api/room/widgets/ChatBubbleMessage.ts @@ -8,7 +8,6 @@ export class ChatBubbleMessage public width: number = 0; public height: number = 0; public elementRef: HTMLDivElement = null; - public visible: boolean = false; public skipMovement: boolean = false; private _top: number = 0; diff --git a/src/components/room/widgets/chat/ChatWidgetMessageView.tsx b/src/components/room/widgets/chat/ChatWidgetMessageView.tsx index ef3537ff..cc63422b 100644 --- a/src/components/room/widgets/chat/ChatWidgetMessageView.tsx +++ b/src/components/room/widgets/chat/ChatWidgetMessageView.tsx @@ -6,13 +6,15 @@ interface ChatWidgetMessageViewProps { chat: ChatBubbleMessage; makeRoom: (chat: ChatBubbleMessage) => void; + onBubbleReady?: () => void; bubbleWidth?: number; } export const ChatWidgetMessageView: FC = props => { - const { chat = null, makeRoom = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL } = props; + const { chat = null, makeRoom = null, onBubbleReady = null, bubbleWidth = RoomChatSettings.CHAT_BUBBLE_WIDTH_NORMAL } = props; const [ isVisible, setIsVisible ] = useState(false); + const [ isReady, setIsReady ] = useState(false); const elementRef = useRef(); const getBubbleWidth = useMemo(() => @@ -30,6 +32,8 @@ export const ChatWidgetMessageView: FC = props => useEffect(() => { + setIsVisible(false); + const element = elementRef.current; if(!element) return; @@ -53,20 +57,26 @@ export const ChatWidgetMessageView: FC = props => chat.top = top; } - if(!chat.visible) - { - makeRoom(chat); - - chat.visible = true; - } + setIsReady(true); return () => { chat.elementRef = null; - } - }, [ elementRef, chat, makeRoom ]); - useEffect(() => setIsVisible(chat.visible), [ chat.visible ]); + setIsReady(false); + } + }, [ chat ]); + + useEffect(() => + { + if(!isReady || !chat || isVisible) return; + + if(makeRoom) makeRoom(chat); + + if(onBubbleReady) onBubbleReady(); + + setIsVisible(true); + }, [ chat, isReady, isVisible, makeRoom, onBubbleReady ]); return (
GetRoomEngine().selectRoomObject(chat.roomId, chat.senderId, RoomObjectCategory.UNIT) }> diff --git a/src/components/room/widgets/chat/ChatWidgetView.tsx b/src/components/room/widgets/chat/ChatWidgetView.tsx index 88d97e60..b3aa1290 100644 --- a/src/components/room/widgets/chat/ChatWidgetView.tsx +++ b/src/components/room/widgets/chat/ChatWidgetView.tsx @@ -1,5 +1,5 @@ import { IWorkerEventTracker, RoomChatSettings } from '@nitrots/nitro-renderer'; -import { FC, useEffect, useRef, useState } from 'react'; +import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { AddWorkerEventTracker, ChatBubbleMessage, DoChatsOverlap, GetConfiguration, RemoveWorkerEventTracker, SendWorkerEvent } from '../../../../api'; import { useChatWidget } from '../../../../hooks'; import { ChatWidgetMessageView } from './ChatWidgetMessageView'; @@ -9,18 +9,35 @@ let TIMER_TRACKER: number = 0; export const ChatWidgetView: FC<{}> = props => { const [ timerId, setTimerId ] = useState(TIMER_TRACKER++); - const { chatMessages = [], setChatMessages = null, chatSettings = null, getScrollSpeed = 6000, removeHiddenChats = null, moveAllChatsUp = null } = useChatWidget(); + const { pendingChats = null, chatSettings = null, getScrollSpeed = 6000, moveAllChatsUp = null } = useChatWidget(); + const [ renderedChats, setRenderedChats ] = useState([]); const elementRef = useRef(); + const isProcessing = useRef(false); - const checkOverlappingChats = (chat: ChatBubbleMessage, moved: number, tempChats: ChatBubbleMessage[]) => + const removeHiddenChats = useCallback(() => { - const totalChats = chatMessages.length; + setRenderedChats(prevValue => + { + if(prevValue) + { + const newMessages = prevValue.filter(chat => ((chat.top > (-(chat.height) * 2)))); + + if(newMessages.length !== prevValue.length) return newMessages; + } + + return prevValue; + }) + }, []); + + const checkOverlappingChats = useCallback((chat: ChatBubbleMessage, moved: number, tempChats: ChatBubbleMessage[]) => + { + const totalChats = renderedChats.length; if(!totalChats) return; for(let i = (totalChats - 1); i >= 0; i--) { - const collides = chatMessages[i]; + const collides = renderedChats[i]; if(!collides || (chat === collides) || (tempChats.indexOf(collides) >= 0) || (((collides.top + collides.height) - moved) > (chat.top + chat.height))) continue; @@ -38,9 +55,9 @@ export const ChatWidgetView: FC<{}> = props => checkOverlappingChats(collides, amount, tempChats); } } - } + }, [ renderedChats ]); - const makeRoom = (chat: ChatBubbleMessage) => + const makeRoom = useCallback((chat: ChatBubbleMessage) => { if(chatSettings.mode === RoomChatSettings.CHAT_MODE_FREE_FLOW) { @@ -59,17 +76,50 @@ export const ChatWidgetView: FC<{}> = props => if(spaceAvailable < requiredSpace) { - chatMessages.forEach(existingChat => + setRenderedChats(prevValue => { - if(existingChat === chat) return; + prevValue.forEach(prevChat => + { + if(prevChat === chat) return; - existingChat.top -= amount; + prevChat.top -= amount; + }); + + return prevValue; }); removeHiddenChats(); } } - } + }, [ chatSettings, checkOverlappingChats, removeHiddenChats ]); + + const onBubbleReady = useCallback(() => + { + isProcessing.current = false; + }, []); + + useEffect(() => + { + const processNextChat = () => + { + if(isProcessing.current) return; + + const chat = pendingChats?.current?.shift(); + + if(!chat) return; + + isProcessing.current = true; + + setRenderedChats(prevValue => [ ...prevValue, chat ]); + } + + const interval = setInterval(() => processNextChat(), 50); + + return () => + { + clearInterval(interval); + } + }, [ pendingChats ]); useEffect(() => { @@ -82,7 +132,7 @@ export const ChatWidgetView: FC<{}> = props => elementRef.current.style.height = `${ newHeight }px`; - setChatMessages(prevValue => + setRenderedChats(prevValue => { if(prevValue) { @@ -101,7 +151,7 @@ export const ChatWidgetView: FC<{}> = props => { window.removeEventListener('resize', resize); } - }, [ setChatMessages ]); + }, []); useEffect(() => { @@ -139,7 +189,7 @@ export const ChatWidgetView: FC<{}> = props => return (
- { chatMessages.map(chat => ) } + { renderedChats.map(chat => ) }
); } diff --git a/src/hooks/rooms/widgets/useChatWidget.ts b/src/hooks/rooms/widgets/useChatWidget.ts index e8db7439..e3db1b1a 100644 --- a/src/hooks/rooms/widgets/useChatWidget.ts +++ b/src/hooks/rooms/widgets/useChatWidget.ts @@ -1,5 +1,5 @@ import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, GetGuestRoomResultEvent, NitroPoint, PetFigureData, RoomChatSettings, RoomChatSettingsEvent, RoomDragEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomUserData, SystemChatStyleEnum, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { ChatBubbleMessage, ChatEntryType, ChatHistoryCurrentDate, GetAvatarRenderManager, GetConfiguration, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; import { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events'; import { useRoom } from '../useRoom'; @@ -22,6 +22,7 @@ const useChatWidgetState = () => const { roomSession = null } = useRoom(); const { addChatEntry } = useChatHistory(); const isDisposed = useRef(false); + const pendingChats = useRef([]); const getScrollSpeed = useMemo(() => { @@ -95,7 +96,7 @@ const useChatWidgetState = () => return existing; } - const removeHiddenChats = () => + const removeHiddenChats = useCallback(() => { setChatMessages(prevValue => { @@ -108,7 +109,7 @@ const useChatWidgetState = () => return prevValue; }) - } + }, []); const moveAllChatsUp = (amount: number) => { @@ -248,6 +249,7 @@ const useChatWidgetState = () => color); setChatMessages(prevValue => [ ...prevValue, chatMessage ]); + pendingChats?.current?.push(chatMessage); addChatEntry({ id: -1, entityId: userData.roomIndex, name: username, imageUrl, style: styleId, chatType: chatType, entityType: userData.type, message: formattedText, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId, color }); }); @@ -286,7 +288,7 @@ const useChatWidgetState = () => } }, []); - return { chatMessages, setChatMessages, chatSettings, getScrollSpeed, removeHiddenChats, moveAllChatsUp }; + return { chatMessages, setChatMessages, chatSettings, getScrollSpeed, removeHiddenChats, moveAllChatsUp, pendingChats }; } export const useChatWidget = useChatWidgetState;