You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/components/session/SessionInboxView.tsx

274 lines
8.9 KiB
TypeScript

import React from 'react';
import { Provider } from 'react-redux';
import { bindActionCreators } from 'redux';
import { getMessageQueue } from '../../session';
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';
// 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;
};
type State = {
isInitialLoadComplete: boolean;
settingsCategory?: SessionSettingCategory;
};
// tslint:disable: react-a11y-img-has-alt
export class SessionInboxView extends React.Component<Props, State> {
private store: any;
constructor(props: any) {
super(props);
this.state = {
isInitialLoadComplete: false,
settingsCategory: undefined,
};
// 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);
void this.setupLeftPane();
// ConversationCollection
// this.listenTo(inboxCollection, 'messageError', () => {
// if (this.networkStatusView) {
// this.networkStatusView.render();
// }
// });
// this.networkStatusView = new Whisper.NetworkStatusView();
// this.$el
// .find('.network-status-container')
// .append(this.networkStatusView.render().el);
// extension.expired(expired => {
// if (expired) {
// const banner = new Whisper.ExpiredAlertBanner().render();
// banner.$el.prependTo(this.$el);
// this.$el.addClass('expired');
// }
// });
}
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>
); }
private renderLeftPane() {
return (
<FilteredLeftPane
showSessionSettingsCategory={this.showSessionSettingsCategory}
showSessionViewConversation={this.showSessionViewConversation}
settingsCategory={this.state.settingsCategory}
/>
);
}
private renderSettings() {
const isSecondaryDevice = !!window.textsecure.storage.get('isSecondaryDevice');
const category = this.state.settingsCategory || SessionSettingCategory.Appearance;
return (
<SettingsView
isSecondaryDevice={isSecondaryDevice}
category={category}
/>
);
}
private renderSessionConversation() {
return (
<div className="session-conversation">
<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,
});
if (!tmpMsg) {
return null;
}
// find the corresponding conversation of this message
const conv = window.ConversationController.get(
tmpMsg.get('conversationId')
);
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];
if (!msg || !msg.message) {
return null;
}
return { msg: msg.message };
}
private async handleMessageSentSuccess(sentMessage: any, wrappedEnvelope: any) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
msg.handleMessageSentSuccess(sentMessage, wrappedEnvelope);
}
private async handleMessageSentFailure(sentMessage: any, error: any) {
const fetchedData = await this.fetchHandleMessageSentData(sentMessage);
if (!fetchedData) {
return;
}
const { msg } = fetchedData;
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
);
const filledConversations = conversations.map(async (conv: any) => {
const messages = await window.getMessagesByKey(conv.id);
return { ...conv, messages };
});
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,
},
};
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
);
// this.openConversationAction = openConversationExternal;
this.fetchHandleMessageSentData = this.fetchHandleMessageSentData.bind(
this
);
this.handleMessageSentFailure = this.handleMessageSentFailure.bind(this);
this.handleMessageSentSuccess = this.handleMessageSentSuccess.bind(this);
// 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('success', this.handleMessageSentSuccess);
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 });
}
private showSessionSettingsCategory(category: SessionSettingCategory) {
this.setState({ settingsCategory: category });
}
private showSessionViewConversation() {
this.setState({ settingsCategory: undefined });
}
}