Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ The app includes five navigable examples:
default rows and composer reply to any message, edit and delete the user's
own, and go to a quoted message wherever it is in the history.

The 0.10.0 showcase seeds a reaction chip, lets Maya toggle an emoji, and opens
the reactor list. The Quoted screen renders the same controls in its custom
message row with `ConvoKitReactionBar`; Live uses the SDK-backed defaults.

The showcase screens pass real `InboxSummary` values to the controlled
`ConvoKitConversationListView` through its `summaries` and `currentUserId`
parameters, so the default row derives the preview line, the `activityAt` time
Expand Down Expand Up @@ -84,12 +88,12 @@ dependencyResolutionManagement {
}

dependencies {
implementation("app.convokit:convokit-android-ui:0.8.0")
implementation("app.convokit:convokit-android-ui:0.10.0")
}
```

The UI artifact exposes the compatible core SDK transitively. An application
may also declare `app.convokit:convokit-android:0.8.0` explicitly.
may also declare `app.convokit:convokit-android:0.10.0` explicitly.

## Live room example

Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ kotlin {
}

dependencies {
implementation("app.convokit:convokit-android-ui:0.9.0")
implementation("app.convokit:convokit-android-ui:0.10.0")
implementation(platform("androidx.compose:compose-bom:2025.05.01"))
implementation("androidx.activity:activity-compose:1.10.1")
implementation("androidx.compose.material3:material3")
Expand Down
36 changes: 36 additions & 0 deletions app/src/main/kotlin/app/convokit/ui/example/ShowcaseScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,17 @@ import androidx.compose.ui.unit.dp
import app.convokit.sdk.Conversation
import app.convokit.sdk.InboxSummary
import app.convokit.sdk.Message
import app.convokit.sdk.MessageReactionSummary
import app.convokit.sdk.ReactionSummary
import app.convokit.sdk.ReactionUser
import app.convokit.sdk.ReactionUsersPage
import app.convokit.ui.ConvoKitReplyPreview
import app.convokit.ui.ConvoKitWindowMode
import app.convokit.ui.components.ConvoKitConversationListView
import app.convokit.ui.components.ConvoKitConversationView
import app.convokit.ui.components.ConvoKitImageLoader
import app.convokit.ui.components.ConvoKitMessageItemScope
import app.convokit.ui.components.ConvoKitReactionBar
import app.convokit.ui.components.ConversationHeaderContent
import app.convokit.ui.components.DefaultComposer
import app.convokit.ui.components.DefaultMediaBlock
Expand Down Expand Up @@ -83,6 +88,13 @@ internal fun ShowcaseScreen(variant: ShowcaseVariant, systemPadding: PaddingValu
// is set the package shows the banner, prefills the composer silently and routes the one
// submit handed to the default and custom composers to `onSaveEdit` instead of `onSendMessage`.
var room by remember(variant) { mutableStateOf(ShowcaseRoom()) }
var reactionSummaries by remember(variant) { mutableStateOf<Map<String, MessageReactionSummary>>(mapOf(
showcaseMessages.last().id to MessageReactionSummary(
showcaseMessages.last().id,
listOf(ReactionSummary("❤️", 2, false)),
false,
),
)) }
// The highlight belongs to whoever owns the state, so a controlled host clears it itself; the
// package's own controller clears its own after about two seconds.
LaunchedEffect(room.highlightedMessageId) {
Expand Down Expand Up @@ -202,6 +214,27 @@ internal fun ShowcaseScreen(variant: ShowcaseVariant, systemPadding: PaddingValu
onReplyToMessage = { room = room.startReplying(it) },
onCancelReply = { room = room.cancelReplying() },
replyPreviewByMessageId = room.replyPreviews,
reactionSummaries = reactionSummaries,
onToggleReaction = { message, emoji ->
val previous = reactionSummaries[message.id]?.reactions.orEmpty()
val found = previous.find { it.emoji == emoji }
val count = (found?.count ?: 0) + if (found?.reactedByMe == true) -1 else 1
val updated = previous.filterNot { it.emoji == emoji } +
if (count > 0) listOf(ReactionSummary(emoji, count, found?.reactedByMe != true)) else emptyList()
reactionSummaries = reactionSummaries + (message.id to MessageReactionSummary(message.id, updated, false))
true
},
onListReactionUsers = { message, emoji, cursor ->
ReactionUsersPage(
if (cursor != null) emptyList() else buildList {
if (reactionSummaries[message.id]?.reactions?.any { it.emoji == emoji && it.reactedByMe } == true) {
add(ReactionUser(currentUserId, "Maya", null, showcaseInstant(40)))
}
add(ReactionUser("alex", "Alex", null, showcaseInstant(40)))
},
null,
)
},
onJumpToMessage = { room = room.jumpTo(it) },
highlightedMessageId = room.highlightedMessageId,
hasNewerMessages = room.hasNewerMessages,
Expand Down Expand Up @@ -407,6 +440,9 @@ private fun QuotedMessage(scope: ConvoKitMessageItemScope) {
}
scope.message.text?.let { Text(it, style = MaterialTheme.typography.bodySmall) }
scope.message.media.forEach { media -> DefaultMediaBlock(media, scope.message) }
scope.listReactionUsers?.let { listUsers ->
ConvoKitReactionBar(scope.reactionSummary, scope.toggleReaction, listUsers)
}
Row(verticalAlignment = Alignment.CenterVertically) {
if (mine) {
Text(
Expand Down
Loading