From 8b9727082a67ada48b4f8e6d5c62b5d9dae51046 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Mon, 25 Mar 2024 21:14:16 -0700 Subject: [PATCH] Add basic WebSocket connectivity with Dero node. - Created a new stargate module that will contain the code to connect with the Dero nodes. This stargate module will use the ktor library, which is a multiplatform networking library that works on both Android and iOS. - Added a bassic connectivity with a Dero node. It just connects with the node, listens for messages, and prints them out to the standard output. - Introduced the ScreenModel library and created a basic ImportAccountScreenModel. ScreenModel classes serve to host all the logic for their corresponding screens. - Added the Internet permssion to the Android app, to be able to connect with the internet. - Removed the Desktop target. After discussing with Ken, we decided that investing on a Desktop app does not make sense. We will focus on Android and iOS only. --- composeApp/build.gradle.kts | 63 +++++++++---------- .../src/androidMain/AndroidManifest.xml | 2 + .../importaccount/ImportAccountScreen.kt | 6 +- .../importaccount/ImportAccountScreenModel.kt | 23 +++++++ .../kotlin/net/agorise/kee/Platform.jvm.kt | 7 --- .../kotlin/net/agorise/kee/main.kt | 20 ------ gradle/libs.versions.toml | 9 ++- settings.gradle.kts | 1 + shared/preferences/build.gradle.kts | 2 - shared/stargate/build.gradle.kts | 40 ++++++++++++ .../net/agorise/shared/stargate/Bridge.kt | 33 ++++++++++ 11 files changed, 141 insertions(+), 65 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt delete mode 100644 composeApp/src/desktopMain/kotlin/net/agorise/kee/Platform.jvm.kt delete mode 100644 composeApp/src/desktopMain/kotlin/net/agorise/kee/main.kt create mode 100644 shared/stargate/build.gradle.kts create mode 100644 shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 137599c..fa6cdfa 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.compose.desktop.application.dsl.TargetFormat - plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidApplication) @@ -15,8 +13,6 @@ kotlin { } } - jvm("desktop") - listOf( iosX64(), iosArm64(), @@ -29,26 +25,39 @@ kotlin { } sourceSets { - val desktopMain by getting - - androidMain.dependencies { - implementation(libs.compose.ui.tooling.preview) - implementation(libs.androidx.activity.compose) + val androidMain by getting { + dependencies { + implementation(libs.compose.ui.tooling.preview) + implementation(libs.androidx.activity.compose) + } } - commonMain.dependencies { - implementation(projects.shared.preferences) - implementation(compose.components.resources) - implementation(compose.components.uiToolingPreview) - implementation(compose.foundation) - implementation(compose.material3) - implementation(compose.runtime) - implementation(compose.ui) - implementation(libs.voyager.navigator) - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1") + val commonMain by getting { + commonMain.dependencies { + implementation(projects.shared.preferences) + implementation(projects.shared.stargate) + + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.runtime) + implementation(compose.ui) + implementation(libs.coroutines.core) + implementation(libs.voyager.navigator) + implementation(libs.voyager.screenmodel) + } } - desktopMain.dependencies { - implementation(compose.desktop.currentOs) + + val iosX64Main by getting + val iosArm64Main by getting + val iosSimulatorArm64Main by getting + val iosMain by creating { + dependsOn(commonMain) + iosX64Main.dependsOn(this) + iosArm64Main.dependsOn(this) + iosSimulatorArm64Main.dependsOn(this) + dependencies {} } } } @@ -86,15 +95,3 @@ android { debugImplementation(libs.compose.ui.tooling) } } - -compose.desktop { - application { - mainClass = "MainKt" - - nativeDistributions { - targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) - packageName = "net.agorise.kee" - packageVersion = "1.0.0" - } - } -} diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index b87d944..f069253 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -1,6 +1,8 @@ + + diff --git a/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt b/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt new file mode 100644 index 0000000..c9bef82 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt @@ -0,0 +1,23 @@ +package net.agorise.kee.ui.screen.importaccount + +import cafe.adriel.voyager.core.model.ScreenModel +import cafe.adriel.voyager.core.model.screenModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.launch +import net.agorise.shared.stargate.Bridge + +class ImportAccountScreenModel : ScreenModel { + private val bridge = Bridge() + + init { + screenModelScope.launch(Dispatchers.IO) { + bridge.start() + } + } + + override fun onDispose() { + super.onDispose() + bridge.stop() + } +} diff --git a/composeApp/src/desktopMain/kotlin/net/agorise/kee/Platform.jvm.kt b/composeApp/src/desktopMain/kotlin/net/agorise/kee/Platform.jvm.kt deleted file mode 100644 index 90a123b..0000000 --- a/composeApp/src/desktopMain/kotlin/net/agorise/kee/Platform.jvm.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.agorise.kee - -class JVMPlatform: Platform { - override val name: String = "Java ${System.getProperty("java.version")}" -} - -actual fun getPlatform(): Platform = JVMPlatform() diff --git a/composeApp/src/desktopMain/kotlin/net/agorise/kee/main.kt b/composeApp/src/desktopMain/kotlin/net/agorise/kee/main.kt deleted file mode 100644 index c08889f..0000000 --- a/composeApp/src/desktopMain/kotlin/net/agorise/kee/main.kt +++ /dev/null @@ -1,20 +0,0 @@ -package net.agorise.kee - -import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Window -import androidx.compose.ui.window.WindowPosition -import androidx.compose.ui.window.application -import androidx.compose.ui.window.rememberWindowState -import cafe.adriel.voyager.navigator.Navigator -import net.agorise.kee.ui.screen.home.HomeScreen - -fun main() = application { - val state = rememberWindowState( - size = DpSize(420.dp, 880.dp), - position = WindowPosition(300.dp, 300.dp) - ) - Window(title = "Kee", onCloseRequest = ::exitApplication, state = state) { - Navigator(HomeScreen()) - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c400245..f5842ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,9 +4,11 @@ android-compileSdk = "34" android-minSdk = "26" android-targetSdk = "34" androidx-activityCompose = "1.8.2" -compose = "1.6.2" +compose = "1.6.4" compose-plugin = "1.6.0" +coroutines = "1.8.0" kotlin = "1.9.22" +ktor = "2.3.9" multiplatform-settings = "1.1.1" voyager = "1.0.0" @@ -14,8 +16,13 @@ voyager = "1.0.0" androidx-activity-compose = { group = "androidx.activity", name ="activity-compose", version.ref = "androidx-activityCompose" } compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "compose" } compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "compose" } +coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" } +ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" } +ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" } +ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktor" } multiplatform-settings = { group="com.russhwolf", name = "multiplatform-settings-no-arg", version.ref = "multiplatform-settings" } voyager-navigator = { group = "cafe.adriel.voyager", name = "voyager-navigator", version.ref = "voyager" } +voyager-screenmodel = { group = "cafe.adriel.voyager", name = "voyager-screenmodel", version.ref = "voyager" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 17f2519..8afceb6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -20,3 +20,4 @@ dependencyResolutionManagement { include(":composeApp") include(":shared:preferences") +include(":shared:stargate") diff --git a/shared/preferences/build.gradle.kts b/shared/preferences/build.gradle.kts index c7cf725..b9a1478 100644 --- a/shared/preferences/build.gradle.kts +++ b/shared/preferences/build.gradle.kts @@ -12,8 +12,6 @@ kotlin { } } - jvm() - iosX64() iosArm64() iosSimulatorArm64() diff --git a/shared/stargate/build.gradle.kts b/shared/stargate/build.gradle.kts new file mode 100644 index 0000000..e367c06 --- /dev/null +++ b/shared/stargate/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.androidLibrary) +} + +kotlin { + androidTarget { + compilations.all { + kotlinOptions { + jvmTarget = "11" + } + } + } + + iosX64() + iosArm64() + iosSimulatorArm64() + + sourceSets { + commonMain.dependencies { + implementation(libs.ktor.client.cio) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.websockets) + } + } +} + +android { + namespace = "net.agorise.shared.stargate" + compileSdk = libs.versions.android.compileSdk.get().toInt() + + defaultConfig { + minSdk = libs.versions.android.minSdk.get().toInt() + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} diff --git a/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt new file mode 100644 index 0000000..aa7ac3b --- /dev/null +++ b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt @@ -0,0 +1,33 @@ +package net.agorise.shared.stargate + +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.websocket.DefaultClientWebSocketSession +import io.ktor.client.plugins.websocket.WebSockets +import io.ktor.client.plugins.websocket.webSocket +import io.ktor.http.HttpMethod +import io.ktor.websocket.Frame +import io.ktor.websocket.readText +import kotlinx.coroutines.flow.receiveAsFlow + +class Bridge { + private val client: HttpClient = HttpClient(CIO) { install(WebSockets) } + + suspend fun start() { + client.webSocket(method = HttpMethod.Get, host = "node.derofoundation.org", port = 11012, path = "/ws") { + outputMessages() + } + } + + fun stop() { + client.close() + } + + private suspend fun DefaultClientWebSocketSession.outputMessages() { + incoming.receiveAsFlow().collect { message -> + (message as? Frame.Text)?.let { textFrame -> + println(textFrame.readText()) + } + } + } +}