link back backbone conversation events to redux store

This commit is contained in:
Audric Ackermann 2020-11-13 17:17:48 +11:00
parent 918eeae275
commit 2f2eb2ad53
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
26 changed files with 354 additions and 433 deletions

View File

@ -11,7 +11,6 @@ exports.createTemplate = (options, messages) => {
openReleaseNotes,
openSupportPage,
platform,
setupAsStandalone,
setupWithImport,
showAbout,
showDebugLog,
@ -153,12 +152,6 @@ exports.createTemplate = (options, messages) => {
const fileMenu = template[0];
// These are in reverse order, since we're prepending them one at a time
if (options.development) {
fileMenu.submenu.unshift({
label: messages.menuSetupAsStandalone.message,
click: setupAsStandalone,
});
}
fileMenu.submenu.unshift({
type: 'separator',
@ -177,13 +170,7 @@ exports.createTemplate = (options, messages) => {
};
function updateForMac(template, messages, options) {
const {
includeSetup,
setupAsStandalone,
setupWithImport,
showAbout,
showWindow,
} = options;
const { includeSetup, setupWithImport, showAbout, showWindow } = options;
// Remove About item and separator from Help menu, since it's on the first menu
template[4].submenu.pop();
@ -205,13 +192,6 @@ function updateForMac(template, messages, options) {
],
};
if (options.development) {
fileMenu.submenu.push({
label: messages.menuSetupAsStandalone.message,
click: setupAsStandalone,
});
}
template.unshift(fileMenu);
}

View File

@ -165,7 +165,6 @@
let initialLoadComplete = false;
let newVersion = false;
window.owsDesktopApp = {};
window.document.title = window.getTitle();
// start a background worker for ecc
@ -477,13 +476,6 @@
}
);
Whisper.events.on('setupAsStandalone', () => {
const { appView } = window.owsDesktopApp;
if (appView) {
appView.openStandalone();
}
});
function manageExpiringData() {
window.Signal.Data.cleanSeenMessages();
window.Signal.Data.cleanLastHashes();
@ -570,7 +562,6 @@
const appView = new Whisper.AppView({
el: $('body'),
});
window.owsDesktopApp.appView = appView;
Whisper.WallClockListener.init(Whisper.events);
Whisper.ExpiringMessagesListener.init(Whisper.events);
@ -608,12 +599,6 @@
window.addEventListener('focus', () => Whisper.Notifications.clear());
window.addEventListener('unload', () => Whisper.Notifications.fastClear());
Whisper.events.on('showConversation', (id, messageId) => {
if (appView) {
appView.openConversation(id, messageId);
}
});
window.confirmationDialog = params => {
const confirmDialog = new Whisper.SessionConfirmView({
el: $('body'),
@ -634,9 +619,6 @@
confirmDialog.render();
};
window.showSeedDialog = window.owsDesktopApp.appView.showSeedDialog;
window.showPasswordDialog = window.owsDesktopApp.appView.showPasswordDialog;
window.showEditProfileDialog = async callback => {
const ourNumber = window.storage.get('primaryDevicePubKey');
const conversation = await ConversationController.getOrCreateAndWait(
@ -930,7 +912,9 @@
window.log.warn(`Could not connect to ${serverAddress}`);
return;
}
appView.openConversation(conversationId, {});
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(conversationId)
);
}
);
@ -943,7 +927,9 @@
Whisper.Notifications.on('click', (id, messageId) => {
window.showWindow();
if (id) {
appView.openConversation(id, messageId);
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(id, messageId)
);
} else {
appView.openInbox({
initialLoadComplete,
@ -981,7 +967,9 @@
avatarPath,
isRss: conversation.isRss(),
onStartConversation: () => {
Whisper.events.trigger('showConversation', userPubKey);
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(conversation.id)
);
},
});
}
@ -1308,24 +1296,24 @@
}
function onChangeTheme() {
const view = window.owsDesktopApp.appView;
if (view) {
view.applyTheme();
}
// const view = window.owsDesktopApp.appView;
// if (view) {
// view.applyTheme();
// }
}
function onEmpty() {
initialLoadComplete = true;
window.readyForUpdates();
let interval = setInterval(() => {
const view = window.owsDesktopApp.appView;
if (view) {
clearInterval(interval);
interval = null;
view.onEmpty();
}
}, 500);
// let interval = setInterval(() => {
// const view = window.owsDesktopApp.appView;
// if (view) {
// clearInterval(interval);
// interval = null;
// view.onEmpty();
// }
// }, 500);
Whisper.Notifications.enable();
}
@ -1345,10 +1333,10 @@
const { count } = ev;
window.log.info(`onProgress: Message count is ${count}`);
const view = window.owsDesktopApp.appView;
if (view) {
view.onProgress(count);
}
// const view = window.owsDesktopApp.appView;
// if (view) {
// view.onProgress(count);
// }
}
function onConfiguration(ev) {
const { configuration } = ev;

View File

@ -1,4 +1,4 @@
/* global Whisper, Backbone, textsecure, libsignal, log */
/* global Whisper, textsecure, libsignal, log */
/* eslint-disable more/no-then */
@ -9,33 +9,7 @@
window.Whisper = window.Whisper || {};
const conversations = new Whisper.ConversationCollection();
const inboxCollection = new (Backbone.Collection.extend({
initialize() {
this.listenTo(conversations, 'add change:active_at', this.addActive);
this.listenTo(conversations, 'reset', () => this.reset([]));
this.listenTo(conversations, 'remove', this.remove);
this.startPruning();
},
addActive(model) {
if (model.get('active_at')) {
this.add(model);
model.updateLastMessage();
} else {
this.remove(model);
}
},
startPruning() {
const halfHour = 30 * 60 * 1000;
this.interval = setInterval(() => {
this.forEach(conversation => {
conversation.trigger('prune');
});
}, halfHour);
},
}))();
window.getInboxCollection = () => inboxCollection;
window.getConversations = () => conversations;
window.getMessagesByKey = async key => {
@ -154,6 +128,15 @@
window.SnodePool.getSnodesFor(id),
]);
}
if (window.inboxStore) {
conversation.on('change', this.updateReduxConvoChanged);
window.inboxStore.dispatch(
window.actionsCreators.conversationAdded(
conversation.id,
conversation.getProps()
)
);
}
});
return conversation;
@ -203,7 +186,13 @@
await window.Signal.Data.removeConversation(id, {
Conversation: Whisper.Conversation,
});
conversation.off('change', this.updateReduxConvoChanged);
conversations.remove(conversation);
if (window.inboxStore) {
window.inboxStore.dispatch(
window.actionsCreators.conversationRemoved(conversation.id)
);
}
},
getOrCreateAndWait(id, type) {
return this._initialPromise.then(() => {
@ -237,6 +226,22 @@
this._initialPromise = Promise.resolve();
this._initialFetchComplete = false;
conversations.reset([]);
if (window.inboxStore) {
conversations.forEach(convo =>
convo.off('change', this.updateReduxConvoChanged)
);
window.inboxStore.dispatch(
window.actionsCreators.removeAllConversations()
);
}
},
updateReduxConvoChanged(convo) {
if (window.inboxStore) {
window.inboxStore.dispatch(
window.actionsCreators.conversationChanged(convo.id, convo.getProps())
);
}
},
async load() {
window.log.info('ConversationController: starting initial fetch');
@ -265,6 +270,10 @@
conversation.updateProfileAvatar(),
]);
});
conversations.forEach(conversation => {
// register for change event on each conversation, and forward to redux
conversation.on('change', this.updateReduxConvoChanged);
});
await Promise.all(promises);
// Remove any unused images

