diff --git a/ts/components/conversation/message/reactions/ReactionPopup.tsx b/ts/components/conversation/message/reactions/ReactionPopup.tsx index 42084f254..23082b095 100644 --- a/ts/components/conversation/message/reactions/ReactionPopup.tsx +++ b/ts/components/conversation/message/reactions/ReactionPopup.tsx @@ -5,6 +5,7 @@ import { Data } from '../../../../data/data'; import { PubKey } from '../../../../session/types/PubKey'; import { isDarkTheme } from '../../../../state/selectors/theme'; import { nativeEmojiData } from '../../../../util/emoji'; +import { findAndFormatContact } from '../../../../models/message'; export type TipPosition = 'center' | 'left' | 'right'; @@ -78,7 +79,7 @@ const generateContactsString = async ( if (message) { let meIndex = -1; results = senders.map((sender, index) => { - const contact = message.findAndFormatContact(sender); + const contact = findAndFormatContact(sender); if (contact.isMe) { meIndex = index; } diff --git a/ts/components/dialog/ReactListModal.tsx b/ts/components/dialog/ReactListModal.tsx index 828ee6015..3b643190a 100644 --- a/ts/components/dialog/ReactListModal.tsx +++ b/ts/components/dialog/ReactListModal.tsx @@ -23,6 +23,7 @@ import { ContactName } from '../conversation/ContactName'; import { MessageReactions } from '../conversation/message/message-content/MessageReactions'; import { SessionIconButton } from '../icon'; import { SessionWrapperModal } from '../SessionWrapperModal'; +import { findAndFormatContact } from '../../models/message'; const StyledReactListContainer = styled(Flex)` width: 376px; @@ -100,7 +101,7 @@ const ReactionSenders = (props: ReactionSendersProps) => { const message = await Data.getMessageById(messageId); if (message) { handleClose(); - const contact = message.findAndFormatContact(sender); + const contact = findAndFormatContact(sender); dispatch( updateUserDetailsModal({ conversationId: sender, diff --git a/ts/models/message.ts b/ts/models/message.ts index 82fb208c1..152cfed29 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -43,6 +43,7 @@ import { PropsForGroupUpdateLeft, PropsForGroupUpdateName, PropsForMessageWithoutConvoProps, + PropsForQuote, } from '../state/ducks/conversations'; import { VisibleMessage, @@ -286,7 +287,7 @@ export class MessageModel extends Backbone.Model { const disabled = !expireTimer; const basicProps: PropsForExpirationTimer = { - ...this.findAndFormatContact(source), + ...findAndFormatContact(source), timespan, disabled, type: fromSync ? 'fromSync' : UserUtils.isUsFromCache(source) ? 'fromMe' : 'fromOther', @@ -339,7 +340,7 @@ export class MessageModel extends Backbone.Model { return null; } - const contact = this.findAndFormatContact(dataExtractionNotification.source); + const contact = findAndFormatContact(dataExtractionNotification.source); return { ...dataExtractionNotification, @@ -361,7 +362,7 @@ export class MessageModel extends Backbone.Model { return null; } - const contact = this.findAndFormatContact(messageRequestResponse.source); + const contact = findAndFormatContact(messageRequestResponse.source); return { ...messageRequestResponse, @@ -537,26 +538,6 @@ export class MessageModel extends Backbone.Model { return props; } - public processQuoteAttachment(attachment: any) { - const { thumbnail } = attachment; - const path = thumbnail && thumbnail.path && getAbsoluteAttachmentPath(thumbnail.path); - const objectUrl = thumbnail && thumbnail.objectUrl; - - const thumbnailWithObjectUrl = - !path && !objectUrl - ? null - : // tslint:disable: prefer-object-spread - Object.assign({}, attachment.thumbnail || {}, { - objectUrl: path || objectUrl, - }); - - return Object.assign({}, attachment, { - isVoiceMessage: isVoiceMessage(attachment), - thumbnail: thumbnailWithObjectUrl, - }); - // tslint:enable: prefer-object-spread - } - public getPropsForPreview(): Array | null { const previews = this.get('preview') || null; @@ -596,11 +577,12 @@ export class MessageModel extends Backbone.Model { const { author, id, referencedMessageNotFound } = quote; const contact: ConversationModel = author && getConversationController().get(author); - const authorName = contact ? contact.getContactProfileNameOrShortenedPubKey() : null; + const authorName = + contact && contact.isPrivate() ? contact.getContactProfileNameOrShortenedPubKey() : null; let isFromMe = contact ? contact.id === UserUtils.getOurPubKeyStrFromCache() : false; - if (this.getConversation()?.isPublic() && PubKey.hasBlindedPrefix(author)) { + if (contact?.isPublic() && PubKey.hasBlindedPrefix(author)) { const room = OpenGroupData.getV2OpenGroupRoom(this.get('conversationId')); if (room && roomHasBlindEnabled(room)) { const usFromCache = findCachedBlindedIdFromUnblinded( @@ -640,9 +622,7 @@ export class MessageModel extends Backbone.Model { quoteProps.text = sliceQuoteText(quote.text); } - const quoteAttachment = firstAttachment - ? this.processQuoteAttachment(firstAttachment) - : undefined; + const quoteAttachment = firstAttachment ? processQuoteAttachment(firstAttachment) : undefined; if (quoteAttachment) { // only set attachment if referencedMessageNotFound is false and we have one quoteProps.attachment = quoteAttachment; @@ -729,7 +709,7 @@ export class MessageModel extends Backbone.Model { const errorsForContact = errorsGroupedById[id]; const isOutgoingKeyError = false; - const contact = this.findAndFormatContact(id); + const contact = findAndFormatContact(id); return { ...contact, // fallback to the message status if we do not have a status with a user @@ -1217,31 +1197,6 @@ export class MessageModel extends Backbone.Model { } } - public findAndFormatContact(pubkey: string): FindAndFormatContactType { - const contactModel = getConversationController().get(pubkey); - let profileName: string | null = null; - let isMe = false; - - if ( - pubkey === UserUtils.getOurPubKeyStrFromCache() || - (pubkey && pubkey.startsWith('15') && isUsAnySogsFromCache(pubkey)) - ) { - profileName = window.i18n('you'); - isMe = true; - } else { - profileName = contactModel?.getNicknameOrRealUsername() || null; - } - - return { - pubkey: pubkey, - avatarPath: contactModel ? contactModel.getAvatarPath() : null, - name: contactModel?.getRealSessionUsername() || null, - profileName, - title: contactModel?.getTitle() || null, - isMe, - }; - } - private dispatchMessageUpdate() { updatesToDispatch.set(this.id, this.getMessageModelProps()); throttledAllMessagesDispatch(); @@ -1410,48 +1365,92 @@ export class MessageCollection extends Backbone.Collection {} MessageCollection.prototype.model = MessageModel; -// TODO rename and consolidate with getPropsForQuote -export function verifyQuote( - convo: ConversationModel, - msg: PropsForMessageWithoutConvoProps | undefined -) { - const referencedMessageNotFound = Boolean(msg); - const authorName = convo ? convo.getContactProfileNameOrShortenedPubKey() : null; - let isFromMe = convo ? convo.id === UserUtils.getOurPubKeyStrFromCache() : false; +export function findAndFormatContact(pubkey: string): FindAndFormatContactType { + const contactModel = getConversationController().get(pubkey); + let profileName: string | null = null; + let isMe = false; + + if ( + pubkey === UserUtils.getOurPubKeyStrFromCache() || + (pubkey && pubkey.startsWith('15') && isUsAnySogsFromCache(pubkey)) + ) { + profileName = window.i18n('you'); + isMe = true; + } else { + profileName = contactModel?.getNicknameOrRealUsername() || null; + } - // NOTE follows PropsForQuote except the sender can be undefined - let quoteProps: any = { - authorName: authorName || 'Unknown', - isFromMe, - referencedMessageNotFound, + return { + pubkey: pubkey, + avatarPath: contactModel ? contactModel.getAvatarPath() : null, + name: contactModel?.getRealSessionUsername() || null, + profileName, + title: contactModel?.getTitle() || null, + isMe, }; +} - if (!msg) { - return quoteProps; +function processQuoteAttachment(attachment: any) { + const { thumbnail } = attachment; + const path = thumbnail && thumbnail.path && getAbsoluteAttachmentPath(thumbnail.path); + const objectUrl = thumbnail && thumbnail.objectUrl; + + const thumbnailWithObjectUrl = + !path && !objectUrl + ? null + : // tslint:disable: prefer-object-spread + Object.assign({}, attachment.thumbnail || {}, { + objectUrl: path || objectUrl, + }); + + return Object.assign({}, attachment, { + isVoiceMessage: isVoiceMessage(attachment), + thumbnail: thumbnailWithObjectUrl, + }); + // tslint:enable: prefer-object-spread +} + +// TODO rename and consolidate with getPropsForQuote +export function overrideWithSourceMessage( + quote: PropsForQuote, + msg: MessageModelPropsWithoutConvoProps +): PropsForQuote { + const msgProps = msg.propsForMessage; + if (!msgProps || msgProps.isDeleted) { + return quote; } - const id = msg.id; - const author = msg.sender; + const convo = getConversationController().getOrThrow(String(msgProps?.convoId)); + + const sender = msgProps.sender && isEmpty(msgProps.sender) ? msgProps.sender : quote.sender; + const contact = findAndFormatContact(sender); + const authorName = contact?.profileName || contact?.name || 'Unknown'; + const attachment = + msgProps.attachments && msgProps.attachments[0] ? msgProps.attachments[0] : quote.attachment; - if (convo?.isPublic() && PubKey.hasBlindedPrefix(author)) { - const room = OpenGroupData.getV2OpenGroupRoom(msg.convoId); + let isFromMe = convo ? convo.id === UserUtils.getOurPubKeyStrFromCache() : false; + + if (convo?.isPublic() && PubKey.hasBlindedPrefix(sender)) { + const room = OpenGroupData.getV2OpenGroupRoom(msgProps.convoId); if (room && roomHasBlindEnabled(room)) { const usFromCache = findCachedBlindedIdFromUnblinded( UserUtils.getOurPubKeyStrFromCache(), room.serverPublicKey ); - if (usFromCache && usFromCache === author) { + if (usFromCache && usFromCache === sender) { isFromMe = true; } } } - const attachment = msg.attachments && msg.attachments[0]; - quoteProps = { - ...quoteProps, - sender: author, - messageId: id, - attachment: referencedMessageNotFound && attachment ? attachment : undefined, + const quoteProps: PropsForQuote = { + text: msgProps.text || quote.text, + attachment: attachment ? processQuoteAttachment(attachment) : undefined, + isFromMe, + sender, + authorName, + messageId: msgProps.id || quote.messageId, + referencedMessageNotFound: false, }; return quoteProps; diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index be3a5d48a..fe8fa6272 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -8,7 +8,6 @@ import { MessageModelPropsWithConvoProps, MessageModelPropsWithoutConvoProps, MessagePropsDetails, - PropsForQuote, ReduxConversationType, SortedMessageModelProps, } from '../ducks/conversations'; @@ -37,7 +36,7 @@ import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions'; import { filter, isEmpty, pick, sortBy } from 'lodash'; -import { verifyQuote } from '../../models/message'; +import { overrideWithSourceMessage } from '../../models/message'; export const getConversations = (state: StateType): ConversationsStateType => state.conversations; @@ -977,7 +976,7 @@ export const getMessageQuoteProps = createSelector( } const direction = msgProps.propsForMessage.direction; - const quote = msgProps.propsForQuote; + let quote = msgProps.propsForQuote; if (!direction || !quote || isEmpty(quote)) { return undefined; } @@ -987,18 +986,13 @@ export const getMessageQuoteProps = createSelector( return undefined; } - let quoteProps: PropsForQuote = quote; - - const conversationId = convosProps.selectedConversation; - const sourceMessage = convosProps.quotes[`${messageId}-${sender}`].propsForMessage; - if (conversationId && sourceMessage) { - const convo = getConversationController().get(conversationId); - quoteProps = verifyQuote(convo, sourceMessage); + const sourceMessage = convosProps.quotes[`${messageId}-${sender}`]; + if (sourceMessage) { + quote = overrideWithSourceMessage(quote, sourceMessage); } - window.log.debug(`WIP: quoteProps`, quoteProps); - - return { direction, quote: quoteProps }; + window.log.debug(`WIP: quote`, quote); + return { direction, quote }; } );