From e4c0c7b7ba1755913d74f514b6ff0baa566a6e0f Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Sun, 27 Feb 2022 19:35:11 +0100 Subject: [PATCH] feat: prepare for supporting buffer navigation and message loading --- .../quasseldroid/QuasseldroidRouter.kt | 38 +++++-- .../quasseldroid/messages/MessageBuffer.kt | 12 +++ .../quasseldroid/messages/MessageStore.kt | 100 ++++++++++++++++++ .../service/ClientSessionWrapper.kt | 9 ++ .../quasseldroid/service/QuasselBackend.kt | 2 +- .../quasseldroid/service/QuasselBinder.kt | 4 +- .../quasseldroid/service/QuasselRunner.kt | 20 ++-- .../{ => components}/ConnectedClientCard.kt | 2 +- .../ui/{ => components}/CoreInfoView.kt | 2 +- .../ui/{ => components}/LoginView.kt | 15 +-- .../ui/{ => components}/PasswordTextField.kt | 2 +- .../ui/{ => routes}/CoreInfoRoute.kt | 4 +- .../ui/{HomeView.kt => routes/HomeRoute.kt} | 14 +-- .../quasseldroid/ui/routes/LoginRoute.kt | 17 +++ .../justjanne.kotlin.android.gradle.kts | 7 +- .../main/kotlin/justjanne.kotlin.gradle.kts | 2 + gradle/libs.versions.toml | 2 +- 17 files changed, 211 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt create mode 100644 app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt create mode 100644 app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt rename app/src/main/java/de/justjanne/quasseldroid/ui/{ => components}/ConnectedClientCard.kt (97%) rename app/src/main/java/de/justjanne/quasseldroid/ui/{ => components}/CoreInfoView.kt (97%) rename app/src/main/java/de/justjanne/quasseldroid/ui/{ => components}/LoginView.kt (90%) rename app/src/main/java/de/justjanne/quasseldroid/ui/{ => components}/PasswordTextField.kt (98%) rename app/src/main/java/de/justjanne/quasseldroid/ui/{ => routes}/CoreInfoRoute.kt (87%) rename app/src/main/java/de/justjanne/quasseldroid/ui/{HomeView.kt => routes/HomeRoute.kt} (85%) create mode 100644 app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt diff --git a/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt b/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt index 424550bc3..8ed54ebf1 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/QuasseldroidRouter.kt @@ -1,21 +1,47 @@ package de.justjanne.quasseldroid +import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.navArgument import de.justjanne.quasseldroid.service.QuasselBackend -import de.justjanne.quasseldroid.ui.CoreInfoRoute -import de.justjanne.quasseldroid.ui.HomeView -import de.justjanne.quasseldroid.ui.LoginRoute +import de.justjanne.quasseldroid.ui.routes.CoreInfoRoute +import de.justjanne.quasseldroid.ui.routes.HomeRoute +import de.justjanne.quasseldroid.ui.routes.LoginRoute @Composable fun QuasseldroidRouter(backend: QuasselBackend) { val navController = rememberNavController() NavHost(navController = navController, startDestination = "login") { - composable("login") { LoginRoute(backend, navController) } - composable("home") { HomeView(backend, navController) } - composable("coreInfo") { CoreInfoRoute(backend, navController) } + composable("login") { + LoginRoute(backend, navController) + } + composable("home") { + HomeRoute(backend, navController) + } + + composable( + "buffer/{bufferId}", + listOf(navArgument("bufferId") { type = NavType.IntType }) + ) { + Text("Buffer ${it.arguments?.getInt("bufferId")}") + } + composable("bufferViewConfigs") { + Text("List of BufferViewConfigs") + } + composable( + "bufferViewConfigs/{bufferViewConfigId}", + listOf(navArgument("bufferViewConfigId") { type = NavType.IntType }) + ) { + Text("BufferViewConfig ${it.arguments?.getInt("bufferViewConfigId")}") + } + + composable("coreInfo") { + CoreInfoRoute(backend, navController) + } } } diff --git a/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt new file mode 100644 index 000000000..6df763cce --- /dev/null +++ b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageBuffer.kt @@ -0,0 +1,12 @@ +package de.justjanne.quasseldroid.messages + +import de.justjanne.libquassel.protocol.models.Message + +data class MessageBuffer( + /** + * Whether the chronologically latest message for a given buffer id is in the buffer. + * If yes, new messages that arrive for this buffer should be appened to the end. + */ + val atEnd: Boolean, + val messages: List<Message> +) diff --git a/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt new file mode 100644 index 000000000..c9f670522 --- /dev/null +++ b/app/src/main/java/de/justjanne/quasseldroid/messages/MessageStore.kt @@ -0,0 +1,100 @@ +package de.justjanne.quasseldroid.messages + +import de.justjanne.libquassel.client.syncables.ClientBacklogManager +import de.justjanne.libquassel.protocol.models.Message +import de.justjanne.libquassel.protocol.models.ids.BufferId +import de.justjanne.libquassel.protocol.models.ids.MsgId +import de.justjanne.libquassel.protocol.util.StateHolder +import de.justjanne.libquassel.protocol.variant.into +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import java.io.Closeable + +class MessageStore( + incoming: Flow<Message>, + private val backlogManager: ClientBacklogManager +) : Closeable, StateHolder<Map<BufferId, MessageBuffer>> { + private val state = MutableStateFlow(mapOf<BufferId, MessageBuffer>()) + override fun state() = state.value + override fun flow() = state + + private val scope = CoroutineScope(Dispatchers.IO) + private val disposable = incoming.onEach { message -> + val bufferId = message.bufferInfo.bufferId + state.update { messages -> + val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList()) + if (buffer.atEnd) { + messages + Pair(bufferId, buffer.copy(messages = buffer.messages + message)) + } else { + messages + } + } + }.launchIn(scope) + + fun loadAround(bufferId: BufferId, messageId: MsgId) { + scope.launch { + state.update { messages -> + val (before, after) = listOf( + async { backlogManager.backlog(bufferId, messageId) }, + async { backlogManager.backlogForward(bufferId, messageId) }, + ).awaitAll() + + val updated = MessageBuffer( + atEnd = false, + messages = (before + after) + .mapNotNull { it.into<Message>() } + .sortedBy { it.messageId } + ) + messages + Pair(bufferId, updated) + } + } + } + + fun loadBefore(bufferId: BufferId) { + scope.launch { + state.update { messages -> + val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList()) + val messageId = buffer.messages.firstOrNull()?.messageId ?: MsgId(-1) + val data = backlogManager.backlog(bufferId, messageId) + .mapNotNull { it.into<Message>() } + val updated = buffer.copy( + messages = (buffer.messages + data) + .sortedBy { it.messageId } + ) + messages + Pair(bufferId, updated) + } + } + } + + fun loadAfter(bufferId: BufferId) { + scope.launch { + state.update { messages -> + val buffer = messages[bufferId] ?: MessageBuffer(true, emptyList()) + val messageId = buffer.messages.lastOrNull()?.messageId ?: MsgId(-1) + val data = backlogManager.backlogForward(bufferId, messageId) + .mapNotNull { it.into<Message>() } + val updated = buffer.copy( + messages = (buffer.messages + data) + .sortedBy { it.messageId } + ) + messages + Pair(bufferId, updated) + } + } + } + + override fun close() { + runBlocking { + disposable.cancelAndJoin() + } + } +} diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt b/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt new file mode 100644 index 000000000..a52a88fb6 --- /dev/null +++ b/app/src/main/java/de/justjanne/quasseldroid/service/ClientSessionWrapper.kt @@ -0,0 +1,9 @@ +package de.justjanne.quasseldroid.service + +import de.justjanne.libquassel.client.session.ClientSession +import de.justjanne.quasseldroid.messages.MessageStore + +data class ClientSessionWrapper( + val session: ClientSession, + val messages: MessageStore +) diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt index 5d8ebb5b0..6f2edb9d0 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBackend.kt @@ -15,7 +15,7 @@ import de.justjanne.quasseldroid.util.lifecycle.LifecycleStatus import kotlinx.coroutines.flow.MutableStateFlow class QuasselBackend : DefaultContextualLifecycleObserver(), ServiceConnection, - StateHolder<ClientSession?> { + StateHolder<ClientSessionWrapper?> { private var connectionData: ConnectionData? = null override fun flow() = state.flatMap() diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt index db890aef0..993619d8c 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselBinder.kt @@ -6,8 +6,8 @@ import de.justjanne.libquassel.protocol.util.StateHolder import kotlinx.coroutines.flow.StateFlow class QuasselBinder( - private val state: StateFlow<ClientSession?> -) : Binder(), StateHolder<ClientSession?> { + private val state: StateFlow<ClientSessionWrapper?> +) : Binder(), StateHolder<ClientSessionWrapper?> { constructor(runner: QuasselRunner) : this(runner.flow()) override fun flow() = state diff --git a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt index e8d8ca7c5..93512a477 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/service/QuasselRunner.kt @@ -8,6 +8,7 @@ import de.justjanne.libquassel.protocol.connection.ProtocolVersion import de.justjanne.libquassel.protocol.features.FeatureSet import de.justjanne.libquassel.protocol.io.CoroutineChannel import de.justjanne.libquassel.protocol.util.StateHolder +import de.justjanne.quasseldroid.messages.MessageStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -20,16 +21,16 @@ import javax.net.ssl.SSLContext class QuasselRunner( private val address: InetSocketAddress, private val auth: Pair<String, String> -) : Thread("Quassel Runner"), Closeable, StateHolder<ClientSession?> { +) : Thread("Quassel Runner"), Closeable, StateHolder<ClientSessionWrapper?> { private val channel = CoroutineChannel() - override fun state(): ClientSession? = state.value - override fun flow(): StateFlow<ClientSession?> = state + override fun state(): ClientSessionWrapper? = state.value + override fun flow(): StateFlow<ClientSessionWrapper?> = state - private val state = MutableStateFlow<ClientSession?>(null) + private val state = MutableStateFlow<ClientSessionWrapper?>(null) init { - start() + start() } override fun run() { @@ -49,7 +50,14 @@ class QuasselRunner( ) ), SSLContext.getDefault() - ).also { state.value = it } + ) + state.value = ClientSessionWrapper( + session, + messages = MessageStore( + session.rpcHandler.messages(), + session.backlogManager + ) + ) session.handshakeHandler.init( "Quasseltest v0.1", "2022-02-24", diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt similarity index 97% rename from app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt index 314956f18..66af09a56 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/ConnectedClientCard.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/ConnectedClientCard.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt similarity index 97% rename from app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt index 90b99fc45..c25cdce54 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoView.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/CoreInfoView.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt similarity index 90% rename from app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt index bd1388dcf..2c1e30c75 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/LoginView.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/LoginView.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.components import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth @@ -15,28 +15,15 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import de.justjanne.quasseldroid.service.ConnectionData -import de.justjanne.quasseldroid.service.QuasselBackend import de.justjanne.quasseldroid.util.TextFieldValueSaver import java.net.InetSocketAddress -@Composable -fun LoginRoute(backend: QuasselBackend, navController: NavController) { - val context = LocalContext.current - LoginView(onLogin = { - if (backend.login(context, it)) { - navController.navigate("home") - } - }) -} - @Preview(name = "Login", showBackground = true) @Composable fun LoginView(onLogin: (ConnectionData) -> Unit = {}) { diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt similarity index 98% rename from app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt index a4741b39b..978fa20da 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/PasswordTextField.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/components/PasswordTextField.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.components import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.text.KeyboardActions diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt similarity index 87% rename from app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt index c509d7c7d..cc17d865f 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/CoreInfoRoute.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/CoreInfoRoute.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.routes import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding @@ -10,6 +10,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import de.justjanne.libquassel.protocol.util.flatMap import de.justjanne.quasseldroid.service.QuasselBackend +import de.justjanne.quasseldroid.ui.components.CoreInfoView import de.justjanne.quasseldroid.util.mapNullable import de.justjanne.quasseldroid.util.rememberFlow @@ -17,6 +18,7 @@ import de.justjanne.quasseldroid.util.rememberFlow fun CoreInfoRoute(backend: QuasselBackend, navController: NavController) { val coreInfo = rememberFlow(null) { backend.flow() + .mapNullable { it.session } .flatMap() .mapNullable { it.coreInfo } .flatMap() diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt similarity index 85% rename from app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt rename to app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt index e139fb490..165d193ba 100644 --- a/app/src/main/java/de/justjanne/quasseldroid/ui/HomeView.kt +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/HomeRoute.kt @@ -1,4 +1,4 @@ -package de.justjanne.quasseldroid.ui +package de.justjanne.quasseldroid.ui.routes import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -7,11 +7,8 @@ import androidx.compose.foundation.lazy.items import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.platform.LocalContext import androidx.navigation.NavController -import de.justjanne.libquassel.protocol.models.ids.BufferId import de.justjanne.libquassel.protocol.syncables.state.BufferViewConfigState import de.justjanne.libquassel.protocol.util.combineLatest import de.justjanne.libquassel.protocol.util.flatMap @@ -20,11 +17,15 @@ import de.justjanne.quasseldroid.util.mapNullable import de.justjanne.quasseldroid.util.rememberFlow @Composable -fun HomeView(backend: QuasselBackend, navController: NavController) { - val session = rememberFlow(null) { backend.flow() } +fun HomeRoute(backend: QuasselBackend, navController: NavController) { + val session = rememberFlow(null) { + backend.flow() + .mapNullable { it.session } + } val bufferViewConfigs: List<BufferViewConfigState> = rememberFlow(emptyList()) { backend.flow() + .mapNullable { it.session } .flatMap() .mapNullable { it.bufferViewManager } .flatMap() @@ -34,6 +35,7 @@ fun HomeView(backend: QuasselBackend, navController: NavController) { val initStatus = rememberFlow(null) { backend.flow() + .mapNullable { it.session } .mapNullable { it.baseInitHandler } .flatMap() } diff --git a/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt new file mode 100644 index 000000000..789c05079 --- /dev/null +++ b/app/src/main/java/de/justjanne/quasseldroid/ui/routes/LoginRoute.kt @@ -0,0 +1,17 @@ +package de.justjanne.quasseldroid.ui.routes + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavController +import de.justjanne.quasseldroid.service.QuasselBackend +import de.justjanne.quasseldroid.ui.components.LoginView + +@Composable +fun LoginRoute(backend: QuasselBackend, navController: NavController) { + val context = LocalContext.current + LoginView(onLogin = { + if (backend.login(context, it)) { + navController.navigate("home") + } + }) +} diff --git a/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts b/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts index fc84b973d..bb75c465b 100644 --- a/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts +++ b/gradle/convention/src/main/kotlin/justjanne.kotlin.android.gradle.kts @@ -1,3 +1,5 @@ +import gradle.kotlin.dsl.accessors._9f9f63157b527b37420ecbe9e569524a.implementation +import gradle.kotlin.dsl.accessors._9f9f63157b527b37420ecbe9e569524a.testImplementation import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { @@ -8,7 +10,10 @@ plugins { } dependencies { - "implementation"("org.jetbrains.kotlin:kotlin-stdlib:1.6.10") + implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0") } tasks.withType<KotlinCompile> { diff --git a/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts b/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts index 39b8cf9c0..04838711e 100644 --- a/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts +++ b/gradle/convention/src/main/kotlin/justjanne.kotlin.gradle.kts @@ -10,6 +10,8 @@ plugins { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") + testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0") } tasks.withType<KotlinCompile> { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fdcd6bae8..bdf9f59c7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -libquassel = "0.8.1" +libquassel = "0.9.0" androidx-activity = "1.4.0" androidx-appcompat = "1.4.1" androidx-compose = "1.1.1" -- GitLab