Chats move

This commit is contained in:
Bill 2021-06-30 06:10:19 -04:00
parent dfaf239052
commit 37d614e168
6 changed files with 140 additions and 70 deletions

View File

@ -0,0 +1,41 @@
import { NitroPoint, NitroRectangle } from 'nitro-renderer';
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetRoomViewUpdateEvent extends RoomWidgetUpdateEvent
{
public static SIZE_CHANGED: string = 'RWRVUE_ROOM_VIEW_SIZE_CHANGED';
public static SCALE_CHANGED: string = 'RWRVUE_ROOM_VIEW_SCALE_CHANGED';
public static POSITION_CHANGED: string = 'RWRVUE_ROOM_VIEW_POSITION_CHANGED';
private _roomViewRectangle: NitroRectangle;
private _positionDelta: NitroPoint;
private _scale: number;
constructor(type: string, view: NitroRectangle = null, position: NitroPoint = null, scale: number = 0)
{
super(type);
this._roomViewRectangle = view;
this._positionDelta = position;
this._scale = scale;
}
public get roomViewRectangle(): NitroRectangle
{
if(!this._roomViewRectangle) return null;
return this._roomViewRectangle.clone();
}
public get positionDelta(): NitroPoint
{
if(!this._positionDelta) return null;
return this._positionDelta.clone();
}
public get scale(): number
{
return this._scale;
}
}

View File

@ -2,6 +2,7 @@ export * from './RoomWidgetAvatarInfoEvent';
export * from './RoomWidgetObjectNameEvent'; export * from './RoomWidgetObjectNameEvent';
export * from './RoomWidgetRoomEngineUpdateEvent'; export * from './RoomWidgetRoomEngineUpdateEvent';
export * from './RoomWidgetRoomObjectUpdateEvent'; export * from './RoomWidgetRoomObjectUpdateEvent';
export * from './RoomWidgetRoomViewUpdateEvent';
export * from './RoomWidgetUpdateDanceStatusEvent'; export * from './RoomWidgetUpdateDanceStatusEvent';
export * from './RoomWidgetUpdateEvent'; export * from './RoomWidgetUpdateEvent';
export * from './RoomWidgetUpdateInfostandEvent'; export * from './RoomWidgetUpdateInfostandEvent';

View File

