diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 347ce28af..989091a89 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -800,6 +800,26 @@ class XMTPModule : Module() { } } + AsyncFunction("groupName") Coroutine { clientAddress: String, id: String -> + withContext(Dispatchers.IO) { + logV("groupName") + val client = clients[clientAddress] ?: throw XMTPException("No client") + val group = findGroup(clientAddress, id) + + group?.name + } + } + + AsyncFunction("updateGroupName") Coroutine { clientAddress: String, id: String, groupName: String -> + withContext(Dispatchers.IO) { + logV("updateGroupName") + val client = clients[clientAddress] ?: throw XMTPException("No client") + val group = findGroup(clientAddress, id) + + group?.updateGroupName(groupName) + } + } + AsyncFunction("isGroupActive") Coroutine { clientAddress: String, id: String -> withContext(Dispatchers.IO) { logV("isGroupActive") diff --git a/example/src/tests/groupTests.ts b/example/src/tests/groupTests.ts index 414fd365f..eb75e26a4 100644 --- a/example/src/tests/groupTests.ts +++ b/example/src/tests/groupTests.ts @@ -1356,6 +1356,48 @@ test('skipSync parameter behaves as expected', async () => { return true }) +test('can read and update group name', async () => { + const [alix, bo, caro] = await createClients(3) + const alixGroup = await alix.conversations.newGroup([bo.address]) + + let groupName = await alixGroup.groupName() + + assert(groupName === 'New Group', 'group name should be "New Group"') + + await alixGroup.updateGroupName('Test name update 1') + + groupName = await alixGroup.groupName() + + assert( + groupName === 'Test name update 1', + 'group name should be "Test name update 1"' + ) + + const boGroup = (await bo.conversations.listGroups())[0] + groupName = await boGroup.groupName(true) + + assert(groupName === 'New Group', 'group name should be "New Group"') + + await boGroup.sync() + + groupName = await boGroup.groupName(true) + + assert( + groupName === 'Test name update 1', + 'group name should be "Test name update 1"' + ) + + await alixGroup.addMembers([caro.address]) + const caroGroup = (await caro.conversations.listGroups())[0] + + groupName = await caroGroup.groupName(true) + assert( + groupName === 'Test name update 1', + 'group name should be "Test name update 1"' + ) + return true +}) + // Commenting this out so it doesn't block people, but nice to have? // test('can stream messages for a long time', async () => { // const bo = await Client.createRandom({ env: 'local', enableAlphaMls: true }) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 778e169a5..e9d73212d 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -696,6 +696,30 @@ public class XMTPModule: Module { try await group.removeMembers(addresses: peerAddresses) } + + AsyncFunction("groupName") { (clientAddress: String, id: String) -> String in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + + return try group.groupName() + } + + AsyncFunction("updateGroupName") { (clientAddress: String, id: String, groupName: String) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + + try await group.updateGroupName(groupName: groupName) + } AsyncFunction("isGroupActive") { (clientAddress: String, id: String) -> Bool in guard let client = await clientsManager.getClient(key: clientAddress) else { diff --git a/src/index.ts b/src/index.ts index ad722b918..af5d07bf3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -220,6 +220,21 @@ export async function removeGroupMembers( return XMTPModule.removeGroupMembers(clientAddress, id, addresses) } +export function groupName( + address: string, + id: string +): string | PromiseLike { + return XMTPModule.groupName(address, id) +} + +export function updateGroupName( + address: string, + id: string, + groupName: string +): Promise { + return XMTPModule.updateGroupName(address, id, groupName) +} + export async function sign( clientAddress: string, digest: Uint8Array, diff --git a/src/lib/Group.ts b/src/lib/Group.ts index da0fb0315..e8ab3b353 100644 --- a/src/lib/Group.ts +++ b/src/lib/Group.ts @@ -194,6 +194,18 @@ export class Group< return XMTP.removeGroupMembers(this.client.address, this.id, addresses) } + async groupName(skipSync = false): Promise { + if (!skipSync) { + await this.sync() + } + + return XMTP.groupName(this.client.address, this.id) + } + + async updateGroupName(groupName: string): Promise { + return XMTP.updateGroupName(this.client.address, this.id, groupName) + } + async isActive(skipSync = false): Promise { if (!skipSync) { await this.sync()