This commit is contained in:
MyNameIsBatman 2021-09-18 04:09:49 -03:00
parent f5d47756ce
commit a54be45a4f
10 changed files with 110 additions and 27 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

View File

@ -693,6 +693,18 @@
height: 16px; height: 16px;
} }
&.icon-friendlist-warning {
background: url('../images/friendlist/icons/icon_warning.png');
width: 23px;
height: 21px;
}
&.icon-friendlist-new-message {
background: url('../images/friendlist/icons/icon_new_message.png');
width: 14px;
height: 16px;
}
&.spin { &.spin {
animation: rotating 1s linear infinite; animation: rotating 1s linear infinite;
} }

View File

@ -77,7 +77,8 @@ export const FriendsMessageHandler: FC<{}> = props =>
dispatchFriendsState({ dispatchFriendsState({
type: FriendsActions.ADD_CHAT_MESSAGE, type: FriendsActions.ADD_CHAT_MESSAGE,
payload: { payload: {
chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData) chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, userId, parser.messageText, parser.secondsSinceSent, parser.extraData),
boolValue: true
} }
}); });
}, [ dispatchFriendsState ]); }, [ dispatchFriendsState ]);

View File

@ -6,19 +6,25 @@ export class MessengerChat
private _isRead: boolean; private _isRead: boolean;
private _messageGroups: MessengerChatMessageGroup[]; private _messageGroups: MessengerChatMessageGroup[];
constructor(friendId: number, isRead: boolean = true) constructor(friendId: number)
{ {
this._friendId = friendId; this._friendId = friendId;
this._isRead = isRead; this._isRead = true;
this._messageGroups = []; this._messageGroups = [];
} }
public addMessage(message: MessengerChatMessage): void public addMessage(message: MessengerChatMessage, setAsNotRead: boolean = true, isSystem: boolean = false): void
{ {
if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId)); if(!this.lastMessageGroup || this.lastMessageGroup.userId !== message.senderId || isSystem || this.lastMessageGroup.isSystem) this._messageGroups.push(new MessengerChatMessageGroup(message.senderId, isSystem));
this.lastMessageGroup.addMessage(message); this.lastMessageGroup.addMessage(message);
this._isRead = false;
if(setAsNotRead) this._isRead = false;
}
public read(): void
{
this._isRead = true;
} }
public get friendId(): number public get friendId(): number

View File