@ -1,6 +1,7 @@
import { RoomObjectCategory, RoomSessionChatEvent } from 'nitro-renderer'; import { RoomDragEvent, RoomObjectCategory, RoomSessionChatEvent } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../../../api'; import { GetRoomEngine, GetRoomSession } from '../../../../api';
import { useRoomEngineEvent } from '../../../../hooks/events';
import { useRoomSessionManagerEvent } from '../../../../hooks/events/nitro/session/room-session-manager-event'; import { useRoomSessionManagerEvent } from '../../../../hooks/events/nitro/session/room-session-manager-event';
import { useRoomContext } from '../../context/RoomContext'; import { useRoomContext } from '../../context/RoomContext';
import { ChatWidgetViewProps } from './ChatWidgetView.types'; import { ChatWidgetViewProps } from './ChatWidgetView.types';
@ -10,8 +11,8 @@ import { GetBubbleLocation } from './utils/ChatWidgetUtilities';
export const ChatWidgetView: FC<ChatWidgetViewProps> = props => export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{ {
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const [ chatMessages, setChatMessages ] = useState<ChatBubbleMessage[]>([]); const [ chatMessages, setChatMessages ] = useState<ChatBubbleMessage[]>([]);
const { roomSession = null } = useRoomContext();
const elementRef = useRef<HTMLDivElement>(); const elementRef = useRef<HTMLDivElement>();
const removeFirstHiddenChat = useCallback(() => const removeFirstHiddenChat = useCallback(() =>
@ -20,7 +21,7 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
const lastChat = chatMessages[0]; const lastChat = chatMessages[0];
if((lastChat.lastTop > (-(lastChat.height) * 2))) return; if((lastChat.top > (-(lastChat.height) * 2))) return;
setChatMessages(prevValue => setChatMessages(prevValue =>
{ {
@ -34,9 +35,7 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
const moveChatUp = useCallback((chat: ChatBubbleMessage, amount: number) => const moveChatUp = useCallback((chat: ChatBubbleMessage, amount: number) =>
{ {
chat.lastTop -= amount; chat.top -= amount;
if(chat.elementRef) chat.elementRef.style.top = (chat.lastTop + 'px');
}, []); }, []);
const moveAllChatsUp = useCallback((amount: number) => const moveAllChatsUp = useCallback((amount: number) =>
@ -48,7 +47,7 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
const makeRoom = useCallback((chat: ChatBubbleMessage) => const makeRoom = useCallback((chat: ChatBubbleMessage) =>
{ {
const lowestPoint = ((chat.lastTop + chat.height) - 1); const lowestPoint = ((chat.top + chat.height) - 1);
const requiredSpace = (chat.height + 1); const requiredSpace = (chat.height + 1);
const spaceAvailable = (elementRef.current.offsetHeight - lowestPoint); const spaceAvailable = (elementRef.current.offsetHeight - lowestPoint);
@ -56,11 +55,11 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{ {
const amount = (requiredSpace - spaceAvailable); const amount = (requiredSpace - spaceAvailable);
chatMessages.forEach((existingChat, index) => chatMessages.forEach(existingChat =>
{ {
if(existingChat === chat) return; if(existingChat === chat) return;
moveChatUp(existingChat, amount) moveChatUp(existingChat, amount);
}); });
} }
}, [ chatMessages, moveChatUp ]); }, [ chatMessages, moveChatUp ]);
@ -69,7 +68,7 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{ {
setChatMessages(prevValue => setChatMessages(prevValue =>
{ {
return [ ...prevValue, chat ] return [ ...prevValue, chat ];
}); });
}, []); }, []);
@ -80,11 +79,6 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
if(!roomObject) return; if(!roomObject) return;
const canvasId = 1; const canvasId = 1;
const roomGeometry = GetRoomEngine().getRoomInstanceGeometry(event.session.roomId, canvasId);
if(!roomGeometry) return;
const objectLocation = roomObject.getLocation(); const objectLocation = roomObject.getLocation();
const bubbleLocation = GetBubbleLocation(event.session.roomId, objectLocation, canvasId); const bubbleLocation = GetBubbleLocation(event.session.roomId, objectLocation, canvasId);
const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.objectId); const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.objectId);
@ -138,31 +132,37 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionChatEvent); useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionChatEvent);
// useEffect(() => const onRoomDragEvent = useCallback((event: RoomDragEvent) =>
// { {
// const interval = setInterval(() => moveAllChatsUp(15), 500); if(!chatMessages.length) return;
// return () => if(event.roomId !== roomSession.roomId) return;
// {
// if(interval) clearInterval(interval); chatMessages.forEach(chat =>
// } {
// }, [ chatMessages, moveAllChatsUp ]); if(!chat.elementRef) return;
chat.left = (chat.elementRef.offsetLeft + event.offsetX);
});
}, [ roomSession, chatMessages ]);
useRoomEngineEvent(RoomDragEvent.ROOM_DRAG, onRoomDragEvent);
useEffect(() => useEffect(() =>
{ {
const interval = setInterval(() => removeFirstHiddenChat(), 1000); const interval = setInterval(() => moveAllChatsUp(15), 4500);
return () => return () =>
{ {
if(interval) clearInterval(interval); if(interval) clearInterval(interval);
} }
}, [ removeFirstHiddenChat ]); }, [ chatMessages, moveAllChatsUp ]);
return ( return (
<div ref={ elementRef } className="nitro-chat-widget"> <div ref={ elementRef } className="nitro-chat-widget">
{ chatMessages && (chatMessages.length > 0) && chatMessages.map((chat, index) => { chatMessages.map(chat =>
{ {
return <ChatWidgetMessageView key={ index } chat={ chat } makeRoom={ makeRoom } /> return <ChatWidgetMessageView key={ chat.id } chat={ chat } makeRoom={ makeRoom } />
})} })}
</div> </div>
); );

View File

