Skip to content
68 changes: 68 additions & 0 deletions docs/pages/chat-apps/content-types/read-receipts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,17 @@ if (message.contentTypeId === 'xmtp.org/readReceipt:1.0') {
```

```kotlin [Kotlin]
// Get the last read times for all participants in the conversation
val lastReadTimes = conversation.getLastReadTimes()

// lastReadTimes is a Map<String, Long> where:
// - key is the inbox ID
// - value is the timestamp in nanoseconds when they last read the conversation
lastReadTimes.forEach { (inboxId, timestamp) ->
println("Inbox $inboxId last read at: $timestamp")
}

// Or check if a message was read by iterating through messages
val message: DecodedMessage = conversation.messages().first()
if (message.encodedContent.type == ContentTypeReadReceipt) {
// The message is a ReadReceipt
Expand All @@ -126,12 +137,69 @@ if (message.encodedContent.type == ContentTypeReadReceipt) {
```

```swift [Swift]
// Get the last read times for all participants in the conversation
let lastReadTimes = try conversation.getLastReadTimes()

// lastReadTimes is a [String: Int64] where:
// - key is the inbox ID
// - value is the timestamp in nanoseconds when they last read the conversation
for (inboxId, timestamp) in lastReadTimes {
print("Inbox \(inboxId) last read at: \(timestamp)")
}

// Or check if a message was read by iterating through messages
let content: ReadReceipt = try message.content()
content.timestamp // "2019-09-26T07:58:30.996+0200"
```

:::

## Get last read times

Get the timestamp of when each participant last read the conversation:

:::code-group

```tsx [React Native]
// React Native doesn't have a getLastReadTimes() convenience method.
// Track read receipts manually by filtering messages:
const messages = await conversation.messages();
const readReceipts = messages.filter(
(msg) => msg.contentTypeId === 'xmtp.org/readReceipt:1.0'
);

// Build a map of last read times by sender
const lastReadTimes = new Map<string, Date>();
readReceipts.forEach((receipt) => {
const existing = lastReadTimes.get(receipt.senderInboxId);
if (!existing || receipt.sent > existing) {
lastReadTimes.set(receipt.senderInboxId, receipt.sent);
}
});
```

```kotlin [Kotlin]
// Get last read times for a conversation
val lastReadTimes = conversation.getLastReadTimes()

// Returns Map<InboxId, Long> where value is timestamp in nanoseconds
lastReadTimes.forEach { (inboxId, timestampNs) ->
println("$inboxId last read at $timestampNs")
}
```

```swift [Swift]
// Get last read times for a conversation
let lastReadTimes = try conversation.getLastReadTimes()

// Returns [String: Int64] where value is timestamp in nanoseconds
for (inboxId, timestampNs) in lastReadTimes {
print("\(inboxId) last read at \(timestampNs)")
}
```

:::

## Display a read receipt

`ReadReceipts` have an `undefined` or `nil` fallback, indicating the message is not expected to be displayed. To learn more, see [Handle unsupported content types](/chat-apps/content-types/fallback) section.
Expand Down
97 changes: 88 additions & 9 deletions docs/pages/chat-apps/core-messaging/create-conversations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,43 @@ let group = try await alix.conversations.newGroup([bo.inboxId, caro.inboxId],

:::

### Create a group chat using identities

Instead of using inbox IDs, you can create groups directly using identities (EOA or SCW addresses). This is useful when you have wallet addresses but haven't yet resolved them to inbox IDs.

:::code-group

```tsx [React Native]
// Create a group using identities instead of inbox IDs
const group = await client.conversations.newGroupWithIdentities(
[memberIdentity1, memberIdentity2],
{ name: 'Group Name', description: 'Group description' }
);
```

```kotlin [Kotlin]
// Create a group using identities instead of inbox IDs
val group = client.conversations.newGroupWithIdentities(
identities = listOf(memberIdentity1, memberIdentity2),
name = "Group Name",
description = "Group description"
)
```

```swift [Swift]
// Create a group using identities instead of inbox IDs
let group = try await client.conversations.newGroupWithIdentities(
with: [memberIdentity1, memberIdentity2],
name: "Group Name",
description: "Group description"
)
```

:::

## Optimistically create a new group chat

Optimistic group creation enables instant group chat creation and message preparation before adding members and even when offline.
Optimistic group creation enables instant group chat creation and message preparation before adding members and even when offline.

For example, use optimistic group creation when your user creates a new group without any members listed.

Expand Down Expand Up @@ -264,6 +298,35 @@ let conversation = try await client.conversations.newConversation(inboxId)

:::

### Create a DM using an identity

You can also create a DM directly using an identity (EOA or SCW address) instead of an inbox ID:

:::code-group

```tsx [React Native]
// Create or find a DM using an identity
const dm = await client.conversations.findOrCreateDmWithIdentity(peerPublicIdentity);
```

```kotlin [Kotlin]
// Create or find a DM using a identity
val dm = client.conversations.findOrCreateDmWithIdentity(peerPublicIdentity)

// Or use newConversationWithIdentity
val conversation = client.conversations.newConversationWithIdentity(peerPublicIdentity)
```

```swift [Swift]
// Create or find a DM using an identity
let dm = try await client.conversations.findOrCreateDmWithIdentity(with: peerPublicIdentity)

// Or use newConversationWithIdentity
let conversation = try await client.conversations.newConversationWithIdentity(with: peerPublicIdentity)
```

:::

## Conversation helper methods

Use these helper methods to quickly locate and access specific conversations—whether by conversation ID, topic, group ID, or DM identity—returning the appropriate ConversationContainer, group, or DM object.
Expand Down Expand Up @@ -314,8 +377,12 @@ await alix.conversations.findConversation(conversation.id);
await alix.conversations.findConversationByTopic(conversation.topic);
// Returns a Group
await alix.conversations.findGroup(group.id);
// Returns a DM
// Returns a DM by inbox ID
await alix.conversations.findDmByInboxId(bo.inboxId);
// Returns a DM by identity
await alix.conversations.findDmByIdentity(bo.identity);
// Returns a specific message
await alix.conversations.findMessage(messageId);
```

```kotlin [Kotlin]
Expand All @@ -324,18 +391,30 @@ alix.conversations.findConversation(conversation.id)
alix.conversations.findConversationByTopic(conversation.topic)
// Returns a Group
alix.conversations.findGroup(group.id)
// Returns a DM
alix.conversations.findDmbyInboxId(bo.inboxId);
// Returns a DM by inbox ID
alix.conversations.findDmByInboxId(bo.inboxId)
// Returns a DM by identity
alix.conversations.findDmByIdentity(bo.publicIdentity)
// Returns a specific message
alix.conversations.findMessage(messageId)
// Returns a message with reactions
alix.conversations.findEnrichedMessage(messageId)
```

```swift [Swift]
// Returns a ConversationContainer
try alix.conversations.findConversation(conversation.id)
try alix.conversations.findConversationByTopic(conversation.topic)
try await alix.conversations.findConversation(conversationId: conversation.id)
try await alix.conversations.findConversationByTopic(topic: conversation.topic)
// Returns a Group
try alix.conversations.findGroup(group.id)
// Returns a DM
try alix.conversations. findDmbyInboxId(bo.inboxId)
try await alix.conversations.findGroup(groupId: group.id)
// Returns a DM by inbox ID
try await alix.conversations.findDmByInboxId(inboxId: bo.inboxId)
// Returns a DM by identity
try await alix.conversations.findDmByIdentity(publicIdentity: bo.publicIdentity)
// Returns a specific message
try alix.conversations.findMessage(messageId: messageId)
// Returns a message with reactions
try alix.conversations.findEnrichedMessage(messageId: messageId)
```

:::
Expand Down
52 changes: 37 additions & 15 deletions docs/pages/chat-apps/core-messaging/disappearing-messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,24 @@ await client.conversations.createGroup([inboxId], {
```

```tsx [React Native]
// DM
import { DisappearingMessageSettings } from '@xmtp/react-native-sdk';

// DM - DisappearingMessageSettings is passed directly as second parameter
await client.conversations.newConversation(
inboxId,
{
disappearingMessageSettings: DisappearingMessageSettings(
disappearStartingAtNs: 1738620126404999936,
retentionDurationInNs: 1800000000000000
)
}
)
new DisappearingMessageSettings(1738620126404999936, 1800000000000000)
);

// Group
// Group - DisappearingMessageSettings is passed in options object
await client.conversations.newGroup(
[inboxId],
{
disappearingMessageSettings: DisappearingMessageSettings(
disappearStartingAtNs: 1738620126404999936,
retentionDurationInNs: 1800000000000000
disappearingMessageSettings: new DisappearingMessageSettings(
1738620126404999936,
1800000000000000
)
}
)
);
```

```kotlin [Kotlin]
Expand Down Expand Up @@ -221,8 +218,8 @@ conversation.isDisappearingMessagesEnabled();
```

```kotlin [Kotlin]
conversation.disappearingMessageSettings
conversation.isDisappearingMessagesEnabled
val settings = conversation.disappearingMessageSettings()
val isEnabled = conversation.isDisappearingMessagesEnabled()
```

```swift [Swift]
Expand Down Expand Up @@ -256,6 +253,17 @@ messages.forEach { message ->
}
```

```tsx [React Native]
const messages = await group.messages();

messages.forEach((message) => {
if (message.expiresAtNs) {
const expirationTime = new Date(Number(message.expiresAtNs) / 1_000_000);
console.log('Message expires at:', expirationTime);
}
});
```

```swift [Swift]
let messages = try await group.messages()

Expand Down Expand Up @@ -305,6 +313,20 @@ for await (const deletedMessage of stream) {
stream.end();
```

```tsx [React Native]
// Stream message deletions
await client.conversations.streamMessageDeletions(
async (deletedMessage) => {
console.log('Message deleted:', deletedMessage.id);
// Update your UI to remove the message
},
() => console.log('Stream closed') // optional onClose callback
);

// To cancel the stream
await client.conversations.cancelStreamMessageDeletions();
```

:::

:::warning[Deprecated API]
Expand Down
8 changes: 4 additions & 4 deletions docs/pages/chat-apps/core-messaging/group-metadata.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const groupName = await group.groupName();
```

```kotlin [Kotlin]
group.name
val groupName = group.name()
```

```swift [Swift]
Expand Down Expand Up @@ -81,7 +81,7 @@ const groupDescription = await group.groupDescription();
```

```kotlin [Kotlin]
group.description
val groupDescription = group.description()
```

```swift [Swift]
Expand Down Expand Up @@ -133,7 +133,7 @@ const groupName = await group.imageUrl();
```

```kotlin [Kotlin]
group.imageURL
val groupImageUrl = group.imageUrl()
```

```swift [Swift]
Expand Down Expand Up @@ -187,7 +187,7 @@ const appData = await group.appData();
```

```kotlin [Kotlin]
val appData = group.appData
val appData = group.appData()
```

:::
Expand Down
Loading