diff --git a/js/ConversationController.d.ts b/js/ConversationController.d.ts new file mode 100644 index 000000000..64703285c --- /dev/null +++ b/js/ConversationController.d.ts @@ -0,0 +1,9 @@ +import { ConversationModel } from "./models/conversations"; + +export type ConversationControllerType = { + reset: () => void; + load: () => Promise; + get: (id: string) => ConversationModel | undefined; + getOrCreateAndWait: (id: string, type: string) => Promise; getOrCreate: (id: string, type: string) => Promise; + +} \ No newline at end of file diff --git a/js/models/conversations.d.ts b/js/models/conversations.d.ts index f8ae37c73..9dd16fa33 100644 --- a/js/models/conversations.d.ts +++ b/js/models/conversations.d.ts @@ -18,6 +18,9 @@ interface ConversationAttributes { isKickedFromGroup?: boolean; avatarPath?: string; isMe?: boolean; + subscriberCount?: number; + sessionRestoreSeen?: boolean; + is_medium_group?: boolean; } export interface ConversationModel @@ -29,10 +32,10 @@ export interface ConversationModel isSessionResetReceived: () => boolean; updateExpirationTimer: ( expireTimer: number | null, - source: string, - receivedAt: number, - options: object - ) => void; + source?: string, + receivedAt?: number, + options?: object + ) => Promise; isPrivate: () => boolean; isVerified: () => boolean; toggleVerified: () => Promise; @@ -47,7 +50,47 @@ export interface ConversationModel getName: () => string; addMessage: (attributes: Partial) => Promise; isMediumGroup: () => boolean; + getNickname: () => string | undefined; + setNickname: (nickname: string | undefined) => Promise; + + isPublic: () => boolean; + isClosedGroup: () => boolean; + isRss: () => boolean; + isBlocked: () => boolean; + isClosable: () => boolean; + isOnline: () => boolean; + isModerator: (id?: string) => boolean; + lastMessage: string; messageCollection: Backbone.Collection; + + // types to make more specific + sendMessage: (body: any, attachments: any, quote: any, preview: any, groupInvitation: any, otherOptions: any) => Promise; + updateGroupAdmins: any; + setLokiProfile: any; + onSessionResetReceived: any; + setVerifiedDefault: any; + setVerified: any; + setUnverified: any; + getNumber: any; + getProfileName: any; + getAvatarPath: any; + markRead: any; + showChannelLightbox: any; + deletePublicMessages: any; + getMessagesWithTimestamp: any; + makeQuote: any; + unblock: any; + deleteContact: any; + endSession: any; + block: any; + copyPublicKey: any; + getAvatar: any; + notifyTyping: any; + setSecondaryStatus: any; + queueJob: any; + sendGroupInfo: any; + resetMessageSelection: any; + onUpdateGroupName: any; } diff --git a/js/models/conversations.js b/js/models/conversations.js index b9e1e9202..a5739f561 100644 --- a/js/models/conversations.js +++ b/js/models/conversations.js @@ -523,7 +523,7 @@ }, // Get messages with the given timestamp - _getMessagesWithTimestamp(pubKey, timestamp) { + getMessagesWithTimestamp(pubKey, timestamp) { if (this.id !== pubKey) { return []; } @@ -535,12 +535,12 @@ }, async onCalculatingPoW(pubKey, timestamp) { - const messages = this._getMessagesWithTimestamp(pubKey, timestamp); + const messages = this.getMessagesWithTimestamp(pubKey, timestamp); await Promise.all(messages.map(m => m.setCalculatingPoW())); }, async onPublicMessageSent(pubKey, timestamp, serverId, serverTimestamp) { - const messages = this._getMessagesWithTimestamp(pubKey, timestamp); + const messages = this.getMessagesWithTimestamp(pubKey, timestamp); if (messages && messages.length === 1) { await messages[0].setIsPublic(true); await messages[0].setServerId(serverId); diff --git a/js/views/conversation_view.js b/js/views/conversation_view.js index c0cab9f9a..cf1a186f2 100644 --- a/js/views/conversation_view.js +++ b/js/views/conversation_view.js @@ -1800,7 +1800,7 @@ } if (message) { - const quote = await this.model.makeQuote(this.quotedMessage); + const quote = await this.model.makeQuote(message); this.quote = quote; this.focusMessageFieldAndClearDisabled(); diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 38151716b..e04229d54 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -2607,64 +2607,7 @@ flex-grow: 0; } -.module-left-pane__tabs { - color: $color-dark-05; - background-color: $color-dark-75; - display: flex; - flex-direction: row; - - .tab { - width: 50%; - padding: 16px; - text-align: center; - cursor: pointer; - - &:hover { - background-color: $color-dark-72; - } - } - - .tab.selected { - background-color: #383c46; - } -} - -.module-left-pane__archive-header { - height: 48px; - width: 100%; - - display: inline-flex; - flex-direction: row; - align-items: center; - - border-bottom: 1px solid $color-gray-15; -} - -.module-left-pane__to-inbox-button { - margin-inline-start: 2px; - - width: 35px; - height: 35px; - - cursor: pointer; - @include color-svg('../images/back.svg', $color-gray-60); -} - -.module-left-pane__archive-header-text { - color: $color-gray-90; - font-size: 16px; - font-weight: 300px; -} - -.module-left-pane__archive-helper-text { - flex-grow: 0; - flex-shrink: 0; - padding: 1em; - font-size: 12px; - color: $color-gray-60; - background-color: $color-gray-05; -} .module-left-pane__list { flex-grow: 1; @@ -2677,83 +2620,7 @@ outline: none; } -.module-left-pane__archived-button { - font-size: 14px; - height: 64px; - line-height: 64px; - text-align: center; - font-weight: 300; - color: $color-gray-60; - - cursor: pointer; - &:hover { - background-color: $color-gray-05; - } -} - -.module-left-pane__archived-button__archived-count { - font-size: 12px; - font-weight: 300; - color: $color-gray-60; - background-color: $color-gray-05; - padding: 6px; - padding-top: 1px; - padding-bottom: 1px; - border-radius: 10px; -} - -// Module: Start New Conversation - -.module-start-new-conversation { - display: flex; - flex-direction: row; - align-items: center; - cursor: pointer; - padding: 8px 16px; - opacity: 0.7; - - &.valid { - opacity: 1; - } -} - -.module-start-new-conversation__avatar { - display: inline-block; - height: 48px; - width: 48px; - border-radius: 50%; - background-size: cover; - vertical-align: middle; - text-align: center; - line-height: 48px; - overflow-x: hidden; - text-overflow: ellipsis; - color: #ffffff; - font-size: 18px; - background-color: #616161; -} - -.module-start-new-conversation__content { - overflow: hidden; - margin-inline-start: 12px; - flex: 1; -} - -.module-start-new-conversation__number { - margin: 0; - font-size: 1em; - text-overflow: ellipsis; - overflow-x: hidden; - text-align: left; - font-weight: 300; -} -.module-start-new-conversation__text { - margin-top: 3px; - font-style: italic; - color: $color-gray-60; - font-size: 13px; -} // Third-party module: react-contextmenu diff --git a/ts/components/DevicePairingDialog.tsx b/ts/components/DevicePairingDialog.tsx index c141a2c8d..b5c24680e 100644 --- a/ts/components/DevicePairingDialog.tsx +++ b/ts/components/DevicePairingDialog.tsx @@ -177,6 +177,9 @@ export class DevicePairingDialog extends React.Component { public renderUnpairDeviceView() { const { pubKeyToUnpair } = this.props; + if (!pubKeyToUnpair) { + throw new Error('pubKeyToUnpair must be set in renderUnpairDeviceView()'); + } const secretWords = window.mnemonic.pubkey_to_secret_words(pubKeyToUnpair); const conv = window.ConversationController.get(pubKeyToUnpair); let description; @@ -286,9 +289,12 @@ export class DevicePairingDialog extends React.Component { title: window.i18n('devicePairedSuccessfully'), type: 'success', }); - const conv = window.ConversationController.get(this.state.currentPubKey); - if (conv) { - conv.setNickname(this.state.deviceAlias); + const { currentPubKey } = this.state; + if(currentPubKey) { + const conv = window.ConversationController.get(currentPubKey); + if (conv) { + void conv.setNickname(this.state.deviceAlias); + } } return; diff --git a/ts/components/SearchResults.tsx b/ts/components/SearchResults.tsx index 0791320e5..ac72109aa 100644 --- a/ts/components/SearchResults.tsx +++ b/ts/components/SearchResults.tsx @@ -17,7 +17,6 @@ export type PropsData = { messages: Array; regionCode: string; searchTerm: string; - showStartNewConversation: boolean; }; type PropsHousekeeping = { @@ -37,14 +36,12 @@ export class SearchResults extends React.Component { messages, openConversation, searchTerm, - showStartNewConversation, } = this.props; const haveConversations = conversations && conversations.length; const haveContacts = contacts && contacts.length; const haveMessages = messages && messages.length; const noResults = - !showStartNewConversation && !haveConversations && !haveContacts && !haveMessages; diff --git a/ts/components/StartNewConversation.tsx b/ts/components/StartNewConversation.tsx deleted file mode 100644 index 69650cd06..000000000 --- a/ts/components/StartNewConversation.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; - -import { LocalizerType } from '../types/Util'; -import { validateNumber } from '../types/PhoneNumber'; - -export interface Props { - phoneNumber: string; - i18n: LocalizerType; - onClick: () => void; -} - -export class StartNewConversation extends React.PureComponent { - public render() { - const { phoneNumber, i18n, onClick } = this.props; - - const error = validateNumber(phoneNumber, i18n); - const avatar = error ? '!' : '#'; - const click = error ? undefined : onClick; - - return ( -
-
{avatar}
-
-
- {phoneNumber} -
-
- {error || i18n('startConversation')} -
-
-
- ); - } -} diff --git a/ts/components/conversation/Message.tsx b/ts/components/conversation/Message.tsx index 0962d19b0..c42bbfb6e 100644 --- a/ts/components/conversation/Message.tsx +++ b/ts/components/conversation/Message.tsx @@ -38,6 +38,7 @@ import { ContextMenu, ContextMenuTrigger, MenuItem } from 'react-contextmenu'; import { SessionIcon, SessionIconSize, SessionIconType } from '../session/icon'; import { ReplyingToMessageProps } from '../session/conversation/SessionCompositionBox'; import _ from 'lodash'; +import { MessageModel } from '../../../js/models/messages'; declare global { interface Window { @@ -113,7 +114,7 @@ export interface Props { onClickLinkPreview?: (url: string) => void; onCopyText?: () => void; onSelectMessage: (messageId: string) => void; - onReply?: (messageProps: ReplyingToMessageProps) => void; + onReply?: (messagId: number) => void; onRetrySend?: () => void; onDownload?: (isDangerous: boolean) => void; onDelete?: () => void; @@ -1155,15 +1156,7 @@ export class Message extends React.PureComponent { private onReplyPrivate(e: Event) { e.stopPropagation(); if (this.props && this.props.onReply) { - const messageProps = _.pick( - this.props, - 'id', - 'timestamp', - 'attachments', - 'text', - 'convoId' - ); - this.props.onReply(messageProps); + this.props.onReply(this.props.timestamp); } } } diff --git a/ts/components/session/conversation/SessionCompositionBox.tsx b/ts/components/session/conversation/SessionCompositionBox.tsx index be0b0bcab..c00528b33 100644 --- a/ts/components/session/conversation/SessionCompositionBox.tsx +++ b/ts/components/session/conversation/SessionCompositionBox.tsx @@ -18,10 +18,12 @@ import { Constants } from '../../../session'; import { toArray } from 'react-emoji-render'; import { SessionQuotedMessageComposition } from './SessionQuotedMessageComposition'; import { Flex } from '../Flex'; +import _ from 'lodash'; export interface ReplyingToMessageProps { convoId: string; id: string; + author: string; timestamp: number; text?: string; attachments?: Array; @@ -325,15 +327,22 @@ export class SessionCompositionBox extends React.Component { // handle Attachments const { attachments } = this.state; + const { quotedMessageProps } = this.props; // Send message this.props.onMessageSending(); + const extractedQuotedMessageProps = _.pick(quotedMessageProps, + 'id', + 'author', + 'text', + 'attachments'); + try { await this.props.sendMessage( messagePlaintext, attachments, - undefined, + extractedQuotedMessageProps, undefined, null, {} diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index 2b4ff4edd..ddcaf3364 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -61,7 +61,8 @@ interface State { dropZoneFiles: any; // quoted message - quotedMessageProps?: ReplyingToMessageProps; + quotedMessageTimestamp?: number; + quotedMessageProps?: any; } interface Props { @@ -144,6 +145,9 @@ export class SessionConversation extends React.Component { const conversationModel = window.ConversationController.get( this.state.conversationKey ); + if (!conversationModel) { + throw new Error('conversation null on ConversationController.get()'); + } conversationModel.on('change', () => { this.setState( { @@ -184,7 +188,7 @@ export class SessionConversation extends React.Component { // New messages get from message collection. const messageCollection = window.ConversationController.get( this.state.conversationKey - ).messageCollection; + )?.messageCollection; } public async componentWillReceiveProps(nextProps: any) { @@ -213,6 +217,9 @@ export class SessionConversation extends React.Component { const conversationModel = window.ConversationController.get( conversationKey ); + if (!conversationModel) { + throw new Error('conversation null on ConversationController.get()'); + } const isRss = conversation.isRss; // TODO VINCE: OPTIMISE FOR NEW SENDING??? @@ -225,6 +232,7 @@ export class SessionConversation extends React.Component { const showSafetyNumber = this.state.infoViewState === 'safetyNumber'; const showMessageDetails = this.state.infoViewState === 'messageDetails'; + return (
{this.renderHeader()}
@@ -290,7 +298,7 @@ export class SessionConversation extends React.Component { onExitVoiceNoteView={this.onExitVoiceNoteView} quotedMessageProps={quotedMessageProps} removeQuotedMessage={() => { - this.replyToMessage(undefined); + void this.replyToMessage(undefined); }} /> )} @@ -389,7 +397,9 @@ export class SessionConversation extends React.Component { }; messageProps.quote = quoteProps || undefined; - messageProps.onReply = this.replyToMessage; + messageProps.onReply = (messageId: number) => { + void this.replyToMessage(messageId); + }; return ; } @@ -411,6 +421,9 @@ export class SessionConversation extends React.Component { if (initialFetchComplete) { return; } + if (!conversationModel) { + throw new Error('conversation null on ConversationController.get()'); + } const messageSet = await window.Signal.Data.getMessagesByConversation( conversationKey, @@ -494,7 +507,9 @@ export class SessionConversation extends React.Component { public getHeaderProps() { const { conversationKey } = this.state; const conversation = window.ConversationController.get(conversationKey); - + if (!conversation) { + throw new Error('conversation null on ConversationController.get()'); + } const expireTimer = conversation.get('expireTimer'); const expirationSettingName = expireTimer ? window.Whisper.ExpirationTimerOptions.getName(expireTimer || 0) @@ -601,12 +616,15 @@ export class SessionConversation extends React.Component { public getGroupSettingsProps() { const { conversationKey } = this.state; const conversation = window.ConversationController.get(conversationKey); + if (!conversation) { + throw new Error('conversation null on ConversationController.get()'); + } const ourPK = window.textsecure.storage.user.getNumber(); const members = conversation.get('members') || []; const isAdmin = conversation.isMediumGroup() ? true - : conversation.get('groupAdmins').includes(ourPK); + : conversation.get('groupAdmins')?.includes(ourPK); return { id: conversation.id, @@ -631,9 +649,9 @@ export class SessionConversation extends React.Component { onSetDisappearingMessages: (seconds: any) => { if (seconds > 0) { - conversation.updateExpirationTimer(seconds); + void conversation.updateExpirationTimer(seconds); } else { - conversation.updateExpirationTimer(null); + void conversation.updateExpirationTimer(null); } }, @@ -691,6 +709,12 @@ export class SessionConversation extends React.Component { // Set sending state 5% to show message sending const initialValue = 5; this.updateSendingProgress(initialValue, 1); + if (this.state.quotedMessageTimestamp) { + this.setState({ + quotedMessageTimestamp: undefined, + quotedMessageProps: undefined, + }); + } } public onMessageSuccess() { @@ -707,6 +731,9 @@ export class SessionConversation extends React.Component { // If you're not friends, don't mark anything as read. Otherwise // this will automatically accept friend request. const conversation = window.ConversationController.get(conversationKey); + if (!conversation) { + throw new Error('conversation null on ConversationController.get()'); + } if (conversation.isBlocked()) { return; } @@ -724,8 +751,7 @@ export class SessionConversation extends React.Component { } if (unread) { - const model = window.ConversationController.get(conversationKey); - model.markRead(unread.attributes.received_at); + conversation.markRead(unread.attributes.received_at); } } @@ -805,6 +831,9 @@ export class SessionConversation extends React.Component { ); const multiple = selectedMessages.length > 1; + if (!conversationModel) { + throw new Error('conversation null on ConversationController.get()'); + } const isPublic = conversationModel.isPublic(); // In future, we may be able to unsend private messages also @@ -1039,9 +1068,27 @@ export class SessionConversation extends React.Component { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~ MESSAGE QUOTE ~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - private replyToMessage(quotedMessageProps?: ReplyingToMessageProps) { - if (!_.isEqual(this.state.quotedMessageProps, quotedMessageProps)) { - this.setState({ quotedMessageProps }); + private async replyToMessage(quotedMessageTimestamp ?: number) { + if (!_.isEqual(this.state.quotedMessageTimestamp, quotedMessageTimestamp)) { + const { conversationKey } = this.state; + const conversationModel = window.ConversationController.get( + conversationKey + ); + if (!conversationModel) { + throw new Error('conversation null on ConversationController.get()'); + } + const conversation = this.props.conversations.conversationLookup[ + conversationKey + ]; + let quotedMessageProps = null; + if (quotedMessageTimestamp) { + const quotedMessageModel = conversationModel.getMessagesWithTimestamp(conversation.id, quotedMessageTimestamp); + if (quotedMessageModel && quotedMessageModel.length === 1) { + quotedMessageProps = await conversationModel.makeQuote(quotedMessageModel[0]); + } + } + this.setState({ quotedMessageTimestamp, quotedMessageProps }); + } } diff --git a/ts/components/session/conversation/SessionQuotedMessageComposition.tsx b/ts/components/session/conversation/SessionQuotedMessageComposition.tsx index fc58665be..c6b7d1557 100644 --- a/ts/components/session/conversation/SessionQuotedMessageComposition.tsx +++ b/ts/components/session/conversation/SessionQuotedMessageComposition.tsx @@ -11,7 +11,7 @@ interface Props { } const QuotedMessageComposition = styled.div` - width: 50%; + width: 100%; `; const QuotedMessageCompositionReply = styled.div` diff --git a/ts/components/session/settings/SessionSettingListItem.tsx b/ts/components/session/settings/SessionSettingListItem.tsx index 13fd3179a..ceb8e1629 100644 --- a/ts/components/session/settings/SessionSettingListItem.tsx +++ b/ts/components/session/settings/SessionSettingListItem.tsx @@ -9,7 +9,7 @@ import { SessionSettingType } from './SessionSettings'; import { SessionRadioGroup } from '../SessionRadioGroup'; interface Props { - title: string; + title?: string; description?: string; type: SessionSettingType | undefined; value: any; diff --git a/ts/components/session/settings/SessionSettings.tsx b/ts/components/session/settings/SessionSettings.tsx index 163fe0046..418496997 100644 --- a/ts/components/session/settings/SessionSettings.tsx +++ b/ts/components/session/settings/SessionSettings.tsx @@ -50,7 +50,7 @@ interface LocalSettingType { value?: any; content: any | undefined; hidden: any; - title: string; + title?: string; type: SessionSettingType | undefined; setFn: any; onClick: any; diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts index bb6fec351..c8757ae0b 100644 --- a/ts/receiver/contentMessage.ts +++ b/ts/receiver/contentMessage.ts @@ -575,12 +575,13 @@ async function handleTypingMessage( // A sender here could be referring to a group. // Groups don't have primary devices so we need to take that into consideration. + // Note: we do not support group typing message for now. const user = PubKey.from(source); const primaryDevice = user ? await MultiDeviceProtocol.getPrimaryDevice(user) : null; - const convoId = groupId || (primaryDevice && primaryDevice.key) || source; + const convoId = (primaryDevice && primaryDevice.key) || source; const conversation = ConversationController.get(convoId); diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts index ea8049a71..ec82b40b0 100644 --- a/ts/receiver/dataMessage.ts +++ b/ts/receiver/dataMessage.ts @@ -321,7 +321,7 @@ export async function handleDataMessage( const source = envelope.senderIdentity || senderPubKey; const ownDevice = await MultiDeviceProtocol.isOurDevice(source); - const ownMessage = conversation.isMediumGroup() && ownDevice; + const ownMessage = conversation?.isMediumGroup() && ownDevice; const ev: any = {}; if (ownMessage) { @@ -711,6 +711,9 @@ export async function handleMessageEvent(event: MessageEvent): Promise { // the conversation with the primary device of that source (can be the same as conversationOrigin) const conversation = window.ConversationController.get(conversationId); + if (!conversation) { + throw new Error('conversation null on ConversationController.get()'); + } conversation.queueJob(() => { handleMessageJob( diff --git a/ts/receiver/groups.ts b/ts/receiver/groups.ts index 2c74f92a0..b5874dedf 100644 --- a/ts/receiver/groups.ts +++ b/ts/receiver/groups.ts @@ -52,9 +52,9 @@ export async function preprocessGroupMessage( // NOTE: we use group admins to tell if this is // the creation of the group (initial update) - const groupAdminsSet = - conversation.get('groupAdmins') && - conversation.get('groupAdmins').length > 0; + const groupAdmins = conversation.get('groupAdmins'); + const groupAdminsSet = groupAdmins && groupAdmins.length > 0; + const newGroup = !groupAdminsSet; const knownMembers = conversation.get('members'); @@ -87,7 +87,7 @@ export async function preprocessGroupMessage( } else { // be sure to drop a message from a non admin if it tries to change group members // or change the group name - const fromAdmin = conversation.get('groupAdmins').includes(primarySource); + const fromAdmin = conversation.get('groupAdmins')?.includes(primarySource); if (!fromAdmin) { // Make sure the message is not removing members / renaming the group diff --git a/ts/receiver/mediumGroups.ts b/ts/receiver/mediumGroups.ts index 1265a35ba..22f856114 100644 --- a/ts/receiver/mediumGroups.ts +++ b/ts/receiver/mediumGroups.ts @@ -167,12 +167,12 @@ async function handleNewGroup( const members = membersBinary.map(toHex); const admins = adminsBinary.map(toHex); - const maybeConvo = await window.ConversationController.get(groupId); + const maybeConvo = window.ConversationController.get(groupId); const groupExists = !!maybeConvo; if (groupExists) { - if (maybeConvo.get('isKickedFromGroup')) { + if (maybeConvo && maybeConvo.get('isKickedFromGroup')) { // TODO: indicate that we've been re-invited // to the group if that is the case @@ -211,7 +211,7 @@ async function handleNewGroup( convo.set({ unreadCount: Number(convo.get('unreadCount')) + 1, }); - convo.commit(); + await convo.commit(); const secretKeyHex = toHex(groupPrivateKey); @@ -275,9 +275,9 @@ async function handleMediumGroupChange( const groupId = toHex(groupPublicKey); - const maybeConvo = await window.ConversationController.get(groupId); + const convo = window.ConversationController.get(groupId); - if (!maybeConvo) { + if (!convo) { log.warn( 'Ignoring a medium group update message (INFO) for a non-existing group' ); @@ -287,7 +287,6 @@ async function handleMediumGroupChange( return; } - const convo = maybeConvo as ConversationModel; // ***** Updating the group ***** @@ -336,13 +335,13 @@ async function handleMediumGroupChange( convo.updateTextInputState(); window.SwarmPolling.removePubkey(groupId); } else { - if (maybeConvo.get('isKickedFromGroup')) { + if (convo.get('isKickedFromGroup')) { // Enable typing: - maybeConvo.set('isKickedFromGroup', false); - maybeConvo.set('left', false); + convo.set('isKickedFromGroup', false); + convo.set('left', false); // Subscribe to this group id window.SwarmPolling.addGroupId(new PubKey(groupId)); - maybeConvo.updateTextInputState(); + convo.updateTextInputState(); } } diff --git a/ts/receiver/multidevice.ts b/ts/receiver/multidevice.ts index a46de5286..1d1f01fe5 100644 --- a/ts/receiver/multidevice.ts +++ b/ts/receiver/multidevice.ts @@ -160,7 +160,7 @@ async function handleAuthorisationForSelf( ); } else { const { primaryDevicePubKey, grantSignature } = pairingAuthorisation; - if (grantSignature && grantSignature.length > 0) { + if (grantSignature && grantSignature.length > 0 && primaryDevicePubKey) { // Authorisation received to become a secondary device window.log.info( `Received pairing authorisation from ${primaryDevicePubKey}` @@ -381,11 +381,6 @@ async function onContactReceived(details: any) { conversation.setProfileKey(profileKey); } - // Do not set name to allow working with lokiProfile and nicknames - conversation.set({ - // name: details.name, - color: details.color, - }); if (details.name && details.name.length) { await conversation.setLokiProfile({ displayName: details.name }); diff --git a/ts/receiver/syncMessages.ts b/ts/receiver/syncMessages.ts index 4c180ee87..2d3fb7350 100644 --- a/ts/receiver/syncMessages.ts +++ b/ts/receiver/syncMessages.ts @@ -188,7 +188,7 @@ async function handleBlocked( ); async function markConvoBlocked(block: boolean, n: string) { - const conv = await window.ConversationController.get(n); + const conv = window.ConversationController.get(n); if (conv) { if (conv.isPrivate()) { await BlockedNumberController.setBlocked(n, block); diff --git a/ts/session/medium_group/index.ts b/ts/session/medium_group/index.ts index 4949066a4..f1065f063 100644 --- a/ts/session/medium_group/index.ts +++ b/ts/session/medium_group/index.ts @@ -189,7 +189,7 @@ export async function leaveMediumGroup(groupId: string) { window.SwarmPolling.removePubkey(groupId); // TODO audric: we just left a group, we have to regenerate our senderkey - const maybeConvo = await ConversationController.get(groupId); + const maybeConvo = ConversationController.get(groupId); if (!maybeConvo) { window.log.error('Cannot leave non-existing group'); @@ -497,7 +497,7 @@ interface GroupInfo { members: Array; // Primary keys is_medium_group: boolean; active?: boolean; - expireTimer?: number; + expireTimer?: number | null; avatar?: any; color?: any; // what is this??? blocked?: boolean; @@ -830,11 +830,11 @@ async function updateOrCreateGroup(details: GroupInfo) { await conversation.commit(); const { expireTimer } = details; - const isValidExpireTimer = typeof expireTimer === 'number'; - if (!isValidExpireTimer) { + const isValidExpireTimer = expireTimer !== undefined && typeof expireTimer === 'number'; + + if (expireTimer === undefined || typeof expireTimer !== 'number') { return; } - const source = textsecure.storage.user.getNumber(); const receivedAt = Date.now(); await conversation.updateExpirationTimer(expireTimer, source, receivedAt, { diff --git a/ts/state/selectors/search.ts b/ts/state/selectors/search.ts index 2b2436e53..17a997bc3 100644 --- a/ts/state/selectors/search.ts +++ b/ts/state/selectors/search.ts @@ -95,9 +95,6 @@ export const getSearchResults = createSelector( }), regionCode: regionCode, searchTerm: state.query, - - // We only want to show the start conversation if we don't have the query in our lookup - showStartNewConversation: !lookup[state.query], }; } ); diff --git a/ts/window.d.ts b/ts/window.d.ts index 8fbca2229..a654a8871 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -12,7 +12,9 @@ import { LibTextsecure } from '../libtextsecure'; import { ConversationType } from '../js/modules/data'; import { RecoveryPhraseUtil } from '../libloki/modules/mnemonic'; import { ConfirmationDialogParams } from '../background'; -import {} from 'styled-components/cssprop'; +import { } from 'styled-components/cssprop'; + +import { ConversationControllerType } from '../js/ConversationController'; /* We declare window stuff here instead of global.d.ts because we are importing other declarations. If you import anything in global.d.ts, the type system won't work correctly. @@ -21,7 +23,7 @@ If you import anything in global.d.ts, the type system won't work correctly. declare global { interface Window { CONSTANTS: any; - ConversationController: any; + ConversationController: ConversationControllerType; Events: any; Lodash: any; LokiAppDotNetServerAPI: any;