@ -1,11 +1,10 @@
import { FC, MouseEvent, useCallback, useEffect, useRef, useState } from 'react'; import { FC, MouseEvent, useCallback, useEffect, useRef, useState } from 'react';
import { GetSessionDataManager } from '../../../../../api';
import { ChatWidgetMessageViewProps } from './ChatWidgetMessageView.types'; import { ChatWidgetMessageViewProps } from './ChatWidgetMessageView.types';
export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props => export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
{ {
const { chat = null, makeRoom = null } = props; const { chat = null, makeRoom = null } = props;
const [ isVisible, setIsVisible ] = useState(true); const [ isVisible, setIsVisible ] = useState(false);
const [ messageParts, setMessageParts ] = useState<{text: string, className?: string, style?: any, onClick?: () => void}[]>(null); const [ messageParts, setMessageParts ] = useState<{text: string, className?: string, style?: any, onClick?: () => void}[]>(null);
const elementRef = useRef<HTMLDivElement>(); const elementRef = useRef<HTMLDivElement>();
@ -14,37 +13,37 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
}, []); }, []);
useEffect(() => // useEffect(() =>
{ // {
if(messageParts) return; // if(messageParts) return;
const userNameMention = '@' + GetSessionDataManager().userName; // const userNameMention = '@' + GetSessionDataManager().userName;
const matches = [...chat.text.matchAll(new RegExp(userNameMention + '\\b', 'gi'))]; // const matches = [...chat.text.matchAll(new RegExp(userNameMention + '\\b', 'gi'))];
if(matches.length > 0) // if(matches.length > 0)
{ // {
const prevText = chat.text.substr(0, matches[0].index); // const prevText = chat.text.substr(0, matches[0].index);
const postText = chat.text.substring(matches[0].index + userNameMention.length, chat.text.length); // const postText = chat.text.substring(matches[0].index + userNameMention.length, chat.text.length);
setMessageParts( // setMessageParts(
[ // [
{ text: prevText }, // { text: prevText },
{ text: userNameMention, className: 'chat-mention', onClick: () => {alert('I clicked in the mention')}}, // { text: userNameMention, className: 'chat-mention', onClick: () => {alert('I clicked in the mention')}},
{ text: postText } // { text: postText }
] // ]
); // );
} // }
else // else
{ // {
setMessageParts( // setMessageParts(
[ // [
{ text: chat.text } // { text: chat.text }
] // ]
); // );
} // }
}, [ chat ]); // }, [ chat ]);
useEffect(() => useEffect(() =>
{ {
@ -59,34 +58,35 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
chat.height = height; chat.height = height;
chat.elementRef = element; chat.elementRef = element;
let left = chat.lastLeft; let left = chat.left;
let top = chat.lastTop; let top = chat.top;
if(!left && !top) if(!left && !top)
{ {
left = (chat.location.x - (width / 2)); left = (chat.location.x - (width / 2));
top = (element.parentElement.offsetHeight - height); top = (element.parentElement.offsetHeight - height);
chat.lastLeft = left; chat.left = left;
chat.lastTop = top; chat.top = top;
} }
element.style.left = (left + 'px');
element.style.top = (top + 'px');
if(!chat.visible) if(!chat.visible)
{ {
makeRoom(chat); makeRoom(chat);
}
chat.visible = true; chat.visible = true;
//setIsVisible(true); }
return () => return () =>
{ {
chat.elementRef = null; chat.elementRef = null;
} }
}, [ elementRef, isVisible, chat, makeRoom ]); }, [ elementRef, chat, makeRoom ]);
useEffect(() =>
{
setIsVisible(chat.visible);
}, [ chat.visible ]);
return ( return (
<div ref={ elementRef } className="bubble-container" style={ { visibility: (isVisible ? 'visible' : 'hidden') } }> <div ref={ elementRef } className="bubble-container" style={ { visibility: (isVisible ? 'visible' : 'hidden') } }>
@ -96,7 +96,9 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
{ (chat.imageUrl && (chat.imageUrl !== '')) && <div className="user-image" style={ { backgroundImage: 'url(' + chat.imageUrl + ')' } } /> } { (chat.imageUrl && (chat.imageUrl !== '')) && <div className="user-image" style={ { backgroundImage: 'url(' + chat.imageUrl + ')' } } /> }
</div> </div>
<div className="chat-content"> <div className="chat-content">
<b className="username mr-1">{ chat.username }</b><span className="message"> { <b className="username mr-1">{ chat.username }</b>
{ chat.text }
<span className="message"> {
messageParts && messageParts.map((part, index) => messageParts && messageParts.map((part, index) =>
{ {
return <span key={ index } className={ part.className } style={ part.style } onClick={ part.onClick }>{ part.text }</span> return <span key={ index } className={ part.className } style={ part.style } onClick={ part.onClick }>{ part.text }</span>

View File

@ -2,15 +2,16 @@ import { INitroPoint } from 'nitro-renderer';
export class ChatBubbleMessage export class ChatBubbleMessage
{ {
public static BUBBLE_COUNTER: number = -1; public static BUBBLE_COUNTER: number = 0;
public id: number = -1; public id: number = -1;
public width: number = 0; public width: number = 0;
public height: number = 0; public height: number = 0;
public lastTop: number = 0;
public lastLeft: number = 0;
public elementRef: HTMLDivElement = null; public elementRef: HTMLDivElement = null;
public visible: boolean = false; public visible: boolean = false;
private _top: number = 0;
private _left: number = 0;
constructor( constructor(
public text: string = '', public text: string = '',
@ -23,4 +24,28 @@ export class ChatBubbleMessage
) { ) {
this.id = ++ChatBubbleMessage.BUBBLE_COUNTER; this.id = ++ChatBubbleMessage.BUBBLE_COUNTER;
} }
public get top(): number
{
return this._top;
}
public set top(value: number)
{
this._top = value;
if(this.elementRef) this.elementRef.style.top = (this._top + 'px');
}
public get left(): number
{
return this._top;
}
public set left(value: number)
{
this._left = value;
if(this.elementRef) this.elementRef.style.left = (this._left + 'px');
}
} }

View File

@ -6,6 +6,7 @@
border: 2px solid rgba($white, 0.5); border: 2px solid rgba($white, 0.5);
border-radius: $border-radius; border-radius: $border-radius;
font-size: $font-size-sm; font-size: $font-size-sm;
z-index: $context-menu-zindex;
&.name-only { &.name-only {
background-color: rgba($black, 0.7); background-color: rgba($black, 0.7);