add key for all messages list so we can scroll to them programnatically

pull/1753/head
audric 4 years ago
parent 8766cf3f8a
commit 12ff3379e1

@ -8,7 +8,7 @@ import { SpacerXS, Text } from '../basic/Text';
export const DataExtractionNotification = (props: PropsForDataExtractionNotification) => { export const DataExtractionNotification = (props: PropsForDataExtractionNotification) => {
const theme = useTheme(); const theme = useTheme();
const { name, type, source } = props; const { name, type, source, messageId } = props;
let contentText: string; let contentText: string;
if (type === SignalService.DataExtractionNotification.Type.MEDIA_SAVED) { if (type === SignalService.DataExtractionNotification.Type.MEDIA_SAVED) {
@ -23,6 +23,7 @@ export const DataExtractionNotification = (props: PropsForDataExtractionNotifica
flexDirection="column" flexDirection="column"
alignItems="center" alignItems="center"
margin={theme.common.margins.sm} margin={theme.common.margins.sm}
id={messageId}
> >
<SessionIcon <SessionIcon
iconType={SessionIconType.Upload} iconType={SessionIconType.Upload}

@ -15,7 +15,7 @@ export const GroupInvitation = (props: PropsForGroupInvitation) => {
const openGroupInvitation = window.i18n('openGroupInvitation'); const openGroupInvitation = window.i18n('openGroupInvitation');
return ( return (
<div className="group-invitation-container"> <div className="group-invitation-container" id={props.messageId}>
<div className={classNames(classes)}> <div className={classNames(classes)}>
<div className="contents"> <div className="contents">
<SessionIconButton <SessionIconButton

@ -91,7 +91,7 @@ function renderChange(change: PropsForGroupUpdateType) {
export const GroupNotification = (props: PropsForGroupUpdate) => { export const GroupNotification = (props: PropsForGroupUpdate) => {
const { changes } = props; const { changes } = props;
return ( return (
<div className="module-group-notification"> <div className="module-group-notification" id={props.messageId}>
{(changes || []).map((change, index) => ( {(changes || []).map((change, index) => (
<div key={index} className="module-group-notification__change"> <div key={index} className="module-group-notification__change">
{renderChange(change)} {renderChange(change)}

@ -54,6 +54,7 @@ import { MessageContextMenu } from './MessageContextMenu';
import { ReadableMessage } from './ReadableMessage'; import { ReadableMessage } from './ReadableMessage';
import { remote } from 'electron'; import { remote } from 'electron';
import { isElectronWindowFocused } from '../../session/utils/WindowUtils'; import { isElectronWindowFocused } from '../../session/utils/WindowUtils';
import { getConversationController } from '../../session/conversations';
// Same as MIN_WIDTH in ImageGrid.tsx // Same as MIN_WIDTH in ImageGrid.tsx
const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200; const MINIMUM_LINK_PREVIEW_IMAGE_WIDTH = 200;
@ -176,6 +177,9 @@ class MessageInner extends React.PureComponent<Props, State> {
window.inboxStore?.dispatch( window.inboxStore?.dispatch(
messageExpired({ messageId: this.props.id, conversationKey: this.props.convoId }) messageExpired({ messageId: this.props.id, conversationKey: this.props.convoId })
); );
getConversationController()
.get(this.props.convoId)
?.updateLastMessage();
}; };
this.expiredTimeout = setTimeout(setExpired, EXPIRED_DELAY); this.expiredTimeout = setTimeout(setExpired, EXPIRED_DELAY);
} }

@ -1,52 +1,52 @@
import React, { useContext } from 'react'; import React from 'react';
import { Intl } from '../Intl'; import { Intl } from '../Intl';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { SessionIcon, SessionIconSize, SessionIconType } from '../session/icon'; import { SessionIcon, SessionIconSize, SessionIconType } from '../session/icon';
import { ThemeContext } from 'styled-components';
import { PropsForExpirationTimer } from '../../state/ducks/conversations'; import { PropsForExpirationTimer } from '../../state/ducks/conversations';
export const TimerNotification = (props: PropsForExpirationTimer) => { const TimerNotificationContent = (props: PropsForExpirationTimer) => {
function renderContents() { const { phoneNumber, profileName, timespan, type, disabled } = props;
const { phoneNumber, profileName, timespan, type, disabled } = props; const changeKey = disabled ? 'disabledDisappearingMessages' : 'theyChangedTheTimer';
const changeKey = disabled ? 'disabledDisappearingMessages' : 'theyChangedTheTimer';
const contact = ( const contact = (
<span key={`external-${phoneNumber}`} className="module-timer-notification__contact"> <span key={`external-${phoneNumber}`} className="module-timer-notification__contact">
{profileName || phoneNumber} {profileName || phoneNumber}
</span> </span>
); );
switch (type) { switch (type) {
case 'fromOther': case 'fromOther':
return <Intl id={changeKey} components={[contact, timespan]} />; return <Intl id={changeKey} components={[contact, timespan]} />;
case 'fromMe': case 'fromMe':
return disabled return disabled
? window.i18n('youDisabledDisappearingMessages') ? window.i18n('youDisabledDisappearingMessages')
: window.i18n('youChangedTheTimer', [timespan]); : window.i18n('youChangedTheTimer', [timespan]);
case 'fromSync': case 'fromSync':
return disabled return disabled
? window.i18n('disappearingMessagesDisabled') ? window.i18n('disappearingMessagesDisabled')
: window.i18n('timerSetOnSync', [timespan]); : window.i18n('timerSetOnSync', [timespan]);
default: default:
throw missingCaseError(type); throw missingCaseError(type);
}
} }
const themeContext = useContext(ThemeContext); };
export const TimerNotification = (props: PropsForExpirationTimer) => {
return ( return (
<div className="module-timer-notification"> <div className="module-timer-notification" id={props.messageId}>
<div className="module-timer-notification__message"> <div className="module-timer-notification__message">
<div> <div>
<SessionIcon <SessionIcon
iconType={SessionIconType.Stopwatch} iconType={SessionIconType.Stopwatch}
iconSize={SessionIconSize.Small} iconSize={SessionIconSize.Small}
iconColor={'#ABABAB'} iconColor={'#ABABAB'}
theme={themeContext}
/> />
</div> </div>
<div>{renderContents()}</div> <div>
<TimerNotificationContent {...props} />
</div>
</div> </div>
</div> </div>
); );

@ -32,7 +32,6 @@ export const SessionMessagesList = (props: {
<GroupUpdateItem <GroupUpdateItem
key={messageProps.propsForMessage.id} key={messageProps.propsForMessage.id}
groupNotificationProps={groupNotificationProps} groupNotificationProps={groupNotificationProps}
messageId={messageProps.propsForMessage.id}
/> />
); );
} }
@ -42,7 +41,6 @@ export const SessionMessagesList = (props: {
<GroupInvitationItem <GroupInvitationItem
key={messageProps.propsForMessage.id} key={messageProps.propsForMessage.id}
propsForGroupInvitation={propsForGroupInvitation} propsForGroupInvitation={propsForGroupInvitation}
messageId={messageProps.propsForMessage.id}
/> />
); );
} }
@ -52,18 +50,13 @@ export const SessionMessagesList = (props: {
<DataExtractionNotificationItem <DataExtractionNotificationItem
key={messageProps.propsForMessage.id} key={messageProps.propsForMessage.id}
propsForDataExtractionNotification={propsForDataExtractionNotification} propsForDataExtractionNotification={propsForDataExtractionNotification}
messageId={messageProps.propsForMessage.id}
/> />
); );
} }
if (timerProps) { if (timerProps) {
return ( return (
<TimerNotificationItem <TimerNotificationItem key={messageProps.propsForMessage.id} timerProps={timerProps} />
key={messageProps.propsForMessage.id}
timerProps={timerProps}
messageId={messageProps.propsForMessage.id}
/>
); );
} }

@ -269,7 +269,6 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
topTopMessage > containerTop - 10 && !this.props.areMoreMessagesBeingFetched; topTopMessage > containerTop - 10 && !this.props.areMoreMessagesBeingFetched;
if (shouldFetchMore) { if (shouldFetchMore) {
console.warn('shouldFetchMore', shouldFetchMore);
const { messagesProps } = this.props; const { messagesProps } = this.props;
const oldLen = messagesProps.length; const oldLen = messagesProps.length;
@ -344,23 +343,18 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
} }
} }
private scrollToMessage(messageId: string, smooth: boolean = false, alignOnTop = false) { private scrollToMessage(messageId: string, scrollIsQuote: boolean = false) {
const messageElementDom = document.getElementById(messageId); const messageElementDom = document.getElementById(messageId);
messageElementDom?.scrollIntoView({ messageElementDom?.scrollIntoView({
behavior: 'auto', behavior: 'auto',
block: alignOnTop ? 'start' : 'center', block: 'center',
}); });
// we consider that a `smooth` set to true, means it's a quoted message, so highlight this message on the UI // we consider that a `scrollIsQuote` set to true, means it's a quoted message, so highlight this message on the UI
if (smooth) { if (scrollIsQuote) {
window.inboxStore?.dispatch(quotedMessageToAnimate(messageId)); window.inboxStore?.dispatch(quotedMessageToAnimate(messageId));
this.setupTimeoutResetQuotedHighlightedMessage(messageId); this.setupTimeoutResetQuotedHighlightedMessage(messageId);
} }
const messageContainer = this.props.messageContainerRef.current;
if (!messageContainer) {
return;
}
} }
private scrollToBottom() { private scrollToBottom() {

@ -31,56 +31,54 @@ export const UnreadIndicator = (props: { messageId: string }) => {
return <SessionLastSeenIndicator key={`unread-indicator-${props.messageId}`} />; return <SessionLastSeenIndicator key={`unread-indicator-${props.messageId}`} />;
}; };
export const GroupUpdateItem = (props: { export const GroupUpdateItem = (props: { groupNotificationProps: PropsForGroupUpdate }) => {
messageId: string;
groupNotificationProps: PropsForGroupUpdate;
}) => {
return ( return (
<React.Fragment key={props.messageId}> <React.Fragment key={props.groupNotificationProps.messageId}>
<GroupNotification key={props.messageId} {...props.groupNotificationProps} /> <GroupNotification
<UnreadIndicator messageId={props.messageId} /> key={props.groupNotificationProps.messageId}
{...props.groupNotificationProps}
/>
<UnreadIndicator messageId={props.groupNotificationProps.messageId} />
</React.Fragment> </React.Fragment>
); );
}; };
export const GroupInvitationItem = (props: { export const GroupInvitationItem = (props: {
messageId: string;
propsForGroupInvitation: PropsForGroupInvitation; propsForGroupInvitation: PropsForGroupInvitation;
}) => { }) => {
return ( return (
<React.Fragment key={props.messageId}> <React.Fragment key={props.propsForGroupInvitation.messageId}>
<GroupInvitation key={props.messageId} {...props.propsForGroupInvitation} /> <GroupInvitation
key={props.propsForGroupInvitation.messageId}
{...props.propsForGroupInvitation}
/>
<UnreadIndicator messageId={props.messageId} /> <UnreadIndicator messageId={props.propsForGroupInvitation.messageId} />
</React.Fragment> </React.Fragment>
); );
}; };
export const DataExtractionNotificationItem = (props: { export const DataExtractionNotificationItem = (props: {
messageId: string;
propsForDataExtractionNotification: PropsForDataExtractionNotification; propsForDataExtractionNotification: PropsForDataExtractionNotification;
}) => { }) => {
return ( return (
<React.Fragment key={props.messageId}> <React.Fragment key={props.propsForDataExtractionNotification.messageId}>
<DataExtractionNotification <DataExtractionNotification
key={props.messageId} key={props.propsForDataExtractionNotification.messageId}
{...props.propsForDataExtractionNotification} {...props.propsForDataExtractionNotification}
/> />
<UnreadIndicator messageId={props.messageId} /> <UnreadIndicator messageId={props.propsForDataExtractionNotification.messageId} />
</React.Fragment> </React.Fragment>
); );
}; };
export const TimerNotificationItem = (props: { export const TimerNotificationItem = (props: { timerProps: PropsForExpirationTimer }) => {
messageId: string;
timerProps: PropsForExpirationTimer;
}) => {
return ( return (
<React.Fragment key={props.messageId}> <React.Fragment key={props.timerProps.messageId}>
<TimerNotification key={props.messageId} {...props.timerProps} /> <TimerNotification key={props.timerProps.messageId} {...props.timerProps} />
<UnreadIndicator messageId={props.messageId} /> <UnreadIndicator messageId={props.timerProps.messageId} />
</React.Fragment> </React.Fragment>
); );
}; };

@ -298,6 +298,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
timespan, timespan,
disabled, disabled,
type: fromSync ? 'fromSync' : UserUtils.isUsFromCache(source) ? 'fromMe' : 'fromOther', type: fromSync ? 'fromSync' : UserUtils.isUsFromCache(source) ? 'fromMe' : 'fromOther',
messageId: this.id,
}; };
return basicProps; return basicProps;
@ -347,6 +348,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return { return {
...dataExtractionNotification, ...dataExtractionNotification,
name: contact.profileName || contact.name || dataExtractionNotification.source, name: contact.profileName || contact.name || dataExtractionNotification.source,
messageId: this.id,
}; };
} }
@ -462,6 +464,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return { return {
changes, changes,
messageId: this.id,
}; };
} }

@ -111,6 +111,7 @@ export interface DataExtractionNotificationMsg {
export type PropsForDataExtractionNotification = DataExtractionNotificationMsg & { export type PropsForDataExtractionNotification = DataExtractionNotificationMsg & {
name: string; name: string;
messageId: string;
}; };
export interface MessageAttributesOptionals { export interface MessageAttributesOptionals {

@ -66,6 +66,7 @@ export type PropsForExpirationTimer = {
profileName: string | null; profileName: string | null;
title: string | null; title: string | null;
type: 'fromMe' | 'fromSync' | 'fromOther'; type: 'fromMe' | 'fromSync' | 'fromOther';
messageId: string;
}; };
export type PropsForGroupUpdateGeneral = { export type PropsForGroupUpdateGeneral = {
@ -105,6 +106,7 @@ export type PropsForGroupUpdateArray = Array<PropsForGroupUpdateType>;
export type PropsForGroupUpdate = { export type PropsForGroupUpdate = {
changes: PropsForGroupUpdateArray; changes: PropsForGroupUpdateArray;
messageId: string;
}; };
export type PropsForGroupInvitation = { export type PropsForGroupInvitation = {
@ -391,7 +393,7 @@ function handleMessageExpiredOrDeleted(
messageId: string; messageId: string;
conversationKey: string; conversationKey: string;
}> }>
) { ): ConversationsStateType {
const { conversationKey, messageId } = action.payload; const { conversationKey, messageId } = action.payload;
if (conversationKey === state.selectedConversation) { if (conversationKey === state.selectedConversation) {
// search if we find this message id. // search if we find this message id.
@ -412,6 +414,8 @@ function handleMessageExpiredOrDeleted(
return { return {
...state, ...state,
messages: editedMessages, messages: editedMessages,
firstUnreadMessageId:
state.firstUnreadMessageId === messageId ? undefined : state.firstUnreadMessageId,
}; };
} }

Loading…
Cancel
Save