diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index e438284d9..bbf2a426b 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -394,6 +394,15 @@ class XMTPModule : Module() { } } + AsyncFunction("listAll") { clientAddress: String -> + val client = clients[clientAddress] ?: throw XMTPException("No client") + val conversationContainerList = client.conversations.list(includeGroups = true) + conversationContainerList.map { conversation -> + conversations[conversation.cacheKey(clientAddress)] = conversation + ConversationContainerWrapper.encode(client, conversation) + } + } + AsyncFunction("loadMessages") { clientAddress: String, topic: String, limit: Int?, before: Long?, after: Long?, direction: String? -> logV("loadMessages") val conversation = diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConversationContainerWrapper.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConversationContainerWrapper.kt index 4207cdf6f..8995c4cff 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConversationContainerWrapper.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ConversationContainerWrapper.kt @@ -1,6 +1,7 @@ package expo.modules.xmtpreactnativesdk.wrappers import android.util.Base64 +import com.google.gson.GsonBuilder import org.xmtp.android.library.Client import org.xmtp.android.library.Conversation @@ -20,5 +21,11 @@ class ConversationContainerWrapper { } } } + + fun encode(client: Client, conversation: Conversation): String { + val gson = GsonBuilder().create() + val obj = ConversationContainerWrapper.encodeToObj(client, conversation) + return gson.toJson(obj) + } } } diff --git a/example/src/tests.ts b/example/src/tests.ts index 3905a729f..a5dd6e84c 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -580,6 +580,40 @@ test('can stream groups', async () => { return true }) +test('can list all groups and conversations', async () => { + // Create three MLS enabled Clients + const aliceClient = await Client.createRandom({ + env: 'local', + enableAlphaMls: true, + }) + const bobClient = await Client.createRandom({ + env: 'local', + enableAlphaMls: true, + }) + const camClient = await Client.createRandom({ + env: 'local', + enableAlphaMls: true, + }) + + // Add one group and one conversation + const bobGroup = await bobClient.conversations.newGroup([aliceClient.address]) + const aliceConversation = await aliceClient.conversations.newConversation( + camClient.address + ) + + const listedContainers = await aliceClient.conversations.listAll() + + // Verify informatioin in listed containers is correct + if (listedContainers[0].topic !== bobGroup.topic || + listedContainers[0].version !== ConversationVersion.GROUP || + listedContainers[1].version !== ConversationVersion.DIRECT || + listedContainers[1].createdAt !== aliceConversation.createdAt) { + throw Error('Listed containers should match streamed containers') + } + + return true +}) + test('can stream all groups and conversations', async () => { // Create three MLS enabled Clients const aliceClient = await Client.createRandom({ diff --git a/src/index.ts b/src/index.ts index 2d79e5085..d88613c0d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,6 +18,7 @@ import type { Query } from './lib/Query' import { ConversationSendPayload } from './lib/types' import { DefaultContentTypes } from './lib/types/DefaultContentType' import { getAddress } from './utils/address' +import { ConversationContainer, ConversationVersion } from './lib/ConversationContainer' export * from './context' export * from './hooks' @@ -255,6 +256,22 @@ export async function listConversations< ) } +export async function listAll< + ContentTypes extends DefaultContentTypes = DefaultContentTypes, +>(client: Client): Promise[]> { + const list = await XMTPModule.listAll(client.address) + return list.map( + (json: string) => { + const jsonObj = JSON.parse(json) + if (jsonObj.version === ConversationVersion.GROUP) { + return new Group(client, jsonObj) + } else { + return new Conversation(client, jsonObj) + } + } + ) +} + export async function listMessages< ContentTypes extends DefaultContentTypes = DefaultContentTypes, >( diff --git a/src/lib/Conversations.ts b/src/lib/Conversations.ts index 95e11124b..2436b86e0 100644 --- a/src/lib/Conversations.ts +++ b/src/lib/Conversations.ts @@ -82,6 +82,22 @@ export default class Conversations< return result } + /** + * This method returns a list of all conversations and groups that the client is a member of. + * + * @returns {Promise} A Promise that resolves to an array of ConversationContainer objects. + */ + async listAll(): Promise[]> { + console.log("attempting list all from Conversations") + const result = await XMTPModule.listAll(this.client) + + for (const conversationContainer of result) { + this.known[conversationContainer.topic] = true + } + + return result + } + /** * This method streams groups that the client is a member of. * @@ -193,10 +209,6 @@ export default class Conversations< } this.known[conversationContainer.topic] = true - console.log( - 'Version on emitter call: ' + - JSON.stringify({ clientAddress, conversationContainer }) - ) if (conversationContainer.version === ConversationVersion.GROUP) { return await callback( new Group(this.client, conversationContainer as Group)