Fix timeline crash when deleting the oldest visible message
This commit is contained in:
parent
6de2710841
commit
45393b1ca5
2 changed files with 25 additions and 23 deletions
|
@ -115,7 +115,7 @@ type PropsHousekeepingType = {
|
||||||
warning?: WarningType;
|
warning?: WarningType;
|
||||||
contactSpoofingReview?: ContactSpoofingReviewPropType;
|
contactSpoofingReview?: ContactSpoofingReviewPropType;
|
||||||
|
|
||||||
getTimestampForMessage: (_: string) => number;
|
getTimestampForMessage: (messageId: string) => undefined | number;
|
||||||
getPreferredBadge: PreferredBadgeSelectorType;
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
theme: ThemeType;
|
theme: ThemeType;
|
||||||
|
@ -220,7 +220,7 @@ type StateType = {
|
||||||
oneTimeScrollRow?: number;
|
oneTimeScrollRow?: number;
|
||||||
visibleRows?: {
|
visibleRows?: {
|
||||||
newestFullyVisible?: VisibleRowType;
|
newestFullyVisible?: VisibleRowType;
|
||||||
oldestPartiallyVisible?: VisibleRowType;
|
oldestPartiallyVisibleMessageId?: string;
|
||||||
oldestFullyVisible?: VisibleRowType;
|
oldestFullyVisible?: VisibleRowType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -612,7 +612,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let newestFullyVisible: undefined | VisibleRowType;
|
let newestFullyVisible: undefined | VisibleRowType;
|
||||||
let oldestPartiallyVisible: undefined | VisibleRowType;
|
let oldestPartiallyVisibleMessageId: undefined | string;
|
||||||
let oldestFullyVisible: undefined | VisibleRowType;
|
let oldestFullyVisible: undefined | VisibleRowType;
|
||||||
|
|
||||||
const { children } = innerScrollContainer;
|
const { children } = innerScrollContainer;
|
||||||
|
@ -646,20 +646,18 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thisRow = {
|
|
||||||
offsetTop,
|
|
||||||
row: parseInt(child.getAttribute('data-row') || '-1', 10),
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
|
|
||||||
const bottom = offsetTop + offsetHeight;
|
const bottom = offsetTop + offsetHeight;
|
||||||
|
|
||||||
if (bottom >= visibleTop && !oldestPartiallyVisible) {
|
if (bottom >= visibleTop && !oldestPartiallyVisibleMessageId) {
|
||||||
oldestPartiallyVisible = thisRow;
|
oldestPartiallyVisibleMessageId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offsetTop + AT_TOP_THRESHOLD >= visibleTop) {
|
if (offsetTop + AT_TOP_THRESHOLD >= visibleTop) {
|
||||||
oldestFullyVisible = thisRow;
|
oldestFullyVisible = {
|
||||||
|
offsetTop,
|
||||||
|
row: parseInt(child.getAttribute('data-row') || '-1', 10),
|
||||||
|
id,
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -667,7 +665,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
this.setState(oldState => {
|
this.setState(oldState => {
|
||||||
const visibleRows = {
|
const visibleRows = {
|
||||||
newestFullyVisible,
|
newestFullyVisible,
|
||||||
oldestPartiallyVisible,
|
oldestPartiallyVisibleMessageId,
|
||||||
oldestFullyVisible,
|
oldestFullyVisible,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1289,8 +1287,15 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let floatingHeader: ReactNode;
|
let floatingHeader: ReactNode;
|
||||||
const oldestPartiallyVisibleRow = visibleRows?.oldestPartiallyVisible;
|
const oldestPartiallyVisibleMessageId =
|
||||||
if (oldestPartiallyVisibleRow) {
|
visibleRows?.oldestPartiallyVisibleMessageId;
|
||||||
|
// It's possible that a message was removed from `items` but we still have its ID in
|
||||||
|
// state. `getTimestampForMessage` might return undefined in that case.
|
||||||
|
const oldestPartiallyVisibleMessageTimestamp =
|
||||||
|
oldestPartiallyVisibleMessageId
|
||||||
|
? getTimestampForMessage(oldestPartiallyVisibleMessageId)
|
||||||
|
: undefined;
|
||||||
|
if (oldestPartiallyVisibleMessageTimestamp) {
|
||||||
floatingHeader = (
|
floatingHeader = (
|
||||||
<TimelineFloatingHeader
|
<TimelineFloatingHeader
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
@ -1300,10 +1305,10 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||||
? { marginTop: lastMeasuredWarningHeight }
|
? { marginTop: lastMeasuredWarningHeight }
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
timestamp={getTimestampForMessage(oldestPartiallyVisibleRow.id)}
|
timestamp={oldestPartiallyVisibleMessageTimestamp}
|
||||||
visible={
|
visible={
|
||||||
(hasRecentlyScrolled || isLoadingMessages) &&
|
(hasRecentlyScrolled || isLoadingMessages) &&
|
||||||
(!haveOldest || oldestPartiallyVisibleRow.id !== items[0])
|
(!haveOldest || oldestPartiallyVisibleMessageId !== items[0])
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -38,7 +38,7 @@ import { renderEmojiPicker } from './renderEmojiPicker';
|
||||||
import { renderReactionPicker } from './renderReactionPicker';
|
import { renderReactionPicker } from './renderReactionPicker';
|
||||||
|
|
||||||
import { getOwn } from '../../util/getOwn';
|
import { getOwn } from '../../util/getOwn';
|
||||||
import { assert, strictAssert } from '../../util/assert';
|
import { assert } from '../../util/assert';
|
||||||
import { missingCaseError } from '../../util/missingCaseError';
|
import { missingCaseError } from '../../util/missingCaseError';
|
||||||
import { getGroupMemberships } from '../../util/getGroupMemberships';
|
import { getGroupMemberships } from '../../util/getGroupMemberships';
|
||||||
import {
|
import {
|
||||||
|
@ -295,11 +295,8 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => {
|
||||||
const selectedMessage = getSelectedMessage(state);
|
const selectedMessage = getSelectedMessage(state);
|
||||||
|
|
||||||
const messageSelector = getMessageSelector(state);
|
const messageSelector = getMessageSelector(state);
|
||||||
const getTimestampForMessage = (messageId: string): number => {
|
const getTimestampForMessage = (messageId: string): undefined | number =>
|
||||||
const result = messageSelector(messageId)?.timestamp;
|
messageSelector(messageId)?.timestamp;
|
||||||
strictAssert(result, 'Expected a message');
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
|
Loading…
Reference in a new issue