@ -2,7 +2,8 @@ export class MessengerChatMessage
{ {
public static MESSAGE: number = 0; public static MESSAGE: number = 0;
public static ROOM_INVITE: number = 1; public static ROOM_INVITE: number = 1;
public static SYSTEM_NOTIFICATION: number = 2; public static SECURITY_ALERT: number = 2;
public static STATUS_ALERT: number = 3;
private _type: number; private _type: number;
private _senderId: number; private _senderId: number;

View File

@ -4,11 +4,13 @@ export class MessengerChatMessageGroup
{ {
private _userId: number; private _userId: number;
private _messages: MessengerChatMessage[]; private _messages: MessengerChatMessage[];
private _isSystem: boolean;
constructor(userId: number) constructor(userId: number, isSystem: boolean)
{ {
this._userId = userId; this._userId = userId;
this._messages = []; this._messages = [];
this._isSystem = isSystem;
} }
public addMessage(message: MessengerChatMessage): void public addMessage(message: MessengerChatMessage): void
@ -25,4 +27,9 @@ export class MessengerChatMessageGroup
{ {
return this._messages; return this._messages;
} }
public get isSystem(): boolean
{
return this._isSystem;
}
} }

View File

@ -19,6 +19,7 @@ export interface IFriendsState
friends: MessengerFriend[]; friends: MessengerFriend[];
requests: MessengerRequest[]; requests: MessengerRequest[];
activeChats: MessengerChat[]; activeChats: MessengerChat[];
firstChatEverOpen: boolean;
} }
export interface IFriendsAction export interface IFriendsAction
@ -32,6 +33,7 @@ export interface IFriendsAction
chats?: MessengerChat[]; chats?: MessengerChat[];
chatMessage?: MessengerChatMessage; chatMessage?: MessengerChatMessage;
numberValue?: number; numberValue?: number;
boolValue?: boolean;
} }
} }
@ -43,6 +45,7 @@ export class FriendsActions
public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE'; public static PROCESS_UPDATE: string = 'FA_PROCESS_UPDATE';
public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS'; public static PROCESS_REQUESTS: string = 'FA_PROCESS_REQUESTS';
public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS'; public static SET_ACTIVE_CHATS: string = 'FA_SET_ACTIVE_CHATS';
public static SET_CHAT_READ: string = 'FA_SET_CHAT_READ';
public static ADD_CHAT_MESSAGE: string = 'FA_ADD_CHAT_MESSAGE'; public static ADD_CHAT_MESSAGE: string = 'FA_ADD_CHAT_MESSAGE';
} }
@ -50,7 +53,8 @@ export const initialFriends: IFriendsState = {
settings: null, settings: null,
friends: [], friends: [],
requests: [], requests: [],
activeChats: [] activeChats: [],
firstChatEverOpen: false
} }
export const FriendsReducer: Reducer<IFriendsState, IFriendsAction> = (state, action) => export const FriendsReducer: Reducer<IFriendsState, IFriendsAction> = (state, action) =>
@ -145,11 +149,25 @@ export const FriendsReducer: Reducer<IFriendsState, IFriendsAction> = (state, ac
case FriendsActions.SET_ACTIVE_CHATS: { case FriendsActions.SET_ACTIVE_CHATS: {
const activeChats = (action.payload.chats || []); const activeChats = (action.payload.chats || []);
if(!state.firstChatEverOpen && activeChats.length > 0) activeChats[0].addMessage(new MessengerChatMessage(MessengerChatMessage.SECURITY_ALERT, 0, null, 0), false, true);
return { ...state, activeChats, firstChatEverOpen: true };
}
case FriendsActions.SET_CHAT_READ: {
const friendId = action.payload.numberValue;
const activeChats = Array.from(state.activeChats);
let activeChatIndex = activeChats.findIndex(c => c.friendId === friendId);
if(activeChatIndex > -1) activeChats[activeChatIndex].read();
return { ...state, activeChats }; return { ...state, activeChats };
} }
case FriendsActions.ADD_CHAT_MESSAGE: { case FriendsActions.ADD_CHAT_MESSAGE: {
const message = action.payload.chatMessage; const message = action.payload.chatMessage;
const toFriendId = action.payload.numberValue; const toFriendId = action.payload.numberValue;
const setAsNotRead = action.payload.boolValue;
const activeChats = Array.from(state.activeChats); const activeChats = Array.from(state.activeChats);
@ -157,11 +175,11 @@ export const FriendsReducer: Reducer<IFriendsState, IFriendsAction> = (state, ac
if(activeChatIndex === -1) if(activeChatIndex === -1)
{ {
activeChats.push(new MessengerChat(message.senderId, false)); activeChats.push(new MessengerChat(message.senderId));
activeChatIndex = activeChats.length - 1; activeChatIndex = activeChats.length - 1;
} }
activeChats[activeChatIndex].addMessage(message); activeChats[activeChatIndex].addMessage(message, setAsNotRead);
return { ...state, activeChats }; return { ...state, activeChats };
} }

View File

@ -1,5 +1,5 @@
.nitro-friends-messenger { .nitro-friends-messenger {
width: 300px; width: 280px;
.friend-head { .friend-head {
position: relative; position: relative;
@ -7,6 +7,13 @@
height: 40px; height: 40px;
overflow: hidden; overflow: hidden;
.icon {
position: absolute;
top: 1px;
right: 1px;
z-index: 10;
}
.avatar-image { .avatar-image {
position: absolute; position: absolute;
margin-left: -27px; margin-left: -27px;

View File

@ -50,7 +50,7 @@ export const FriendsMessengerView: FC<{}> = props =>
if(existingChatIndex === -1) if(existingChatIndex === -1)
{ {
const clonedActiveChats = Array.from(activeChats); const clonedActiveChats = Array.from(activeChats);
clonedActiveChats.push(new MessengerChat(friendId, true)); clonedActiveChats.push(new MessengerChat(friendId));
dispatchFriendsState({ dispatchFriendsState({
type: FriendsActions.SET_ACTIVE_CHATS, type: FriendsActions.SET_ACTIVE_CHATS,
@ -75,8 +75,24 @@ export const FriendsMessengerView: FC<{}> = props =>
return friend.figure; return friend.figure;
}, [ friends ]); }, [ friends ]);
const selectedChat = useMemo(() => const selectChat = useCallback((index: number) =>
{ {
const chat = activeChats[index];
if(!chat) return;
dispatchFriendsState({
type: FriendsActions.SET_CHAT_READ,
payload: {
numberValue: chat.friendId
}
});
setSelectedChatIndex(index);
}, [ activeChats, dispatchFriendsState ]);
const selectedChat = useMemo(() =>
{
return activeChats[selectedChatIndex]; return activeChats[selectedChatIndex];
}, [ activeChats, selectedChatIndex ]); }, [ activeChats, selectedChatIndex ]);
@ -131,7 +147,8 @@ export const FriendsMessengerView: FC<{}> = props =>
type: FriendsActions.ADD_CHAT_MESSAGE, type: FriendsActions.ADD_CHAT_MESSAGE,
payload: { payload: {
chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, 0, message, (new Date().getMilliseconds())), chatMessage: new MessengerChatMessage(MessengerChatMessage.MESSAGE, 0, message, (new Date().getMilliseconds())),
numberValue: selectedChat.friendId numberValue: selectedChat.friendId,
boolValue: false
} }
}); });
setMessage(''); setMessage('');
@ -152,7 +169,8 @@ export const FriendsMessengerView: FC<{}> = props =>
<div className="d-flex gap-2 overflow-auto pb-1"> <div className="d-flex gap-2 overflow-auto pb-1">
{ activeChats && activeChats.map((chat, index) => { activeChats && activeChats.map((chat, index) =>
{ {
return <div key={ index } className="friend-head bg-muted rounded flex-shrink-0 cursor-pointer" onClick={ () => setSelectedChatIndex(index) }> return <div key={ index } className="friend-head rounded flex-shrink-0 cursor-pointer bg-muted" onClick={ () => selectChat(index) }>
{ !chat.isRead && <i className="icon icon-friendlist-new-message" /> }
<AvatarImageView figure={ getFriendFigure(chat.friendId) } headOnly={true} direction={3} /> <AvatarImageView figure={ getFriendFigure(chat.friendId) } headOnly={true} direction={3} />
</div>; </div>;
}) } }) }
@ -176,18 +194,31 @@ export const FriendsMessengerView: FC<{}> = props =>
{ selectedChat.messageGroups.map((group, groupIndex) => { selectedChat.messageGroups.map((group, groupIndex) =>
{ {
return <div key={ groupIndex } className={ 'd-flex gap-2 w-100 justify-content-' + (group.userId === 0 ? 'end' : 'start') }> return <div key={ groupIndex } className={ 'd-flex gap-2 w-100 justify-content-' + (group.userId === 0 ? 'end' : 'start') }>
{ group.userId !== 0 && <div className="message-avatar flex-shrink-0"> { group.isSystem && <>
<AvatarImageView figure={ selectedChatFriend.figure } direction={ 2 } />
</div> }
<div className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (group.userId === 0 ? 'right' : 'left') }>
{ group.messages.map((message, messageIndex) => { group.messages.map((message, messageIndex) =>
{ {
return <div key={ messageIndex } className="text-break">{ message.message }</div> return <div key={ messageIndex } className="text-break">
}) } { message.type === MessengerChatMessage.SECURITY_ALERT && <div className="bg-light rounded mb-2 d-flex gap-2 px-2 py-1 small text-muted align-items-center">
</div> <i className="icon icon-friendlist-warning flex-shrink-0" />
{ group.userId === 0 && <div className="message-avatar flex-shrink-0"> <div>{ LocalizeText('messenger.moderationinfo') }</div>
<AvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } /> </div> }
</div> } </div>
}) }
</> }
{ !group.isSystem && <>
{ group.userId !== 0 && <div className="message-avatar flex-shrink-0">
<AvatarImageView figure={ selectedChatFriend.figure } direction={ 2 } />
</div> }
<div className={ 'bg-light text-black border-radius mb-2 rounded py-1 px-2 messages-group-' + (group.userId === 0 ? 'right' : 'left') }>
{ group.messages.map((message, messageIndex) =>
{
return <div key={ messageIndex } className="text-break">{ message.message }</div>
}) }
</div>
{ group.userId === 0 && <div className="message-avatar flex-shrink-0">
<AvatarImageView figure={ GetSessionDataManager().figure } direction={ 4 } />
</div> }
</> }
</div>; </div>;
}) } }) }
</div> </div>