diff --git a/package.json b/package.json index 6a5eeca1..e049da50 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/public/renderer-config.json b/public/renderer-config.json index 40a50115..1c0e5540 100644 --- a/public/renderer-config.json +++ b/public/renderer-config.json @@ -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" diff --git a/src/App.scss b/src/App.scss index 2849b9bf..db2b719e 100644 --- a/src/App.scss +++ b/src/App.scss @@ -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%; diff --git a/src/views/friends/common/MessengerThread.ts b/src/views/friends/common/MessengerThread.ts index cc2f0f48..a1bfe0e7 100644 --- a/src/views/friends/common/MessengerThread.ts +++ b/src/views/friends/common/MessengerThread.ts @@ -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; } } diff --git a/src/views/friends/views/messenger/FriendsMessengerView.scss b/src/views/friends/views/messenger/FriendsMessengerView.scss index 596ab19f..b36cfbc0 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.scss +++ b/src/views/friends/views/messenger/FriendsMessengerView.scss @@ -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 { diff --git a/src/views/friends/views/messenger/FriendsMessengerView.tsx b/src/views/friends/views/messenger/FriendsMessengerView.tsx index 4760cbc9..5544e2b1 100644 --- a/src/views/friends/views/messenger/FriendsMessengerView.tsx +++ b/src/views/friends/views/messenger/FriendsMessengerView.tsx @@ -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([]); - const [ activeThreadIndex, setActiveThreadIndex ] = useState(-1); - const [ hiddenThreadIndexes, setHiddenThreadIndexes ] = useState([]); - const [ messageText, setMessageText ] = useState(''); - const [ updateValue, setUpdateValue ] = useState({}); + const [isVisible, setIsVisible] = useState(false); + const [messageThreads, setMessageThreads] = useState([]); + const [activeThreadIndex, setActiveThreadIndex] = useState(-1); + const [hiddenThreadIndexes, setHiddenThreadIndexes] = useState([]); + const [messageText, setMessageText] = useState(''); + const [updateValue, setUpdateValue] = useState({}); const { friends = [] } = useFriendsContext(); const messagesBox = useRef(); 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) => { 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 ( - - setIsVisible(false) } /> + + setIsVisible(false)} /> - - { visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) => + + + {LocalizeText('toolbar.icon.label.messenger')} + + {visibleThreads && (visibleThreads.length > 0) && visibleThreads.map((thread, index) => { const messageThreadIndex = messageThreads.indexOf(thread); return ( -
setActiveThreadIndex(messageThreadIndex) }> - { thread.unread && - } - { thread.participant.id > 0 && } - { thread.participant.id <= 0 && } - -
+ setActiveThreadIndex(messageThreadIndex)}> + {thread.unread && + + } +
+ + {thread.participant.id > 0 && } + {thread.participant.id <= 0 && } + +
+ {thread.participant.name} +
); - }) } -
- - { (activeThreadIndex >= 0) && - - { LocalizeText('messenger.window.separator', [ 'FRIEND_NAME' ], [ messageThreads[activeThreadIndex].participant.name ]) } - } -
-
- { (activeThreadIndex >= 0) && - <> - - - - - - - - - - - { LocalizeText('messenger.window.button.report') } - - closeThread(activeThreadIndex) }> - - - - - + })} - - setMessageText(event.target.value) } onKeyDown={ onKeyDown } /> - - { LocalizeText('widgets.chatinput.say') } - - - } + + + {(activeThreadIndex >= 0) && + <> + {LocalizeText('messenger.window.separator', ['FRIEND_NAME'], [messageThreads[activeThreadIndex].participant.name])} + + + + + + + + + + + {LocalizeText('messenger.window.button.report')} + + closeThread(activeThreadIndex)}> + + + + + + + + setMessageText(event.target.value)} onKeyDown={onKeyDown} /> + + {LocalizeText('widgets.chatinput.say')} + + + } + +
);