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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The app demonstrates:
- embedding `ConvoKitConversation` from `app.convokit:convokit-android-ui` in an Android Views application with `ComposeView`;
- delegating message history, sending, editing and deleting your own messages, quoted replies and jump-to-message, media rendering, typing and read receipts to the reusable UI library;
- calling the 0.9.0 core surface directly from the host: sending with `replyToMessageId`, resolving a whole page of quoted rows with one `getReplyPreviews` call, centring a window with `getMessageContext`, and telling the coded `MESSAGE_NOT_FOUND` and `CONVERSATION_NOT_FOUND` answers apart;
- calling the reaction core API directly: add/remove one exact `👍🏽`, read a batched summary, and load the first page of reactors, while the embedded UI handles its own reaction controls;
- creating an adapter after each successful login and disposing the old conversation before disconnecting or switching users.

The sample no longer maintains a second message renderer, composer, or raw
Expand All @@ -36,9 +37,9 @@ The host handles system-bar, display-cutout and keyboard insets before embedding
Compose, so padding is not applied twice. Local host tests use Robolectric and
synthetic insets; they do not prove hosted authorization or physical-device chat.

### Published 0.9.0 SDKs
### Published 0.10.0 SDKs

The example consumes the published 0.9.0 core and UI from maven.convokit.app.
The example consumes the published 0.10.0 core and UI from maven.convokit.app.
The embedded room acknowledges a concrete message for precise read positions,
defers acknowledgements while the host is hidden, correlates pending sends
with live/history confirmations before HTTP returns, and sends the caller's
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ android {
}

dependencies {
implementation("app.convokit:convokit-android:0.9.0")
implementation("app.convokit:convokit-android-ui:0.9.0")
implementation("app.convokit:convokit-android:0.10.0")
implementation("app.convokit:convokit-android-ui:0.10.0")
implementation("androidx.activity:activity-ktx:1.10.1")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.9.1")
Expand Down
35 changes: 35 additions & 0 deletions app/src/main/kotlin/app/convokit/example/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class MainActivity : AppCompatActivity() {
onBackPressedDispatcher.addCallback(this, roomBack)
binding.joinButton.setOnClickListener { joinRoom() }
binding.replyDemoButton.setOnClickListener { runReplyDemo() }
binding.reactionDemoButton.setOnClickListener { runReactionDemo() }
}

private fun joinRoom() {
Expand Down Expand Up @@ -106,6 +107,7 @@ class MainActivity : AppCompatActivity() {
joinedRoomId = roomId
binding.replyDemoStatus.setText(R.string.reply_demo_hint)
binding.replyDemoButton.isEnabled = true
binding.reactionDemoButton.isEnabled = true
roomBack.isEnabled = true
} catch (cause: Throwable) {
withContext(NonCancellable) { convoKit.disconnectUser() }
Expand All @@ -124,6 +126,7 @@ class MainActivity : AppCompatActivity() {
binding.chatContent.disposeComposition()
binding.room.visibility = View.GONE
binding.replyDemoButton.isEnabled = false
binding.reactionDemoButton.isEnabled = false
joinedRoomId = null
binding.joinForm.visibility = View.VISIBLE
binding.status.text = getString(R.string.disconnecting)
Expand Down Expand Up @@ -160,6 +163,38 @@ class MainActivity : AppCompatActivity() {
}
}

/** Direct core API tour. The Compose conversation handles its own picker and chips. */
private fun runReactionDemo() {
val roomId = joinedRoomId ?: return
binding.reactionDemoButton.isEnabled = false
binding.reactionDemoStatus.setText(R.string.reaction_demo_running)
lifecycleScope.launch {
try {
val newest = convoKit.getMessages(roomId, limit = 1).firstOrNull()
val report = if (newest == null) {
getString(R.string.reaction_demo_empty)
} else {
val emoji = "👍🏽" // Preserve the exact Unicode sequence, including its skin tone.
val added = convoKit.addReaction(newest.id, emoji)
val summary = convoKit.getReactionSummaries(roomId, listOf(newest.id))
.firstOrNull()?.reactions?.find { it.emoji == emoji }
val reactors = convoKit.listReactionUsers(newest.id, emoji, limit = 10)
val removed = convoKit.removeReaction(newest.id, emoji)
"Added $emoji to ${newest.id}: changed=${added.changed}; " +
"count=${summary?.count ?: 0}, reactedByMe=${summary?.reactedByMe ?: false}; " +
"reactors on first page=${reactors.data.size}, next page=${reactors.nextCursor != null}; " +
"removed: changed=${removed.changed}."
}
if (joinedRoomId == roomId) binding.reactionDemoStatus.text = report
} catch (cause: Throwable) {
if (cause is CancellationException) throw cause
if (joinedRoomId == roomId) binding.reactionDemoStatus.setText(R.string.reaction_demo_failed)
} finally {
binding.reactionDemoButton.isEnabled = joinedRoomId != null
}
}
}

private suspend fun issueUserToken(appUserId: String): String {
val response = postJson(
"${BuildConfig.DEMO_BACKEND_URL}/api/auth/token".toHttpUrl(),
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@
android:textColor="@color/convokit_text"
android:textSize="13sp" />
</ScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/reaction_demo_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:enabled="false"
android:text="@string/reaction_demo" />
<TextView
android:id="@+id/reaction_demo_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:accessibilityLiveRegion="polite"
android:text="@string/reaction_demo_hint"
android:textColor="@color/convokit_text"
android:textSize="13sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@
<string name="reply_demo_hint">Quotes the newest message, resolves every quoted row on the page in one call, centres a window on the quote and shows the two 404s a host must tell apart. Running it sends one message to this room.</string>
<string name="reply_demo_running">Running the quoted-reply demo…</string>
<string name="reply_demo_failed">The quoted-reply demo could not reach ConvoKit. Check your connection and try again.</string>
<string name="reaction_demo">Run the reaction API demo</string>
<string name="reaction_demo_hint">Adds and removes one 👍🏽 on the newest message, reads its batched summary, and pages the reactor list. The conversation above handles reactions automatically.</string>
<string name="reaction_demo_running">Running the reaction API demo…</string>
<string name="reaction_demo_empty">This room has no message to react to yet.</string>
<string name="reaction_demo_failed">The reaction API demo could not reach ConvoKit. Check access and try again.</string>
</resources>
Loading