mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-26 15:40:51 +01:00
Chat History update
This commit is contained in:
parent
e9d9fd4253
commit
0d0f1bf62c
@ -6,6 +6,10 @@ export interface IChatEntry
|
|||||||
look?: string;
|
look?: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
entityType?: number;
|
entityType?: number;
|
||||||
|
style?: number;
|
||||||
|
chatType?: number;
|
||||||
|
imageUrl?: string;
|
||||||
|
color?: string;
|
||||||
roomId: number;
|
roomId: number;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
type: number;
|
type: number;
|
||||||
|
@ -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 { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { AutoSizer, CellMeasurer, CellMeasurerCache, List, ListRowProps, ListRowRenderer, Size } from 'react-virtualized';
|
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 { Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||||
import { useChatHistory } from '../../hooks';
|
import { useChatHistory } from '../../hooks';
|
||||||
|
|
||||||
|
const avatarColorCache: Map<string, number> = new Map();
|
||||||
|
const avatarImageCache: Map<string, string> = new Map();
|
||||||
|
|
||||||
export const ChatHistoryView: FC<{}> = props =>
|
export const ChatHistoryView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const { chatHistory = [] } = useChatHistory();
|
const { chatHistory = [] } = useChatHistory();
|
||||||
const elementRef = useRef<List>(null);
|
const elementRef = useRef<List>(null);
|
||||||
|
|
||||||
|
const [ searchText, setSearchText ] = useState<string>('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 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 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 (
|
return (
|
||||||
<CellMeasurer cache={ cache } columnIndex={ 0 } key={ props.key } parent={ props.parent } rowIndex={ props.index }>
|
<CellMeasurer cache={ cache } columnIndex={ 0 } key={ props.key } parent={ props.parent } rowIndex={ props.index }>
|
||||||
<Flex key={ props.key } style={ props.style } className="p-1" gap={ 1 }>
|
<Flex key={ props.key } style={ props.style } className="p-1" gap={ 2 }>
|
||||||
<Text variant="muted">{ item.timestamp }</Text>
|
<Text variant="muted">{ item.timestamp }</Text>
|
||||||
{ (item.type === ChatEntryType.TYPE_CHAT) &&
|
{ (item.type === ChatEntryType.TYPE_CHAT) &&
|
||||||
<>
|
<div className="bubble-container" style={ { position: 'relative' } }>
|
||||||
<Text pointer noWrap dangerouslySetInnerHTML={ { __html: (item.name + ':') } } />
|
{ (item.style === 0) &&
|
||||||
<Text textBreak wrap grow>{ item.message }</Text>
|
<div className="user-container-bg" style={ { backgroundColor: item.color } } /> }
|
||||||
</> }
|
<div className={ `chat-bubble bubble-${ item.style } type-${ item.chatType }` } style={ { maxWidth: '100%' } }>
|
||||||
|
<div className="user-container">
|
||||||
|
{ item.imageUrl && (item.imageUrl.length > 0) &&
|
||||||
|
<div className="user-image" style={ { backgroundImage: `url(${ item.imageUrl })` } } /> }
|
||||||
|
</div>
|
||||||
|
<div className="chat-content">
|
||||||
|
<b className="username mr-1" dangerouslySetInnerHTML={ { __html: `${ item.name }: ` } } />
|
||||||
|
<span className="message" dangerouslySetInnerHTML={ { __html: `${ item.message }` } } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> }
|
||||||
{ (item.type === ChatEntryType.TYPE_ROOM_INFO) &&
|
{ (item.type === ChatEntryType.TYPE_ROOM_INFO) &&
|
||||||
<>
|
<>
|
||||||
<i className="icon icon-small-room" />
|
<i className="icon icon-small-room" />
|
||||||
@ -81,22 +138,27 @@ export const ChatHistoryView: FC<{}> = props =>
|
|||||||
<NitroCardView uniqueKey="chat-history" className="nitro-chat-history" theme="primary-slim">
|
<NitroCardView uniqueKey="chat-history" className="nitro-chat-history" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('room.chathistory.button.text') } onCloseClick={ event => setIsVisible(false) }/>
|
<NitroCardHeaderView headerText={ LocalizeText('room.chathistory.button.text') } onCloseClick={ event => setIsVisible(false) }/>
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<AutoSizer defaultWidth={ 300 } defaultHeight={ 200 } onResize={ onResize }>
|
<Flex column fullHeight gap={ 2 }>
|
||||||
{ ({ height, width }) =>
|
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } value={ searchText } onChange={ event => setSearchText(event.target.value) } />
|
||||||
{
|
<div className="h-100">
|
||||||
return (
|
<AutoSizer defaultWidth={ 300 } defaultHeight={ 170 } onResize={ onResize }>
|
||||||
<List
|
{ ({ height, width }) =>
|
||||||
ref={ elementRef }
|
{
|
||||||
width={ width }
|
return (
|
||||||
height={ height }
|
<List
|
||||||
rowCount={ chatHistory.length }
|
ref={ elementRef }
|
||||||
rowHeight={ cache.rowHeight }
|
width={ width }
|
||||||
className={ 'chat-history-list' }
|
height={ height }
|
||||||
rowRenderer={ RowRenderer }
|
rowCount={ chatHistory.length }
|
||||||
deferredMeasurementCache={ cache } />
|
rowHeight={ cache.rowHeight }
|
||||||
)
|
className={ 'chat-history-list' }
|
||||||
} }
|
rowRenderer={ RowRenderer }
|
||||||
</AutoSizer>
|
deferredMeasurementCache={ cache } />
|
||||||
|
)
|
||||||
|
} }
|
||||||
|
</AutoSizer>
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView>
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
|
@ -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 { useState } from 'react';
|
||||||
import { useBetween } from 'use-between';
|
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';
|
import { useMessageEvent, useRoomSessionManagerEvent } from '../events';
|
||||||
|
|
||||||
const CHAT_HISTORY_MAX = 1000;
|
const CHAT_HISTORY_MAX = 1000;
|
||||||
@ -63,19 +63,6 @@ const useChatHistoryState = () =>
|
|||||||
return newValue;
|
return newValue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
useRoomSessionManagerEvent<RoomSessionChatEvent>(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>(RoomSessionEvent.STARTED, event => setNeedsRoomInsert(true));
|
useRoomSessionManagerEvent<RoomSessionEvent>(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 });
|
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);
|
export const useChatHistory = () => useBetween(useChatHistoryState);
|
||||||
|
@ -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 { 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 { 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 { useMessageEvent, useRoomEngineEvent, useRoomSessionManagerEvent } from '../../events';
|
||||||
import { useRoom } from '../useRoom';
|
import { useRoom } from '../useRoom';
|
||||||
|
import { useChatHistory } from './../../chat-history/useChatHistory';
|
||||||
|
|
||||||
const avatarColorCache: Map<string, number> = new Map();
|
const avatarColorCache: Map<string, number> = new Map();
|
||||||
const avatarImageCache: Map<string, string> = new Map();
|
const avatarImageCache: Map<string, string> = new Map();
|
||||||
@ -19,6 +20,7 @@ const useChatWidgetState = () =>
|
|||||||
protection: RoomChatSettings.FLOOD_FILTER_NORMAL
|
protection: RoomChatSettings.FLOOD_FILTER_NORMAL
|
||||||
});
|
});
|
||||||
const { roomSession = null } = useRoom();
|
const { roomSession = null } = useRoom();
|
||||||
|
const { addChatEntry } = useChatHistory();
|
||||||
const isDisposed = useRef(false);
|
const isDisposed = useRef(false);
|
||||||
|
|
||||||
const getScrollSpeed = useMemo(() =>
|
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(
|
const chatMessage = new ChatBubbleMessage(
|
||||||
userData.roomIndex,
|
userData.roomIndex,
|
||||||
RoomObjectCategory.UNIT,
|
RoomObjectCategory.UNIT,
|
||||||
roomSession.roomId,
|
roomSession.roomId,
|
||||||
text,
|
text,
|
||||||
RoomChatFormatter(text),
|
formattedText,
|
||||||
username,
|
username,
|
||||||
new NitroPoint(bubbleLocation.x, bubbleLocation.y),
|
new NitroPoint(bubbleLocation.x, bubbleLocation.y),
|
||||||
chatType,
|
chatType,
|
||||||
styleId,
|
styleId,
|
||||||
imageUrl,
|
imageUrl,
|
||||||
(avatarColor && (('#' + (avatarColor.toString(16).padStart(6, '0'))) || null)));
|
color);
|
||||||
|
|
||||||
setChatMessages(prevValue => [ ...prevValue, chatMessage ]);
|
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>(RoomDragEvent.ROOM_DRAG, event =>
|
useRoomEngineEvent<RoomDragEvent>(RoomDragEvent.ROOM_DRAG, event =>
|
||||||
|
Loading…
Reference in New Issue
Block a user