change messenger styling

This commit is contained in:
dank074 2021-12-11 17:00:38 -06:00
parent e933e0f677
commit b5ef9abac8
6 changed files with 134 additions and 131 deletions

View File

@ -14,7 +14,7 @@
"@nitrots/nitro-renderer": "file:../nitro-renderer",
"animate.css": "^4.1.1",
"classnames": "^2.3.1",
"node-sass": "^5.0.0",
"node-sass": "^6.0.1",
"react": "^17.0.2",
"react-bootstrap": "^2.0.0-alpha.2",
"react-dom": "^17.0.2",

View File

@ -101,20 +101,7 @@
"elephants"
],
"preload.assets.urls": [
"${images.url}/additions/user_blowkiss.png",
"${images.url}/additions/user_idle_left_1.png",
"${images.url}/additions/user_idle_left_2.png",
"${images.url}/additions/user_idle_right_1.png",
"${images.url}/additions/user_idle_right_2.png",
"${images.url}/additions/user_muted.png",
"${images.url}/additions/user_muted_small.png",
"${images.url}/additions/user_typing.png",
"${images.url}/additions/number_1.png",
"${images.url}/additions/number_2.png",
"${images.url}/additions/number_3.png",
"${images.url}/additions/number_4.png",
"${images.url}/additions/number_5.png",
"${images.url}/additions/pet_experience_bubble.png",
"${asset.url}/bundled/generic/avatar_additions.nitro",
"${images.url}/loading_icon.png",
"${images.url}/clear_icon.png",
"${images.url}/big_arrow.png"

View File

@ -56,6 +56,9 @@ $help-height: 450px;
$nitropedia-width: 400px;
$nitropedia-height: 400px;
$messenger-width: 500px;
$messenger-height: 370px;
.nitro-app {
width: 100%;
height: 100%;

View File

@ -12,20 +12,20 @@ export class MessengerThread
private _participant: MessengerFriend;
private _groups: MessengerThreadChatGroup[];
private _lastUpdated: Date;
private _unread: boolean;
private _unreadCount: number;
constructor(participant: MessengerFriend, isNew: boolean = true)
{
this._participant = participant;
this._groups = [];
this._lastUpdated = new Date();
this._unread = false;
this._unreadCount = 0;
if(isNew)
{
this.addMessage(null, LocalizeText('messenger.moderationinfo'), 0, null, MessengerThreadChat.SECURITY_NOTIFICATION);
this._unread = false;
this._unreadCount = 0;
}
}
@ -45,7 +45,7 @@ export class MessengerThread
group.addChat(chat);
this._lastUpdated = new Date();
this._unread = true;
this._unreadCount++;
return chat;
}
@ -65,7 +65,7 @@ export class MessengerThread
public setRead(): void
{
this._unread = false;
this._unreadCount = 0;
}
public get participant(): MessengerFriend
@ -83,8 +83,13 @@ export class MessengerThread
return this._lastUpdated;
}
public get unreadCount(): number
{
return this._unreadCount;
}
public get unread(): boolean
{
return this._unread;
return this._unreadCount > 0;
}
}

View File