View File

@ -598,7 +598,6 @@
isExpired: this.hasExpired,
expirationLength,
expirationTimestamp,
multiSelectMode: conversation && conversation.selectedMessages.size > 0,
isPublic: !!this.get('isPublic'),
isRss: !!this.get('isRss'),
isKickedFromGroup:

View File

@ -49,7 +49,9 @@ const { SessionModal } = require('../../ts/components/session/SessionModal');
const {
SessionSeedModal,
} = require('../../ts/components/session/SessionSeedModal');
const { SessionInboxView} = require('../../ts/components/session/SessionInboxView')
const {
SessionInboxView,
} = require('../../ts/components/session/SessionInboxView');
const {
SessionPasswordModal,
} = require('../../ts/components/session/SessionPasswordModal');

View File

@ -123,25 +123,18 @@
return Promise.resolve();
},
onEmpty() {
const view = this.inboxView;
// const view = this.inboxView;
this.initialLoadComplete = true;
if (view) {
view.onEmpty();
}
// this.initialLoadComplete = true;
// if (view) {
// view.onEmpty();
// }
},
onProgress(count) {
const view = this.inboxView;
if (view) {
view.onProgress(count);
}
},
openConversation(id, messageId) {
if (id) {
this.openInbox().then(() => {
this.inboxView.openConversation(id, messageId);
});
}
// const view = this.inboxView;
// if (view) {
// view.onProgress(count);
// }
},
showEditProfileDialog(options) {
const dialog = new Whisper.EditProfileDialogView(options);

View File

@ -1,15 +1,11 @@
/*
global
$
ConversationController,
extension,
ConversationController
getConversations,
getInboxCollection,
i18n,
Whisper,
textsecure,
Signal,
*/
// eslint-disable-next-line func-names
@ -18,11 +14,6 @@
window.Whisper = window.Whisper || {};
Whisper.AppLoadingScreen = Whisper.View.extend({
templateName: 'app-loading-screen',
className: 'app-loading-screen',
});
Whisper.InboxViewWhisper = Whisper.View.extend({
templateName: 'two-column',
className: 'inbox index',
@ -67,35 +58,6 @@
this.setupLeftPane();
},
startConnectionListener() {
this.interval = setInterval(() => {
const status = window.getSocketStatus();
switch (status) {
case WebSocket.CONNECTING:
break;
case WebSocket.OPEN:
clearInterval(this.interval);
// Default to connected, but lokinet is slow so we pretend empty event
this.onEmpty();
this.interval = null;
break;
case WebSocket.CLOSING:
case WebSocket.CLOSED:
clearInterval(this.interval);
this.interval = null;
// if we failed to connect, we pretend we got an empty event
this.onEmpty();
break;
default:
// We also replicate empty here
this.onEmpty();
break;
}
}, 1000);
},
onEmpty() {
const view = this.appLoadingScreen;
if (view) {

View File

@ -2,27 +2,27 @@
// eslint-disable-next-line func-names
(function() {
'use strict';
'use strict';
window.Whisper = window.Whisper || {};
window.Whisper = window.Whisper || {};
Whisper.InboxView = Whisper.View.extend({
initialize() {
this.render();
},
Whisper.InboxView = Whisper.View.extend({
initialize() {
this.render();
},
render() {
this.dialogView = new Whisper.ReactWrapperView({
className: 'inbox index',
Component: window.Signal.Components.SessionInboxView,
});
render() {
this.dialogView = new Whisper.ReactWrapperView({
className: 'inbox index',
Component: window.Signal.Components.SessionInboxView,
});
this.$el.append(this.dialogView.el);
return this;
},
this.$el.append(this.dialogView.el);
return this;
},
close() {
this.remove();
},
});
})();
close() {
this.remove();
},
});
})();

View File

@ -513,12 +513,6 @@ function setupWithImport() {
}
}
function setupAsStandalone() {
if (mainWindow) {
mainWindow.webContents.send('set-up-as-standalone');
}
}
let passwordWindow;
function showPasswordWindow() {
if (passwordWindow) {
@ -868,7 +862,6 @@ function setupMenu(options) {
openSupportPage,
platform,
setupWithImport,
setupAsStandalone,
});
const template = createTemplate(menuOptions, locale.messages);
const menu = Menu.buildFromTemplate(template);

View File

@ -240,10 +240,6 @@ ipc.on('set-up-with-import', () => {
Whisper.events.trigger('setupWithImport');
});
ipc.on('set-up-as-standalone', () => {
Whisper.events.trigger('setupAsStandalone');
});
ipc.on('get-theme-setting', () => {
const theme = window.Events.getThemeSetting();
ipc.send('get-success-theme-setting', theme);

View File

@ -1,4 +1,4 @@
.inbox {
.inbox {
height: 100%;
overflow: hidden;
}

View File

@ -27,49 +27,20 @@
}
}
.conversation-item {
display: flex;
flex-direction: column;
flex-grow: 1;
.conversation-item__options-pane {
position: absolute;
height: 100%;
outline: none;
right: 0vw;
.selection-mode {
.messages-container > *:not(.message-selected) {
animation: toShadow $session-transition-duration;
opacity: 0.25;
}
transition: transform 1.5 * $session-transition-duration ease-in-out;
transform: translateX(100%);
will-change: transform;
width: 25vw;
.conversation-header {
.conversation-header {
&--items-wrapper {
.session-icon {
opacity: 0;
}
user-select: none;
pointer-events: none;
opacity: 0.25;
}
}
}
}
&__options-pane {
position: absolute;
height: 100%;
right: 0vw;
transition: transform 1.5 * $session-transition-duration ease-in-out;
transform: translateX(100%);
will-change: transform;
width: 25vw;
&.show {
transform: none;
transition: transform $session-transition-duration ease-in-out;
z-index: 2;
}
&.show {
transform: none;
transition: transform $session-transition-duration ease-in-out;
z-index: 2;
}
}
@ -116,6 +87,28 @@
flex-grow: 1;
display: flex;
flex-direction: column;
max-width: calc(100vw - 380px);
.selection-mode {
.messages-container > *:not(.message-selected) {
animation: toShadow $session-transition-duration;
opacity: 0.25;
}
.conversation-header {
.conversation-header {
&--items-wrapper {
.session-icon {
opacity: 0;
}
user-select: none;
pointer-events: none;
opacity: 0.25;
}
}
}
}
}
.conversation-content {
@ -173,7 +166,6 @@
flex-grow: 1;
flex-direction: column-reverse;
position: relative;
overflow-y: auto;
overflow-x: hidden;
min-width: 370px;
scrollbar-width: 4px;

View File

@ -108,9 +108,11 @@ $session-compose-margin: 20px;
&__sections-container {
height: 100vh;
flex-shrink: 0;
width: 80px;
overflow-x: hidden;
display: inline-flex;
flex-direction: column;
overflow: auto;
@include themify($themes) {
border-right: themed('sessionBorder');
}

View File

@ -51,7 +51,6 @@ describe('SignalMenu', () => {
openSupportPage: null,
platform,
includeSetup,
setupAsStandalone: null,
setupWithImport: null,
showAbout: null,
showDebugLog: null,

View File

@ -168,7 +168,11 @@ export class LeftPane extends React.Component<Props> {
}
private renderSettingSection() {
const { isSecondaryDevice, showSessionSettingsCategory, settingsCategory } = this.props;
const {
isSecondaryDevice,
showSessionSettingsCategory,
settingsCategory,
} = this.props;
const category = settingsCategory || SessionSettingCategory.Appearance;

View File

@ -21,7 +21,7 @@ export type PropsData = {
type PropsHousekeeping = {
i18n: LocalizerType;
openConversation: (id: string, messageId?: string) => void;
openConversationExternal: (id: string, messageId?: string) => void;
};
type Props = PropsData & PropsHousekeeping;
@ -34,7 +34,7 @@ export class SearchResults extends React.Component<Props> {
hideMessagesHeader,
i18n,
messages,
openConversation,
openConversationExternal,
searchTerm,
} = this.props;
@ -59,14 +59,14 @@ export class SearchResults extends React.Component<Props> {
<ConversationListItemWithDetails
key={conversation.phoneNumber}
{...conversation}
onClick={openConversation}
onClick={openConversationExternal}
i18n={i18n}
/>
))}
</div>
) : null}
{haveContacts
? this.renderContacts(i18n('contactsHeader'), contacts, true)
? this.renderContacts(i18n('contactsHeader'), contacts)
: null}
{haveMessages ? (
@ -80,7 +80,7 @@ export class SearchResults extends React.Component<Props> {
<MessageSearchResult
key={message.id}
{...message}
onClick={openConversation}
onClick={openConversationExternal}
i18n={i18n}
/>
))}
@ -91,10 +91,9 @@ export class SearchResults extends React.Component<Props> {
}
private renderContacts(
header: string,
items: Array<ConversationListItemPropsType>,
contacts?: boolean
items: Array<ConversationListItemPropsType>
) {
const { i18n, openConversation } = this.props;
const { i18n, openConversationExternal } = this.props;
return (
<div className="module-search-results__contacts">
@ -103,7 +102,7 @@ export class SearchResults extends React.Component<Props> {
<ConversationListItemWithDetails
key={contact.phoneNumber}
{...contact}
onClick={openConversation}
onClick={openConversationExternal}
i18n={i18n}
/>
))}

View File

@ -127,7 +127,13 @@ export class LeftPaneContactSection extends React.Component<Props, State> {
if (error) {
ToastUtils.pushToastError('addContact', error);
} else {
window.Whisper.events.trigger('showConversation', sessionID);
// tslint:disable-next-line: no-floating-promises
window.ConversationController.getOrCreateAndWait(
sessionID,
'private'
).then(() => {
this.props.openConversationExternal(sessionID);
});
}
}

View File

@ -144,7 +144,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
<SearchResults
{...searchResults}
contacts={contacts}
openConversation={openConversationExternal}
openConversationExternal={openConversationExternal}
i18n={window.i18n}
/>
);
@ -378,7 +378,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
this.setState({ valuePasted: value });
}
private handleMessageButtonClick() {
private async handleMessageButtonClick() {
const { openConversationExternal } = this.props;
if (!this.state.valuePasted && !this.props.searchTerm) {
@ -394,6 +394,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
const error = validateNumber(pubkey);
if (!error) {
await window.ConversationController.getOrCreateAndWait(pubkey, 'private');
openConversationExternal(pubkey);
} else {
ToastUtils.pushToastError('invalidPubKey', error);

View File

@ -58,7 +58,7 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
}
public renderRow(item: any): JSX.Element {
const {settingsCategory} = this.props;
const { settingsCategory } = this.props;
return (
<div
key={item.id}

View File

@ -6,14 +6,16 @@ import { createStore } from '../../state/createStore';
import { StateType } from '../../state/reducer';
import { SmartLeftPane } from '../../state/smart/LeftPane';
import { SmartSessionConversation } from '../../state/smart/SessionConversation';
import { SessionSettingCategory, SettingsView } from './settings/SessionSettings';
import {
SessionSettingCategory,
SettingsView,
} from './settings/SessionSettings';
// Workaround: A react component's required properties are filtering up through connect()
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31363
const FilteredLeftPane = SmartLeftPane as any;
const FilteredSessionConversation = SmartSessionConversation as any;
type Props = {
focusedSection: number;
};
@ -21,38 +23,44 @@ type Props = {
type State = {
isInitialLoadComplete: boolean;
settingsCategory?: SessionSettingCategory;
networkError: boolean;
};
// tslint:disable: react-a11y-img-has-alt
export class SessionInboxView extends React.Component<Props, State> {
private store: any;
private store: any;
private interval: NodeJS.Timeout | null = null;
constructor(props: any) {
super(props);
this.state = {
isInitialLoadComplete: false,
settingsCategory: undefined,
};
constructor(props: any) {
super(props);
this.state = {
isInitialLoadComplete: false,
settingsCategory: undefined,
networkError: false,
};
// Inbox
const inboxCollection = window.getInboxCollection();
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this);
this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this);
this.showSessionSettingsCategory = this.showSessionSettingsCategory.bind(this);
this.showSessionViewConversation = this.showSessionViewConversation.bind(this);
const conversationModels = window.getConversations();
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this);
this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this);
this.showSessionSettingsCategory = this.showSessionSettingsCategory.bind(
this
);
this.showSessionViewConversation = this.showSessionViewConversation.bind(
this
);
void this.setupLeftPane();
void this.setupLeftPane();
// ConversationCollection
// ConversationCollection
conversationModels;
// this.listenTo(inboxCollection, 'messageError', () => {
// if (this.networkStatusView) {
// this.networkStatusView.render();
// }
// if (this.networkStatusView) {
// this.networkStatusView.render();
// }
// });
// this.networkStatusView = new Whisper.NetworkStatusView();
@ -67,24 +75,26 @@ export class SessionInboxView extends React.Component<Props, State> {
// this.$el.addClass('expired');
// }
// });
}
public render() {
if (!this.state.isInitialLoadComplete) {
return <></>;
}
public render() {
if (!this.state.isInitialLoadComplete) {
return <></>;
}
const isSettingsView = this.state.settingsCategory !== undefined;
return (
<Provider store={this.store}>
<div className="gutter">
<div className="network-status-container"/>
{this.renderLeftPane()}
</div>
{isSettingsView ? this.renderSettings() : this.renderSessionConversation()}
</Provider>
); }
const isSettingsView = this.state.settingsCategory !== undefined;
return (
<Provider store={this.store}>
<div className="gutter">
<div className="network-status-container" />
{this.renderLeftPane()}
</div>
{isSettingsView
? this.renderSettings()
: this.renderSessionConversation()}
</Provider>
);
}
private renderLeftPane() {
return (
@ -97,14 +107,14 @@ export class SessionInboxView extends React.Component<Props, State> {
}
private renderSettings() {
const isSecondaryDevice = !!window.textsecure.storage.get('isSecondaryDevice');
const category = this.state.settingsCategory || SessionSettingCategory.Appearance;
const isSecondaryDevice = !!window.textsecure.storage.get(
'isSecondaryDevice'
);
const category =
this.state.settingsCategory || SessionSettingCategory.Appearance;
return (
<SettingsView
isSecondaryDevice={isSecondaryDevice}
category={category}
/>
<SettingsView isSecondaryDevice={isSecondaryDevice} category={category} />
);
}
@ -114,154 +124,134 @@ export class SessionInboxView extends React.Component<Props, State> {
<FilteredSessionConversation />
</div>
);
}
}
private async fetchHandleMessageSentData(m: any) {
// nobody is listening to this freshly fetched message .trigger calls
const tmpMsg = await window.Signal.Data.getMessageById(m.identifier, {
Message: window.Whisper.Message,
});
private async fetchHandleMessageSentData(m: any) {
// nobody is listening to this freshly fetched message .trigger calls
const tmpMsg = await window.Signal.Data.getMessageById(m.identifier, {
Message: window.Whisper.Message,
});
if (!tmpMsg) {
return null;
}
if (!tmpMsg) {
return null;
}
// find the corresponding conversation of this message
const conv = window.ConversationController.get(
tmpMsg.get('conversationId')
);
// find the corresponding conversation of this message
const conv = window.ConversationController.get(
tmpMsg.get('conversationId')
);
if (!conv) {
return null;
}
if (!conv) {
return null;
}
// then, find in this conversation the very same message
// const msg = conv.messageCollection.models.find(
// convMsg => convMsg.id === tmpMsg.id
// );
const msg = window.MessageController._get()[m.identifier];
// then, find in this conversation the very same message
// const msg = conv.messageCollection.models.find(
// convMsg => convMsg.id === tmpMsg.id
// );
const msg = window.MessageController._get()[m.identifier];
if (!msg || !msg.message) {
return null;
}
if (!msg || !msg.message) {
return null;
}
return { msg: msg.message };
}
return { msg: msg.message };
}
private async handleMessageSentSuccess(sentMessage: any, wrappedEnvelope: any) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
private async handleMessageSentSuccess(
sentMessage: any,
wrappedEnvelope: any
) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
msg.handleMessageSentSuccess(sentMessage, wrappedEnvelope);
}
msg.handleMessageSentSuccess(sentMessage, wrappedEnvelope);
}
private async handleMessageSentFailure(sentMessage: any, error: any) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
private async handleMessageSentFailure(sentMessage: any, error: any) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
await msg.handleMessageSentFailure(sentMessage, error);
}
await msg.handleMessageSentFailure(sentMessage, error);
}
private async setupLeftPane() {
// Here we set up a full redux store with initial state for our LeftPane Root
const convoCollection = window.getConversations();
const conversations = convoCollection.map(
(conversation: any) => conversation.cachedProps
);
private async setupLeftPane() {
// Here we set up a full redux store with initial state for our LeftPane Root
const convoCollection = window.getConversations();
const conversations = convoCollection.map(
(conversation: any) => conversation.cachedProps
);
const filledConversations = conversations.map(async (conv: any) => {
const messages = await window.getMessagesByKey(conv.id);
return { ...conv, messages };
});
const filledConversations = conversations.map(async (conv: any) => {
const messages = await window.getMessagesByKey(conv.id);
return { ...conv, messages };
});
const fullFilledConversations = await Promise.all(filledConversations);
const fullFilledConversations = await Promise.all(filledConversations);
const initialState = {
conversations: {
conversationLookup: window.Signal.Util.makeLookup(
fullFilledConversations,
'id'
),
},
user: {
regionCode: window.storage.get('regionCode'),
ourNumber:
window.storage.get('primaryDevicePubKey') ||
window.textsecure.storage.user.getNumber(),
isSecondaryDevice: !!window.storage.get('isSecondaryDevice'),
i18n: window.i18n,
},
section: {
focusedSection: 1,
},
};
const initialState = {
conversations: {
conversationLookup: window.Signal.Util.makeLookup(
fullFilledConversations,
'id'
),
},
user: {
regionCode: window.storage.get('regionCode'),
ourNumber:
window.storage.get('primaryDevicePubKey') ||
window.textsecure.storage.user.getNumber(),
isSecondaryDevice: !!window.storage.get('isSecondaryDevice'),
i18n: window.i18n,
},
section: {
focusedSection: 1,
},
};
this.store = createStore(initialState);
window.inboxStore = this.store;
this.store = createStore(initialState);
window.inboxStore = this.store;
// Enables our redux store to be updated by backbone events in the outside world
const {
conversationAdded,
conversationChanged,
conversationRemoved,
removeAllConversations,
messageExpired,
openConversationExternal,
} = bindActionCreators(
window.Signal.State.Ducks.conversations.actions,
this.store.dispatch
);
const { userChanged } = bindActionCreators(
window.Signal.State.Ducks.user.actions,
this.store.dispatch
);
const { messageChanged } = bindActionCreators(
window.Signal.State.Ducks.messages.actions,
this.store.dispatch
);
// Enables our redux store to be updated by backbone events in the outside world
const { messageExpired } = bindActionCreators(
window.Signal.State.Ducks.conversations.actions,
this.store.dispatch
);
window.actionsCreators = window.Signal.State.Ducks.conversations.actions;
const { userChanged } = bindActionCreators(
window.Signal.State.Ducks.user.actions,
this.store.dispatch
);
const { messageChanged } = bindActionCreators(
window.Signal.State.Ducks.messages.actions,
this.store.dispatch
);
// this.openConversationAction = openConversationExternal;
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this);
this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this);
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this);
this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this);
getMessageQueue().events.addListener(
'success',
this.handleMessageSentSuccess
);
// this.listenTo(convoCollection, 'remove', conversation => {
// const { id } = conversation || {};
// conversationRemoved(id);
// });
// this.listenTo(convoCollection, 'add', conversation => {
// const { id, cachedProps } = conversation || {};
// conversationAdded(id, cachedProps);
// });
// this.listenTo(convoCollection, 'change', conversation => {
// const { id, cachedProps } = conversation || {};
// conversationChanged(id, cachedProps);
// });
// this.listenTo(convoCollection, 'reset', removeAllConversations);
getMessageQueue().events.addListener('fail', this.handleMessageSentFailure);
getMessageQueue()
.events.addListener('success', this.handleMessageSentSuccess);
window.Whisper.events.on('messageExpired', messageExpired);
window.Whisper.events.on('messageChanged', messageChanged);
window.Whisper.events.on('userChanged', userChanged);
getMessageQueue()
.events.addListener('fail', this.handleMessageSentFailure);
window.Whisper.events.on('messageExpired', messageExpired);
window.Whisper.events.on('messageChanged', messageChanged);
window.Whisper.events.on('userChanged', userChanged);
// Finally, add it to the DOM
// this.$('.left-pane-placeholder').append(this.leftPaneView.el);
this.setState({ isInitialLoadComplete: true });
}
this.setState({ isInitialLoadComplete: true });
}
private showSessionSettingsCategory(category: SessionSettingCategory) {
this.setState({ settingsCategory: category });
@ -270,4 +260,34 @@ export class SessionInboxView extends React.Component<Props, State> {
private showSessionViewConversation() {
this.setState({ settingsCategory: undefined });
}
// private startConnectionListener() {
// this.interval = global.setInterval(() => {
// const status = window.getSocketStatus();
// switch (status) {
// case WebSocket.CONNECTING:
// break;
// case WebSocket.OPEN:
// if (this.interval) {
// clearInterval(this.interval);
// }
// // Default to connected, but lokinet is slow so we pretend empty event
// // this.onEmpty();
// this.interval = null;
// break;
// case WebSocket.CLOSING:
// case WebSocket.CLOSED:
// if (this.interval) {
// clearInterval(this.interval);
// }
// this.interval = null;
// // if we failed to connect, we pretend we got an empty event
// // this.onEmpty();
// break;
// default:
// // We also replicate empty here
// // this.onEmpty();
// }
// }, 1000);
// }
}

View File

@ -151,7 +151,6 @@ export class SessionConversation extends React.Component<Props, State> {
// ~~~~~~~~~~~~~~~~ LIFECYCLES ~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public componentDidUpdate(prevProps: Props, prevState: State) {
if (this.props.conversationKey !== prevProps.conversationKey) {
void this.loadInitialMessages();

View File

@ -128,7 +128,9 @@ export async function createMediumGroup(
convo.updateGroupAdmins(admins);
window.owsDesktopApp.appView.openConversation(groupId, {});
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(groupId)
);
// Subscribe to this group id
window.SwarmPolling.addGroupId(new PubKey(groupId));
@ -177,7 +179,9 @@ export async function createLegacyGroup(
await sendGroupUpdate(convo, diff, groupDetails, dbMessage.id);
window.textsecure.messaging.sendGroupSyncMessage([convo]);
window.owsDesktopApp.appView.openConversation(groupId, {});
window.inboxStore.dispatch(
window.actionsCreators.openConversationExternal(groupId)
);
}
export async function leaveMediumGroup(groupId: string) {

View File

@ -241,7 +241,6 @@ export function reducer(
selectedConversation = undefined;
}
}
return {
...state,
selectedConversation,
@ -255,7 +254,6 @@ export function reducer(
const { payload } = action;
const { id } = payload;
const { conversationLookup } = state;
return {
...state,
conversationLookup: omit(conversationLookup, [id]),
@ -270,15 +268,10 @@ export function reducer(
if (action.type === 'SELECTED_CONVERSATION_CHANGED') {
const { payload } = action;
const { id } = payload;
if (state.selectedConversation !== id) {
window.owsDesktopApp.appView.openConversation(id, {});
}
return {
...state,
selectedConversation: id,
};
}
return state;
}

View File

@ -75,7 +75,6 @@ export const actions = {
search,
clearSearch,
updateSearchTerm,
startNewConversation,
};
function search(
@ -143,22 +142,6 @@ function updateSearchTerm(query: string): UpdateSearchTermActionType {
},
};
}
function startNewConversation(
query: string,
options: { regionCode: string }
): ClearSearchActionType {
const { regionCode } = options;
const normalized = normalize(query, { regionCode });
if (!normalized) {
throw new Error('Attempted to start new conversation with invalid number');
}
trigger('showConversation', normalized);
return {
type: 'SEARCH_CLEAR',
payload: null,
};
}
// Helper functions for search

View File

@ -40,10 +40,8 @@ function getConversationTitle(
if (conversation.type === 'group') {
const { i18n } = options;
return i18n('unknown');
}
return format(conversation.phoneNumber, options);
}
@ -65,7 +63,6 @@ export const _getConversationComparator = (
if (leftTimestamp && rightTimestamp && leftTimestamp !== rightTimestamp) {
return rightTimestamp - leftTimestamp;
}
const leftTitle = getConversationTitle(left, {
i18n,
ourRegionCode,

4
ts/window.d.ts vendored
View File

@ -102,7 +102,6 @@ declare global {
GroupBuffer: any;
SwarmPolling: SwarmPolling;
MediaRecorder: any;
owsDesktopApp: any;
loadImage: any;
dataURLToBlobSync: any;
autoOrientImage: any;
@ -112,8 +111,9 @@ declare global {
) => Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }>;
setClockParams: any;
clientClockSynced: number | undefined;
getInboxCollection: any;
getMessagesByKey: any;
inboxStore: Store;
getSocketStatus: any;
actionsCreators: any;
}
}