diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 4c391d62e..b52d09c64 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -404,6 +404,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 574e663f4..1af77351b 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 @@ -18,5 +19,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 979ac0fcd..3c55dd053 100644 --- a/example/src/tests.ts +++ b/example/src/tests.ts @@ -579,6 +579,42 @@ 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 1e90e9c92..5e57721a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,10 @@ import { PreparedLocalMessage, } from './lib/ContentCodec' import { Conversation } from './lib/Conversation' +import { + ConversationContainer, + ConversationVersion, +} from './lib/ConversationContainer' import { DecodedMessage } from './lib/DecodedMessage' import { Group } from './lib/Group' import type { Query } from './lib/Query' @@ -263,6 +267,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..9e78656e3 100644 --- a/src/lib/Conversations.ts +++ b/src/lib/Conversations.ts @@ -82,6 +82,21 @@ 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[]> { + 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 +208,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)