Convert ReactWrapperView
to TypeScript
This commit is contained in:
parent
bb9a270bfd
commit
63189f3f91
16 changed files with 325 additions and 364 deletions
|
@ -26,23 +26,14 @@ const { ChatColorPicker } = require('../../ts/components/ChatColorPicker');
|
||||||
const {
|
const {
|
||||||
ConfirmationDialog,
|
ConfirmationDialog,
|
||||||
} = require('../../ts/components/ConfirmationDialog');
|
} = require('../../ts/components/ConfirmationDialog');
|
||||||
const {
|
|
||||||
ContactDetail,
|
|
||||||
} = require('../../ts/components/conversation/ContactDetail');
|
|
||||||
const {
|
const {
|
||||||
ContactModal,
|
ContactModal,
|
||||||
} = require('../../ts/components/conversation/ContactModal');
|
} = require('../../ts/components/conversation/ContactModal');
|
||||||
const { Emojify } = require('../../ts/components/conversation/Emojify');
|
const { Emojify } = require('../../ts/components/conversation/Emojify');
|
||||||
const { ErrorModal } = require('../../ts/components/ErrorModal');
|
|
||||||
const { Lightbox } = require('../../ts/components/Lightbox');
|
|
||||||
const {
|
|
||||||
MediaGallery,
|
|
||||||
} = require('../../ts/components/conversation/media-gallery/MediaGallery');
|
|
||||||
const {
|
const {
|
||||||
MessageDetail,
|
MessageDetail,
|
||||||
} = require('../../ts/components/conversation/MessageDetail');
|
} = require('../../ts/components/conversation/MessageDetail');
|
||||||
const { Quote } = require('../../ts/components/conversation/Quote');
|
const { Quote } = require('../../ts/components/conversation/Quote');
|
||||||
const { ProgressModal } = require('../../ts/components/ProgressModal');
|
|
||||||
const {
|
const {
|
||||||
StagedLinkPreview,
|
StagedLinkPreview,
|
||||||
} = require('../../ts/components/conversation/StagedLinkPreview');
|
} = require('../../ts/components/conversation/StagedLinkPreview');
|
||||||
|
@ -52,7 +43,6 @@ const {
|
||||||
const {
|
const {
|
||||||
SystemTraySettingsCheckboxes,
|
SystemTraySettingsCheckboxes,
|
||||||
} = require('../../ts/components/conversation/SystemTraySettingsCheckboxes');
|
} = require('../../ts/components/conversation/SystemTraySettingsCheckboxes');
|
||||||
const { WhatsNewLink } = require('../../ts/components/WhatsNewLink');
|
|
||||||
|
|
||||||
// State
|
// State
|
||||||
const {
|
const {
|
||||||
|
@ -320,19 +310,13 @@ exports.setup = (options = {}) => {
|
||||||
AttachmentList,
|
AttachmentList,
|
||||||
ChatColorPicker,
|
ChatColorPicker,
|
||||||
ConfirmationDialog,
|
ConfirmationDialog,
|
||||||
ContactDetail,
|
|
||||||
ContactModal,
|
ContactModal,
|
||||||
Emojify,
|
Emojify,
|
||||||
ErrorModal,
|
|
||||||
Lightbox,
|
|
||||||
MediaGallery,
|
|
||||||
MessageDetail,
|
MessageDetail,
|
||||||
Quote,
|
Quote,
|
||||||
ProgressModal,
|
|
||||||
StagedLinkPreview,
|
StagedLinkPreview,
|
||||||
DisappearingTimeDialog,
|
DisappearingTimeDialog,
|
||||||
SystemTraySettingsCheckboxes,
|
SystemTraySettingsCheckboxes,
|
||||||
WhatsNewLink,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Roots = {
|
const Roots = {
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
// Copyright 2018-2020 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
/* global Backbone: false */
|
|
||||||
/* global i18n: false */
|
|
||||||
/* global React: false */
|
|
||||||
/* global ReactDOM: false */
|
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
|
||||||
(function () {
|
|
||||||
window.Whisper = window.Whisper || {};
|
|
||||||
|
|
||||||
window.Whisper.ReactWrapperView = Backbone.View.extend({
|
|
||||||
className: 'react-wrapper',
|
|
||||||
initialize(options) {
|
|
||||||
const {
|
|
||||||
Component,
|
|
||||||
JSX,
|
|
||||||
props,
|
|
||||||
onClose,
|
|
||||||
tagName,
|
|
||||||
className,
|
|
||||||
onInitialRender,
|
|
||||||
elCallback,
|
|
||||||
} = options;
|
|
||||||
this.render();
|
|
||||||
if (elCallback) {
|
|
||||||
elCallback(this.el);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tagName = tagName;
|
|
||||||
this.className = className;
|
|
||||||
this.JSX = JSX;
|
|
||||||
this.Component = Component;
|
|
||||||
this.onClose = onClose;
|
|
||||||
this.onInitialRender = onInitialRender;
|
|
||||||
|
|
||||||
this.update(props);
|
|
||||||
|
|
||||||
this.hasRendered = false;
|
|
||||||
},
|
|
||||||
update(propsOrJSX, cb) {
|
|
||||||
const reactElement = this.JSX
|
|
||||||
? propsOrJSX || this.JSX
|
|
||||||
: React.createElement(this.Component, this.augmentProps(propsOrJSX));
|
|
||||||
|
|
||||||
ReactDOM.render(reactElement, this.el, () => {
|
|
||||||
if (cb) {
|
|
||||||
try {
|
|
||||||
cb();
|
|
||||||
} catch (error) {
|
|
||||||
window.SignalContext.log.error(
|
|
||||||
'ReactWrapperView.update error:',
|
|
||||||
error && error.stack ? error.stack : error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.hasRendered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hasRendered = true;
|
|
||||||
if (this.onInitialRender) {
|
|
||||||
this.onInitialRender();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
augmentProps(props) {
|
|
||||||
return {
|
|
||||||
...props,
|
|
||||||
close: () => {
|
|
||||||
this.remove();
|
|
||||||
},
|
|
||||||
i18n,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
remove() {
|
|
||||||
if (this.onClose) {
|
|
||||||
this.onClose();
|
|
||||||
}
|
|
||||||
ReactDOM.unmountComponentAtNode(this.el);
|
|
||||||
Backbone.View.prototype.remove.call(this);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})();
|
|
|
@ -134,6 +134,7 @@ import type { UUID } from './types/UUID';
|
||||||
import * as log from './logging/log';
|
import * as log from './logging/log';
|
||||||
import { loadRecentEmojis } from './util/loadRecentEmojis';
|
import { loadRecentEmojis } from './util/loadRecentEmojis';
|
||||||
import { deleteAllLogs } from './util/deleteAllLogs';
|
import { deleteAllLogs } from './util/deleteAllLogs';
|
||||||
|
import { ReactWrapperView } from './views/ReactWrapperView';
|
||||||
import { ToastCaptchaFailed } from './components/ToastCaptchaFailed';
|
import { ToastCaptchaFailed } from './components/ToastCaptchaFailed';
|
||||||
import { ToastCaptchaSolved } from './components/ToastCaptchaSolved';
|
import { ToastCaptchaSolved } from './components/ToastCaptchaSolved';
|
||||||
import { ToastConversationArchived } from './components/ToastConversationArchived';
|
import { ToastConversationArchived } from './components/ToastConversationArchived';
|
||||||
|
@ -1114,7 +1115,7 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
window.showKeyboardShortcuts = () => {
|
window.showKeyboardShortcuts = () => {
|
||||||
if (!shortcutGuideView) {
|
if (!shortcutGuideView) {
|
||||||
shortcutGuideView = new window.Whisper.ReactWrapperView({
|
shortcutGuideView = new ReactWrapperView({
|
||||||
className: 'shortcut-guide-wrapper',
|
className: 'shortcut-guide-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createShortcutGuideModal(
|
JSX: window.Signal.State.Roots.createShortcutGuideModal(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2018-2021 Signal Messenger, LLC
|
// Copyright 2018-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
|
@ -16,7 +16,7 @@ import { Avatar, AvatarSize } from './Avatar';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import { IMAGE_PNG, isImage, isVideo } from '../types/MIME';
|
import { IMAGE_PNG, isImage, isVideo } from '../types/MIME';
|
||||||
import type { LocalizerType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
import type { MediaItemType, MessageAttributesType } from '../types/MediaItem';
|
import type { MediaItemType, MediaItemMessageType } from '../types/MediaItem';
|
||||||
import { formatDuration } from '../util/formatDuration';
|
import { formatDuration } from '../util/formatDuration';
|
||||||
import { useRestoreFocus } from '../hooks/useRestoreFocus';
|
import { useRestoreFocus } from '../hooks/useRestoreFocus';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
@ -31,7 +31,7 @@ export type PropsType = {
|
||||||
onForward?: (messageId: string) => void;
|
onForward?: (messageId: string) => void;
|
||||||
onSave?: (options: {
|
onSave?: (options: {
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
message: MessageAttributesType;
|
message: MediaItemMessageType;
|
||||||
index: number;
|
index: number;
|
||||||
}) => void;
|
}) => void;
|
||||||
selectedIndex?: number;
|
selectedIndex?: number;
|
||||||
|
@ -676,7 +676,7 @@ function LightboxHeader({
|
||||||
}: {
|
}: {
|
||||||
getConversation: (id: string) => ConversationType;
|
getConversation: (id: string) => ConversationType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
message: MessageAttributesType;
|
message: MediaItemMessageType;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const conversation = getConversation(message.conversationId);
|
const conversation = getConversation(message.conversationId);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
// Copyright 2018-2021 Signal Messenger, LLC
|
// Copyright 2018-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import type { MessageAttributesType } from '../../../../model-types.d';
|
||||||
import type { AttachmentType } from '../../../../types/Attachment';
|
import type { AttachmentType } from '../../../../types/Attachment';
|
||||||
import type { Message } from './Message';
|
|
||||||
|
|
||||||
export type ItemClickEvent = {
|
export type ItemClickEvent = {
|
||||||
message: Message;
|
message: Pick<MessageAttributesType, 'sent_at'>;
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
type: 'media' | 'documents';
|
type: 'media' | 'documents';
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2018-2020 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import type { AttachmentType } from '../../../../types/Attachment';
|
|
||||||
|
|
||||||
export type Message = {
|
|
||||||
id: string;
|
|
||||||
attachments: Array<AttachmentType>;
|
|
||||||
// Assuming this is for the API
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
received_at: number;
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
received_at_ms: number;
|
|
||||||
};
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
applyNewAvatar,
|
applyNewAvatar,
|
||||||
decryptGroupDescription,
|
decryptGroupDescription,
|
||||||
|
@ -23,6 +24,8 @@ import type { PreJoinConversationType } from '../state/ducks/conversations';
|
||||||
import { SignalService as Proto } from '../protobuf';
|
import { SignalService as Proto } from '../protobuf';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { showToast } from '../util/showToast';
|
import { showToast } from '../util/showToast';
|
||||||
|
import { ReactWrapperView } from '../views/ReactWrapperView';
|
||||||
|
import { ErrorModal } from '../components/ErrorModal';
|
||||||
import { ToastAlreadyGroupMember } from '../components/ToastAlreadyGroupMember';
|
import { ToastAlreadyGroupMember } from '../components/ToastAlreadyGroupMember';
|
||||||
import { ToastAlreadyRequestedToJoin } from '../components/ToastAlreadyRequestedToJoin';
|
import { ToastAlreadyRequestedToJoin } from '../components/ToastAlreadyRequestedToJoin';
|
||||||
import { HTTPError } from '../textsecure/Errors';
|
import { HTTPError } from '../textsecure/Errors';
|
||||||
|
@ -373,14 +376,13 @@ export async function joinViaLink(hash: string): Promise<void> {
|
||||||
|
|
||||||
log.info(`joinViaLink/${logId}: Showing modal`);
|
log.info(`joinViaLink/${logId}: Showing modal`);
|
||||||
|
|
||||||
let groupV2InfoDialog: Backbone.View | undefined =
|
let groupV2InfoDialog: Backbone.View | undefined = new ReactWrapperView({
|
||||||
new window.Whisper.ReactWrapperView({
|
className: 'group-v2-join-dialog-wrapper',
|
||||||
className: 'group-v2-join-dialog-wrapper',
|
JSX: window.Signal.State.Roots.createGroupV2JoinModal(window.reduxStore, {
|
||||||
JSX: window.Signal.State.Roots.createGroupV2JoinModal(window.reduxStore, {
|
join,
|
||||||
join,
|
onClose: closeDialog,
|
||||||
onClose: closeDialog,
|
}),
|
||||||
}),
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// We declare a new function here so we can await but not block
|
// We declare a new function here so we can await but not block
|
||||||
const fetchAvatar = async () => {
|
const fetchAvatar = async () => {
|
||||||
|
@ -427,15 +429,17 @@ export async function joinViaLink(hash: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showErrorDialog(description: string, title: string) {
|
function showErrorDialog(description: string, title: string) {
|
||||||
const errorView = new window.Whisper.ReactWrapperView({
|
const errorView = new ReactWrapperView({
|
||||||
className: 'error-modal-wrapper',
|
className: 'error-modal-wrapper',
|
||||||
Component: window.Signal.Components.ErrorModal,
|
JSX: (
|
||||||
props: {
|
<ErrorModal
|
||||||
title,
|
i18n={window.i18n}
|
||||||
description,
|
title={title}
|
||||||
onClose: () => {
|
description={description}
|
||||||
errorView.remove();
|
onClose={() => {
|
||||||
},
|
errorView.remove();
|
||||||
},
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -1,27 +1,26 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import type { MessageAttributesType } from '../model-types.d';
|
||||||
import type { AttachmentType } from './Attachment';
|
import type { AttachmentType } from './Attachment';
|
||||||
import type { MIMEType } from './MIME';
|
import type { MIMEType } from './MIME';
|
||||||
|
|
||||||
export type MessageAttributesType = {
|
export type MediaItemMessageType = Pick<
|
||||||
attachments: Array<AttachmentType>;
|
MessageAttributesType,
|
||||||
conversationId: string;
|
| 'attachments'
|
||||||
id: string;
|
| 'conversationId'
|
||||||
// eslint-disable-next-line camelcase
|
| 'id'
|
||||||
received_at: number;
|
| 'received_at'
|
||||||
// eslint-disable-next-line camelcase
|
| 'received_at_ms'
|
||||||
received_at_ms: number;
|
| 'sent_at'
|
||||||
// eslint-disable-next-line camelcase
|
>;
|
||||||
sent_at: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MediaItemType = {
|
export type MediaItemType = {
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
contentType?: MIMEType;
|
contentType?: MIMEType;
|
||||||
index: number;
|
index: number;
|
||||||
loop?: boolean;
|
loop?: boolean;
|
||||||
message: MessageAttributesType;
|
message: MediaItemMessageType;
|
||||||
objectURL?: string;
|
objectURL?: string;
|
||||||
thumbnailObjectUrl?: string;
|
thumbnailObjectUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright 2020-2021 Signal Messenger, LLC
|
// Copyright 2020-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { webFrame } from 'electron';
|
import { webFrame } from 'electron';
|
||||||
import type { AudioDevice } from 'ringrtc';
|
import type { AudioDevice } from 'ringrtc';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
import type { ZoomFactorType } from '../types/Storage.d';
|
import type { ZoomFactorType } from '../types/Storage.d';
|
||||||
import type {
|
import type {
|
||||||
|
@ -15,6 +16,9 @@ import * as Stickers from '../types/Stickers';
|
||||||
import type { SystemTraySetting } from '../types/SystemTraySetting';
|
import type { SystemTraySetting } from '../types/SystemTraySetting';
|
||||||
import { parseSystemTraySetting } from '../types/SystemTraySetting';
|
import { parseSystemTraySetting } from '../types/SystemTraySetting';
|
||||||
|
|
||||||
|
import { ReactWrapperView } from '../views/ReactWrapperView';
|
||||||
|
import { ErrorModal } from '../components/ErrorModal';
|
||||||
|
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import { calling } from '../services/calling';
|
import { calling } from '../services/calling';
|
||||||
import { getConversationsWithCustomColorSelector } from '../state/selectors/conversations';
|
import { getConversationsWithCustomColorSelector } from '../state/selectors/conversations';
|
||||||
|
@ -406,7 +410,7 @@ export function createIPCEvents(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const stickerPreviewModalView = new window.Whisper.ReactWrapperView({
|
const stickerPreviewModalView = new ReactWrapperView({
|
||||||
className: 'sticker-preview-modal-wrapper',
|
className: 'sticker-preview-modal-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createStickerPreviewModal(
|
JSX: window.Signal.State.Roots.createStickerPreviewModal(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -419,14 +423,16 @@ export function createIPCEvents(
|
||||||
'showStickerPack: Ran into an error!',
|
'showStickerPack: Ran into an error!',
|
||||||
error && error.stack ? error.stack : error
|
error && error.stack ? error.stack : error
|
||||||
);
|
);
|
||||||
const errorView = new window.Whisper.ReactWrapperView({
|
const errorView = new ReactWrapperView({
|
||||||
className: 'error-modal-wrapper',
|
className: 'error-modal-wrapper',
|
||||||
Component: window.Signal.Components.ErrorModal,
|
JSX: (
|
||||||
props: {
|
<ErrorModal
|
||||||
onClose: () => {
|
i18n={window.i18n}
|
||||||
errorView.remove();
|
onClose={() => {
|
||||||
},
|
errorView.remove();
|
||||||
},
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -447,16 +453,18 @@ export function createIPCEvents(
|
||||||
'showGroupViaLink: Ran into an error!',
|
'showGroupViaLink: Ran into an error!',
|
||||||
error && error.stack ? error.stack : error
|
error && error.stack ? error.stack : error
|
||||||
);
|
);
|
||||||
const errorView = new window.Whisper.ReactWrapperView({
|
const errorView = new ReactWrapperView({
|
||||||
className: 'error-modal-wrapper',
|
className: 'error-modal-wrapper',
|
||||||
Component: window.Signal.Components.ErrorModal,
|
JSX: (
|
||||||
props: {
|
<ErrorModal
|
||||||
title: window.i18n('GroupV2--join--general-join-failure--title'),
|
i18n={window.i18n}
|
||||||
description: window.i18n('GroupV2--join--general-join-failure'),
|
title={window.i18n('GroupV2--join--general-join-failure--title')}
|
||||||
onClose: () => {
|
description={window.i18n('GroupV2--join--general-join-failure')}
|
||||||
errorView.remove();
|
onClose={() => {
|
||||||
},
|
errorView.remove();
|
||||||
},
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.isShowingModal = false;
|
window.isShowingModal = false;
|
||||||
|
@ -513,14 +521,16 @@ export function createIPCEvents(
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUnknownSgnlLinkModal(): void {
|
function showUnknownSgnlLinkModal(): void {
|
||||||
const errorView = new window.Whisper.ReactWrapperView({
|
const errorView = new ReactWrapperView({
|
||||||
className: 'error-modal-wrapper',
|
className: 'error-modal-wrapper',
|
||||||
Component: window.Signal.Components.ErrorModal,
|
JSX: (
|
||||||
props: {
|
<ErrorModal
|
||||||
description: window.i18n('unknown-sgnl-link'),
|
i18n={window.i18n}
|
||||||
onClose: () => {
|
description={window.i18n('unknown-sgnl-link')}
|
||||||
errorView.remove();
|
onClose={() => {
|
||||||
},
|
errorView.remove();
|
||||||
},
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
// Copyright 2021-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import type { Message } from '../components/conversation/media-gallery/types/Message';
|
import type { MessageAttributesType } from '../model-types.d';
|
||||||
|
|
||||||
export function getMessageTimestamp(message: Message): number {
|
export function getMessageTimestamp(
|
||||||
|
message: Pick<MessageAttributesType, 'received_at' | 'received_at_ms'>
|
||||||
|
): number {
|
||||||
return message.received_at_ms || message.received_at;
|
return message.received_at_ms || message.received_at;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7967,7 +7967,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/util/createIPCEvents.ts",
|
"path": "ts/util/createIPCEvents.tsx",
|
||||||
"line": " if ($('.dark-overlay').length) {",
|
"line": " if ($('.dark-overlay').length) {",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-08-18T18:22:55.307Z",
|
"updated": "2021-08-18T18:22:55.307Z",
|
||||||
|
@ -7975,7 +7975,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/util/createIPCEvents.ts",
|
"path": "ts/util/createIPCEvents.tsx",
|
||||||
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
|
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-08-18T18:22:55.307Z",
|
"updated": "2021-08-18T18:22:55.307Z",
|
||||||
|
@ -7983,7 +7983,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/util/createIPCEvents.ts",
|
"path": "ts/util/createIPCEvents.tsx",
|
||||||
"line": " $('.dark-overlay').on('click', () => $('.dark-overlay').remove());",
|
"line": " $('.dark-overlay').on('click', () => $('.dark-overlay').remove());",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-08-18T18:22:55.307Z",
|
"updated": "2021-08-18T18:22:55.307Z",
|
||||||
|
@ -7991,7 +7991,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/util/createIPCEvents.ts",
|
"path": "ts/util/createIPCEvents.tsx",
|
||||||
"line": " removeDarkOverlay: () => $('.dark-overlay').remove(),",
|
"line": " removeDarkOverlay: () => $('.dark-overlay').remove(),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-08-18T18:22:55.307Z",
|
"updated": "2021-08-18T18:22:55.307Z",
|
||||||
|
@ -7999,7 +7999,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-prepend(",
|
"rule": "jQuery-prepend(",
|
||||||
"path": "ts/util/createIPCEvents.ts",
|
"path": "ts/util/createIPCEvents.tsx",
|
||||||
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
|
"line": " $(document.body).prepend('<div class=\"dark-overlay\"></div>');",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-08-18T18:22:55.307Z",
|
"updated": "2021-08-18T18:22:55.307Z",
|
||||||
|
@ -8021,84 +8021,84 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " template: () => $('#app-loading-screen').html(),",
|
"line": " template: () => $('#app-loading-screen').html(),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.$('.message').text(message);",
|
"line": " this.$('.message').text(message);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " template: () => $('#two-column').html(),",
|
"line": " template: () => $('#two-column').html(),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " el: this.$('.conversation-stack'),",
|
"line": " el: this.$('.conversation-stack'),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.$('.no-conversation-open').toggle(!isAnyConversationOpen);",
|
"line": " this.$('.no-conversation-open').toggle(!isAnyConversationOpen);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-10-08T17:40:22.770Z"
|
"updated": "2021-10-08T17:40:22.770Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.$('.left-pane-placeholder').replaceWith(this.leftPaneView.el);",
|
"line": " this.$('.left-pane-placeholder').replaceWith(this.leftPaneView.el);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-10-08T17:40:22.770Z"
|
"updated": "2021-10-08T17:40:22.770Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-$(",
|
"rule": "jQuery-$(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);",
|
"line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-10-22T20:58:48.103Z"
|
"updated": "2021-10-22T20:58:48.103Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-append(",
|
"rule": "jQuery-append(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);",
|
"line": " this.$('.whats-new-placeholder').append(this.whatsNewLink.el);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-10-22T20:58:48.103Z"
|
"updated": "2021-10-22T20:58:48.103Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-appendTo(",
|
"rule": "jQuery-appendTo(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " view.$el.appendTo(this.el);",
|
"line": " view.$el.appendTo(this.el);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-html(",
|
"rule": "jQuery-html(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " template: () => $('#app-loading-screen').html(),",
|
"line": " template: () => $('#app-loading-screen').html(),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-html(",
|
"rule": "jQuery-html(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " template: () => $('#two-column').html(),",
|
"line": " template: () => $('#two-column').html(),",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rule": "jQuery-prependTo(",
|
"rule": "jQuery-prependTo(",
|
||||||
"path": "ts/views/inbox_view.ts",
|
"path": "ts/views/inbox_view.tsx",
|
||||||
"line": " this.appLoadingScreen.$el.prependTo(this.el);",
|
"line": " this.appLoadingScreen.$el.prependTo(this.el);",
|
||||||
"reasonCategory": "usageTrusted",
|
"reasonCategory": "usageTrusted",
|
||||||
"updated": "2021-09-15T21:07:50.995Z"
|
"updated": "2021-09-15T21:07:50.995Z"
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
// Copyright 2021-2022 Signal Messenger, LLC
|
// Copyright 2021-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import { ReactWrapperView } from '../views/ReactWrapperView';
|
||||||
|
import { ErrorModal } from '../components/ErrorModal';
|
||||||
|
import { ProgressModal } from '../components/ProgressModal';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { clearTimeoutIfNecessary } from './clearTimeoutIfNecessary';
|
import { clearTimeoutIfNecessary } from './clearTimeoutIfNecessary';
|
||||||
|
|
||||||
|
@ -26,9 +30,9 @@ export async function longRunningTaskWrapper<T>({
|
||||||
|
|
||||||
// Note: this component uses a portal to render itself into the top-level DOM. No
|
// Note: this component uses a portal to render itself into the top-level DOM. No
|
||||||
// need to attach it to the DOM here.
|
// need to attach it to the DOM here.
|
||||||
progressView = new window.Whisper.ReactWrapperView({
|
progressView = new ReactWrapperView({
|
||||||
className: 'progress-modal-wrapper',
|
className: 'progress-modal-wrapper',
|
||||||
Component: window.Signal.Components.ProgressModal,
|
JSX: <ProgressModal i18n={window.i18n} />,
|
||||||
});
|
});
|
||||||
spinnerStart = Date.now();
|
spinnerStart = Date.now();
|
||||||
}, TWO_SECONDS);
|
}, TWO_SECONDS);
|
||||||
|
@ -73,14 +77,16 @@ export async function longRunningTaskWrapper<T>({
|
||||||
|
|
||||||
// Note: this component uses a portal to render itself into the top-level DOM. No
|
// Note: this component uses a portal to render itself into the top-level DOM. No
|
||||||
// need to attach it to the DOM here.
|
// need to attach it to the DOM here.
|
||||||
const errorView: Backbone.View = new window.Whisper.ReactWrapperView({
|
const errorView: Backbone.View = new ReactWrapperView({
|
||||||
className: 'error-modal-wrapper',
|
className: 'error-modal-wrapper',
|
||||||
Component: window.Signal.Components.ErrorModal,
|
JSX: (
|
||||||
props: {
|
<ErrorModal
|
||||||
onClose: (): void => {
|
i18n={window.i18n}
|
||||||
errorView.remove();
|
onClose={() => {
|
||||||
},
|
errorView.remove();
|
||||||
},
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
49
ts/views/ReactWrapperView.ts
Normal file
49
ts/views/ReactWrapperView.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2018-2022 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import type { ReactElement } from 'react';
|
||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
import * as Backbone from 'backbone';
|
||||||
|
|
||||||
|
export class ReactWrapperView extends Backbone.View {
|
||||||
|
private readonly onClose?: () => unknown;
|
||||||
|
private JSX: ReactElement;
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
className,
|
||||||
|
onClose,
|
||||||
|
JSX,
|
||||||
|
}: Readonly<{
|
||||||
|
className?: string;
|
||||||
|
onClose?: () => unknown;
|
||||||
|
JSX: ReactElement;
|
||||||
|
}>) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.className = className ?? 'react-wrapper';
|
||||||
|
this.JSX = JSX;
|
||||||
|
this.onClose = onClose;
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(JSX: ReactElement): void {
|
||||||
|
this.JSX = JSX;
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
override render(): this {
|
||||||
|
this.el.className = this.className;
|
||||||
|
ReactDOM.render(this.JSX, this.el);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
override remove(): this {
|
||||||
|
if (this.onClose) {
|
||||||
|
this.onClose();
|
||||||
|
}
|
||||||
|
ReactDOM.unmountComponentAtNode(this.el);
|
||||||
|
Backbone.View.prototype.remove.call(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
|
import type * as Backbone from 'backbone';
|
||||||
|
import type { ComponentProps } from 'react';
|
||||||
|
import * as React from 'react';
|
||||||
import { debounce, flatten, omit, throttle } from 'lodash';
|
import { debounce, flatten, omit, throttle } from 'lodash';
|
||||||
import { render } from 'mustache';
|
import { render } from 'mustache';
|
||||||
|
|
||||||
|
@ -23,10 +26,7 @@ import type {
|
||||||
QuotedMessageType,
|
QuotedMessageType,
|
||||||
} from '../model-types.d';
|
} from '../model-types.d';
|
||||||
import type { LinkPreviewType } from '../types/message/LinkPreviews';
|
import type { LinkPreviewType } from '../types/message/LinkPreviews';
|
||||||
import type {
|
import type { MediaItemType, MediaItemMessageType } from '../types/MediaItem';
|
||||||
MediaItemType,
|
|
||||||
MessageAttributesType as MediaItemMessageType,
|
|
||||||
} from '../types/MediaItem';
|
|
||||||
import type { MessageModel } from '../models/messages';
|
import type { MessageModel } from '../models/messages';
|
||||||
import { getMessageById } from '../messages/getMessageById';
|
import { getMessageById } from '../messages/getMessageById';
|
||||||
import { getContactId } from '../messages/helpers';
|
import { getContactId } from '../messages/helpers';
|
||||||
|
@ -43,6 +43,7 @@ import {
|
||||||
} from '../util/whatTypeOfConversation';
|
} from '../util/whatTypeOfConversation';
|
||||||
import { findAndFormatContact } from '../util/findAndFormatContact';
|
import { findAndFormatContact } from '../util/findAndFormatContact';
|
||||||
import * as Bytes from '../Bytes';
|
import * as Bytes from '../Bytes';
|
||||||
|
import { getPreferredBadgeSelector } from '../state/selectors/badges';
|
||||||
import {
|
import {
|
||||||
canReply,
|
canReply,
|
||||||
getAttachmentsForMessage,
|
getAttachmentsForMessage,
|
||||||
|
@ -55,6 +56,9 @@ import {
|
||||||
getMessagesByConversation,
|
getMessagesByConversation,
|
||||||
} from '../state/selectors/conversations';
|
} from '../state/selectors/conversations';
|
||||||
import { getActiveCallState } from '../state/selectors/calling';
|
import { getActiveCallState } from '../state/selectors/calling';
|
||||||
|
import { getTheme } from '../state/selectors/user';
|
||||||
|
import { ReactWrapperView } from './ReactWrapperView';
|
||||||
|
import { Lightbox } from '../components/Lightbox';
|
||||||
import { ConversationDetailsMembershipList } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
import { ConversationDetailsMembershipList } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
||||||
import { showSafetyNumberChangeDialog } from '../shims/showSafetyNumberChangeDialog';
|
import { showSafetyNumberChangeDialog } from '../shims/showSafetyNumberChangeDialog';
|
||||||
import type {
|
import type {
|
||||||
|
@ -65,7 +69,6 @@ import type {
|
||||||
import * as LinkPreview from '../types/LinkPreview';
|
import * as LinkPreview from '../types/LinkPreview';
|
||||||
import * as VisualAttachment from '../types/VisualAttachment';
|
import * as VisualAttachment from '../types/VisualAttachment';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import type { AnyViewClass, BasicReactWrapperViewClass } from '../window.d';
|
|
||||||
import type { EmbeddedContactType } from '../types/EmbeddedContact';
|
import type { EmbeddedContactType } from '../types/EmbeddedContact';
|
||||||
import { createConversationView } from '../state/roots/createConversationView';
|
import { createConversationView } from '../state/roots/createConversationView';
|
||||||
import { AttachmentToastType } from '../types/AttachmentToastType';
|
import { AttachmentToastType } from '../types/AttachmentToastType';
|
||||||
|
@ -116,18 +119,20 @@ import { RecordingState } from '../state/ducks/audioRecorder';
|
||||||
import { UUIDKind } from '../types/UUID';
|
import { UUIDKind } from '../types/UUID';
|
||||||
import type { UUIDStringType } from '../types/UUID';
|
import type { UUIDStringType } from '../types/UUID';
|
||||||
import { retryDeleteForEveryone } from '../util/retryDeleteForEveryone';
|
import { retryDeleteForEveryone } from '../util/retryDeleteForEveryone';
|
||||||
|
import { ContactDetail } from '../components/conversation/ContactDetail';
|
||||||
|
import { MediaGallery } from '../components/conversation/media-gallery/MediaGallery';
|
||||||
|
import type { ItemClickEvent } from '../components/conversation/media-gallery/types/ItemClickEvent';
|
||||||
|
|
||||||
type AttachmentOptions = {
|
type AttachmentOptions = {
|
||||||
messageId: string;
|
messageId: string;
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type PanelType = { view: Backbone.View; headerTitle?: string };
|
||||||
|
|
||||||
const FIVE_MINUTES = 1000 * 60 * 5;
|
const FIVE_MINUTES = 1000 * 60 * 5;
|
||||||
const LINK_PREVIEW_TIMEOUT = 60 * 1000;
|
const LINK_PREVIEW_TIMEOUT = 60 * 1000;
|
||||||
|
|
||||||
window.Whisper = window.Whisper || {};
|
|
||||||
|
|
||||||
const { Whisper } = window;
|
|
||||||
const { Message } = window.Signal.Types;
|
const { Message } = window.Signal.Types;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -247,14 +252,14 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
|
|
||||||
// Sub-views
|
// Sub-views
|
||||||
private contactModalView?: Backbone.View;
|
private contactModalView?: Backbone.View;
|
||||||
private conversationView?: BasicReactWrapperViewClass;
|
private conversationView?: Backbone.View;
|
||||||
private forwardMessageModal?: Backbone.View;
|
private forwardMessageModal?: Backbone.View;
|
||||||
private lightboxView?: BasicReactWrapperViewClass;
|
private lightboxView?: ReactWrapperView;
|
||||||
private migrationDialog?: Backbone.View;
|
private migrationDialog?: Backbone.View;
|
||||||
private stickerPreviewModalView?: Backbone.View;
|
private stickerPreviewModalView?: Backbone.View;
|
||||||
|
|
||||||
// Panel support
|
// Panel support
|
||||||
private panels: Array<AnyViewClass> = [];
|
private panels: Array<PanelType> = [];
|
||||||
private previousFocus?: HTMLElement;
|
private previousFocus?: HTMLElement;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -676,7 +681,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
timelineProps,
|
timelineProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.conversationView = new Whisper.ReactWrapperView({ JSX });
|
this.conversationView = new ReactWrapperView({ JSX });
|
||||||
this.$('.ConversationView__template').append(this.conversationView.el);
|
this.$('.ConversationView__template').append(this.conversationView.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,7 +993,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
(item: GroupV2PendingMemberType) => item.uuid
|
(item: GroupV2PendingMemberType) => item.uuid
|
||||||
);
|
);
|
||||||
|
|
||||||
this.migrationDialog = new Whisper.ReactWrapperView({
|
this.migrationDialog = new ReactWrapperView({
|
||||||
className: 'group-v1-migration-wrapper',
|
className: 'group-v1-migration-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createGroupV1MigrationModal(
|
JSX: window.Signal.State.Roots.createGroupV1MigrationModal(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -1106,7 +1111,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
if (this.panels && this.panels.length) {
|
if (this.panels && this.panels.length) {
|
||||||
for (let i = 0, max = this.panels.length; i < max; i += 1) {
|
for (let i = 0, max = this.panels.length; i < max; i += 1) {
|
||||||
const panel = this.panels[i];
|
const panel = this.panels[i];
|
||||||
panel.remove();
|
panel.view.remove();
|
||||||
}
|
}
|
||||||
window.reduxActions.conversations.setSelectedConversationPanelDepth(0);
|
window.reduxActions.conversations.setSelectedConversationPanelDepth(0);
|
||||||
}
|
}
|
||||||
|
@ -1334,7 +1339,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.forwardMessageModal = new Whisper.ReactWrapperView({
|
this.forwardMessageModal = new ReactWrapperView({
|
||||||
JSX: window.Signal.State.Roots.createForwardMessageModal(
|
JSX: window.Signal.State.Roots.createForwardMessageModal(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
{
|
{
|
||||||
|
@ -1623,20 +1628,24 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
).filter(isNotNil);
|
).filter(isNotNil);
|
||||||
|
|
||||||
// Unlike visual media, only one non-image attachment is supported
|
// Unlike visual media, only one non-image attachment is supported
|
||||||
const documents = rawDocuments
|
const documents: Array<MediaItemType> = [];
|
||||||
.filter(message =>
|
rawDocuments.forEach(message => {
|
||||||
Boolean(message.attachments && message.attachments.length)
|
const attachments = message.attachments || [];
|
||||||
)
|
const attachment = attachments[0];
|
||||||
.map(message => {
|
if (!attachment) {
|
||||||
const attachments = message.attachments || [];
|
return;
|
||||||
const attachment = attachments[0];
|
}
|
||||||
return {
|
|
||||||
contentType: attachment.contentType,
|
documents.push({
|
||||||
index: 0,
|
contentType: attachment.contentType,
|
||||||
attachment,
|
index: 0,
|
||||||
message,
|
attachment,
|
||||||
};
|
// We do this cast because we know there attachments (see the checks above).
|
||||||
|
message: message as MessageAttributesType & {
|
||||||
|
attachments: Array<AttachmentType>;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const saveAttachment = async ({
|
const saveAttachment = async ({
|
||||||
attachment,
|
attachment,
|
||||||
|
@ -1666,11 +1675,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
message,
|
message,
|
||||||
attachment,
|
attachment,
|
||||||
type,
|
type,
|
||||||
}: {
|
}: ItemClickEvent) => {
|
||||||
message: MessageAttributesType;
|
|
||||||
attachment: AttachmentType;
|
|
||||||
type: 'documents' | 'media';
|
|
||||||
}) => {
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'documents': {
|
case 'documents': {
|
||||||
saveAttachment({ message, attachment });
|
saveAttachment({ message, attachment });
|
||||||
|
@ -1719,20 +1724,22 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
Component: window.Signal.Components.MediaGallery,
|
// We present an empty panel briefly, while we wait for props to load.
|
||||||
|
JSX: <></>,
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
view.headerTitle = window.i18n('allMedia');
|
const headerTitle = window.i18n('allMedia');
|
||||||
|
|
||||||
const update = async () => {
|
const update = async () => {
|
||||||
view.update(await getProps());
|
const props = await getProps();
|
||||||
|
view.update(<MediaGallery i18n={window.i18n} {...props} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -1758,7 +1765,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
showGV1Members(): void {
|
showGV1Members(): void {
|
||||||
const { contactCollection } = this.model;
|
const { contactCollection, id } = this.model;
|
||||||
|
|
||||||
const memberships =
|
const memberships =
|
||||||
contactCollection?.map((conversation: ConversationModel) => {
|
contactCollection?.map((conversation: ConversationModel) => {
|
||||||
|
@ -1768,19 +1775,29 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
};
|
};
|
||||||
}) || [];
|
}) || [];
|
||||||
|
|
||||||
const view = new Whisper.ReactWrapperView({
|
const reduxState = window.reduxStore.getState();
|
||||||
|
const getPreferredBadge = getPreferredBadgeSelector(reduxState);
|
||||||
|
const theme = getTheme(reduxState);
|
||||||
|
|
||||||
|
const view = new ReactWrapperView({
|
||||||
className: 'group-member-list panel',
|
className: 'group-member-list panel',
|
||||||
Component: ConversationDetailsMembershipList,
|
JSX: (
|
||||||
props: {
|
<ConversationDetailsMembershipList
|
||||||
canAddNewMembers: false,
|
canAddNewMembers={false}
|
||||||
i18n: window.i18n,
|
conversationId={id}
|
||||||
maxShownMemberCount: 32,
|
i18n={window.i18n}
|
||||||
memberships,
|
getPreferredBadge={getPreferredBadge}
|
||||||
showContactModal: this.showContactModal.bind(this),
|
maxShownMemberCount={32}
|
||||||
},
|
memberships={memberships}
|
||||||
|
showContactModal={contactId => {
|
||||||
|
this.showContactModal(contactId);
|
||||||
|
}}
|
||||||
|
theme={theme}
|
||||||
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1913,14 +1930,18 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.listenTo(message, 'expired', closeLightbox);
|
this.listenTo(message, 'expired', closeLightbox);
|
||||||
this.listenTo(message, 'change', () => {
|
this.listenTo(message, 'change', () => {
|
||||||
if (this.lightboxView) {
|
if (this.lightboxView) {
|
||||||
this.lightboxView.update(getProps());
|
this.lightboxView.update(<Lightbox {...getProps()} />);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const getProps = () => {
|
const getProps = (): ComponentProps<typeof Lightbox> => {
|
||||||
const { path, contentType } = tempAttachment;
|
const { path, contentType } = tempAttachment;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
close: () => {
|
||||||
|
this.lightboxView?.remove();
|
||||||
|
},
|
||||||
|
i18n: window.i18n,
|
||||||
media: [
|
media: [
|
||||||
{
|
{
|
||||||
attachment: tempAttachment,
|
attachment: tempAttachment,
|
||||||
|
@ -1928,7 +1949,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
contentType,
|
contentType,
|
||||||
index: 0,
|
index: 0,
|
||||||
message: {
|
message: {
|
||||||
attachments: message.get('attachments'),
|
attachments: message.get('attachments') || [],
|
||||||
id: message.get('id'),
|
id: message.get('id'),
|
||||||
conversationId: message.get('conversationId'),
|
conversationId: message.get('conversationId'),
|
||||||
received_at: message.get('received_at'),
|
received_at: message.get('received_at'),
|
||||||
|
@ -1946,10 +1967,9 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.lightboxView = undefined;
|
this.lightboxView = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lightboxView = new Whisper.ReactWrapperView({
|
this.lightboxView = new ReactWrapperView({
|
||||||
className: 'lightbox-wrapper',
|
className: 'lightbox-wrapper',
|
||||||
Component: window.Signal.Components.Lightbox,
|
JSX: <Lightbox {...getProps()} />,
|
||||||
props: getProps(),
|
|
||||||
onClose: closeLightbox,
|
onClose: closeLightbox,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2025,7 +2045,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.stickerPreviewModalView = new Whisper.ReactWrapperView({
|
this.stickerPreviewModalView = new ReactWrapperView({
|
||||||
className: 'sticker-preview-modal-wrapper',
|
className: 'sticker-preview-modal-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createStickerPreviewModal(
|
JSX: window.Signal.State.Roots.createStickerPreviewModal(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -2074,16 +2094,25 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.lightboxView = undefined;
|
this.lightboxView = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lightboxView = new Whisper.ReactWrapperView({
|
this.lightboxView = new ReactWrapperView({
|
||||||
className: 'lightbox-wrapper',
|
className: 'lightbox-wrapper',
|
||||||
Component: window.Signal.Components.Lightbox,
|
JSX: (
|
||||||
props: {
|
<Lightbox
|
||||||
getConversation: getConversationSelector(window.reduxStore.getState()),
|
close={() => {
|
||||||
media,
|
this.lightboxView?.remove();
|
||||||
onForward: this.showForwardMessageModal.bind(this),
|
}}
|
||||||
onSave,
|
i18n={window.i18n}
|
||||||
selectedIndex: selectedIndex >= 0 ? selectedIndex : 0,
|
getConversation={getConversationSelector(
|
||||||
},
|
window.reduxStore.getState()
|
||||||
|
)}
|
||||||
|
media={media}
|
||||||
|
onForward={messageId => {
|
||||||
|
this.showForwardMessageModal(messageId);
|
||||||
|
}}
|
||||||
|
onSave={onSave}
|
||||||
|
selectedIndex={selectedIndex >= 0 ? selectedIndex : 0}
|
||||||
|
/>
|
||||||
|
),
|
||||||
onClose: () => window.Signal.Backbone.Views.Lightbox.hide(),
|
onClose: () => window.Signal.Backbone.Views.Lightbox.hide(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2177,7 +2206,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
showGroupLinkManagement(): void {
|
showGroupLinkManagement(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
JSX: window.Signal.State.Roots.createGroupLinkManagement(
|
JSX: window.Signal.State.Roots.createGroupLinkManagement(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -2191,14 +2220,14 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
view.headerTitle = window.i18n('ConversationDetails--group-link');
|
const headerTitle = window.i18n('ConversationDetails--group-link');
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
showGroupV2Permissions(): void {
|
showGroupV2Permissions(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
JSX: window.Signal.State.Roots.createGroupV2Permissions(
|
JSX: window.Signal.State.Roots.createGroupV2Permissions(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -2212,14 +2241,14 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
view.headerTitle = window.i18n('permissions');
|
const headerTitle = window.i18n('permissions');
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
showPendingInvites(): void {
|
showPendingInvites(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
JSX: window.Signal.State.Roots.createPendingInvites(window.reduxStore, {
|
JSX: window.Signal.State.Roots.createPendingInvites(window.reduxStore, {
|
||||||
conversationId: this.model.id,
|
conversationId: this.model.id,
|
||||||
|
@ -2232,14 +2261,16 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
view.headerTitle = window.i18n('ConversationDetails--requests-and-invites');
|
const headerTitle = window.i18n(
|
||||||
|
'ConversationDetails--requests-and-invites'
|
||||||
|
);
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
showConversationNotificationsSettings(): void {
|
showConversationNotificationsSettings(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
JSX: window.Signal.State.Roots.createConversationNotificationsSettings(
|
JSX: window.Signal.State.Roots.createConversationNotificationsSettings(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -2251,23 +2282,22 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
view.headerTitle = window.i18n('ConversationDetails--notifications');
|
const headerTitle = window.i18n('ConversationDetails--notifications');
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
showChatColorEditor(): void {
|
showChatColorEditor(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel',
|
className: 'panel',
|
||||||
JSX: window.Signal.State.Roots.createChatColorPicker(window.reduxStore, {
|
JSX: window.Signal.State.Roots.createChatColorPicker(window.reduxStore, {
|
||||||
conversationId: this.model.get('id'),
|
conversationId: this.model.get('id'),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
const headerTitle = window.i18n('ChatColorPicker__menu-title');
|
||||||
|
|
||||||
view.headerTitle = window.i18n('ChatColorPicker__menu-title');
|
this.addPanel({ view, headerTitle });
|
||||||
|
|
||||||
this.listenBack(view);
|
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2331,16 +2361,16 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.onOutgoingVideoCallInConversation.bind(this),
|
this.onOutgoingVideoCallInConversation.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'conversation-details-pane panel',
|
className: 'conversation-details-pane panel',
|
||||||
JSX: window.Signal.State.Roots.createConversationDetails(
|
JSX: window.Signal.State.Roots.createConversationDetails(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
props
|
props
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
view.headerTitle = '';
|
const headerTitle = '';
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view, headerTitle });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2366,7 +2396,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.resetPanel();
|
this.resetPanel();
|
||||||
};
|
};
|
||||||
|
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: 'panel message-detail-wrapper',
|
className: 'panel message-detail-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createMessageDetail(
|
JSX: window.Signal.State.Roots.createMessageDetail(
|
||||||
window.reduxStore,
|
window.reduxStore,
|
||||||
|
@ -2386,12 +2416,12 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
this.listenTo(message, 'expired', onClose);
|
this.listenTo(message, 'expired', onClose);
|
||||||
// We could listen to all involved contacts, but we'll call that overkill
|
// We could listen to all involved contacts, but we'll call that overkill
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
showStickerManager(): void {
|
showStickerManager(): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
className: ['sticker-manager-wrapper', 'panel'].join(' '),
|
className: ['sticker-manager-wrapper', 'panel'].join(' '),
|
||||||
JSX: window.Signal.State.Roots.createStickerManager(window.reduxStore),
|
JSX: window.Signal.State.Roots.createStickerManager(window.reduxStore),
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
|
@ -2399,7 +2429,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view });
|
||||||
view.render();
|
view.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2413,27 +2443,29 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
uuid: UUIDStringType;
|
uuid: UUIDStringType;
|
||||||
};
|
};
|
||||||
}): void {
|
}): void {
|
||||||
const view = new Whisper.ReactWrapperView({
|
const view = new ReactWrapperView({
|
||||||
Component: window.Signal.Components.ContactDetail,
|
|
||||||
className: 'contact-detail-pane panel',
|
className: 'contact-detail-pane panel',
|
||||||
props: {
|
JSX: (
|
||||||
contact,
|
<ContactDetail
|
||||||
hasSignalAccount: Boolean(signalAccount),
|
i18n={window.i18n}
|
||||||
onSendMessage: () => {
|
contact={contact}
|
||||||
if (signalAccount) {
|
hasSignalAccount={Boolean(signalAccount)}
|
||||||
this.startConversation(
|
onSendMessage={() => {
|
||||||
signalAccount.phoneNumber,
|
if (signalAccount) {
|
||||||
signalAccount.uuid
|
this.startConversation(
|
||||||
);
|
signalAccount.phoneNumber,
|
||||||
}
|
signalAccount.uuid
|
||||||
},
|
);
|
||||||
},
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
this.resetPanel();
|
this.resetPanel();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenBack(view);
|
this.addPanel({ view });
|
||||||
}
|
}
|
||||||
|
|
||||||
startConversation(e164: string, uuid: UUIDStringType): void {
|
startConversation(e164: string, uuid: UUIDStringType): void {
|
||||||
|
@ -2460,24 +2492,24 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
listenBack(view: AnyViewClass): void {
|
addPanel(panel: PanelType): void {
|
||||||
this.panels = this.panels || [];
|
this.panels = this.panels || [];
|
||||||
|
|
||||||
if (this.panels.length === 0) {
|
if (this.panels.length === 0) {
|
||||||
this.previousFocus = document.activeElement as HTMLElement;
|
this.previousFocus = document.activeElement as HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.panels.unshift(view);
|
this.panels.unshift(panel);
|
||||||
view.$el.insertAfter(this.$('.panel').last());
|
panel.view.$el.insertAfter(this.$('.panel').last());
|
||||||
view.$el.one('animationend', () => {
|
panel.view.$el.one('animationend', () => {
|
||||||
view.$el.addClass('panel--static');
|
panel.view.$el.addClass('panel--static');
|
||||||
});
|
});
|
||||||
|
|
||||||
window.reduxActions.conversations.setSelectedConversationPanelDepth(
|
window.reduxActions.conversations.setSelectedConversationPanelDepth(
|
||||||
this.panels.length
|
this.panels.length
|
||||||
);
|
);
|
||||||
window.reduxActions.conversations.setSelectedConversationHeaderTitle(
|
window.reduxActions.conversations.setSelectedConversationHeaderTitle(
|
||||||
view.headerTitle
|
panel.headerTitle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
resetPanel(): void {
|
resetPanel(): void {
|
||||||
|
@ -2485,7 +2517,7 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const view = this.panels.shift();
|
const panel = this.panels.shift();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.panels.length === 0 &&
|
this.panels.length === 0 &&
|
||||||
|
@ -2497,12 +2529,12 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.panels.length > 0) {
|
if (this.panels.length > 0) {
|
||||||
this.panels[0].$el.fadeIn(250);
|
this.panels[0].view.$el.fadeIn(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view) {
|
if (panel) {
|
||||||
view.$el.addClass('panel--remove').one('transitionend', () => {
|
panel.view.$el.addClass('panel--remove').one('transitionend', () => {
|
||||||
view.remove();
|
panel.view.remove();
|
||||||
|
|
||||||
if (this.panels.length === 0) {
|
if (this.panels.length === 0) {
|
||||||
// Make sure poppers are positioned properly
|
// Make sure poppers are positioned properly
|
|
@ -1,11 +1,14 @@
|
||||||
// Copyright 2014-2021 Signal Messenger, LLC
|
// Copyright 2014-2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
import * as Backbone from 'backbone';
|
import * as Backbone from 'backbone';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import type { ConversationModel } from '../models/conversations';
|
import type { ConversationModel } from '../models/conversations';
|
||||||
|
import { ReactWrapperView } from './ReactWrapperView';
|
||||||
import { showToast } from '../util/showToast';
|
import { showToast } from '../util/showToast';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
|
import { WhatsNewLink } from '../components/WhatsNewLink';
|
||||||
import { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed';
|
import { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed';
|
||||||
|
|
||||||
window.Whisper = window.Whisper || {};
|
window.Whisper = window.Whisper || {};
|
||||||
|
@ -163,12 +166,13 @@ Whisper.InboxView = Whisper.View.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { showWhatsNewModal } = window.reduxActions.globalModals;
|
const { showWhatsNewModal } = window.reduxActions.globalModals;
|
||||||
this.whatsNewLink = new Whisper.ReactWrapperView({
|
this.whatsNewLink = new ReactWrapperView({
|
||||||
Component: window.Signal.Components.WhatsNewLink,
|
JSX: (
|
||||||
props: {
|
<WhatsNewLink
|
||||||
i18n: window.i18n,
|
i18n={window.i18n}
|
||||||
showWhatsNewModal,
|
showWhatsNewModal={showWhatsNewModal}
|
||||||
},
|
/>
|
||||||
|
),
|
||||||
});
|
});
|
||||||
this.$('.whats-new-placeholder').append(this.whatsNewLink.el);
|
this.$('.whats-new-placeholder').append(this.whatsNewLink.el);
|
||||||
},
|
},
|
||||||
|
@ -176,7 +180,7 @@ Whisper.InboxView = Whisper.View.extend({
|
||||||
if (this.leftPaneView) {
|
if (this.leftPaneView) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.leftPaneView = new Whisper.ReactWrapperView({
|
this.leftPaneView = new ReactWrapperView({
|
||||||
className: 'left-pane-wrapper',
|
className: 'left-pane-wrapper',
|
||||||
JSX: window.Signal.State.Roots.createLeftPane(window.reduxStore),
|
JSX: window.Signal.State.Roots.createLeftPane(window.reduxStore),
|
||||||
});
|
});
|
34
ts/window.d.ts
vendored
34
ts/window.d.ts
vendored
|
@ -74,17 +74,11 @@ import { BatcherType } from './util/batcher';
|
||||||
import { AttachmentList } from './components/conversation/AttachmentList';
|
import { AttachmentList } from './components/conversation/AttachmentList';
|
||||||
import { ChatColorPicker } from './components/ChatColorPicker';
|
import { ChatColorPicker } from './components/ChatColorPicker';
|
||||||
import { ConfirmationDialog } from './components/ConfirmationDialog';
|
import { ConfirmationDialog } from './components/ConfirmationDialog';
|
||||||
import { ContactDetail } from './components/conversation/ContactDetail';
|
|
||||||
import { ContactModal } from './components/conversation/ContactModal';
|
import { ContactModal } from './components/conversation/ContactModal';
|
||||||
import { ErrorModal } from './components/ErrorModal';
|
|
||||||
import { Lightbox } from './components/Lightbox';
|
|
||||||
import { MediaGallery } from './components/conversation/media-gallery/MediaGallery';
|
|
||||||
import { MessageDetail } from './components/conversation/MessageDetail';
|
import { MessageDetail } from './components/conversation/MessageDetail';
|
||||||
import { ProgressModal } from './components/ProgressModal';
|
|
||||||
import { Quote } from './components/conversation/Quote';
|
import { Quote } from './components/conversation/Quote';
|
||||||
import { StagedLinkPreview } from './components/conversation/StagedLinkPreview';
|
import { StagedLinkPreview } from './components/conversation/StagedLinkPreview';
|
||||||
import { DisappearingTimeDialog } from './components/DisappearingTimeDialog';
|
import { DisappearingTimeDialog } from './components/DisappearingTimeDialog';
|
||||||
import { WhatsNewLink } from './components/WhatsNewLink';
|
|
||||||
import { DownloadedAttachmentType } from './types/Attachment';
|
import { DownloadedAttachmentType } from './types/Attachment';
|
||||||
import { ElectronLocaleType } from './util/mapToSupportLocale';
|
import { ElectronLocaleType } from './util/mapToSupportLocale';
|
||||||
import { SignalProtocolStore } from './SignalProtocolStore';
|
import { SignalProtocolStore } from './SignalProtocolStore';
|
||||||
|
@ -370,17 +364,11 @@ declare global {
|
||||||
AttachmentList: typeof AttachmentList;
|
AttachmentList: typeof AttachmentList;
|
||||||
ChatColorPicker: typeof ChatColorPicker;
|
ChatColorPicker: typeof ChatColorPicker;
|
||||||
ConfirmationDialog: typeof ConfirmationDialog;
|
ConfirmationDialog: typeof ConfirmationDialog;
|
||||||
ContactDetail: typeof ContactDetail;
|
|
||||||
ContactModal: typeof ContactModal;
|
ContactModal: typeof ContactModal;
|
||||||
DisappearingTimeDialog: typeof DisappearingTimeDialog;
|
DisappearingTimeDialog: typeof DisappearingTimeDialog;
|
||||||
ErrorModal: typeof ErrorModal;
|
|
||||||
Lightbox: typeof Lightbox;
|
|
||||||
MediaGallery: typeof MediaGallery;
|
|
||||||
MessageDetail: typeof MessageDetail;
|
MessageDetail: typeof MessageDetail;
|
||||||
ProgressModal: typeof ProgressModal;
|
|
||||||
Quote: typeof Quote;
|
Quote: typeof Quote;
|
||||||
StagedLinkPreview: typeof StagedLinkPreview;
|
StagedLinkPreview: typeof StagedLinkPreview;
|
||||||
WhatsNewLink: typeof WhatsNewLink;
|
|
||||||
};
|
};
|
||||||
OS: typeof OS;
|
OS: typeof OS;
|
||||||
State: {
|
State: {
|
||||||
|
@ -506,17 +494,6 @@ export class CanvasVideoRenderer {
|
||||||
constructor(canvas: Ref<HTMLCanvasElement>);
|
constructor(canvas: Ref<HTMLCanvasElement>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnyViewClass extends window.Backbone.View<any> {
|
|
||||||
public headerTitle?: string;
|
|
||||||
static show(view: typeof AnyViewClass, element: Element): void;
|
|
||||||
|
|
||||||
constructor(options?: any);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BasicReactWrapperViewClass extends AnyViewClass {
|
|
||||||
public update(options: any): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WhisperType = {
|
export type WhisperType = {
|
||||||
Conversation: typeof ConversationModel;
|
Conversation: typeof ConversationModel;
|
||||||
ConversationCollection: typeof ConversationModelCollectionType;
|
ConversationCollection: typeof ConversationModelCollectionType;
|
||||||
|
@ -530,18 +507,11 @@ export type WhisperType = {
|
||||||
|
|
||||||
// Backbone views
|
// Backbone views
|
||||||
|
|
||||||
// Modernized
|
|
||||||
ConversationView: typeof ConversationView;
|
ConversationView: typeof ConversationView;
|
||||||
|
|
||||||
// Note: we can no longer use 'View.extend' once we've moved to Typescript's preferred
|
// Note: we can no longer use 'View.extend' once we've moved to Typescript's preferred
|
||||||
// 'extend View' syntax. Thus, we'll need to typescriptify most of it at once.
|
// 'extend View' syntax. Thus, we'll need to typescriptify most of it at once.
|
||||||
|
|
||||||
ClearDataView: typeof AnyViewClass;
|
InboxView: typeof Backbone.View;
|
||||||
ConversationLoadingScreen: typeof AnyViewClass;
|
View: typeof Backbone.View;
|
||||||
GroupMemberList: typeof AnyViewClass;
|
|
||||||
InboxView: typeof AnyViewClass;
|
|
||||||
KeyVerificationPanelView: typeof AnyViewClass;
|
|
||||||
ReactWrapperView: typeof BasicReactWrapperViewClass;
|
|
||||||
SafetyNumberChangeDialogView: typeof AnyViewClass;
|
|
||||||
View: typeof AnyViewClass;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue