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

This commit is contained in:
audric 2021-07-22 15:04:46 +10:00
parent 8766cf3f8a
commit 12ff3379e1
11 changed files with 71 additions and 73 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -269,7 +269,6 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
topTopMessage > containerTop - 10 && !this.props.areMoreMessagesBeingFetched;
if (shouldFetchMore) {
console.warn('shouldFetchMore', shouldFetchMore);
const { messagesProps } = this.props;
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);
messageElementDom?.scrollIntoView({
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
if (smooth) {
// we consider that a `scrollIsQuote` set to true, means it's a quoted message, so highlight this message on the UI
if (scrollIsQuote) {
window.inboxStore?.dispatch(quotedMessageToAnimate(messageId));
this.setupTimeoutResetQuotedHighlightedMessage(messageId);
}
const messageContainer = this.props.messageContainerRef.current;
if (!messageContainer) {
return;
}
}
private scrollToBottom() {

View File

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

View File

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

View File

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

View File

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