Some fixes for windowed render
This commit is contained in:
parent
e4d2e28ec4
commit
0b0214cbf9
4 changed files with 84 additions and 49 deletions
|
@ -2252,12 +2252,18 @@
|
||||||
|
|
||||||
const existing = this.model.get('quotedMessageId');
|
const existing = this.model.get('quotedMessageId');
|
||||||
if (existing !== messageId) {
|
if (existing !== messageId) {
|
||||||
const timestamp = messageId ? Date.now() : null;
|
|
||||||
this.model.set({
|
this.model.set({
|
||||||
quotedMessageId: messageId,
|
quotedMessageId: messageId,
|
||||||
draftTimestamp: timestamp,
|
|
||||||
timestamp,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (messageId) {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
this.model.set({
|
||||||
|
draftTimestamp: timestamp,
|
||||||
|
timestamp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await this.saveModel();
|
await this.saveModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,6 +494,10 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
renderTypingBubble,
|
renderTypingBubble,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
const styleWithWidth = {
|
||||||
|
...style,
|
||||||
|
width: `${this.mostRecentWidth}px`,
|
||||||
|
};
|
||||||
const row = index;
|
const row = index;
|
||||||
const oldestUnreadRow = this.getLastSeenIndicatorRow();
|
const oldestUnreadRow = this.getLastSeenIndicatorRow();
|
||||||
const typingBubbleRow = this.getTypingBubbleRow();
|
const typingBubbleRow = this.getTypingBubbleRow();
|
||||||
|
@ -501,13 +505,13 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
if (!haveOldest && row === 0) {
|
if (!haveOldest && row === 0) {
|
||||||
rowContents = (
|
rowContents = (
|
||||||
<div data-row={row} style={style}>
|
<div data-row={row} style={styleWithWidth}>
|
||||||
{renderLoadingRow(id)}
|
{renderLoadingRow(id)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (oldestUnreadRow === row) {
|
} else if (oldestUnreadRow === row) {
|
||||||
rowContents = (
|
rowContents = (
|
||||||
<div data-row={row} style={style}>
|
<div data-row={row} style={styleWithWidth}>
|
||||||
{renderLastSeenIndicator(id)}
|
{renderLastSeenIndicator(id)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -516,7 +520,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
<div
|
<div
|
||||||
data-row={row}
|
data-row={row}
|
||||||
className="module-timeline__message-container"
|
className="module-timeline__message-container"
|
||||||
style={style}
|
style={styleWithWidth}
|
||||||
>
|
>
|
||||||
{renderTypingBubble(id)}
|
{renderTypingBubble(id)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -534,7 +538,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
id={messageId}
|
id={messageId}
|
||||||
data-row={row}
|
data-row={row}
|
||||||
className="module-timeline__message-container"
|
className="module-timeline__message-container"
|
||||||
style={style}
|
style={styleWithWidth}
|
||||||
>
|
>
|
||||||
{renderItem(messageId, this.props)}
|
{renderItem(messageId, this.props)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -715,6 +719,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
this.updateWithVisibleRows(forceFocus);
|
this.updateWithVisibleRows(forceFocus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// tslint:disable-next-line cyclomatic-complexity
|
||||||
public componentDidUpdate(prevProps: Props) {
|
public componentDidUpdate(prevProps: Props) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
@ -763,35 +768,48 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
const oldFirstIndex = 0;
|
const oldFirstIndex = 0;
|
||||||
const oldFirstId = prevProps.items[oldFirstIndex];
|
const oldFirstId = prevProps.items[oldFirstIndex];
|
||||||
|
|
||||||
const newIndex = items.findIndex(item => item === oldFirstId);
|
const newFirstIndex = items.findIndex(item => item === oldFirstId);
|
||||||
if (newIndex < 0) {
|
if (newFirstIndex < 0) {
|
||||||
this.resizeAll();
|
this.resizeAll();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newRow = this.fromItemIndexToRow(newIndex);
|
const newRow = this.fromItemIndexToRow(newFirstIndex);
|
||||||
|
const delta = newFirstIndex - oldFirstIndex;
|
||||||
|
if (delta > 0) {
|
||||||
|
// We're loading more new messages at the top; we want to stay at the top
|
||||||
|
this.resizeAll();
|
||||||
|
this.setState({ oneTimeScrollRow: newRow });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We continue on after our atTop check; because if we're not loading new messages
|
||||||
|
// we still have to check for all the other situations which might require a
|
||||||
|
// resize.
|
||||||
|
|
||||||
|
const oldLastIndex = prevProps.items.length - 1;
|
||||||
|
const oldLastId = prevProps.items[oldLastIndex];
|
||||||
|
|
||||||
|
const newLastIndex = items.findIndex(item => item === oldLastId);
|
||||||
|
if (newLastIndex < 0) {
|
||||||
this.resizeAll();
|
this.resizeAll();
|
||||||
this.setState({ oneTimeScrollRow: newRow });
|
|
||||||
} else {
|
|
||||||
const oldLastIndex = prevProps.items.length - 1;
|
|
||||||
const oldLastId = prevProps.items[oldLastIndex];
|
|
||||||
|
|
||||||
const newIndex = items.findIndex(item => item === oldLastId);
|
return;
|
||||||
if (newIndex < 0) {
|
}
|
||||||
this.resizeAll();
|
|
||||||
|
|
||||||
return;
|
const indexDelta = newLastIndex - oldLastIndex;
|
||||||
}
|
|
||||||
|
|
||||||
const indexDelta = newIndex - oldLastIndex;
|
// If we've just added to the end of the list, then the index of the last id's
|
||||||
|
// index won't have changed, and we can rely on List's detection that items is
|
||||||
// If we've just added to the end of the list, then the index of the last id's
|
// different for the necessary re-render.
|
||||||
// index won't have changed, and we can rely on List's detection that items is
|
if (indexDelta !== 0) {
|
||||||
// different for the necessary re-render.
|
this.resizeAll();
|
||||||
if (indexDelta !== 0) {
|
} else if (typingContact && prevProps.typingContact) {
|
||||||
this.resizeAll();
|
// The last row will be off, because it was previously the typing indicator
|
||||||
}
|
this.resizeAll();
|
||||||
}
|
}
|
||||||
} else if (messageHeightChanges) {
|
} else if (messageHeightChanges) {
|
||||||
this.resizeAll();
|
this.resizeAll();
|
||||||
|
|
|
@ -857,6 +857,30 @@ export function reducer(
|
||||||
totalUnread,
|
totalUnread,
|
||||||
} = existingConversation.metrics;
|
} = existingConversation.metrics;
|
||||||
|
|
||||||
|
if (messages.length < 1) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lookup = fromPairs(
|
||||||
|
existingConversation.messageIds.map(id => [id, messagesLookup[id]])
|
||||||
|
);
|
||||||
|
messages.forEach(message => {
|
||||||
|
lookup[message.id] = message;
|
||||||
|
});
|
||||||
|
|
||||||
|
const sorted = orderBy(values(lookup), ['received_at'], ['ASC']);
|
||||||
|
const messageIds = sorted.map(message => message.id);
|
||||||
|
|
||||||
|
const first = sorted[0];
|
||||||
|
const last = sorted[sorted.length - 1];
|
||||||
|
|
||||||
|
if (!newest) {
|
||||||
|
newest = pick(first, ['id', 'received_at']);
|
||||||
|
}
|
||||||
|
if (!oldest) {
|
||||||
|
oldest = pick(last, ['id', 'received_at']);
|
||||||
|
}
|
||||||
|
|
||||||
const existingTotal = existingConversation.messageIds.length;
|
const existingTotal = existingConversation.messageIds.length;
|
||||||
if (isNewMessage && existingTotal > 0) {
|
if (isNewMessage && existingTotal > 0) {
|
||||||
const lastMessageId = existingConversation.messageIds[existingTotal - 1];
|
const lastMessageId = existingConversation.messageIds[existingTotal - 1];
|
||||||
|
@ -869,27 +893,6 @@ export function reducer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newIds = messages.map(message => message.id);
|
|
||||||
const newChanges = intersection(newIds, existingConversation.messageIds);
|
|
||||||
const heightChangeMessageIds = uniq([
|
|
||||||
...newChanges,
|
|
||||||
...existingConversation.heightChangeMessageIds,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const lookup = fromPairs(
|
|
||||||
existingConversation.messageIds.map(id => [id, messagesLookup[id]])
|
|
||||||
);
|
|
||||||
|
|
||||||
messages.forEach(message => {
|
|
||||||
lookup[message.id] = message;
|
|
||||||
});
|
|
||||||
|
|
||||||
const sorted = orderBy(values(lookup), ['received_at'], ['ASC']);
|
|
||||||
const messageIds = sorted.map(message => message.id);
|
|
||||||
|
|
||||||
const first = sorted[0];
|
|
||||||
const last = sorted.length > 0 ? sorted[sorted.length - 1] : null;
|
|
||||||
|
|
||||||
if (first && oldest && first.received_at < oldest.received_at) {
|
if (first && oldest && first.received_at < oldest.received_at) {
|
||||||
oldest = pick(first, ['id', 'received_at']);
|
oldest = pick(first, ['id', 'received_at']);
|
||||||
}
|
}
|
||||||
|
@ -897,6 +900,7 @@ export function reducer(
|
||||||
newest = pick(last, ['id', 'received_at']);
|
newest = pick(last, ['id', 'received_at']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newIds = messages.map(message => message.id);
|
||||||
const newMessageIds = difference(newIds, existingConversation.messageIds);
|
const newMessageIds = difference(newIds, existingConversation.messageIds);
|
||||||
const { isNearBottom } = existingConversation;
|
const { isNearBottom } = existingConversation;
|
||||||
|
|
||||||
|
@ -924,6 +928,12 @@ export function reducer(
|
||||||
totalUnread = (totalUnread || 0) + newUnread;
|
totalUnread = (totalUnread || 0) + newUnread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changedIds = intersection(newIds, existingConversation.messageIds);
|
||||||
|
const heightChangeMessageIds = uniq([
|
||||||
|
...changedIds,
|
||||||
|
...existingConversation.heightChangeMessageIds,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
messagesLookup: {
|
messagesLookup: {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import memoizee from 'memoizee';
|
import memoizee from 'memoizee';
|
||||||
|
import { isNumber } from 'lodash';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { format } from '../../types/PhoneNumber';
|
import { format } from '../../types/PhoneNumber';
|
||||||
|
|
||||||
|
@ -388,7 +389,7 @@ export function _conversationMessagesSelector(
|
||||||
items,
|
items,
|
||||||
messageHeightChanges,
|
messageHeightChanges,
|
||||||
oldestUnreadIndex:
|
oldestUnreadIndex:
|
||||||
oldestUnreadIndex && oldestUnreadIndex >= 0
|
isNumber(oldestUnreadIndex) && oldestUnreadIndex >= 0
|
||||||
? oldestUnreadIndex
|
? oldestUnreadIndex
|
||||||
: undefined,
|
: undefined,
|
||||||
resetCounter,
|
resetCounter,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue