Skip to content

Commit

Permalink
Cache rendered messages (#1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
borisyankov committed Aug 16, 2017
1 parent 8c126f1 commit cc747c0
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 125 deletions.
2 changes: 1 addition & 1 deletion src/common/Avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Avatar extends PureComponent {
status?: UserStatus,
realm: string,
shape: 'square' | 'rounded' | 'circle',
onPress?: () => void,
onPress: () => void,
};

static defaultProps = {
Expand Down
10 changes: 4 additions & 6 deletions src/common/ImageAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ export default class ImageAvatar extends PureComponent {
avatarUrl: string,
size: number,
shape: string,
children: [],
onPress?: () => void,
onPress: () => void,
};

static defaultProps = {
onPress: nullFunction,
};

render() {
const { avatarUrl, size, shape, onPress, children } = this.props;
const { avatarUrl, size, shape, onPress } = this.props;
const touchableStyle = {
height: size,
width: size,
Expand All @@ -34,9 +33,8 @@ export default class ImageAvatar extends PureComponent {
style={touchableStyle}
source={{ uri: avatarUrl }}
resizeMode="cover"
borderRadius={borderRadius}>
{children}
</ImageBackground>
borderRadius={borderRadius}
/>
</Touchable>
);
}
Expand Down
62 changes: 32 additions & 30 deletions src/common/TextAvatar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* @flow */
import React from 'react';
import React, { PureComponent } from 'react';
import { Text, StyleSheet, View } from 'react-native';

import { Touchable } from './';
Expand All @@ -25,34 +25,36 @@ const styles = StyleSheet.create({
},
});

type Props = {
name: string,
size: number,
shape: string,
children: [],
onPress?: () => void,
};

export default ({ name, size, status, shape, onPress, children }: Props) => {
const frameSize = {
height: size,
width: size,
borderRadius:
shape === 'rounded' ? size / 8 : shape === 'circle' ? size / 2 : shape === 'square' ? 0 : 0,
backgroundColor: colorHashFromName(name),
};
const textSize = {
fontSize: size / 3,
export default class TextAvatar extends PureComponent {
props: {
name: string,
size: number,
shape?: string,
onPress?: () => void,
};

return (
<Touchable onPress={onPress}>
<View style={[styles.frame, frameSize]}>
<Text style={[styles.text, textSize]}>
{initialsFromName(name)}
</Text>
{children}
</View>
</Touchable>
);
};
render() {
const { name, size, shape, onPress } = this.props;

const frameSize = {
height: size,
width: size,
borderRadius:
shape === 'rounded' ? size / 8 : shape === 'circle' ? size / 2 : shape === 'square' ? 0 : 0,
backgroundColor: colorHashFromName(name),
};
const textSize = {
fontSize: size / 3,
};

return (
<Touchable onPress={onPress}>
<View style={[styles.frame, frameSize]}>
<Text style={[styles.text, textSize]}>
{initialsFromName(name)}
</Text>
</View>
</Touchable>
);
}
}
6 changes: 3 additions & 3 deletions src/conversations/ConversationGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { NULL_USER } from '../nullObjects';
import type { User, Narrow } from '../types';
import { normalizeRecipients } from '../utils/message';
import { isGroupNarrow } from '../utils/narrow';
import { Avatar, RawLabel, Touchable, UnreadCount } from '../common';
import { TextAvatar, RawLabel, Touchable, UnreadCount } from '../common';
import { BRAND_COLOR } from '../styles';

const styles = StyleSheet.create({
Expand Down Expand Up @@ -36,7 +36,7 @@ class ConversationGroup extends PureComponent {
email: string,
users: User[],
unreadCount: number,
narrow?: Narrow,
narrow: Narrow,
onPress: (emails: string) => void,
};

Expand All @@ -57,7 +57,7 @@ class ConversationGroup extends PureComponent {
return (
<Touchable onPress={this.handlePress}>
<View style={[styles.row, isSelected && styles.selectedRow]}>
<Avatar size={32} name={allNames} />
<TextAvatar size={32} name={allNames} />
<RawLabel
style={[styles.text, isSelected && styles.selectedText]}
numberOfLines={2}
Expand Down
5 changes: 2 additions & 3 deletions src/message/MessageFull.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const styles = StyleSheet.create({
},
});

class MessageFull extends PureComponent {
export default class MessageFull extends PureComponent {
props: {
actions: Actions,
ownEmail: string,
Expand Down Expand Up @@ -60,6 +60,7 @@ class MessageFull extends PureComponent {
isNotYetSent,
handleLinkPress,
} = this.props;

return (
<View style={styles.message}>
<Avatar
Expand Down Expand Up @@ -96,5 +97,3 @@ class MessageFull extends PureComponent {
);
}
}

export default MessageFull;
24 changes: 8 additions & 16 deletions src/message/MessageList.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { nullFunction } from '../nullObjects';
import { LoadingIndicator } from '../common';
import MessageTyping from '../message/MessageTyping';
import InfiniteScrollView from './InfiniteScrollView';
import renderMessages from './renderMessages';
import type { Actions, TypingState, Message, Narrow } from '../types';
import type { Actions, TypingState } from '../types';

type Props = {
actions: Actions,
Expand All @@ -18,8 +17,7 @@ type Props = {
singleFetchProgress: boolean,
onScroll: () => void,
typingUsers?: TypingState,
messages: Array<Message>,
narrow: Narrow,
renderedMessages: any[],
};

export default class MessageList extends PureComponent {
Expand Down Expand Up @@ -49,25 +47,19 @@ export default class MessageList extends PureComponent {
singleFetchProgress,
onScroll,
typingUsers,
messages,
narrow,
renderedMessages,
} = this.props;

const messageList = renderMessages({
messages,
narrow,
});

// `headerIndices` tell the scroll view which components are headers
// and are eligible to be docked at the top of the view.
const headerIndices = [];
for (let i = 0; i < messageList.length; i++) {
const elem = messageList[i];
for (let i = 0; i < renderedMessages.length; i++) {
const elem = renderedMessages[i];
if (elem.props.type === 'header') {
headerIndices.push(i + 1);
}
if (elem.props.type === 'message') {
messageList[i] = (
renderedMessages[i] = (
<TaggedView
key={elem.props.message.id}
tagID={elem.props.message.id.toString()}
Expand All @@ -82,13 +74,13 @@ export default class MessageList extends PureComponent {
<InfiniteScrollView
style={styles.messageList}
automaticallyAdjustContentInset="false"
stickyHeaderIndices={headerIndices}
stickyHeaderIndices={[]}
onStartReached={actions.fetchOlder}
onEndReached={actions.fetchNewer}
autoScrollToBottom={this.autoScrollToBottom}
onScroll={onScroll}>
<LoadingIndicator active={fetchingOlder} caughtUp={caughtUpOlder} />
{messageList}
{renderedMessages}
{!singleFetchProgress && fetchingNewer && <LoadingIndicator active />}
{typingUsers && <MessageTyping users={typingUsers} actions={actions} />}
</InfiniteScrollView>
Expand Down
8 changes: 4 additions & 4 deletions src/message/MessageListContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getAuth,
getFlags,
getCurrentTypingUsers,
getShownMessagesInActiveNarrow,
getRenderedMessages,
getActiveNarrow,
getCaughtUpForActiveNarrow,
} from '../selectors';
Expand Down Expand Up @@ -40,7 +40,7 @@ class MessageListContainer extends PureComponent {
fetchingOlder,
fetchingNewer,
typingUsers,
messages,
renderedMessages,
narrow,
actions,
} = this.props;
Expand All @@ -52,7 +52,7 @@ class MessageListContainer extends PureComponent {
fetchingOlder={fetchingOlder}
fetchingNewer={fetchingNewer}
typingUsers={typingUsers}
messages={messages}
renderedMessages={renderedMessages}
narrow={narrow}
actions={actions}
/>
Expand All @@ -67,7 +67,7 @@ export default connect(
fetchingOlder: state.chat.fetchingOlder,
fetchingNewer: state.chat.fetchingNewer,
typingUsers: getCurrentTypingUsers(state),
messages: getShownMessagesInActiveNarrow(state),
renderedMessages: getRenderedMessages(state),
narrow: getActiveNarrow(state),
flags: getFlags(state),
auth: getAuth(state),
Expand Down
35 changes: 3 additions & 32 deletions src/message/MessageListFlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { nullFunction } from '../nullObjects';
import MessageContainer from './MessageContainer';
import TaggedView from '../native/TaggedView';
import renderMessages from './renderMessages';
import { getFullUrl } from '../utils/url';
import {
constructActionButtons,
executeActionSheetAction,
Expand Down Expand Up @@ -72,32 +71,9 @@ class MessageList extends PureComponent {

render() {
const { styles } = this.context;
const {
auth,
actions,
subscriptions,
users,
messages,
narrow,
mute,
doNarrow,
flags,
twentyFourHourTime,
} = this.props;
const { messages, narrow } = this.props;

const messageList = renderMessages({
onLongPress: this.handleLongPress,
onHeaderLongPress: this.handleHeaderLongPress,
auth,
actions,
subscriptions,
users,
messages,
narrow,
mute,
flags,
twentyFourHourTime,
});
const messageList = renderMessages(messages, narrow);

// `headerIndices` tell the scroll view which components are headers
// and are eligible to be docked at the top of the view.
Expand Down Expand Up @@ -128,14 +104,9 @@ class MessageList extends PureComponent {
keyExtractor={item => item.id}
renderItem={({ item }) =>
<MessageContainer
auth={auth}
actions={actions}
type="message"
message={item}
isBrief={false}
flags={flags}
doNarrow={doNarrow}
avatarUrl={getFullUrl(item.avatar_url, auth.realm)}
users={users}
onLongPress={this.handleLongPress}
/>}
renderSectionHeader={({ section }) =>
Expand Down
12 changes: 5 additions & 7 deletions src/message/__tests__/renderMessages-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ describe('renderMessages', () => {
const narrow = deepFreeze([]);

test('empty messages results in no rendered messages', () => {
const props = deepFreeze({ messages: [] });

const messageList = renderMessages(props);
const messageList = renderMessages([]);
expect(messageList).toEqual([]);
});

Expand All @@ -23,7 +21,7 @@ describe('renderMessages', () => {

const expectedComponentKeys = ['time123', 'header1', '1'];

const messageList = renderMessages({ messages, narrow });
const messageList = renderMessages(messages, narrow);
const messageKeys = messageList.map(x => x.key);

expect(messageKeys).toEqual(expectedComponentKeys);
Expand Down Expand Up @@ -62,7 +60,7 @@ describe('renderMessages', () => {

const expectedComponentKeys = ['time123', 'header1', '1', '2', '3'];

const messageList = renderMessages({ messages, narrow });
const messageList = renderMessages(messages, narrow);
const messageKeys = messageList.map(x => x.key);

expect(messageKeys).toEqual(expectedComponentKeys);
Expand Down Expand Up @@ -104,7 +102,7 @@ describe('renderMessages', () => {

const expectedComponentKeys = ['time123', 'header1', '1', '2', '3'];

const messageList = renderMessages({ messages, narrow });
const messageList = renderMessages(messages, narrow);
const messageKeys = messageList.map(x => x.key);

expect(messageKeys).toEqual(expectedComponentKeys);
Expand Down Expand Up @@ -135,7 +133,7 @@ describe('renderMessages', () => {

const expectedComponentTypes = ['time123', 'header1', '1', '2'];

const messageList = renderMessages({ messages, narrow });
const messageList = renderMessages(messages, narrow);
const messageTypes = messageList.map(x => x.key);

expect(messageTypes).toEqual(expectedComponentTypes);
Expand Down
12 changes: 12 additions & 0 deletions src/message/messageSelectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* @flow */
import { createSelector } from 'reselect';

import { getActiveNarrow } from '../baseSelectors';
import { getShownMessagesInActiveNarrow } from '../chat/chatSelectors';
import renderMessages from './renderMessages';

export const getRenderedMessages = createSelector(
getShownMessagesInActiveNarrow,
getActiveNarrow,
(messages, narrow) => renderMessages(messages, narrow),
);

0 comments on commit cc747c0

Please sign in to comment.