Skip to content

Commit

Permalink
speed up chat (#3660)
Browse files Browse the repository at this point in the history
  • Loading branch information
peterpme authored Apr 10, 2023
1 parent 4f47ec5 commit 9cdb560
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 94 deletions.
11 changes: 0 additions & 11 deletions packages/app-mobile/patches/expo+48.0.4.patch

This file was deleted.

62 changes: 62 additions & 0 deletions packages/app-mobile/patches/expo+48.0.9.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
diff --git a/node_modules/expo/android/build.gradle b/node_modules/expo/android/build.gradle
index f8995f0..a60c4e1 100644
--- a/node_modules/expo/android/build.gradle
+++ b/node_modules/expo/android/build.gradle
@@ -33,7 +33,7 @@ def getRNVersion() {
ensureDependeciesWereEvaluated(project)

group = 'host.exp.exponent'
-version = '48.0.10'
+version = '48.0.9'

buildscript {
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -104,7 +104,7 @@ android {
minSdkVersion safeExtGet("minSdkVersion", 21)
targetSdkVersion safeExtGet("targetSdkVersion", 33)
versionCode 1
- versionName "48.0.10"
+ versionName "48.0.9"
consumerProguardFiles("proguard-rules.pro")
}
lintOptions {
diff --git a/node_modules/expo/build/environment/getInstallationIdAsync.js b/node_modules/expo/build/environment/getInstallationIdAsync.js
index 75366e4..5c83839 100644
--- a/node_modules/expo/build/environment/getInstallationIdAsync.js
+++ b/node_modules/expo/build/environment/getInstallationIdAsync.js
@@ -1,5 +1,5 @@
import * as Application from 'expo-application';
-import uuidv5 from 'uuid/v5';
+import { v5 as uuidv5 } from 'uuid';
let installationId;
const UUID_NAMESPACE = '29cc8a0d-747c-5f85-9ff9-f2f16636d963'; // uuidv5(0, "expo")
export default async function getInstallationIdAsync() {
diff --git a/node_modules/expo/bundledNativeModules.json b/node_modules/expo/bundledNativeModules.json
index 783f93d..6e064e4 100644
--- a/node_modules/expo/bundledNativeModules.json
+++ b/node_modules/expo/bundledNativeModules.json
@@ -33,7 +33,7 @@
"expo-crypto": "~12.2.1",
"expo-dev-client": "~2.1.6",
"expo-device": "~5.2.1",
- "expo-document-picker": "~11.2.2",
+ "expo-document-picker": "~11.2.1",
"expo-face-detector": "~12.1.1",
"expo-file-system": "~15.2.2",
"expo-font": "~11.1.1",
@@ -76,13 +76,13 @@
"expo-system-ui": "~2.2.1",
"expo-task-manager": "~11.1.1",
"expo-tracking-transparency": "~3.0.3",
- "expo-updates": "~0.16.4",
+ "expo-updates": "~0.16.3",
"expo-video-thumbnails": "~7.2.1",
"expo-web-browser": "~12.1.1",
"lottie-react-native": "5.1.4",
"react": "18.2.0",
"react-dom": "18.2.0",
- "react-native": "0.71.6",
+ "react-native": "0.71.4",
"react-native-web": "~0.18.10",
"react-native-branch": "^5.4.0",
"react-native-gesture-handler": "~2.9.0",
67 changes: 67 additions & 0 deletions packages/app-mobile/patches/react-native-gifted-chat+2.0.1.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
diff --git a/node_modules/react-native-gifted-chat/lib/GiftedChat.js b/node_modules/react-native-gifted-chat/lib/GiftedChat.js
index a91d004..54fd541 100644
--- a/node_modules/react-native-gifted-chat/lib/GiftedChat.js
+++ b/node_modules/react-native-gifted-chat/lib/GiftedChat.js
@@ -44,6 +44,7 @@ class GiftedChat extends React.Component {
typingDisabled: false,
text: undefined,
messages: undefined,
+ contextValues: {}
};
this.getLocale = () => this._locale;
this.onKeyboardWillShow = (e) => {
@@ -193,6 +194,11 @@ class GiftedChat extends React.Component {
this.initLocale();
this.setMessages(messages || []);
this.setTextFromProp(text);
+ this.setState({contextValues: {
+ actionSheet: this.props.actionSheet ||
+ (() => { var _a; return (_a = this._actionSheetRef.current) === null || _a === void 0 ? void 0 : _a.getContext(); }),
+ getLocale: this.getLocale,
+ }});
}
componentWillUnmount() {
this.setIsMounted(false);
@@ -416,13 +422,7 @@ class GiftedChat extends React.Component {
}
render() {
if (this.state.isInitialized === true) {
- const actionSheet = this.props.actionSheet ||
- (() => { var _a; return (_a = this._actionSheetRef.current) === null || _a === void 0 ? void 0 : _a.getContext(); });
- const { getLocale } = this;
- return (<GiftedChatContext.Provider value={{
- actionSheet,
- getLocale,
- }}>
+ return (<GiftedChatContext.Provider value={this.state.contextValues}>
<View testID={TEST_ID.WRAPPER} style={styles.wrapper}>
<ActionSheetProvider ref={this._actionSheetRef}>
<View style={styles.container} onLayout={this.onMainViewLayout}>
diff --git a/node_modules/react-native-gifted-chat/lib/MessageContainer.js b/node_modules/react-native-gifted-chat/lib/MessageContainer.js
index 6bdf6da..7256f5a 100644
--- a/node_modules/react-native-gifted-chat/lib/MessageContainer.js
+++ b/node_modules/react-native-gifted-chat/lib/MessageContainer.js
@@ -54,6 +54,7 @@ export default class MessageContainer extends React.PureComponent {
showScrollBottom: false,
hasScrolled: false,
};
+ this._extraData = [undefined, undefined]
this.renderTypingIndicator = () => {
if (Platform.OS === 'web') {
return null;
@@ -191,8 +192,14 @@ export default class MessageContainer extends React.PureComponent {
}
render() {
const { inverted } = this.props;
+ if (
+ this._extraData[0] !== this.props.extraData ||
+ this._extraData[1] !== this.props.isTyping
+ ) {
+ this._extraData = [this.props.extraData, this.props.isTyping]
+ }
return (<View style={this.props.alignTop ? styles.containerAlignTop : styles.container}>
- <FlatList ref={this.props.forwardRef} extraData={[this.props.extraData, this.props.isTyping]} keyExtractor={this.keyExtractor} enableEmptySections automaticallyAdjustContentInsets={false} inverted={inverted} data={this.props.messages} style={styles.listStyle} contentContainerStyle={styles.contentContainerStyle} renderItem={this.renderRow} {...this.props.invertibleScrollViewProps} ListEmptyComponent={this.renderChatEmpty} ListFooterComponent={inverted ? this.renderHeaderWrapper : this.renderFooter} ListHeaderComponent={inverted ? this.renderFooter : this.renderHeaderWrapper} onScroll={this.handleOnScroll} scrollEventThrottle={100} onLayout={this.onLayoutList} onEndReached={this.onEndReached} onEndReachedThreshold={0.1} {...this.props.listViewProps}/>
+ <FlatList ref={this.props.forwardRef} extraData={this._extraData} keyExtractor={this.keyExtractor} enableEmptySections automaticallyAdjustContentInsets={false} inverted={inverted} data={this.props.messages} style={styles.listStyle} contentContainerStyle={styles.contentContainerStyle} renderItem={this.renderRow} {...this.props.invertibleScrollViewProps} ListEmptyComponent={this.renderChatEmpty} ListFooterComponent={inverted ? this.renderHeaderWrapper : this.renderFooter} ListHeaderComponent={inverted ? this.renderFooter : this.renderHeaderWrapper} onScroll={this.handleOnScroll} scrollEventThrottle={100} onLayout={this.onLayoutList} onEndReached={this.onEndReached} onEndReachedThreshold={0.1} {...this.props.listViewProps}/>
{this.state.showScrollBottom && this.props.scrollToBottom
? this.renderScrollToBottomWrapper()
: null}
168 changes: 85 additions & 83 deletions packages/app-mobile/src/screens/Unlocked/Chat/ChatDetailScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { StackScreenProps } from "@react-navigation/stack";

import { useState, useEffect, useCallback, useRef } from "react";
import { Platform, Button, View, Text } from "react-native";
import { useState, useCallback, useMemo } from "react";

import { Video, ResizeMode, AVPlaybackStatus } from "expo-av";
import * as Crypto from "expo-crypto";

// import { Video, ResizeMode, AVPlaybackStatus } from "expo-av";

import { CHAT_MESSAGES } from "@coral-xyz/common";
import { createEmptyFriendship } from "@coral-xyz/db";
Expand All @@ -13,112 +14,103 @@ import {
SignalingManager,
useChatsWithMetadata,
} from "@coral-xyz/tamagui";
import { GiftedChat, MessageVideoProps } from "react-native-gifted-chat";
import { GiftedChat, Send } from "react-native-gifted-chat";
import { v4 as uuidv4 } from "uuid";

import { UserAvatar } from "~components/UserAvatar";
import { ChatStackNavigatorParamList } from "~screens/Unlocked/Chat/ChatHelpers";

function VideoMessage() {
const video = useRef(null);
const [status, setStatus] = useState<AVPlaybackStatus | object>({});
return (
<View>
<Video
ref={video}
style={{ width: 150, height: 100 }}
source={{
uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4",
}}
useNativeControls
resizeMode={ResizeMode.CONTAIN}
isLooping
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
<View>
<Button
title={status.isPlaying ? "Pause" : "Play"}
onPress={() =>
status.isPlaying
? video.current.pauseAsync()
: video.current.playAsync()
}
/>
</View>
</View>
);
}
const generateId = () => {
return Crypto.randomUUID();
};

// function VideoMessage() {
// const video = useRef(null);
// const [status, setStatus] = useState<AVPlaybackStatus | object>({});
// return (
// <View>
// <Video
// ref={video}
// style={{ width: 150, height: 100 }}
// source={{
// uri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4",
// }}
// useNativeControls
// resizeMode={ResizeMode.CONTAIN}
// isLooping
// onPlaybackStatusUpdate={(status) => setStatus(() => status)}
// />
// <View>
// <Button
// title={status.isPlaying ? "Pause" : "Play"}
// onPress={() =>
// status.isPlaying
// ? video.current.pauseAsync()
// : video.current.playAsync()
// }
// />
// </View>
// </View>
// );
// }

const formatDate = (created_at: string) => {
return !isNaN(new Date(parseInt(created_at, 10)).getTime())
? new Date(parseInt(created_at, 10)).getTime()
: 0;
};

const formatChats = (chats) => {
return chats
.map((x) => {
return {
_id: x.client_generated_uuid,
text: x.message,
createdAt: formatDate(x.created_at),
received: x.received,
sent: true,
pending: false,
// Videos / images follow this format
// video:
// "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
// image:
// "https://d33wubrfki0l68.cloudfront.net/7e97b18b02060f1d4b65a5850b49e2488da391bb/d60ff/img/homepage/dissection/3.png",
user: {
_id: x.uuid,
name: x.username,
avatar: x.image,
},
};
})
.reverse();
};

export function ChatDetailScreen({
// navigation,
route,
}: StackScreenProps<ChatStackNavigatorParamList, "ChatDetail">): JSX.Element {
const { roomType, roomId, remoteUserId, remoteUsername } = route.params;
const user = useUser();
const avatarUrl = useAvatarUrl();
const existingChatRef = useRef<any>();

const [isLoadingEarlier, setIsLoadingEarlier] = useState(false);
const { chats } = useChatsWithMetadata({
room: roomId.toString(),
type: roomType,
});

const onLoadEarlier = async () => {
const messages = useMemo(() => formatChats(chats), [chats]);

const onLoadEarlier = useCallback(async () => {
setIsLoadingEarlier(true);
try {
await fetchMoreChatsFor(user.uuid, roomId.toString(), roomType);
} catch (e) {
console.error(e);
} finally {
setIsLoadingEarlier(false);
}
setIsLoadingEarlier(false);
};

const [messages, setMessages] = useState([]);

useEffect(() => {
if (
existingChatRef.current &&
JSON.stringify(chats) === JSON.stringify(existingChatRef.current)
) {
return;
}
if (chats && chats.length) {
SignalingManager.getInstance().debouncedUpdateLastRead(
chats[chats.length - 1]
);
}
const _messages = chats
.map((x) => {
return {
_id: x.client_generated_uuid,
text: x.message,
createdAt: formatDate(x.created_at),
received: x.received,
sent: true,
pending: false,
// Videos / images follow this format
// video:
// "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
// image:
// "https://d33wubrfki0l68.cloudfront.net/7e97b18b02060f1d4b65a5850b49e2488da391bb/d60ff/img/homepage/dissection/3.png",
user: {
_id: x.uuid,
name: x.username,
avatar: x.image,
},
};
})
.reverse();

existingChatRef.current = chats;
setMessages(_messages);
}, [chats]);
}, [roomId, roomType, user.uuid]);

const onSend = useCallback(
async (messages = []) => {
Expand Down Expand Up @@ -166,14 +158,22 @@ export function ChatDetailScreen({
[chats.length, roomId, roomType, user.uuid, remoteUserId, remoteUsername]
);

const renderMessageVideo = useCallback((props: MessageVideoProps<any>) => {
const { video } = props.currentMessage;
return <VideoMessage />;
const renderSend = useCallback((props) => {
return <Send {...props} />;
}, []);

// const renderMessageVideo = useCallback((props: MessageVideoProps<any>) => {
// const { video } = props.currentMessage;
// return <VideoMessage />;
// }, []);

const renderAvatar = useCallback((props) => {
return <UserAvatar uri={props.currentMessage.user.avatar} size={32} />;
}, []);

return (
<GiftedChat
messageIdGenerator={() => uuidv4()}
messageIdGenerator={generateId}
showAvatarForEveryMessage
alwaysShowSend
loadEarlier
Expand All @@ -183,7 +183,9 @@ export function ChatDetailScreen({
inverted
messages={messages}
onSend={onSend}
renderMessageVideo={renderMessageVideo}
renderSend={renderSend}
renderAvatar={renderAvatar}
// renderMessageVideo={renderMessageVideo}
user={{
_id: user.uuid,
name: user.username,
Expand Down

1 comment on commit 9cdb560

@vercel
Copy link

@vercel vercel bot commented on 9cdb560 Apr 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.