-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: extension for integration with Jetpack Compose
Added `com.ably.chat:chat-extensions-compose` package with extension functions for better integration with Jetpack Compose.
- Loading branch information
Showing
26 changed files
with
915 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
chat-android/src/main/java/com/ably/chat/annotations/Annotations.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
@file:Suppress("Filename") | ||
|
||
package com.ably.chat.annotations | ||
|
||
/** | ||
* API marked with this annotation is internal, and it is not intended to be used outside Ably. | ||
* It could be modified or removed without any notice. Using it outside Ably could cause undefined behaviour and/or | ||
* any unexpected effects. | ||
*/ | ||
@MustBeDocumented | ||
@RequiresOptIn( | ||
level = RequiresOptIn.Level.WARNING, | ||
message = "This API is experimental in Ably Chat SDK. Roughly speaking, there is a chance " + | ||
"that those declarations will be deprecated in the near future or the semantics of " + | ||
"their behavior may change in some way that may break some code", | ||
) | ||
@Target( | ||
AnnotationTarget.CLASS, | ||
AnnotationTarget.TYPEALIAS, | ||
AnnotationTarget.FUNCTION, | ||
AnnotationTarget.PROPERTY, | ||
AnnotationTarget.FIELD, | ||
AnnotationTarget.CONSTRUCTOR, | ||
AnnotationTarget.PROPERTY_SETTER, | ||
) | ||
public annotation class ExperimentalChatApi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
plugins { | ||
alias(libs.plugins.android.library) | ||
alias(libs.plugins.android.kotlin) | ||
alias(libs.plugins.maven.publish) | ||
alias(libs.plugins.compose.compiler) | ||
alias(libs.plugins.dokka) | ||
} | ||
|
||
val version = property("VERSION_NAME") | ||
|
||
android { | ||
namespace = "com.ably.chat.extensions.compose" | ||
compileSdk = 34 | ||
defaultConfig { | ||
minSdk = 24 | ||
consumerProguardFiles("consumer-rules.pro") | ||
} | ||
|
||
buildTypes { | ||
release { | ||
isMinifyEnabled = false | ||
|
||
proguardFiles( | ||
getDefaultProguardFile("proguard-android-optimize.txt"), | ||
"proguard-rules.pro", | ||
) | ||
} | ||
} | ||
|
||
buildFeatures { | ||
compose = true | ||
} | ||
|
||
compileOptions { | ||
sourceCompatibility = JavaVersion.VERSION_1_8 | ||
targetCompatibility = JavaVersion.VERSION_1_8 | ||
} | ||
|
||
kotlinOptions { | ||
jvmTarget = "1.8" | ||
} | ||
|
||
@Suppress("UnstableApiUsage") | ||
testOptions { | ||
unitTests { | ||
isReturnDefaultValues = true | ||
} | ||
} | ||
} | ||
|
||
kotlin { | ||
explicitApi() | ||
} | ||
|
||
dependencies { | ||
implementation(project(":chat-android")) | ||
implementation(libs.androidx.activity.compose) | ||
implementation(libs.androidx.compose.foundation) | ||
testImplementation(libs.junit) | ||
testImplementation(libs.mockk) | ||
testImplementation(libs.coroutine.test) | ||
testImplementation(libs.turbine) | ||
testImplementation(libs.molecule) | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
POM_ARTIFACT_ID=chat-extensions-compose | ||
POM_NAME=Ably Chat SDK library extensions for Jetpack Compose | ||
POM_DESCRIPTION=Ably Chat SDK library extensions for Jetpack Compose. | ||
POM_PACKAGING=aar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
</manifest> |
27 changes: 27 additions & 0 deletions
27
chat-extensions-compose/src/main/kotlin/com/ably/chat/extensions/compose/Connection.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.ably.chat.extensions.compose | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import com.ably.chat.Connection | ||
import com.ably.chat.ConnectionStatus | ||
import com.ably.chat.annotations.ExperimentalChatApi | ||
import com.ably.chat.statusAsFlow | ||
|
||
/** | ||
* @return active connection status | ||
*/ | ||
@ExperimentalChatApi | ||
@Composable | ||
public fun Connection.asComposable(): ConnectionStatus { | ||
var connectionStatus by remember(this) { mutableStateOf(status) } | ||
|
||
LaunchedEffect(this) { | ||
statusAsFlow().collect { connectionStatus = it.current } | ||
} | ||
|
||
return connectionStatus | ||
} |
86 changes: 86 additions & 0 deletions
86
chat-extensions-compose/src/main/kotlin/com/ably/chat/extensions/compose/Messages.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.ably.chat.extensions.compose | ||
|
||
import androidx.compose.foundation.lazy.LazyListState | ||
import androidx.compose.foundation.lazy.rememberLazyListState | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.DisposableEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.rememberCoroutineScope | ||
import androidx.compose.runtime.setValue | ||
import com.ably.chat.Message | ||
import com.ably.chat.MessageEventType | ||
import com.ably.chat.Messages | ||
import com.ably.chat.PaginatedResult | ||
import com.ably.chat.annotations.ExperimentalChatApi | ||
import kotlinx.coroutines.launch | ||
|
||
/** | ||
* @return paginated messages | ||
*/ | ||
@ExperimentalChatApi | ||
@Composable | ||
public fun Messages.asComposable(): PaginatedMessages { | ||
val listState = rememberLazyListState() | ||
var loaded by remember(this) { mutableStateOf(listOf<Message>()) } | ||
var loading by remember(this) { mutableStateOf(true) } | ||
var lastReceivedPaginatedResult: PaginatedResult<Message>? by remember(this) { mutableStateOf(null) } | ||
|
||
val coroutineScope = rememberCoroutineScope() | ||
|
||
DisposableEffect(this) { | ||
val subscription = subscribe { event -> | ||
when (event.type) { | ||
MessageEventType.Created -> { | ||
loaded += event.message | ||
coroutineScope.launch { | ||
listState.animateScrollToItem(loaded.size - 1) | ||
} | ||
} | ||
|
||
MessageEventType.Updated -> loaded = loaded.map { | ||
if (it.serial != event.message.serial) it else event.message | ||
} | ||
|
||
MessageEventType.Deleted -> loaded = loaded.filter { | ||
it.serial != event.message.serial | ||
} | ||
} | ||
} | ||
|
||
coroutineScope.launch { | ||
loading = true | ||
val receivedPaginatedResult = subscription.getPreviousMessages() | ||
lastReceivedPaginatedResult = receivedPaginatedResult | ||
loaded = receivedPaginatedResult.items.reversed() + loaded | ||
loading = false | ||
if (loaded.isNotEmpty()) listState.animateScrollToItem(loaded.size - 1) | ||
} | ||
|
||
onDispose { | ||
subscription.unsubscribe() | ||
} | ||
} | ||
|
||
return DefaultPaginatedMessages( | ||
loaded = loaded, | ||
listState = listState, | ||
loading = loading, | ||
hasMore = lastReceivedPaginatedResult?.hasNext() ?: true, | ||
) | ||
} | ||
|
||
public interface PaginatedMessages { | ||
public val loaded: List<Message> | ||
public val listState: LazyListState | ||
public val loading: Boolean | ||
public val hasMore: Boolean | ||
} | ||
|
||
private data class DefaultPaginatedMessages( | ||
override val loaded: List<Message>, | ||
override val listState: LazyListState, | ||
override val loading: Boolean, | ||
override val hasMore: Boolean, | ||
) : PaginatedMessages |
46 changes: 46 additions & 0 deletions
46
chat-extensions-compose/src/main/kotlin/com/ably/chat/extensions/compose/Occupancy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.ably.chat.extensions.compose | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import com.ably.chat.Occupancy | ||
import com.ably.chat.annotations.ExperimentalChatApi | ||
import com.ably.chat.asFlow | ||
import kotlinx.coroutines.cancelAndJoin | ||
import kotlinx.coroutines.launch | ||
|
||
public data class CurrentOccupancy( | ||
val connections: Int = 0, | ||
val presenceMembers: Int = 0, | ||
) | ||
|
||
/** | ||
* @return current occupancy | ||
*/ | ||
@ExperimentalChatApi | ||
@Composable | ||
public fun Occupancy.asComposable(): CurrentOccupancy { | ||
var currentOccupancy by remember(this) { mutableStateOf(CurrentOccupancy()) } | ||
|
||
LaunchedEffect(this) { | ||
val initialOccupancyGet = launch { | ||
val occupancyEvent = get() | ||
currentOccupancy = CurrentOccupancy( | ||
connections = occupancyEvent.connections, | ||
presenceMembers = occupancyEvent.presenceMembers, | ||
) | ||
} | ||
asFlow().collect { | ||
if (initialOccupancyGet.isActive) initialOccupancyGet.cancelAndJoin() | ||
currentOccupancy = CurrentOccupancy( | ||
connections = it.connections, | ||
presenceMembers = it.presenceMembers, | ||
) | ||
} | ||
} | ||
|
||
return currentOccupancy | ||
} |
35 changes: 35 additions & 0 deletions
35
chat-extensions-compose/src/main/kotlin/com/ably/chat/extensions/compose/Presence.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.ably.chat.extensions.compose | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import com.ably.chat.Presence | ||
import com.ably.chat.PresenceMember | ||
import com.ably.chat.annotations.ExperimentalChatApi | ||
import com.ably.chat.asFlow | ||
import kotlinx.coroutines.cancelAndJoin | ||
import kotlinx.coroutines.launch | ||
|
||
/** | ||
* @return currently present members | ||
*/ | ||
@ExperimentalChatApi | ||
@Composable | ||
public fun Presence.asComposable(): List<PresenceMember> { | ||
var presenceMembers by remember(this) { mutableStateOf(emptyList<PresenceMember>()) } | ||
|
||
LaunchedEffect(this) { | ||
val initialPresenceGet = launch { | ||
presenceMembers = get() | ||
} | ||
asFlow().collect { | ||
if (initialPresenceGet.isActive) initialPresenceGet.cancelAndJoin() | ||
presenceMembers = get() | ||
} | ||
} | ||
|
||
return presenceMembers | ||
} |
27 changes: 27 additions & 0 deletions
27
chat-extensions-compose/src/main/kotlin/com/ably/chat/extensions/compose/Room.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.ably.chat.extensions.compose | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import com.ably.chat.Room | ||
import com.ably.chat.RoomStatus | ||
import com.ably.chat.annotations.ExperimentalChatApi | ||
import com.ably.chat.statusAsFlow | ||
|
||
/** | ||
* @return room status | ||
*/ | ||
@ExperimentalChatApi | ||
@Composable | ||
public fun Room.asComposable(): RoomStatus { | ||
var roomStatus by remember(this) { mutableStateOf(status) } | ||
|
||
LaunchedEffect(this) { | ||
statusAsFlow().collect { roomStatus = it.current } | ||
} | ||
|
||
return roomStatus | ||
} |
Oops, something went wrong.