diff --git a/src/api/chat-history/IChatEntry.ts b/src/api/chat-history/IChatEntry.ts index 472a5dbe..bbef07e5 100644 --- a/src/api/chat-history/IChatEntry.ts +++ b/src/api/chat-history/IChatEntry.ts @@ -6,6 +6,10 @@ export interface IChatEntry look?: string; message?: string; entityType?: number; + style?: number; + chatType?: number; + imageUrl?: string; + color?: string; roomId: number; timestamp: string; type: number; diff --git a/src/components/chat-history/ChatHistoryView.tsx b/src/components/chat-history/ChatHistoryView.tsx index c9653bc8..0f5bdfa8 100644 --- a/src/components/chat-history/ChatHistoryView.tsx +++ b/src/components/chat-history/ChatHistoryView.tsx @@ -1,33 +1,90 @@ -import { ILinkEventTracker } from '@nitrots/nitro-renderer'; +import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, ILinkEventTracker } from '@nitrots/nitro-renderer'; import { FC, useEffect, useMemo, useRef, useState } from 'react'; import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized'; -import { AddEventLinkTracker, ChatEntryType, LocalizeText, RemoveLinkEventTracker } from '../../api'; +import { AddEventLinkTracker, ChatEntryType, GetAvatarRenderManager, LocalizeText, RemoveLinkEventTracker } from '../../api'; import { Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common'; import { useChatHistory } from '../../hooks'; +const avatarColorCache: Map = new Map(); +const avatarImageCache: Map = new Map(); + export const ChatHistoryView: FC<{}> = props => { const [ isVisible, setIsVisible ] = useState(false); const { chatHistory = [] } = useChatHistory(); const elementRef = useRef(null); + const [ searchText, setSearchText ] = useState('z'); + + const setFigureImage = (figure: string) => + { + const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, { + resetFigure: figure => + { + setFigureImage(figure); + }, + dispose: () => + {}, + disposed: false + }); + + if(!avatarImage) return; + + const image = avatarImage.getCroppedImage(AvatarSetType.HEAD); + const color = avatarImage.getPartColor(AvatarFigurePartType.CHEST); + + avatarColorCache.set(figure, ((color && color.rgb) || 16777215)); + + avatarImage.dispose(); + + avatarImageCache.set(figure, image.src); + + return image.src; + } + + const getUserImage = (figure: string) => + { + let existing = avatarImageCache.get(figure); + + if(!existing) existing = setFigureImage(figure); + + return existing; + } + const cache = useMemo(() => new CellMeasurerCache({ defaultHeight: 25, fixedWidth: true }), []); + const filteredChatHistory = useMemo(() => + { + if (searchText.length === 0) return chatHistory; + + return chatHistory.filter((i) => i.message && i.message.includes(searchText)); + }, [ chatHistory, searchText ]); + const RowRenderer: ListRowRenderer = (props: ListRowProps) => { - const item = chatHistory[props.index]; + const item = filteredChatHistory[props.index]; - const isDark = (props.index % 2 === 0); + if (!item) return null; return ( - + { item.timestamp } { (item.type === ChatEntryType.TYPE_CHAT) && - <> - - { item.message } - } +
+ { (item.style === 0) && +
} +
+
+ { item.imageUrl && (item.imageUrl.length > 0) && +
} +
+
+ + +
+
+
} { (item.type === ChatEntryType.TYPE_ROOM_INFO) && <> @@ -81,22 +138,27 @@ export const ChatHistoryView: FC<{}> = props => setIsVisible(false) }/> - - { ({ height, width }) => - { - return ( - - ) - } } - + + setSearchText(event.target.value) } /> +
+ + { ({ height, width }) => + { + return ( + + ) + } } + +
+
); diff --git a/src/hooks/chat-history/useChatHistory.ts b/src/hooks/chat-history/useChatHistory.ts index 7b7292fb..fe619dcc 100644 --- a/src/hooks/chat-history/useChatHistory.ts +++ b/src/hooks/chat-history/useChatHistory.ts @@ -1,7 +1,7 @@ -import { GetGuestRoomResultEvent, NewConsoleMessageEvent, RoomInviteEvent, RoomSessionChatEvent, RoomSessionEvent } from '@nitrots/nitro-renderer'; +import { GetGuestRoomResultEvent, NewConsoleMessageEvent, RoomInviteEvent, RoomSessionEvent } from '@nitrots/nitro-renderer'; import { useState } from 'react'; import { useBetween } from 'use-between'; -import { ChatEntryType, ChatHistoryCurrentDate, GetRoomSession, IChatEntry, IRoomHistoryEntry, MessengerHistoryCurrentDate } from '../../api'; +import { ChatEntryType, ChatHistoryCurrentDate, IChatEntry, IRoomHistoryEntry, MessengerHistoryCurrentDate } from '../../api'; import { useMessageEvent, useRoomSessionManagerEvent } from '../events'; const CHAT_HISTORY_MAX = 1000; @@ -63,19 +63,6 @@ const useChatHistoryState = () => return newValue; }); } - - useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, event => - { - const roomSession = GetRoomSession(); - - if(!roomSession) return; - - const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId); - - if(!userData) return; - - addChatEntry({ id: -1, entityId: userData.webID, name: userData.name, look: userData.figure, entityType: userData.type, message: event.message, timestamp: ChatHistoryCurrentDate(), type: ChatEntryType.TYPE_CHAT, roomId: roomSession.roomId }); - }); useRoomSessionManagerEvent(RoomSessionEvent.STARTED, event => setNeedsRoomInsert(true)); @@ -111,7 +98,7 @@ const useChatHistoryState = () => addMessengerEntry({ id: -1, entityId: parser.senderId, name: '', message: parser.messageText, roomId: -1, timestamp: MessengerHistoryCurrentDate(), type: ChatEntryType.TYPE_IM }); }); - return { chatHistory, roomHistory, messengerHistory }; + return { addChatEntry, chatHistory, roomHistory, messengerHistory }; } export const useChatHistory = () => useBetween(useChatHistoryState); diff --git a/src/hooks/rooms/widgets/useChatWidget.ts b/src/hooks/rooms/widgets/useChatWidget.ts index 3cda8753..13a71c80 100644 --- a/src/hooks/rooms/widgets/useChatWidget.ts +++ b/src/hooks/rooms/widgets/useChatWidget.ts @@ -1,8 +1,9 @@ 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 { ChatBubbleMessage, GetAvatarRenderManager, GetConfigurationManager, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; +import { ChatBubbleMessage, ChatEntryType, ChatHistoryCurrentDate, GetAvatarRenderManager, GetConfigurationManager, GetRoomEngine, GetRoomObjectScreenLocation, IRoomChatSettings, LocalizeText, PlaySound, RoomChatFormatter } from '../../../api'; import { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events'; import { useRoom } from '../useRoom'; +import { useChatHistory } from './../../chat-history/useChatHistory'; const avatarColorCache: Map = new Map(); const avatarImageCache: Map = new Map(); @@ -19,6 +20,7 @@ const useChatWidgetState = () => protection: RoomChatSettings.FLOOD_FILTER_NORMAL }); const { roomSession = null } = useRoom(); + const { addChatEntry } = useChatHistory(); const isDisposed = useRef(false); const getScrollSpeed = useMemo(() => @@ -229,20 +231,24 @@ const useChatWidgetState = () => } } + const formattedText = RoomChatFormatter(text); + const color = (avatarColor && (('#' + (avatarColor.toString(16).padStart(6, '0'))) || null)); + const chatMessage = new ChatBubbleMessage( userData.roomIndex, RoomObjectCategory.UNIT, roomSession.roomId, text, - RoomChatFormatter(text), + formattedText, username, new NitroPoint(bubbleLocation.x, bubbleLocation.y), chatType, styleId, imageUrl, - (avatarColor && (('#' + (avatarColor.toString(16).padStart(6, '0'))) || null))); + color); setChatMessages(prevValue => [ ...prevValue, 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 }); }); useRoomEngineEvent(RoomDragEvent.ROOM_DRAG, event =>