diff --git a/android/build.gradle b/android/build.gradle index a27aa2d73..725acf348 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -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('/xmtp-android/library/build/outputs/aar/library-debug.aar') // implementation 'com.google.crypto.tink:tink-android:1.7.0' diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 200c55f0d..38d0b61a2 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -9,6 +9,7 @@ import androidx.core.net.toUri import com.google.gson.JsonParser import com.google.protobuf.kotlin.toByteString import expo.modules.kotlin.exception.Exceptions +import expo.modules.kotlin.functions.Coroutine import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition import expo.modules.xmtpreactnativesdk.wrappers.ConsentWrapper @@ -28,6 +29,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext import org.json.JSONObject import org.xmtp.android.library.Client import org.xmtp.android.library.ClientOptions @@ -330,7 +332,7 @@ class XMTPModule : Module() { } // Export the conversation's serialized topic data. - AsyncFunction("exportConversationTopicData") { clientAddress: String, topic: String -> + AsyncFunction("exportConversationTopicData") Coroutine { clientAddress: String, topic: String -> logV("exportConversationTopicData") val conversation = findConversation(clientAddress, topic) ?: throw XMTPException("no conversation found for $topic") @@ -437,7 +439,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List -> + AsyncFunction("sendEncodedContent") Coroutine { clientAddress: String, topic: String, encodedContentData: List -> val conversation = findConversation( clientAddress = clientAddress, @@ -458,7 +460,7 @@ class XMTPModule : Module() { conversation.send(encodedContent = encodedContent) } - AsyncFunction("listConversations") { clientAddress: String -> + AsyncFunction("listConversations") Coroutine { clientAddress: String -> logV("listConversations") val client = clients[clientAddress] ?: throw XMTPException("No client") val conversationList = client.conversations.list() @@ -490,7 +492,7 @@ class XMTPModule : Module() { } } - AsyncFunction("loadMessages") { clientAddress: String, topic: String, limit: Int?, before: Long?, after: Long?, direction: String? -> + AsyncFunction("loadMessages") Coroutine { clientAddress: String, topic: String, limit: Int?, before: Long?, after: Long?, direction: String? -> logV("loadMessages") val conversation = findConversation( @@ -527,7 +529,7 @@ class XMTPModule : Module() { )?.map { DecodedMessageWrapper.encode(it) } } - AsyncFunction("loadBatchMessages") { clientAddress: String, topics: List -> + AsyncFunction("loadBatchMessages") Coroutine { clientAddress: String, topics: List -> logV("loadBatchMessages") val client = clients[clientAddress] ?: throw XMTPException("No client") val topicsList = mutableListOf>() @@ -572,7 +574,7 @@ class XMTPModule : Module() { .map { DecodedMessageWrapper.encode(it) } } - AsyncFunction("sendMessage") { clientAddress: String, conversationTopic: String, contentJson: String -> + AsyncFunction("sendMessage") Coroutine { clientAddress: String, conversationTopic: String, contentJson: String -> logV("sendMessage") val conversation = findConversation( @@ -602,7 +604,7 @@ class XMTPModule : Module() { ) } - AsyncFunction("prepareMessage") { clientAddress: String, conversationTopic: String, contentJson: String -> + AsyncFunction("prepareMessage") Coroutine { clientAddress: String, conversationTopic: String, contentJson: String -> logV("prepareMessage") val conversation = findConversation( @@ -625,7 +627,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("prepareEncodedMessage") { clientAddress: String, conversationTopic: String, encodedContentData: List -> + AsyncFunction("prepareEncodedMessage") Coroutine { clientAddress: String, conversationTopic: String, encodedContentData: List -> logV("prepareEncodedMessage") val conversation = findConversation( @@ -658,7 +660,7 @@ class XMTPModule : Module() { ).toJson() } - AsyncFunction("sendPreparedMessage") { clientAddress: String, preparedLocalMessageJson: String -> + AsyncFunction("sendPreparedMessage") Coroutine { clientAddress: String, preparedLocalMessageJson: String -> logV("sendPreparedMessage") val client = clients[clientAddress] ?: throw XMTPException("No client") val local = PreparedLocalMessage.fromJson(preparedLocalMessageJson) @@ -676,7 +678,7 @@ class XMTPModule : Module() { prepared.messageId } - AsyncFunction("createConversation") { clientAddress: String, peerAddress: String, contextJson: String -> + AsyncFunction("createConversation") Coroutine { clientAddress: String, peerAddress: String, contextJson: String -> logV("createConversation: $contextJson") val client = clients[clientAddress] ?: throw XMTPException("No client") val context = JsonParser.parseString(contextJson).asJsonObject @@ -791,7 +793,7 @@ class XMTPModule : Module() { subscribeToAllGroupMessages(clientAddress = clientAddress) } - AsyncFunction("subscribeToMessages") { clientAddress: String, topic: String -> + AsyncFunction("subscribeToMessages") Coroutine { clientAddress: String, topic: String -> logV("subscribeToMessages") subscribeToMessages( clientAddress = clientAddress, @@ -827,7 +829,7 @@ class XMTPModule : Module() { subscriptions[getGroupMessagesKey(clientAddress)]?.cancel() } - AsyncFunction("unsubscribeFromMessages") { clientAddress: String, topic: String -> + AsyncFunction("unsubscribeFromMessages") Coroutine { clientAddress: String, topic: String -> logV("unsubscribeFromMessages") unsubscribeFromMessages( clientAddress = clientAddress, @@ -859,7 +861,7 @@ class XMTPModule : Module() { } } - AsyncFunction("decodeMessage") { clientAddress: String, topic: String, encryptedMessage: String -> + AsyncFunction("decodeMessage") Coroutine { clientAddress: String, topic: String, encryptedMessage: String -> logV("decodeMessage") val encryptedMessageData = Base64.decode(encryptedMessage, NO_WRAP) val envelope = EnvelopeBuilder.buildFromString(topic, Date(), encryptedMessageData) @@ -885,13 +887,13 @@ class XMTPModule : Module() { client.contacts.isDenied(address) } - AsyncFunction("denyContacts") { clientAddress: String, addresses: List -> + AsyncFunction("denyContacts") Coroutine { clientAddress: String, addresses: List -> logV("denyContacts") val client = clients[clientAddress] ?: throw XMTPException("No client") client.contacts.deny(addresses) } - AsyncFunction("allowContacts") { clientAddress: String, addresses: List -> + AsyncFunction("allowContacts") Coroutine { clientAddress: String, addresses: List -> val client = clients[clientAddress] ?: throw XMTPException("No client") client.contacts.allow(addresses) } @@ -902,7 +904,7 @@ class XMTPModule : Module() { consentList.entries.map { ConsentWrapper.encode(it.value) } } - AsyncFunction("conversationConsentState") { clientAddress: String, conversationTopic: String -> + AsyncFunction("conversationConsentState") Coroutine { clientAddress: String, conversationTopic: String -> val conversation = findConversation(clientAddress, conversationTopic) ?: throw XMTPException("no conversation found for $conversationTopic") consentStateToString(conversation.consentState()) @@ -954,7 +956,7 @@ class XMTPModule : Module() { // Helpers // - private fun findConversation( + private suspend fun findConversation( clientAddress: String, topic: String, ): Conversation? { @@ -1118,7 +1120,7 @@ class XMTPModule : Module() { } } - private fun subscribeToMessages(clientAddress: String, topic: String) { + private suspend fun subscribeToMessages(clientAddress: String, topic: String) { val conversation = findConversation( clientAddress = clientAddress, @@ -1188,7 +1190,7 @@ class XMTPModule : Module() { return "groups:$clientAddress" } - private fun unsubscribeFromMessages( + private suspend fun unsubscribeFromMessages( clientAddress: String, topic: String, ) { diff --git a/example/App.tsx b/example/App.tsx index cf3d6828f..f6c70c434 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -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() @@ -100,6 +101,11 @@ export default function App() { component={ConversationCreateScreen} options={{ title: 'New Conversation' }} /> + diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 307a0fe61..6fd46c5dc 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -769,4 +769,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/example/src/LaunchScreen.tsx b/example/src/LaunchScreen.tsx index acfce332c..86e00b16f 100644 --- a/example/src/LaunchScreen.tsx +++ b/example/src/LaunchScreen.tsx @@ -148,6 +148,14 @@ export default function LaunchScreen( External Wallet: + +