Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main => beta #336

Merged
merged 12 commits into from
Apr 1, 2024
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.facebook.react:react-native:0.71.3'
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
implementation "org.xmtp:android:0.8.4"
implementation "org.xmtp:android:0.9.0"
// xmtp-android local testing setup below (comment org.xmtp:android above)
// implementation files('<PATH TO XMTP-ANDROID>/xmtp-android/library/build/outputs/aar/library-debug.aar')
// implementation 'com.google.crypto.tink:tink-android:1.7.0'
Expand Down

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import GroupScreen from './src/GroupScreen'
import HomeScreen from './src/HomeScreen'
import LaunchScreen from './src/LaunchScreen'
import { Navigator } from './src/Navigation'
import StreamScreen from './src/StreamScreen'
import TestScreen from './src/TestScreen'

const queryClient = new QueryClient()
Expand Down Expand Up @@ -100,6 +101,11 @@ export default function App() {
component={ConversationCreateScreen}
options={{ title: 'New Conversation' }}
/>
<Navigator.Screen
name="streamTest"
component={StreamScreen}
options={{ title: 'Stream Tests' }}
/>
</Navigator.Navigator>
</NavigationContainer>
</XmtpProvider>
Expand Down
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -769,4 +769,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2

COCOAPODS: 1.14.3
COCOAPODS: 1.15.2
8 changes: 8 additions & 0 deletions example/src/LaunchScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ export default function LaunchScreen(
accessibilityLabel="Unit-tests"
/>
</View>
<View key="stream-tests" style={{ margin: 16, marginTop: 16 }}>
<Button
color="green"
title="Create Stream Tests"
onPress={() => navigation.navigate('streamTest')}
accessibilityLabel="Unit-tests"
/>
</View>
<View style={styles.divider} />
<Text style={styles.title}>Test Conversations</Text>
<View style={styles.row}>
Expand Down
1 change: 1 addition & 0 deletions example/src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type NavigationParamList = {
group: { id: string }
conversation: { topic: string }
conversationCreate: undefined
streamTest: undefined
}

export const Navigator = createNativeStackNavigator<NavigationParamList>()
329 changes: 329 additions & 0 deletions example/src/StreamScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import React, { useCallback, useEffect, useState } from 'react'
import { Button, FlatList, Text, View, Switch, Pressable } from 'react-native'

import { Client, Conversation, DecodedMessage } from '../../src'

let events: StreamEvent[] = []

const useClient = () => {
const [client, setClient] = useState<Client<any> | null>(null)

useEffect(() => {
Client.createRandom().then((client) => {
setClient(client)
})
}, [])

return client
}

const useConversation = (client: Client<any>, recieve: boolean) => {
const [conversation, setConversation] = useState<Conversation<any> | null>(
null
)
const [otherClientConvo, setOtherClientConvo] =
useState<Conversation<any> | null>(null)
const conversationClient = useClient()

useEffect(() => {
if (!conversationClient) {
return
}
if (!client) {
return
}

const setupConversations = async () => {
const conversation = await client.conversations.newConversation(
conversationClient.address
)
events.push({ type: 'start_conv', timestamp: Date.now() })
setConversation(conversation)
const conversations = await conversationClient.conversations.list()
const otherConvo = conversations.find(
(convo) => convo.topic === conversation.topic
)
if (otherConvo) {
setOtherClientConvo(otherConvo)
}
}

const setupReceiveConvo = async () => {
const conversation =
await conversationClient.conversations.newConversation(
conversationClient.address
)
events.push({ type: 'receive_convo', timestamp: Date.now() })
setOtherClientConvo(conversation)
const conversations = await client.conversations.list()
const otherConvo = conversations.find(
(convo) => convo.topic === conversation.topic
)
if (otherConvo) {
setConversation(otherConvo)
}
}
if (recieve) {
setupReceiveConvo()
} else {
setupConversations()
}
}, [conversationClient, client])

return { conversation, otherClientConvo }
}

interface ConversationItemProps {
client: Client<any>
received: boolean
onSendMessage: () => void
onReceiveMessage: () => void
}

const ConversationItem = ({
client,
received,
onSendMessage,
onReceiveMessage,
}: ConversationItemProps) => {
const { conversation, otherClientConvo } = useConversation(client, received)
const [messages, setMessages] = useState<DecodedMessage[]>([])
const [shouldStream, setShouldStream] = useState<boolean>(true)
const [show, setShow] = useState<boolean>(true)

useEffect(() => {
let sub: (() => void) | undefined = undefined

const setSub = async () => {
sub = await conversation?.streamMessages(async (message) => {
setMessages((prev) => [...prev, message])
})
}
if (shouldStream) {
setSub()
}
return () => {
sub?.()
}
}, [conversation, shouldStream])

const toggleStream = useCallback(() => {
setShouldStream((prev) => !prev)
}, [setShouldStream])

const toggleShow = useCallback(() => {
setShow((prev) => !prev)
}, [setShow])

const sendMessage = useCallback(() => {
conversation?.send('Hello!')
onSendMessage()
}, [conversation, onSendMessage])

const receiveMessage = useCallback(() => {
otherClientConvo?.send('Hi!')
onReceiveMessage()
}, [otherClientConvo, client.address, onReceiveMessage])

return (
<View>
<Pressable onPress={toggleShow}>
<Text style={{ color: show ? 'black' : 'grey' }}>
{conversation?.topic} {messages.length}
</Text>
</Pressable>
{show && (
<>
<View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>
<Button
title="Send new message"
color="green"
onPress={sendMessage}
/>
<Button
title="Receive message"
color="blue"
onPress={receiveMessage}
/>
<View style={{ flexDirection: 'row' }}>
<Text>Stream</Text>
<Switch value={shouldStream} onValueChange={toggleStream} />
</View>
</View>
<FlatList
data={messages}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <Text>{item.sent}</Text>}
/>
</>
)}
</View>
)
}

interface StreamEvent {
type:
| 'start_conv'
| 'receive_convo'
| 'receive_message'
| 'send_message'
| 'conv_stream_start'
| 'conv_stream_cancel'
| 'all_messages_start'
| 'all_messages_cancel'
| 'all_messages_receive'
| 'all_start'
| 'all_cancel'
| 'all_receive'
timestamp: number
}

export default function StreamScreen() {
const client = useClient()
const [showEvents, setShowEvents] = useState<boolean>(false)
const [conversations, setConversations] = useState<boolean[]>([])
const [stream, setStream] = useState<boolean>(true)
const [streamCount, setStreamCount] = useState<number>(0)
const [streamMessages, setStreamMessages] = useState<boolean>(true)
const [streamMessagesCount, setStreamMessagesCount] = useState<number>(0)

useEffect(() => {
events = []
}, [])

const toggleStreamMessages = useCallback(() => {
setStreamMessages((prev) => !prev)
}, [setStreamMessages])
const toggleStreamAll = useCallback(() => {
setStream((prev) => !prev)
}, [setStream])
const toggleShowEvents = useCallback(() => {
setShowEvents((prev) => !prev)
}, [setShowEvents])

const addConversation = useCallback(() => {
setConversations((prev) => [...prev, false])
}, [setConversations])

const removeConversation = useCallback(() => {
setConversations((prev) => prev.slice(0, prev.length - 1))
}, [setConversations])

const onSendMessage = useCallback(() => {
events.push({ type: 'send_message', timestamp: Date.now() })
}, [])

const onReceiveMessage = useCallback(() => {
events.push({ type: 'receive_message', timestamp: Date.now() })
}, [])

const onStreamAllMessages = useCallback(() => {
events.push({ type: 'all_messages_start', timestamp: Date.now() })
}, [])

const onCancelStreamAllMessages = useCallback(() => {
events.push({ type: 'all_messages_cancel', timestamp: Date.now() })
}, [])

const onStreamAll = useCallback(() => {
events.push({ type: 'all_start', timestamp: Date.now() })
}, [])

const onCancelStreamAll = useCallback(() => {
events.push({ type: 'all_cancel', timestamp: Date.now() })
}, [])

useEffect(() => {
if (!client) {
return
}
const setupSub = async () => {
onStreamAllMessages()
client.conversations.streamAllMessages(async () => {
setStreamMessagesCount((prev) => prev + 1)
})
}
if (streamMessages) {
setupSub()
}

return () => {
onCancelStreamAllMessages()
client.conversations.cancelStreamAllMessages()
}
}, [client, stream, onStreamAllMessages, onCancelStreamAllMessages])

useEffect(() => {
if (!client) {
return
}
const setupSub = async () => {
onStreamAll()
client.conversations.stream(async () => {
setStreamCount((prev) => prev + 1)
})
}
if (streamMessages) {
setupSub()
}

return () => {
onCancelStreamAll()
client.conversations.cancelStream()
}
}, [client, stream, onStreamAllMessages, onCancelStreamAllMessages])

if (!client) {
return (
<View>
<Text>Loading</Text>
</View>
)
}

return (
<View style={{ flex: 1 }}>
{showEvents && <Text selectable>{JSON.stringify(events)}</Text>}
<Button title="Show events" onPress={toggleShowEvents} color="blue" />
<View>
<Button
title="Add new conversation"
color="green"
onPress={addConversation}
/>
<Button
title="Remove latest conversation"
color="red"
onPress={removeConversation}
/>
<View style={{ flexDirection: 'row' }}>
<View style={{ flexDirection: 'row' }}>
<Text>Stream All: {streamCount}</Text>
<Switch value={stream} onValueChange={toggleStreamAll} />
</View>
<View style={{ flexDirection: 'row' }}>
<Text>Stream All Messages: {streamMessagesCount}</Text>
<Switch
value={streamMessages}
onValueChange={toggleStreamMessages}
/>
</View>
</View>
</View>
<FlatList
// style={{ flexGrow: 1 }}
data={conversations}
keyExtractor={(item, idx) => idx.toString()}
renderItem={({ item }) => (
<ConversationItem
client={client}
received={item}
onSendMessage={onSendMessage}
onReceiveMessage={onReceiveMessage}
/>
)}
/>
</View>
)
}
Loading
Loading