@ -1,24 +1,27 @@
.nitro-friends-messenger {
width: 280px;
resize: both;
width: $messenger-width;
height: $messenger-height;
.friend-head {
.open-chat-entry {
position: relative;
width: 40px;
height: 40px;
overflow: hidden;
border: 2px solid;
border-color: $light;
.icon {
position: absolute;
top: 1px;
right: 1px;
z-index: 10;
&.active {
border-color: #fffde9;
background-color: #ececec
}
.avatar-image {
position: absolute;
margin-left: -27px;
margin-top: -27px;
.friend-head {
width: 45px;
height: 45px;
overflow: hidden;
.avatar-image {
position: absolute;
margin-left: -27px;
margin-top: -27px;
}
}
}
@ -27,8 +30,6 @@
}
.chat-messages {
height: 200px;
min-height: 200px;
overflow-y: auto;
.message-avatar {

View File

@ -4,10 +4,11 @@ import { AddEventLinkTracker, GetSessionDataManager, GetUserProfile, LocalizeTex
import { MESSENGER_MESSAGE_RECEIVED, MESSENGER_NEW_THREAD, PlaySound } from '../../../../api/utils/PlaySound';
import { FriendsMessengerIconEvent } from '../../../../events';
import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../../../hooks';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutButtonGroup, NitroLayoutFlex, NitroLayoutFlexColumn } from '../../../../layout';
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutButton, NitroLayoutButtonGroup, NitroLayoutFlex, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../../../layout';
import { NitroLayoutBase } from '../../../../layout/base';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
import { ItemCountView } from '../../../shared/item-count/ItemCountView';
import { MessengerThread } from '../../common/MessengerThread';
import { MessengerThreadChat } from '../../common/MessengerThreadChat';
import { useFriendsContext } from '../../context/FriendsContext';
@ -15,41 +16,41 @@ import { FriendsMessengerThreadView } from '../messenger-thread/FriendsMessenger
export const FriendsMessengerView: FC<{}> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ messageThreads, setMessageThreads ] = useState<MessengerThread[]>([]);
const [ activeThreadIndex, setActiveThreadIndex ] = useState(-1);
const [ hiddenThreadIndexes, setHiddenThreadIndexes ] = useState<number[]>([]);
const [ messageText, setMessageText ] = useState('');
const [ updateValue, setUpdateValue ] = useState({});
const [isVisible, setIsVisible] = useState(false);
const [messageThreads, setMessageThreads] = useState<MessengerThread[]>([]);
const [activeThreadIndex, setActiveThreadIndex] = useState(-1);
const [hiddenThreadIndexes, setHiddenThreadIndexes] = useState<number[]>([]);
const [messageText, setMessageText] = useState('');
const [updateValue, setUpdateValue] = useState({});
const { friends = [] } = useFriendsContext();
const messagesBox = useRef<HTMLDivElement>();
const followFriend = useCallback(() =>
{
SendMessageHook(new FollowFriendMessageComposer(messageThreads[activeThreadIndex].participant.id));
}, [ messageThreads, activeThreadIndex ]);
}, [messageThreads, activeThreadIndex]);
const openProfile = useCallback(() =>
{
GetUserProfile(messageThreads[activeThreadIndex].participant.id);
}, [ messageThreads, activeThreadIndex ]);
}, [messageThreads, activeThreadIndex]);
const getFriend = useCallback((userId: number) =>
{
return ((friends.find(friend => (friend.id === userId))) || null);
}, [ friends ]);
}, [friends]);
const visibleThreads = useMemo(() =>
{
return messageThreads.filter((thread, index) =>
{
if(hiddenThreadIndexes.indexOf(index) >= 0) return false;
{
if(hiddenThreadIndexes.indexOf(index) >= 0) return false;
return true;
});
}, [ messageThreads, hiddenThreadIndexes ]);
return true;
});
}, [messageThreads, hiddenThreadIndexes]);
const getMessageThreadWithIndex = useCallback<(userId: number) => [ number, MessengerThread ]>((userId: number) =>
const getMessageThreadWithIndex = useCallback<(userId: number) => [number, MessengerThread]>((userId: number) =>
{
if(messageThreads.length > 0)
{
@ -64,43 +65,43 @@ export const FriendsMessengerView: FC<{}> = props =>
if(hiddenIndex >= 0)
{
setHiddenThreadIndexes(prevValue =>
{
const newIndexes = [ ...prevValue ];
{
const newIndexes = [...prevValue];
newIndexes.splice(hiddenIndex, 1);
newIndexes.splice(hiddenIndex, 1);
return newIndexes;
});
return newIndexes;
});
}
return [ i, thread ];
return [i, thread];
}
}
}
const friend = getFriend(userId);
if(!friend) return [ -1, null ];
if(!friend) return [-1, null];
const thread = new MessengerThread(friend);
const newThreads = [ ...messageThreads, thread ];
const newThreads = [...messageThreads, thread];
setMessageThreads(newThreads);
return [ (newThreads.length - 1), thread ];
}, [ messageThreads, hiddenThreadIndexes, getFriend ]);
return [(newThreads.length - 1), thread];
}, [messageThreads, hiddenThreadIndexes, getFriend]);
const onNewConsoleMessageEvent = useCallback((event: NewConsoleMessageEvent) =>
{
const parser = event.getParser();
const [ threadIndex, thread ] = getMessageThreadWithIndex(parser.senderId);
const [threadIndex, thread] = getMessageThreadWithIndex(parser.senderId);
if((threadIndex === -1) || !thread) return;
thread.addMessage(parser.senderId, parser.messageText, parser.secondsSinceSent, parser.extraData);
setMessageThreads(prevValue => [ ...prevValue ]);
}, [ getMessageThreadWithIndex ]);
setMessageThreads(prevValue => [...prevValue]);
}, [getMessageThreadWithIndex]);
CreateMessageHook(NewConsoleMessageEvent, onNewConsoleMessageEvent);
@ -122,17 +123,17 @@ export const FriendsMessengerView: FC<{}> = props =>
BatchUpdates(() =>
{
setMessageThreads(prevValue => [ ...prevValue ]);
setMessageThreads(prevValue => [...prevValue]);
setMessageText('');
});
}, [ messageThreads, activeThreadIndex, messageText ]);
}, [messageThreads, activeThreadIndex, messageText]);
const onKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
{
if(event.key !== 'Enter') return;
sendMessage();
}, [ sendMessage ]);
}, [sendMessage]);
const linkReceived = useCallback((url: string) =>
{
@ -147,7 +148,7 @@ export const FriendsMessengerView: FC<{}> = props =>
return;
}
const [ threadIndex ] = getMessageThreadWithIndex(parseInt(parts[2]));
const [threadIndex] = getMessageThreadWithIndex(parseInt(parts[2]));
if(threadIndex === -1) return;
@ -156,18 +157,18 @@ export const FriendsMessengerView: FC<{}> = props =>
setActiveThreadIndex(threadIndex);
setIsVisible(true);
});
}, [ getMessageThreadWithIndex ]);
}, [getMessageThreadWithIndex]);
const closeThread = useCallback((threadIndex: number) =>
{
setHiddenThreadIndexes(prevValue =>
{
const values = [ ...prevValue ];
{
const values = [...prevValue];
if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
if(values.indexOf(threadIndex) === -1) values.push(threadIndex);
return values;
});
return values;
});
}, []);
useEffect(() =>
@ -180,19 +181,19 @@ export const FriendsMessengerView: FC<{}> = props =>
AddEventLinkTracker(linkTracker);
return () => RemoveLinkEventTracker(linkTracker);
}, [ linkReceived ]);
}, [linkReceived]);
useEffect(() =>
{
if(!isVisible) return;
if(activeThreadIndex === -1) setActiveThreadIndex(0);
}, [ isVisible, activeThreadIndex ]);
}, [isVisible, activeThreadIndex]);
useEffect(() =>
{
if(hiddenThreadIndexes.indexOf(activeThreadIndex) >= 0) setActiveThreadIndex(0);
}, [ activeThreadIndex, hiddenThreadIndexes ]);
}, [activeThreadIndex, hiddenThreadIndexes]);
useEffect(() =>
{
@ -206,7 +207,7 @@ export const FriendsMessengerView: FC<{}> = props =>
activeThread.setRead();
setUpdateValue({});
}
}, [ isVisible, messageThreads, activeThreadIndex ]);
}, [isVisible, messageThreads, activeThreadIndex]);
useEffect(() =>
{
@ -223,7 +224,7 @@ export const FriendsMessengerView: FC<{}> = props =>
for(const thread of visibleThreads)
{
if(thread.unread)
if(thread.unreadCount > 0)
{
isUnread = true;
@ -232,67 +233,73 @@ export const FriendsMessengerView: FC<{}> = props =>
}
if(isUnread) PlaySound(MESSENGER_MESSAGE_RECEIVED);
dispatchUiEvent(new FriendsMessengerIconEvent(FriendsMessengerIconEvent.UPDATE_ICON, isUnread ? FriendsMessengerIconEvent.UNREAD_ICON : FriendsMessengerIconEvent.SHOW_ICON));
}, [ visibleThreads, updateValue ]);
}, [visibleThreads, updateValue]);
if(!isVisible) return null;
return (
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('messenger.window.title', [ 'OPEN_CHAT_COUNT' ], [ visibleThreads.length.toString() ]) } onCloseClick={ event => setIsVisible(false) } />
<NitroCardView className="nitro-friends-messenger" uniqueKey="nitro-friends-messenger" simple={true}>
<NitroCardHeaderView headerText={LocalizeText('messenger.window.title', ['OPEN_CHAT_COUNT'], [visibleThreads.length.toString()])} onCloseClick={event => setIsVisible(false)} />
<NitroCardContentView>
<NitroLayoutFlex gap={ 2 } overflow="auto">
{ visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
<NitroLayoutGrid>
<NitroLayoutGridColumn size={ 4 }>
<NitroLayoutBase className='text-black fw-bold fs-5'>{LocalizeText('toolbar.icon.label.messenger')}</NitroLayoutBase>
<NitroLayoutFlexColumn className='h-100 overflow-auto'>
{visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) =>
{
const messageThreadIndex = messageThreads.indexOf(thread);
return (
<div key={ index } className="position-relative friend-head rounded flex-shrink-0 cursor-pointer bg-muted" onClick={ event => setActiveThreadIndex(messageThreadIndex) }>
{ thread.unread &&
<NitroLayoutBase className="position-absolute nitro-friends-spritesheet icon-new-message top-1 end-1 z-index-1" /> }
{ thread.participant.id > 0 && <AvatarImageView figure={ thread.participant.figure } headOnly={ true } direction={ 3 } />}
{ thread.participant.id <= 0 && <BadgeImageView isGroup={ true } badgeCode={thread.participant.figure } /> }
</div>
<NitroLayoutFlex key={index} className={`open-chat-entry p-1 cursor-pointer rounded ${activeThreadIndex === messageThreadIndex ? 'active' : ''}`} onClick={event => setActiveThreadIndex(messageThreadIndex)}>
{thread.unread &&
<ItemCountView count={ thread.unreadCount }/>
}
<div className="friend-head rounded flex-shrink-0">
{thread.participant.id > 0 && <AvatarImageView figure={thread.participant.figure} headOnly={true} direction={3} />}
{thread.participant.id <= 0 && <BadgeImageView isGroup={true} badgeCode={thread.participant.figure} />}
</div>
<NitroLayoutBase className='d-flex text-truncate text-black ms-1 align-items-center'>{thread.participant.name}</NitroLayoutBase>
</NitroLayoutFlex>
);
}) }
</NitroLayoutFlex>
<NitroLayoutFlex className="align-items-center my-1" position="relative">
{ (activeThreadIndex >= 0) &&
<NitroLayoutBase className="text-black bg-light pe-2 flex-none">
{ LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) }
</NitroLayoutBase> }
<hr className="bg-dark m-0 w-100" />
</NitroLayoutFlex>
{ (activeThreadIndex >= 0) &&
<>
<NitroLayoutFlex className="mb-2" gap={ 2 }>
<NitroLayoutButtonGroup>
<NitroLayoutButton variant="primary" size="sm" onClick={ followFriend }>
<NitroLayoutBase className="nitro-friends-spritesheet icon-follow" />
</NitroLayoutButton>
<NitroLayoutButton variant="primary" size="sm" onClick={ openProfile }>
<NitroLayoutBase className="nitro-friends-spritesheet icon-profile-sm" />
</NitroLayoutButton>
</NitroLayoutButtonGroup>
<NitroLayoutButton variant="danger" size="sm" onClick={ openProfile }>
{ LocalizeText('messenger.window.button.report') }
</NitroLayoutButton>
<NitroLayoutButton className="ms-auto" variant="primary" size="sm" onClick={ event => closeThread(activeThreadIndex) }>
<NitroLayoutBase className="fas fa-times" />
</NitroLayoutButton>
</NitroLayoutFlex>
<NitroLayoutFlexColumn innerRef={ messagesBox } className="bg-muted p-2 rounded chat-messages mb-2">
<FriendsMessengerThreadView thread={ messageThreads[activeThreadIndex] } />
})}
</NitroLayoutFlexColumn>
<NitroLayoutFlex gap={ 2 }>
<input type="text" className="form-control form-control-sm" placeholder={ LocalizeText('messenger.window.input.default', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) } value={ messageText } onChange={ event => setMessageText(event.target.value) } onKeyDown={ onKeyDown } />
<NitroLayoutButton variant="success" size="sm" onClick={ sendMessage }>
{ LocalizeText('widgets.chatinput.say') }
</NitroLayoutButton>
</NitroLayoutFlex>
</> }
</NitroLayoutGridColumn>
<NitroLayoutGridColumn size={ 8 }>
{(activeThreadIndex >= 0) &&
<>
<NitroLayoutBase className='mb-2 text-black text-center fw-bold fs-6'>{LocalizeText('messenger.window.separator', ['FRIEND_NAME'], [messageThreads[activeThreadIndex].participant.name])}</NitroLayoutBase>
<NitroLayoutFlex className="mb-2" gap={2}>
<NitroLayoutButtonGroup>
<NitroLayoutButton variant="primary" size="sm" onClick={followFriend}>
<NitroLayoutBase className="nitro-friends-spritesheet icon-follow" />
</NitroLayoutButton>
<NitroLayoutButton variant="primary" size="sm" onClick={openProfile}>
<NitroLayoutBase className="nitro-friends-spritesheet icon-profile-sm" />
</NitroLayoutButton>
</NitroLayoutButtonGroup>
<NitroLayoutButton variant="danger" size="sm" onClick={openProfile}>
{LocalizeText('messenger.window.button.report')}
</NitroLayoutButton>
<NitroLayoutButton className="ms-auto" variant="primary" size="sm" onClick={event => closeThread(activeThreadIndex)}>
<NitroLayoutBase className="fas fa-times" />
</NitroLayoutButton>
</NitroLayoutFlex>
<NitroLayoutFlexColumn innerRef={messagesBox} className="bg-muted p-2 rounded chat-messages mb-2 h-100 w-100">
<FriendsMessengerThreadView thread={messageThreads[activeThreadIndex]} />
</NitroLayoutFlexColumn>
<NitroLayoutFlex gap={2}>
<input type="text" className="form-control form-control-sm" placeholder={LocalizeText('messenger.window.input.default', ['FRIEND_NAME'], [messageThreads[activeThreadIndex].participant.name])} value={messageText} onChange={event => setMessageText(event.target.value)} onKeyDown={onKeyDown} />
<NitroLayoutButton variant="success" size="sm" onClick={sendMessage}>
{LocalizeText('widgets.chatinput.say')}
</NitroLayoutButton>
</NitroLayoutFlex>
</>}
</NitroLayoutGridColumn>
</NitroLayoutGrid>
</NitroCardContentView>
</NitroCardView>
);