do not pass props not needed between message list components
This commit is contained in:
parent
ea2dbb4a69
commit
7fa50b4a73
|
@ -17,7 +17,6 @@
|
|||
"postinstall": "electron-builder install-app-deps && rimraf node_modules/dtrace-provider",
|
||||
"start": "cross-env NODE_APP_INSTANCE=$MULTI electron .",
|
||||
"start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .",
|
||||
"start-prod2": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod2 electron .",
|
||||
"grunt": "grunt",
|
||||
"grunt:dev": "yarn clean-transpile; yarn grunt dev --force",
|
||||
"generate": "yarn grunt --force",
|
||||
|
@ -118,7 +117,6 @@
|
|||
"redux": "4.0.1",
|
||||
"redux-logger": "3.0.6",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-promise-middleware": "6.1.0",
|
||||
"reselect": "4.0.0",
|
||||
"rimraf": "2.6.2",
|
||||
"sanitize.css": "^12.0.1",
|
||||
|
|
|
@ -199,7 +199,7 @@ const MessageItem = (props: {
|
|||
if (!lastMessage && !isTyping) {
|
||||
return null;
|
||||
}
|
||||
const text = lastMessage && lastMessage.text ? lastMessage.text : '';
|
||||
const text = lastMessage?.text || '';
|
||||
|
||||
if (isEmpty(text)) {
|
||||
return null;
|
||||
|
@ -280,7 +280,7 @@ const ConversationListItem = (props: Props) => {
|
|||
const membersAvatar = useMembersAvatars(props);
|
||||
|
||||
const openConvo = useCallback(
|
||||
async (e: any) => {
|
||||
async (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
// mousedown is invoked sooner than onClick, but for both right and left click
|
||||
if (e.button === 0) {
|
||||
await openConversationWithMessages({ conversationKey: conversationId });
|
||||
|
@ -294,6 +294,10 @@ const ConversationListItem = (props: Props) => {
|
|||
<div
|
||||
role="button"
|
||||
onMouseDown={openConvo}
|
||||
onMouseUp={e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}}
|
||||
onContextMenu={(e: any) => {
|
||||
contextMenu.show({
|
||||
id: triggerId,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useAppIsFocused } from '../hooks/useAppFocused';
|
||||
import { getFocusedSettingsSection } from '../state/selectors/section';
|
||||
|
||||
import { SmartSessionConversation } from '../state/smart/SessionConversation';
|
||||
|
@ -11,6 +12,9 @@ export const SessionMainPanel = () => {
|
|||
const focusedSettingsSection = useSelector(getFocusedSettingsSection);
|
||||
const isSettingsView = focusedSettingsSection !== undefined;
|
||||
|
||||
// even if it looks like this does nothing, this does update the redux store.
|
||||
useAppIsFocused();
|
||||
|
||||
if (isSettingsView) {
|
||||
return <FilteredSettingsView category={focusedSettingsSection} />;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import React, { useCallback } from 'react';
|
|||
import { InView } from 'react-intersection-observer';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { getMessageById } from '../../data/data';
|
||||
import { useAppIsFocused } from '../../hooks/useAppFocused';
|
||||
import { Constants } from '../../session';
|
||||
import { getConversationController } from '../../session/conversations';
|
||||
import {
|
||||
|
@ -19,6 +18,7 @@ import {
|
|||
getOldestMessageId,
|
||||
getSelectedConversationKey,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { getIsAppFocused } from '../../state/selectors/section';
|
||||
|
||||
type ReadableMessageProps = {
|
||||
children: React.ReactNode;
|
||||
|
@ -45,7 +45,7 @@ const debouncedTriggerLoadMore = _.debounce(
|
|||
export const ReadableMessage = (props: ReadableMessageProps) => {
|
||||
const { messageId, onContextMenu, className, receivedAt, isUnread } = props;
|
||||
|
||||
const isAppFocused = useAppIsFocused();
|
||||
const isAppFocused = useSelector(getIsAppFocused);
|
||||
const dispatch = useDispatch();
|
||||
// onVisible={haveDoneFirstScrollProp ? onVisible : noop}
|
||||
|
||||
|
|
|
@ -49,10 +49,16 @@ export class EditProfileDialog extends React.Component<{}, State> {
|
|||
};
|
||||
|
||||
this.inputEl = React.createRef();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const i18n = window.i18n;
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import { SessionWrapperModal } from '../session/SessionWrapperModal';
|
|||
import { SpacerLG } from '../basic/Text';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateInviteContactModal } from '../../state/ducks/modalDialog';
|
||||
// tslint:disable-next-line: no-submodule-imports
|
||||
import useKey from 'react-use/lib/useKey';
|
||||
|
||||
type Props = {
|
||||
conversationId: string;
|
||||
|
@ -67,7 +69,6 @@ const InviteContactsDialogInner = (props: Props) => {
|
|||
);
|
||||
|
||||
const closeDialog = () => {
|
||||
window.removeEventListener('keyup', onKeyUp);
|
||||
dispatch(updateInviteContactModal(null));
|
||||
};
|
||||
|
||||
|
@ -87,19 +88,13 @@ const InviteContactsDialogInner = (props: Props) => {
|
|||
closeDialog();
|
||||
};
|
||||
|
||||
const onKeyUp = (event: any) => {
|
||||
switch (event.key) {
|
||||
case 'Enter':
|
||||
onClickOK();
|
||||
break;
|
||||
case 'Esc':
|
||||
case 'Escape':
|
||||
closeDialog();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
};
|
||||
window.addEventListener('keyup', onKeyUp);
|
||||
useKey((event: KeyboardEvent) => {
|
||||
return event.key === 'Enter';
|
||||
}, onClickOK);
|
||||
|
||||
useKey((event: KeyboardEvent) => {
|
||||
return event.key === 'Esc' || event.key === 'Escape';
|
||||
}, closeDialog);
|
||||
|
||||
const titleText = `${window.i18n('addingContacts')} ${chatName}`;
|
||||
const cancelText = window.i18n('cancel');
|
||||
|
|
|
@ -48,15 +48,17 @@ export class SessionModal extends React.PureComponent<Props, State> {
|
|||
this.close = this.close.bind(this);
|
||||
this.onKeyUp = this.onKeyUp.bind(this);
|
||||
this.node = null;
|
||||
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
|
||||
document.addEventListener('mousedown', this.handleClick, false);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
|
||||
document.removeEventListener('mousedown', this.handleClick, false);
|
||||
}
|
||||
|
||||
|
@ -118,7 +120,6 @@ export class SessionModal extends React.PureComponent<Props, State> {
|
|||
isVisible: false,
|
||||
});
|
||||
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
document.removeEventListener('mousedown', this.handleClick, false);
|
||||
|
||||
if (this.props.onClose) {
|
||||
|
|
|
@ -109,10 +109,16 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> {
|
|||
admins,
|
||||
isAdmin,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public onClickOK() {
|
||||
const members = this.getWouldBeMembers(this.state.contactList).map(d => d.id);
|
||||
|
||||
|
@ -243,8 +249,6 @@ export class UpdateGroupMembersDialog extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
private closeDialog() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
|
||||
window.inboxStore?.dispatch(updateGroupMembersModal(null));
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,16 @@ export class UpdateGroupNameDialog extends React.Component<Props, State> {
|
|||
avatar: this.convo.getAvatarPath(),
|
||||
};
|
||||
this.inputEl = React.createRef();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public onClickOK() {
|
||||
if (!this.state.groupName.trim()) {
|
||||
this.onShowError(window.i18n('emptyGroupNameError'));
|
||||
|
|
|
@ -173,7 +173,7 @@ const removeAllV1OpenGroups = async () => {
|
|||
if (window.inboxStore) {
|
||||
window.inboxStore?.dispatch(conversationRemoved(v1Convo.id));
|
||||
window.inboxStore?.dispatch(
|
||||
conversationChanged({ id: v1Convo.id, data: v1Convo.getProps() })
|
||||
conversationChanged({ id: v1Convo.id, data: v1Convo.getConversationModelProps() })
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -49,14 +49,19 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
|
|||
this.onKeyUp = this.onKeyUp.bind(this);
|
||||
this.onGroupNameChanged = this.onGroupNameChanged.bind(this);
|
||||
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
|
||||
if (this.inputRef.current) {
|
||||
this.inputRef.current.focus();
|
||||
}
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
|
||||
}
|
||||
|
||||
public getContacts() {
|
||||
const { overlayMode } = this.props;
|
||||
|
|
|
@ -76,7 +76,7 @@ export class SessionInboxView extends React.Component<any, State> {
|
|||
// Here we set up a full redux store with initial state for our LeftPane Root
|
||||
const convoCollection = getConversationController().getConversations();
|
||||
const conversations = convoCollection.map((conversation: ConversationModel) =>
|
||||
conversation.getProps()
|
||||
conversation.getConversationModelProps()
|
||||
);
|
||||
|
||||
const filledConversations = conversations.map((conv: any) => {
|
||||
|
|
|
@ -166,7 +166,7 @@ class SessionCompositionBoxInner extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
public componentDidMount() {
|
||||
setTimeout(this.focusCompositionBox, 100);
|
||||
setTimeout(this.focusCompositionBox, 500);
|
||||
|
||||
const div = this.container;
|
||||
div?.addEventListener('paste', this.handlePaste);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { QuoteClickOptions } from '../../../models/messageType';
|
||||
import { SortedMessageModelProps } from '../../../state/ducks/conversations';
|
||||
import { getSortedMessagesOfSelectedConversation } from '../../../state/selectors/conversations';
|
||||
import { getSortedMessagesTypesOfSelectedConversation } from '../../../state/selectors/conversations';
|
||||
import {
|
||||
DataExtractionNotificationItem,
|
||||
GenericMessageItem,
|
||||
|
@ -14,61 +13,57 @@ import {
|
|||
export const SessionMessagesList = (props: {
|
||||
scrollToQuoteMessage: (options: QuoteClickOptions) => Promise<void>;
|
||||
}) => {
|
||||
const messagesProps = useSelector(getSortedMessagesOfSelectedConversation);
|
||||
const messagesProps = useSelector(getSortedMessagesTypesOfSelectedConversation);
|
||||
|
||||
return (
|
||||
<>
|
||||
{messagesProps.map((messageProps: SortedMessageModelProps) => {
|
||||
const timerProps = messageProps.propsForTimerNotification;
|
||||
const propsForGroupInvitation = messageProps.propsForGroupInvitation;
|
||||
const propsForDataExtractionNotification = messageProps.propsForDataExtractionNotification;
|
||||
|
||||
const groupNotificationProps = messageProps.propsForGroupNotification;
|
||||
|
||||
if (groupNotificationProps) {
|
||||
{messagesProps.map(messageProps => {
|
||||
if (messageProps.messageType === 'group-notification') {
|
||||
return (
|
||||
<GroupUpdateItem
|
||||
key={messageProps.propsForMessage.id}
|
||||
groupNotificationProps={groupNotificationProps}
|
||||
key={messageProps.props.messageId}
|
||||
groupNotificationProps={messageProps.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (propsForGroupInvitation) {
|
||||
if (messageProps.messageType === 'group-invitation') {
|
||||
return (
|
||||
<GroupInvitationItem
|
||||
key={messageProps.propsForMessage.id}
|
||||
propsForGroupInvitation={propsForGroupInvitation}
|
||||
key={messageProps.props.messageId}
|
||||
propsForGroupInvitation={messageProps.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (propsForDataExtractionNotification) {
|
||||
if (messageProps.messageType === 'data-extraction') {
|
||||
return (
|
||||
<DataExtractionNotificationItem
|
||||
key={messageProps.propsForMessage.id}
|
||||
propsForDataExtractionNotification={propsForDataExtractionNotification}
|
||||
key={messageProps.props.messageId}
|
||||
propsForDataExtractionNotification={messageProps.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (timerProps) {
|
||||
if (messageProps.messageType === 'timer-notification') {
|
||||
return (
|
||||
<TimerNotificationItem key={messageProps.propsForMessage.id} timerProps={timerProps} />
|
||||
<TimerNotificationItem
|
||||
key={messageProps.props.messageId}
|
||||
timerProps={messageProps.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!messageProps) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// firstMessageOfSeries tells us to render the avatar only for the first message
|
||||
// in a series of messages from the same user
|
||||
return (
|
||||
<GenericMessageItem
|
||||
key={messageProps.propsForMessage.id}
|
||||
messageId={messageProps.propsForMessage.id}
|
||||
messageProps={messageProps}
|
||||
key={messageProps.props.messageId}
|
||||
messageId={messageProps.props.messageId}
|
||||
scrollToQuoteMessage={props.scrollToQuoteMessage}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
PropsForExpirationTimer,
|
||||
PropsForGroupInvitation,
|
||||
PropsForGroupUpdate,
|
||||
SortedMessageModelProps,
|
||||
} from '../../../state/ducks/conversations';
|
||||
import { getFirstUnreadMessageId } from '../../../state/selectors/conversations';
|
||||
import { DataExtractionNotification } from '../../conversation/DataExtractionNotification';
|
||||
|
@ -77,18 +76,13 @@ export const TimerNotificationItem = (props: { timerProps: PropsForExpirationTim
|
|||
|
||||
export const GenericMessageItem = (props: {
|
||||
messageId: string;
|
||||
messageProps: SortedMessageModelProps;
|
||||
scrollToQuoteMessage: (options: QuoteClickOptions) => Promise<void>;
|
||||
}) => {
|
||||
const messageId = props.messageId;
|
||||
|
||||
const onQuoteClick = props.messageProps.propsForMessage.quote
|
||||
? props.scrollToQuoteMessage
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<React.Fragment key={messageId}>
|
||||
<Message messageId={messageId} onQuoteClick={onQuoteClick} key={messageId} />
|
||||
<Message messageId={messageId} onQuoteClick={props.scrollToQuoteMessage} key={messageId} />
|
||||
<UnreadIndicator messageId={messageId} />
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -93,16 +93,21 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
void this.hasPassword();
|
||||
|
||||
this.onKeyUp = this.onKeyUp.bind(this);
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener('keyup', this.onKeyUp);
|
||||
|
||||
const mediaSetting = window.getSettingValue('media-permissions');
|
||||
this.setState({ mediaSetting });
|
||||
|
||||
setTimeout(() => ($('#password-lock-input') as any).focus(), 100);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
window.removeEventListener('keyup', this.onKeyUp);
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:max-func-body-length */
|
||||
public renderSettingInCategory() {
|
||||
const { category } = this.props;
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
import { remote } from 'electron';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { isElectronWindowFocused } from '../session/utils/WindowUtils';
|
||||
import { setIsAppFocused } from '../state/ducks/section';
|
||||
import { getIsAppFocused } from '../state/selectors/section';
|
||||
|
||||
export function useAppIsFocused() {
|
||||
const [isAppFocused, setIsAppFocused] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const isFocused = useSelector(getIsAppFocused);
|
||||
|
||||
useEffect(() => {
|
||||
setIsAppFocused(isElectronWindowFocused());
|
||||
dispatch(setIsAppFocused(isElectronWindowFocused()));
|
||||
}, []);
|
||||
|
||||
const onFocusCallback = useCallback(
|
||||
(_event, win) => {
|
||||
if (win.webContents.id === 1) {
|
||||
setIsAppFocused(true);
|
||||
}
|
||||
},
|
||||
[setIsAppFocused]
|
||||
);
|
||||
const onFocusCallback = useCallback((_event, win) => {
|
||||
if (win.webContents.id === 1) {
|
||||
dispatch(setIsAppFocused(true));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onBlurCallback = useCallback(
|
||||
(_event, win) => {
|
||||
if (win.webContents.id === 1) {
|
||||
setIsAppFocused(false);
|
||||
}
|
||||
},
|
||||
[setIsAppFocused]
|
||||
);
|
||||
const onBlurCallback = useCallback((_event, win) => {
|
||||
if (win.webContents.id === 1) {
|
||||
dispatch(setIsAppFocused(false));
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
remote.app.on('browser-window-focus', onFocusCallback);
|
||||
|
@ -36,5 +34,5 @@ export function useAppIsFocused() {
|
|||
};
|
||||
});
|
||||
|
||||
return isAppFocused;
|
||||
return isFocused;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { getDecryptedMediaUrl } from '../session/crypto/DecryptedAttachmentsManager';
|
||||
import { perfEnd, perfStart } from '../session/utils/Performance';
|
||||
|
||||
export const useEncryptedFileFetch = (url: string, contentType: string) => {
|
||||
// tslint:disable-next-line: no-bitwise
|
||||
|
@ -10,7 +11,11 @@ export const useEncryptedFileFetch = (url: string, contentType: string) => {
|
|||
const mountedRef = useRef(true);
|
||||
|
||||
async function fetchUrl() {
|
||||
perfStart(`getDecryptedMediaUrl${url}`);
|
||||
|
||||
const decryptedUrl = await getDecryptedMediaUrl(url, contentType);
|
||||
perfEnd(`getDecryptedMediaUrl${url}`, 'getDecryptedMediaUrl');
|
||||
|
||||
if (mountedRef.current) {
|
||||
setUrlToLoad(decryptedUrl);
|
||||
|
||||
|
|
|
@ -223,7 +223,9 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
this.typingRefreshTimer = null;
|
||||
this.typingPauseTimer = null;
|
||||
this.lastReadTimestamp = 0;
|
||||
window.inboxStore?.dispatch(conversationChanged({ id: this.id, data: this.getProps() }));
|
||||
window.inboxStore?.dispatch(
|
||||
conversationChanged({ id: this.id, data: this.getConversationModelProps() })
|
||||
);
|
||||
}
|
||||
|
||||
public idForLogging() {
|
||||
|
@ -407,7 +409,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
return this.get('moderators');
|
||||
}
|
||||
|
||||
public getProps(): ReduxConversationType {
|
||||
public getConversationModelProps(): ReduxConversationType {
|
||||
const groupAdmins = this.getGroupAdmins();
|
||||
const members = this.isGroup() && !this.isPublic() ? this.get('members') : [];
|
||||
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
|
||||
|
@ -804,13 +806,8 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
lastMessageStatus: lastMessageStatusModel,
|
||||
lastMessageNotificationText: lastMessageModel ? lastMessageModel.getNotificationText() : null,
|
||||
});
|
||||
// Because we're no longer using Backbone-integrated saves, we need to manually
|
||||
// clear the changed fields here so our hasChanged() check below is useful.
|
||||
(this as any).changed = {};
|
||||
this.set(lastMessageUpdate);
|
||||
if (this.hasChanged()) {
|
||||
await this.commit();
|
||||
}
|
||||
await this.commit();
|
||||
}
|
||||
|
||||
public async updateExpireTimer(
|
||||
|
@ -917,7 +914,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
conversationChanged({
|
||||
id: this.id,
|
||||
data: {
|
||||
...this.getProps(),
|
||||
...this.getConversationModelProps(),
|
||||
isSelected: false,
|
||||
},
|
||||
})
|
||||
|
@ -945,7 +942,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
window.inboxStore?.dispatch(
|
||||
conversationActions.messageAdded({
|
||||
conversationKey: this.id,
|
||||
messageModelProps: model.getProps(),
|
||||
messageModelProps: model.getMessageModelProps(),
|
||||
})
|
||||
);
|
||||
const unreadCount = await this.getUnreadCount();
|
||||
|
@ -1006,7 +1003,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
|
|||
const allProps: Array<MessageModelPropsWithoutConvoProps> = [];
|
||||
|
||||
for (const nowRead of oldUnreadNowRead) {
|
||||
allProps.push(nowRead.getProps());
|
||||
allProps.push(nowRead.getMessageModelProps());
|
||||
}
|
||||
|
||||
if (allProps.length) {
|
||||
|
|
|
@ -80,10 +80,10 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
|
||||
window.contextMenuShown = false;
|
||||
|
||||
this.getProps();
|
||||
this.getMessageModelProps();
|
||||
}
|
||||
|
||||
public getProps(): MessageModelPropsWithoutConvoProps {
|
||||
public getMessageModelProps(): MessageModelPropsWithoutConvoProps {
|
||||
perfStart(`getPropsMessage-${this.id}`);
|
||||
const messageProps: MessageModelPropsWithoutConvoProps = {
|
||||
propsForMessage: this.getPropsForMessage(),
|
||||
|
@ -1121,7 +1121,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
}
|
||||
}
|
||||
private dispatchMessageUpdate() {
|
||||
updatesToDispatch.set(this.id, this.getProps());
|
||||
updatesToDispatch.set(this.id, this.getMessageModelProps());
|
||||
trotthledAllMessagesDispatch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ export async function onError(ev: any) {
|
|||
window.inboxStore?.dispatch(
|
||||
conversationActions.messageAdded({
|
||||
conversationKey: conversation.id,
|
||||
messageModelProps: message.getProps(),
|
||||
messageModelProps: message.getMessageModelProps(),
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -454,7 +454,7 @@ export async function handleMessageJob(
|
|||
|
||||
updatesToDispatch.set(message.id, {
|
||||
conversationKey: conversation.id,
|
||||
messageModelProps: message.getProps(),
|
||||
messageModelProps: message.getMessageModelProps(),
|
||||
});
|
||||
trotthledAllMessagesAddedDispatch();
|
||||
if (message.get('unread')) {
|
||||
|
|
|
@ -120,7 +120,7 @@ export class ConversationController {
|
|||
window.inboxStore?.dispatch(
|
||||
conversationActions.conversationAdded({
|
||||
id: conversation.id,
|
||||
data: conversation.getProps(),
|
||||
data: conversation.getConversationModelProps(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ export class ConversationController {
|
|||
window.inboxStore?.dispatch(
|
||||
conversationActions.conversationChanged({
|
||||
id: conversation.id,
|
||||
data: conversation.getProps(),
|
||||
data: conversation.getConversationModelProps(),
|
||||
})
|
||||
);
|
||||
window.inboxStore?.dispatch(conversationActions.conversationRemoved(conversation.id));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import promise from 'redux-promise-middleware';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { rootReducer } from './reducer';
|
||||
|
@ -6,7 +5,6 @@ import { persistReducer } from 'redux-persist';
|
|||
|
||||
// tslint:disable-next-line: no-submodule-imports match-default-export-name
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
// @ts-ignore
|
||||
const env = window.getEnvironment();
|
||||
|
||||
|
|
|
@ -300,7 +300,7 @@ async function getMessages(
|
|||
});
|
||||
|
||||
const messageProps: Array<MessageModelPropsWithoutConvoProps> = messageSet.models.map(m =>
|
||||
m.getProps()
|
||||
m.getMessageModelProps()
|
||||
);
|
||||
return messageProps;
|
||||
}
|
||||
|
@ -326,11 +326,11 @@ export const fetchMessagesForConversation = createAsyncThunk(
|
|||
}): Promise<FetchedMessageResults> => {
|
||||
const beforeTimestamp = Date.now();
|
||||
// tslint:disable-next-line: no-console
|
||||
console.time('fetchMessagesForConversation');
|
||||
perfStart('fetchMessagesForConversation');
|
||||
const messagesProps = await getMessages(conversationKey, count);
|
||||
const afterTimestamp = Date.now();
|
||||
// tslint:disable-next-line: no-console
|
||||
console.timeEnd('fetchMessagesForConversation');
|
||||
perfEnd('fetchMessagesForConversation', 'fetchMessagesForConversation');
|
||||
|
||||
const time = afterTimestamp - beforeTimestamp;
|
||||
window?.log?.info(`Loading ${messagesProps.length} messages took ${time}ms to load.`);
|
||||
|
@ -824,10 +824,16 @@ export async function openConversationWithMessages(args: {
|
|||
messageId?: string;
|
||||
}) {
|
||||
const { conversationKey, messageId } = args;
|
||||
perfStart('getFirstUnreadMessageIdInConversation');
|
||||
const firstUnreadIdOnOpen = await getFirstUnreadMessageIdInConversation(conversationKey);
|
||||
perfEnd('getFirstUnreadMessageIdInConversation', 'getFirstUnreadMessageIdInConversation');
|
||||
|
||||
// preload 30 messages
|
||||
perfStart('getMessages');
|
||||
|
||||
const initialMessages = await getMessages(conversationKey, 30);
|
||||
perfEnd('getMessages', 'getMessages');
|
||||
console.warn('initialMessages', initialMessages);
|
||||
|
||||
window.inboxStore?.dispatch(
|
||||
actions.openConversationExternal({
|
||||
|
|
|
@ -2,6 +2,7 @@ import { SessionSettingCategory } from '../../components/session/settings/Sessio
|
|||
|
||||
export const FOCUS_SECTION = 'FOCUS_SECTION';
|
||||
export const FOCUS_SETTINGS_SECTION = 'FOCUS_SETTINGS_SECTION';
|
||||
export const IS_APP_FOCUSED = 'IS_APP_FOCUSED';
|
||||
|
||||
export enum SectionType {
|
||||
Profile,
|
||||
|
@ -23,6 +24,11 @@ type FocusSettingsSectionActionType = {
|
|||
payload: SessionSettingCategory;
|
||||
};
|
||||
|
||||
type IsAppFocusedActionType = {
|
||||
type: 'IS_APP_FOCUSED';
|
||||
payload: boolean;
|
||||
};
|
||||
|
||||
export function showLeftPaneSection(section: SectionType): FocusSectionActionType {
|
||||
return {
|
||||
type: FOCUS_SECTION,
|
||||
|
@ -32,6 +38,13 @@ export function showLeftPaneSection(section: SectionType): FocusSectionActionTyp
|
|||
|
||||
type SectionActionTypes = FocusSectionActionType | FocusSettingsSectionActionType;
|
||||
|
||||
export function setIsAppFocused(focused: boolean): IsAppFocusedActionType {
|
||||
return {
|
||||
type: IS_APP_FOCUSED,
|
||||
payload: focused,
|
||||
};
|
||||
}
|
||||
|
||||
export function showSettingsSection(
|
||||
category: SessionSettingCategory
|
||||
): FocusSettingsSectionActionType {
|
||||
|
@ -46,14 +59,16 @@ export const actions = {
|
|||
showSettingsSection,
|
||||
};
|
||||
|
||||
export const initialSectionState = {
|
||||
export const initialSectionState: SectionStateType = {
|
||||
focusedSection: SectionType.Message,
|
||||
focusedSettingsSection: undefined,
|
||||
isAppFocused: false,
|
||||
};
|
||||
|
||||
export type SectionStateType = {
|
||||
focusedSection: SectionType;
|
||||
focusedSettingsSection?: SessionSettingCategory;
|
||||
isAppFocused: boolean;
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
|
@ -73,6 +88,7 @@ export const reducer = (
|
|||
|
||||
if (castedPayload !== SectionType.Settings) {
|
||||
return {
|
||||
...state,
|
||||
focusedSection: castedPayload,
|
||||
focusedSettingsSection: undefined,
|
||||
};
|
||||
|
@ -89,6 +105,12 @@ export const reducer = (
|
|||
...state,
|
||||
focusedSettingsSection: payload,
|
||||
};
|
||||
|
||||
case IS_APP_FOCUSED:
|
||||
return {
|
||||
...state,
|
||||
isAppFocused: payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -126,6 +126,58 @@ export const getSortedMessagesOfSelectedConversation = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
export type MessagePropsType =
|
||||
| 'group-notification'
|
||||
| 'group-invitation'
|
||||
| 'data-extraction'
|
||||
| 'timer-notification'
|
||||
| 'regular-message';
|
||||
|
||||
export const getSortedMessagesTypesOfSelectedConversation = createSelector(
|
||||
getMessagesOfSelectedConversation,
|
||||
(
|
||||
sortedMessages
|
||||
): Array<{
|
||||
messageType: MessagePropsType;
|
||||
props: any;
|
||||
}> => {
|
||||
return sortedMessages.map(msg => {
|
||||
if (msg.propsForDataExtractionNotification) {
|
||||
return {
|
||||
messageType: 'data-extraction',
|
||||
props: { ...msg.propsForDataExtractionNotification, messageId: msg.propsForMessage.id },
|
||||
};
|
||||
}
|
||||
|
||||
if (msg.propsForGroupInvitation) {
|
||||
return {
|
||||
messageType: 'group-invitation',
|
||||
props: { ...msg.propsForGroupInvitation, messageId: msg.propsForMessage.id },
|
||||
};
|
||||
}
|
||||
|
||||
if (msg.propsForGroupNotification) {
|
||||
return {
|
||||
messageType: 'group-notification',
|
||||
props: { ...msg.propsForGroupNotification, messageId: msg.propsForMessage.id },
|
||||
};
|
||||
}
|
||||
|
||||
if (msg.propsForTimerNotification) {
|
||||
return {
|
||||
messageType: 'data-extraction',
|
||||
props: { ...msg.propsForTimerNotification, messageId: msg.propsForMessage.id },
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
messageType: 'regular-message',
|
||||
props: { messageId: msg.propsForMessage.id },
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
function getConversationTitle(
|
||||
conversation: ReduxConversationType,
|
||||
testingi18n?: LocalizerType
|
||||
|
|
|
@ -15,3 +15,8 @@ export const getFocusedSettingsSection = createSelector(
|
|||
getSection,
|
||||
(state: SectionStateType): SessionSettingCategory | undefined => state.focusedSettingsSection
|
||||
);
|
||||
|
||||
export const getIsAppFocused = createSelector(
|
||||
getSection,
|
||||
(state: SectionStateType): boolean => state.isAppFocused
|
||||
);
|
||||
|
|
|
@ -2,7 +2,6 @@ import * as GoogleChrome from './GoogleChrome';
|
|||
import { arrayBufferToObjectURL } from './arrayBufferToObjectURL';
|
||||
import { isFileDangerous } from './isFileDangerous';
|
||||
import { missingCaseError } from './missingCaseError';
|
||||
import { migrateColor } from './migrateColor';
|
||||
import { makeLookup } from './makeLookup';
|
||||
import * as PasswordUtil from './passwordUtils';
|
||||
import * as AttachmentUtil from './attachmentsUtil';
|
||||
|
@ -15,7 +14,6 @@ export {
|
|||
GoogleChrome,
|
||||
isFileDangerous,
|
||||
makeLookup,
|
||||
migrateColor,
|
||||
missingCaseError,
|
||||
PasswordUtil,
|
||||
AttachmentUtil,
|
||||
|
|
|
@ -290,15 +290,6 @@
|
|||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-html(",
|
||||
"path": "js/views/identicon_svg_view.js",
|
||||
"line": " const html = this.render().$el.html();",
|
||||
"lineNumber": 19,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-15T00:38:04.183Z",
|
||||
"reasonDetail": "Getting the value, not setting it"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/inbox_view.js",
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
// import { missingCaseError } from './missingCaseError';
|
||||
|
||||
type OldColor =
|
||||
| 'amber'
|
||||
| 'blue'
|
||||
| 'blue_grey'
|
||||
| 'brown'
|
||||
| 'cyan'
|
||||
| 'deep_orange'
|
||||
| 'deep_purple'
|
||||
| 'green'
|
||||
| 'grey'
|
||||
| 'indigo'
|
||||
| 'lime'
|
||||
| 'light_blue'
|
||||
| 'light_green'
|
||||
| 'orange'
|
||||
| 'pink'
|
||||
| 'purple'
|
||||
| 'red'
|
||||
| 'teal'
|
||||
| 'yellow';
|
||||
|
||||
type NewColor =
|
||||
| 'red'
|
||||
| 'deep_orange'
|
||||
| 'brown'
|
||||
| 'pink'
|
||||
| 'purple'
|
||||
| 'indigo'
|
||||
| 'blue'
|
||||
| 'teal'
|
||||
| 'green'
|
||||
| 'light_green'
|
||||
| 'blue_grey'
|
||||
| 'grey';
|
||||
|
||||
export function migrateColor(color: OldColor): NewColor {
|
||||
switch (color) {
|
||||
// These colors no longer exist
|
||||
case 'orange':
|
||||
case 'amber':
|
||||
return 'deep_orange';
|
||||
|
||||
case 'yellow':
|
||||
return 'brown';
|
||||
|
||||
case 'deep_purple':
|
||||
return 'purple';
|
||||
|
||||
case 'light_blue':
|
||||
return 'blue';
|
||||
|
||||
case 'cyan':
|
||||
return 'teal';
|
||||
|
||||
case 'lime':
|
||||
return 'light_green';
|
||||
|
||||
// These can stay as they are
|
||||
case 'red':
|
||||
case 'deep_orange':
|
||||
case 'brown':
|
||||
case 'pink':
|
||||
case 'purple':
|
||||
case 'indigo':
|
||||
case 'blue':
|
||||
case 'teal':
|
||||
case 'green':
|
||||
case 'light_green':
|
||||
case 'blue_grey':
|
||||
case 'grey':
|
||||
return color;
|
||||
|
||||
// Can uncomment this to ensure that we've covered all potential cases
|
||||
// default:
|
||||
// throw missingCaseError(color);
|
||||
|
||||
default:
|
||||
return 'grey';
|
||||
}
|
||||
}
|
|
@ -7542,11 +7542,6 @@ redux-persist@^6.0.0:
|
|||
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
|
||||
integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==
|
||||
|
||||
redux-promise-middleware@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-promise-middleware/-/redux-promise-middleware-6.1.0.tgz#ecdb22488cdd673c1a3f0d278d82b48d92ca5d06"
|
||||
integrity sha512-C62Ku3TgMwxFh5r3h1/iD+XPdsoizyHLT74dTkqhJ8c0LCbEVl1z9fm8zKitAjI16e6w6+h3mxf6wHdonaYXfQ==
|
||||
|
||||
redux-thunk@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||
|
|
Loading…
Reference in New Issue