From e51f2f258b4e27cd09f5af6e425ce38c071042a6 Mon Sep 17 00:00:00 2001 From: xiangpl Date: Tue, 12 Mar 2024 10:43:53 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=B7=BB=E5=8A=A0=E5=AF=BC=E8=88=AA=E5=BA=93?= =?UTF-8?q?voyager=202.=E4=BF=AE=E5=A4=8Dsqldelight=20Could=20not=20find?= =?UTF-8?q?=20"co.touchlab:stately-common=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E3=80=82=E8=A7=81=EF=BC=9Ahttps://github.com/cashapp/sqldeligh?= =?UTF-8?q?t/discussions/4356#top?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composeApp/src/commonMain/kotlin/App.kt | 50 +-- gradle/libs.versions.toml | 26 ++ .../yunext/kmp/common/util/Strings.android.kt | 2 +- .../com/yunext/kmp/common/util/Strings.kt | 3 +- .../com/yunext/kmp/common/util/Strings.ios.kt | 2 +- .../com/yunext/kmp/common/util/Strings.jvm.kt | 2 +- .../com/yunext/kmp/common/JvmLoggerTest.kt | 20 + .../com/yunext/kmp/common/TestNullPlusNull.kt | 5 + hddb/build.gradle.kts | 2 + hdhttp/build.gradle.kts | 22 ++ .../com/yunext/kmp/http/DebugKtorClient.kt | 13 + .../com/yunext/kmp/http/HDHttpClient.kt | 8 + .../yunext/kmp/http/HDHttpClientJVMTest.kt | 18 + .../yunext/kmp/resource/color/DebugColors.kt | 30 ++ hdui/build.gradle.kts | 49 +++ .../yunext/kmp/ui/compose/HDCompontents.kt | 112 ++++++ .../com/yunext/kmp/ui/compose/HDComposes.kt | 49 +++ .../yunext/kmp/ui/compose/HDDebugComponent.kt | 13 + .../kmp/ui/compose/HDItemShadowShape.kt | 48 +++ .../com/yunext/kmp/ui/compose/HDModifiers.kt | 217 ++++++++++ .../kmp/ui/compose/HDPressedTextView.kt | 95 +++++ .../com/yunext/kmp/ui/compose/OverScroll.kt | 289 ++++++++++++++ .../com/yunext/kmp/ui/compose/Previews.kt | 24 ++ .../com/yunext/kmp/ui/compose/TwinsTitle.kt | 229 +++++++++++ .../kotlin/com/yunext/kmp/ui/compose/Views.kt | 373 ++++++++++++++++++ .../EYH9XYDI5AKA/ComposeApp-3JGVIRIUZEK4Z.pcm | Bin 88696 -> 88704 bytes .../Session.modulevalidation | 2 +- ...951bfe8f3cd53c99228b0131e163e.sdkstatcache | Bin 1209384 -> 1209384 bytes iosApp/DerivedData/iosApp/info.plist | 2 +- settings.gradle.kts | 3 +- shared/build.gradle.kts | 11 + .../demo/voyager/hiltNavigation/HiltModule.kt | 27 ++ .../ui/demo/voyager/VoyagerDemoApp.kt | 16 + .../basicNavigationScreen/VoyagerDemo.kt | 118 ++++++ .../bottomSheetNavigation/BackScreen.kt | 46 +++ .../ui/demo/voyager/integration/KoinScreen.kt | 21 + .../voyager/integration/KoinScreenModel.kt | 9 + .../NestednavigationScreen.kt | 64 +++ .../virtuals/ui/demo/voyager/sampleItems.kt | 76 ++++ .../voyager/tabNavigation/FavoritesTab.kt | 31 ++ .../ui/demo/voyager/tabNavigation/HomeTab.kt | 31 ++ .../demo/voyager/tabNavigation/ProfileTab.kt | 31 ++ .../demo/voyager/tabNavigation/TabContent.kt | 72 ++++ .../tabNavigation/TabNavigationScreen.kt | 58 +++ .../yunext/virtuals/ui/screen/DemoScreen.kt | 21 +- .../yunext/virtuals/ui/screen/SplashScreen.kt | 47 +++ .../yunext/virtuals/ui/screen/VoyagerApp.kt | 16 + .../ui/screen/adddevice/AddDeviceScreen.kt | 14 + .../ui/screen/configwifi/ConfigWiFiScreen.kt | 14 + .../screen/devicedetail/DeviceDetailScreen.kt | 14 + .../DeviceDetailSubEventScreen.kt | 12 + .../DeviceDetailSubPropertityScreen.kt | 13 + .../DeviceDetailSubServiceScreen.kt | 13 + .../ui/screen/devicelist/DeviceListScreen.kt | 14 + .../virtuals/ui/screen/logger/LoggerScreen.kt | 13 + .../ui/screen/setting/SettingScreen.kt | 14 + 56 files changed, 2482 insertions(+), 42 deletions(-) create mode 100644 hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/TestNullPlusNull.kt create mode 100644 hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/DebugKtorClient.kt create mode 100644 hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/HDHttpClient.kt create mode 100644 hdhttp/src/jvmTest/kotlin/com/yunext/kmp/http/HDHttpClientJVMTest.kt create mode 100644 hdresource/src/commonMain/kotlin/com/yunext/kmp/resource/color/DebugColors.kt create mode 100644 hdui/build.gradle.kts create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDCompontents.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDComposes.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDDebugComponent.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDItemShadowShape.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDModifiers.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDPressedTextView.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/OverScroll.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Previews.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/TwinsTitle.kt create mode 100644 hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Views.kt create mode 100644 shared/src/androidMain/kotlin/com/yunext/virtuals/ui/demo/voyager/hiltNavigation/HiltModule.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/VoyagerDemoApp.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/basicNavigationScreen/VoyagerDemo.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/bottomSheetNavigation/BackScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreenModel.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/nestedNavigation/NestednavigationScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/sampleItems.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/FavoritesTab.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/HomeTab.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/ProfileTab.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabContent.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabNavigationScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/SplashScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/VoyagerApp.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/adddevice/AddDeviceScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/configwifi/ConfigWiFiScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubEventScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubPropertityScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubServiceScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicelist/DeviceListScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/logger/LoggerScreen.kt create mode 100644 shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/setting/SettingScreen.kt diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt index 7d19612..7969cfe 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/App.kt @@ -1,40 +1,30 @@ -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import com.yunext.virtuals.ui.screen.DemoScreen -import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource +import com.yunext.virtuals.ui.screen.VoyagerApp import org.jetbrains.compose.ui.tooling.preview.Preview -import org.jetbrains.compose.resources.DrawableResource - -@OptIn(ExperimentalResourceApi::class) @Composable @Preview fun App() { MaterialTheme { - var showContent by remember { mutableStateOf(false) } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - - DemoScreen() - Button(onClick = { showContent = !showContent }) { - Text("Click me!") - } - AnimatedVisibility(showContent) { - val greeting = remember { Greeting().greet() } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - //Image(painterResource(Res.drawable.compose_multiplatform), null) - Image(painterResource(DrawableResource("compose-multiplatform.xml")), null) - Text("Compose: $greeting") - } - } - } +// var showContent by remember { mutableStateOf(false) } +// Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { +// +// DemoScreen() +// Button(onClick = { showContent = !showContent }) { +// Text("Click me!") +// } +// AnimatedVisibility(showContent) { +// val greeting = remember { Greeting().greet() } +// Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { +// //Image(painterResource(Res.drawable.compose_multiplatform), null) +// Image(painterResource(DrawableResource("compose-multiplatform.xml")), null) +// Text("Compose: $greeting") +// } +// } +// } +// VoyagerDemoApp() +// SplashScreen() + VoyagerApp() } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64d6038..62520e0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,12 @@ kotlinx-coroutines = "1.8.0" #sqlDelight = "1.5.5" sqlDelight2 = "2.0.1" sqlite = "3.42.0.0" +statelyCommon = "1.2.5" +voyager = "1.0.0" + +koin = "3.4.3" +koin-compose = "1.0.4" +hilt = "2.49" [libraries] # test @@ -53,10 +59,22 @@ ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "kto ktor-server-netty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" } ktor-server-tests = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor" } ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } +# voyager +voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" } +voyager-screenModel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" } +voyager-bottomSheetNavigator = { module = "cafe.adriel.voyager:voyager-bottom-sheet-navigator", version.ref = "voyager" } +voyager-tabNavigator = { module = "cafe.adriel.voyager:voyager-tab-navigator", version.ref = "voyager" } +voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", version.ref = "voyager" } +voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" } +voyager-hilt = { module = "cafe.adriel.voyager:voyager-hilt", version.ref = "voyager" } +voyager-kodein = { module = "cafe.adriel.voyager:voyager-kodein", version.ref = "voyager" } +voyager-rxjava = { module = "cafe.adriel.voyager:voyager-rxjava", version.ref = "voyager" } + # publish nexus-publish = { module = "io.github.gradle-nexus.publish-plugin:io.github.gradle-nexus.publish-plugin.gradle.plugin", version.ref = "nexus-publish" } # publish lib @@ -86,7 +104,15 @@ sqlDelight2-driver-android = { module = "app.cash.sqldelight:android-driver", ve sqlDelight2-driver-native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqlDelight2" } sqlDelight2-driver-sqlite = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqlDelight2" } #sqlite = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite" } +sqlite-stately-common = { module = "co.touchlab:stately-common", version.ref = "statelyCommon" } +sqlite-stately-concurrency = { module = "co.touchlab:stately-concurrency", version.ref = "statelyCommon" } +# DI +#koin = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } +#koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-compose" } +#hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } +#hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } +#pluginHilt = { module = "com.google.dagger:hilt-android-gradle-plugin", version.ref = "hilt" } [plugins] diff --git a/hdcommon/src/androidMain/kotlin/com/yunext/kmp/common/util/Strings.android.kt b/hdcommon/src/androidMain/kotlin/com/yunext/kmp/common/util/Strings.android.kt index 0e68abd..6408e27 100644 --- a/hdcommon/src/androidMain/kotlin/com/yunext/kmp/common/util/Strings.android.kt +++ b/hdcommon/src/androidMain/kotlin/com/yunext/kmp/common/util/Strings.android.kt @@ -39,7 +39,7 @@ actual fun hdMD5(text: String, upperCase: Boolean): String? { private const val BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -actual fun hdRandomString(length: Int): String { +actual fun hdUUID(length: Int): String { require(length > 0) { "hdRandomString length must > 0" } diff --git a/hdcommon/src/commonMain/kotlin/com/yunext/kmp/common/util/Strings.kt b/hdcommon/src/commonMain/kotlin/com/yunext/kmp/common/util/Strings.kt index f003830..4efc44c 100644 --- a/hdcommon/src/commonMain/kotlin/com/yunext/kmp/common/util/Strings.kt +++ b/hdcommon/src/commonMain/kotlin/com/yunext/kmp/common/util/Strings.kt @@ -1,4 +1,5 @@ package com.yunext.kmp.common.util expect fun hdMD5(text: String, upperCase: Boolean = false): String? -expect fun hdRandomString(length:Int): String +expect fun hdUUID(length:Int): String + diff --git a/hdcommon/src/iosMain/kotlin/com/yunext/kmp/common/util/Strings.ios.kt b/hdcommon/src/iosMain/kotlin/com/yunext/kmp/common/util/Strings.ios.kt index cbc24d1..4945a9b 100644 --- a/hdcommon/src/iosMain/kotlin/com/yunext/kmp/common/util/Strings.ios.kt +++ b/hdcommon/src/iosMain/kotlin/com/yunext/kmp/common/util/Strings.ios.kt @@ -6,7 +6,7 @@ actual fun hdMD5(text: String, upperCase: Boolean): String? { private const val BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -actual fun hdRandomString(length: Int): String { +actual fun hdUUID(length: Int): String { require(length > 0) { "hdRandomString length must > 0" } diff --git a/hdcommon/src/jvmMain/kotlin/com/yunext/kmp/common/util/Strings.jvm.kt b/hdcommon/src/jvmMain/kotlin/com/yunext/kmp/common/util/Strings.jvm.kt index 8cad4ee..97ae03c 100644 --- a/hdcommon/src/jvmMain/kotlin/com/yunext/kmp/common/util/Strings.jvm.kt +++ b/hdcommon/src/jvmMain/kotlin/com/yunext/kmp/common/util/Strings.jvm.kt @@ -38,7 +38,7 @@ actual fun hdMD5(text: String, upperCase: Boolean): String? { private const val BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -actual fun hdRandomString(length: Int): String { +actual fun hdUUID(length: Int): String { require(length > 0) { "hdRandomString length must > 0" } diff --git a/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/JvmLoggerTest.kt b/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/JvmLoggerTest.kt index 9e7b676..c7deffb 100644 --- a/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/JvmLoggerTest.kt +++ b/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/JvmLoggerTest.kt @@ -2,9 +2,29 @@ package com.yunext.kmp.common import kotlin.test.Test +private data class Rect(val a: Int, val b: Int) +//private data class Rect2(val a: Int, val b: Int) + +private operator fun (List)?.plus(rect: Rect?): (List) = listOf() +//private operator fun Rect?.plus(rect: Any?):Rect? = this?:Rect(0,0) +//private operator fun Rect?.plus(rect: Rect?) = Rect((this?.a ?: 0) + (rect?.a ?: 0), (this?.b ?: 0) + (rect?.b ?: 0)) + +//private operator fun Rect2?.plus(rect: Rect2?) = +// Rect2((this?.a ?: 0) + (rect?.a ?: 0), (this?.b ?: 0) + (rect?.b ?: 0)) + +private fun test() { + val c = null as? List + val r = (null as? List) + null + println("---> r = $r ") +// val a: Rect? = null +// val b: Rect? = null +// val ab = a + b +} + class JvmLoggerTest { @Test fun `test 3rd element`() { + } } \ No newline at end of file diff --git a/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/TestNullPlusNull.kt b/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/TestNullPlusNull.kt new file mode 100644 index 0000000..df477bc --- /dev/null +++ b/hdcommon/src/jvmTest/kotlin/com/yunext/kmp/common/TestNullPlusNull.kt @@ -0,0 +1,5 @@ +package com.yunext.kmp.common + +internal data class Rect2(val a: Int, val b: Int) + +internal operator fun Rect2?.plus(rect: Rect2?) = Rect2((this?.a ?: 0) + (rect?.a ?: 0), (this?.b ?: 0) + (rect?.b ?: 0)) \ No newline at end of file diff --git a/hddb/build.gradle.kts b/hddb/build.gradle.kts index c13a44b..791d58c 100644 --- a/hddb/build.gradle.kts +++ b/hddb/build.gradle.kts @@ -25,6 +25,8 @@ kotlin { dependencies { //put your multiplatform dependencies here implementation(projects.hdcontext) + implementation(libs.sqlite.stately.common) + implementation(libs.sqlite.stately.concurrency) } } val commonTest by getting { diff --git a/hdhttp/build.gradle.kts b/hdhttp/build.gradle.kts index b9e3af8..267756b 100644 --- a/hdhttp/build.gradle.kts +++ b/hdhttp/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidLibrary) + alias(libs.plugins.kotlinSerialization) //id("module.publication") } @@ -24,6 +25,14 @@ kotlin { dependencies { //put your multiplatform dependencies here implementation(projects.hdcontext) + + api(libs.kotlinx.datetime) + api(libs.kotlinx.coroutines.core) + api(libs.ktor.client.core) + api(libs.ktor.client.cio) + api(libs.ktor.client.content.negotiation) + api(libs.ktor.serialization.kotlinx.json) + } } val commonTest by getting { @@ -31,6 +40,19 @@ kotlin { implementation(libs.kotlin.test) } } + + androidMain.dependencies { + api(libs.kotlinx.coroutines.android) + api(libs.ktor.client.okhttp) + } + + iosMain.dependencies { + api(libs.ktor.client.darwin) + } + + jvmMain.dependencies{ + api(libs.ktor.client.okhttp) + } } } diff --git a/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/DebugKtorClient.kt b/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/DebugKtorClient.kt new file mode 100644 index 0000000..6df48f9 --- /dev/null +++ b/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/DebugKtorClient.kt @@ -0,0 +1,13 @@ +package com.yunext.kmp.http + +import io.ktor.client.request.get +import io.ktor.client.statement.bodyAsText + +suspend fun testKtor(): String { +// val response = client.get("https://ktor.io/docs/") +// val response = client.get("https://iot2.qinyuan.cn/web/api/common/getAdvertisement") +// val response = hdHttpClient.get("https://www.baidu.com") + val response = + hdHttpClient.get("https://iot2.qinyuan.cn/web/api/common/getFiles/64c763bd93b173b23a289558 ") + return "findAll" + "\n" + response.bodyAsText() +} \ No newline at end of file diff --git a/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/HDHttpClient.kt b/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/HDHttpClient.kt new file mode 100644 index 0000000..46a6a6c --- /dev/null +++ b/hdhttp/src/commonMain/kotlin/com/yunext/kmp/http/HDHttpClient.kt @@ -0,0 +1,8 @@ +package com.yunext.kmp.http + +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO + +val hdHttpClient by lazy { + HttpClient(CIO) +} \ No newline at end of file diff --git a/hdhttp/src/jvmTest/kotlin/com/yunext/kmp/http/HDHttpClientJVMTest.kt b/hdhttp/src/jvmTest/kotlin/com/yunext/kmp/http/HDHttpClientJVMTest.kt new file mode 100644 index 0000000..bf92718 --- /dev/null +++ b/hdhttp/src/jvmTest/kotlin/com/yunext/kmp/http/HDHttpClientJVMTest.kt @@ -0,0 +1,18 @@ +package com.yunext.kmp.http + +import kotlinx.coroutines.runBlocking +import org.junit.Test + + +class HDHttpClientJVMTest { + + @Test + fun t1(){ + runBlocking { + val result = testKtor() + println("result :$result") + assert(result.isNotEmpty()) + } + + } +} \ No newline at end of file diff --git a/hdresource/src/commonMain/kotlin/com/yunext/kmp/resource/color/DebugColors.kt b/hdresource/src/commonMain/kotlin/com/yunext/kmp/resource/color/DebugColors.kt new file mode 100644 index 0000000..dd09783 --- /dev/null +++ b/hdresource/src/commonMain/kotlin/com/yunext/kmp/resource/color/DebugColors.kt @@ -0,0 +1,30 @@ +package com.yunext.kmp.resource.color + +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color + +val xf98 = Color(0xFFFF9988) +val x98f = Color(0xFF8899ff) +val x9f8 = Color(0xFF99ff88) + +val app_blue_1 = Color(0xff00DBE5) +val app_blue_2 = Color(0xff339DFF) +val app_appColor = Color(0xff339DFF) +val app_textColor_333333 = Color(0xff333333) +val app_textColor_666666 = Color(0xff666666) +val app_textColor_999999 = Color(0xff999999) +val app_red = Color(0xffEC6161) +val app_red_light = app_red.copy(alpha = .1f) +val app_orange = Color(0xffFFA70B) +val app_orange_light = Color(0xffFFA70B).copy(alpha = .15f) +val app_blue_light = app_appColor.copy(alpha = .1f) +val app_gray = Color(0xffDEDFE0) +val app_gray_f4f5f7 = Color(0xffF4F5F7) +val app_gray_light = app_gray.copy(alpha = .6f) +val app_background_70 = Color(1f, 1f, 1f, 0.7f) + + +val app_brush_item_content_spec = Brush.verticalGradient(colors = listOf(Color(0xffF7F8FA), Color(0xFFEFF0F2))) +val app_background_brush = Brush.verticalGradient(colors = listOf(Color(0xFFF4F7FB), Color(0xFFF0F4FC))) +val app_button_brush = Brush.linearGradient(colors = listOf(app_blue_1, app_blue_2)) +val app_button_brush_debug = Brush.linearGradient(colors = listOf(China.r_yan_zhi_hong, China.g_bo_he_lv)) \ No newline at end of file diff --git a/hdui/build.gradle.kts b/hdui/build.gradle.kts new file mode 100644 index 0000000..6187c9b --- /dev/null +++ b/hdui/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.androidLibrary) + alias(libs.plugins.jetbrainsCompose) +} + +kotlin { + targetHierarchy.default() + jvm() + androidTarget { + compilations.all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } + iosX64() + iosArm64() + iosSimulatorArm64() + + sourceSets { + val commonMain by getting { + dependencies { + //put your multiplatform dependencies here + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.components.resources) +// implementation(compose.components.uiToolingPreview) + + implementation(projects.hdresource) + } + } + val commonTest by getting { + dependencies { + implementation(libs.kotlin.test) + } + } + } +} + +android { + namespace = "org.jetbrains.kotlinx.multiplatform.library.template" + compileSdk = libs.versions.android.compileSdk.get().toInt() + defaultConfig { + minSdk = libs.versions.android.minSdk.get().toInt() + } +} diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDCompontents.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDCompontents.kt new file mode 100644 index 0000000..634fba0 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDCompontents.kt @@ -0,0 +1,112 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Star +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.yunext.kmp.resource.color.China + +@Composable +fun XplSpacer(hor: Boolean = true) { + Spacer(modifier = Modifier + .background(hdBrush) + .let { + if (hor) { + it + .fillMaxWidth() + .height(16.dp) + } else { + it + .fillMaxHeight() + .width(16.dp) + } + } + .padding(top = 8.dp, bottom = 8.dp) + + ) +} + + +@Composable +fun XTitle(title: String, desc: String = "") { + Column(Modifier.padding(top = 16.dp, bottom = 16.dp)) { + Text( + text = title, + fontWeight = FontWeight.Bold, + fontSize = 28.sp, + color = China.z_wu_mei_zi + ) + Text( + text = if (desc.isEmpty()) "" else "「$desc」", + fontWeight = FontWeight.Light, + fontSize = 12.sp, + color = China.g_lan_lv + ) + } +} + + +@Composable +fun XTips(tips: String) { + Surface( + modifier = Modifier.padding(8.dp), + shadowElevation = 4.dp, + shape = RoundedCornerShape(8.dp), + color = China.g_zhu_lv + ) { + + + Row( + modifier = Modifier +// .clip(RoundedCornerShape(16.dp)) +// .background(China.zhu_lv) + .padding(16.dp) + + + ) { + Icon( + imageVector = Icons.Default.Star, + contentDescription = null, + tint = China.h_gu_huang + ) + Spacer(modifier = Modifier.width(16.dp)) + Text( + text = "注意:$tips", + color = China.w_qian_shi_bai, + ) + } + } +} + + +@Composable +fun XHuaLiDeFenGeXian(msg: String) { + Row(Modifier.fillMaxWidth().padding(top = 12.dp, bottom = 12.dp)) { + Spacer( + modifier = Modifier.height(0.5.dp).fillMaxWidth().weight(1f) + .background(China.hui_xiao_hui).align(Alignment.CenterVertically) + ) + Text(text = msg, color = China.hui_xiao_hui, fontWeight = FontWeight.Light) + Spacer( + modifier = Modifier.height(0.5.dp).fillMaxWidth().weight(1f) + .background(China.hui_xiao_hui).align(Alignment.CenterVertically) + ) + } +} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDComposes.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDComposes.kt new file mode 100644 index 0000000..f978956 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDComposes.kt @@ -0,0 +1,49 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.FixedScale +import com.yunext.kmp.resource.color.x98f +import com.yunext.kmp.resource.color.x9f8 +import com.yunext.kmp.resource.color.xf98 +import kotlin.random.Random + +fun hdRandomColor(alpha: Float = 1f) = Color( + alpha = alpha, + red = Random.nextFloat(), + green = Random.nextFloat(), + blue = Random.nextFloat(), +) + +val hdBrush = Brush.linearGradient(listOf(x9f8, x98f, xf98)) + +private val contentScales = + arrayOf( + ContentScale.Fit, + ContentScale.Crop, + ContentScale.FillBounds, + ContentScale.FillWidth, + ContentScale.Inside, + ContentScale.None, + ) + +fun randomContentScale(): ContentScale = + (contentScales + FixedScale(Random.nextFloat())).random() + + +val ContentScale.desc: String + get() { + return when (this) { + ContentScale.Fit -> "Fit" + ContentScale.Crop -> "Crop" + ContentScale.FillBounds -> "FillBounds" + ContentScale.FillWidth -> "FillWidth" + ContentScale.Inside -> "Inside" + ContentScale.None -> "None" + is FixedScale -> "FixedScale(${this.value})" + else -> { + this.toString() + } + } + } diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDDebugComponent.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDDebugComponent.kt new file mode 100644 index 0000000..a3ba834 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDDebugComponent.kt @@ -0,0 +1,13 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect + +@Composable +fun Debug(msg:String,tag:String = TAG) { + SideEffect { + println("_${tag}_ $msg") + } +} + +private const val TAG = "xpl" \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDItemShadowShape.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDItemShadowShape.kt new file mode 100644 index 0000000..62ae9dc --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDItemShadowShape.kt @@ -0,0 +1,48 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.yunext.kmp.resource.color.China + +val ItemShape = RoundedCornerShape( + topStart = 12.dp, + topEnd = 12.dp, + bottomStart = 12.dp, + bottomEnd = 12.dp +) + +internal fun Modifier.debugBorder() = this then border(1.dp, China.r_luo_xia_hong) + +@Composable +fun CHItemShadowShape( + modifier: Modifier = Modifier, + elevation: Dp = 8.dp, + content: @Composable () -> Unit, +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .wrapContentSize() +// .background( +// shape = ItemShape, +// color = Color.White +// ) + .shadow( + elevation = elevation, + shape = ItemShape, + clip = false, +// ambientColor = China.b_tian_lan, +// spotColor = China.r_fen_hong + ) + ) { + content() + } +} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDModifiers.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDModifiers.kt new file mode 100644 index 0000000..09c33c7 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDModifiers.kt @@ -0,0 +1,217 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.foundation.Indication +import androidx.compose.foundation.IndicationInstance +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.InteractionSource +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.PressInteraction +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.debugInspectorInfo +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.yunext.kmp.resource.color.app_background_brush +import kotlinx.coroutines.CoroutineScope + + +fun Modifier.hdBorder(width: Dp = 4.dp) = this.border(width, hdRandomColor()) + +@Stable +fun Modifier.xplBackground(color: () -> Color): Modifier { +// return this then BackgroundModifier( +// color = color, +// rtlAware = true, +// inspectorInfo = debugInspectorInfo { +// name = "color" +// properties["color"] = color +// } +// ) + return this.drawWithContent { + drawRect(color()) + drawContent() + } +} + +//private class BackgroundModifier( +// val color: () -> Color, +// val rtlAware: Boolean, +// inspectorInfo: InspectorInfo.() -> Unit, +//) : LayoutModifier, InspectorValueInfo(inspectorInfo) { +// override fun MeasureScope.measure( +// measurable: Measurable, +// constraints: Constraints, +// ): MeasureResult { +// val placeable = measurable.measure(constraints) +// +// +// return layout(placeable.width, placeable.height) { +// placeable.placeRelative(0,0) +// } +// } +// +// override fun equals(other: Any?): Boolean { +// if (this === other) return true +// val otherModifier = other as? BackgroundModifier ?: return false +// +// return color == otherModifier.color +// } +// +// override fun hashCode(): Int { +// var result = color.hashCode() +// result = 31 * result + rtlAware.hashCode() +// return result +// } +// +// override fun toString(): String = "BackgroundModifier(color=$color)" +//} + + +fun Modifier.clip(shape: Shape) = graphicsLayer(shape = shape, clip = true) + +@Composable +fun Modifier.clickablePure( + enabled: Boolean = true, + onClickLabel: String? = null, + role: Role? = null, + onClick: () -> Unit, +//) = this then this.clickable( +) = this then Modifier.clickable( +//) = this.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onClick, + role = role, + onClickLabel = onClickLabel, + enabled = enabled +) + +@Composable +fun Modifier.hdClickable( + enabled: Boolean = true, + onClickLabel: String? = null, + role: Role? = null, + onClick: () -> Unit, +): Modifier { + val interactionSource = remember { MutableInteractionSource() } + val isPressed by interactionSource.collectIsPressedAsState() + val alpha = if (isPressed) .5f else 1f + val scale = if (isPressed) 1.2f else 1f + return Modifier.clickable( + interactionSource = interactionSource, + indication = null,//LocalIndication.current, + onClick = onClick, + role = role, + onClickLabel = onClickLabel, + enabled = enabled + ) + .alpha(alpha = alpha) + .scale(scale) + //.indication(interactionSource, if (isPressed) MyIndication() else null) // todo +} + +fun Modifier.clickableX( + enabled: Boolean = true, + onClickLabel: String? = null, + role: Role? = null, + onClick: () -> Unit, +) = composed(inspectorInfo = debugInspectorInfo { + name = "pressed" + properties["enabled"] = enabled + properties["onClickLabel"] = onClickLabel + properties["role"] = role + properties["onClick"] = onClick +}) { + val interactionSource = remember { MutableInteractionSource() } + val isPressed by interactionSource.collectIsPressedAsState() + val alpha = if (isPressed) .5f else 1f + val scale = if (isPressed) 1.2f else 1f + Modifier + .clickable( + interactionSource = interactionSource, + indication = null,//LocalIndication.current, + onClick = onClick, + role = role, + onClickLabel = onClickLabel, + enabled = enabled + ) + .alpha(alpha = alpha) + .scale(scale) + //.indication(interactionSource, if (isPressed) MyIndication() else null) // todo +} + + +/** + * 详细见CommonRipple + */ +private open class MyIndication : Indication { + open class Inner : IndicationInstance { + + + override fun ContentDrawScope.drawIndication() { + drawCircle(app_background_brush) + draw() + drawContent() + } + + open fun add(interaction: PressInteraction.Press, scope: CoroutineScope) { + + } + + open fun remove(interaction: PressInteraction.Press) { + + } + + open fun ContentDrawScope.draw() { + + } + + + } + + @Composable + protected open fun rememberUpdateIndicationInstance(interactionSource: InteractionSource): Inner { + return remember(interactionSource) { + Inner() + } + } + + @Composable + override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { + val myIndication = rememberUpdateIndicationInstance(interactionSource) + LaunchedEffect(key1 = myIndication) { + interactionSource.interactions.collect { interaction -> + when (interaction) { + is PressInteraction.Press -> { + myIndication.add(interaction, this) + } + + is PressInteraction.Release -> { + myIndication.remove(interaction.press) + } + + is PressInteraction.Cancel -> { + myIndication.remove(interaction.press) + } + } + } + } + return myIndication + } + +} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDPressedTextView.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDPressedTextView.kt new file mode 100644 index 0000000..be0620d --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/HDPressedTextView.kt @@ -0,0 +1,95 @@ +package com.yunext.kmp.ui.compose + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.DragInteraction +import androidx.compose.foundation.interaction.Interaction +import androidx.compose.foundation.interaction.InteractionSource +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.PressInteraction +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier + +@Composable +fun CHPressedView( + content: @Composable (Boolean) -> Unit, + onClick: () -> Unit, + modifier: Modifier = Modifier, + interactionSource: MutableInteractionSource = + remember { MutableInteractionSource() }, +) { + val isPressed by interactionSource.collectIsPressedAsState() + Box( + + modifier = modifier.clickable(interactionSource = interactionSource, indication = null) { + onClick.invoke() + }, contentAlignment = Alignment.Center + ) { +// AnimatedVisibility(visible = isPressed) { +// if (isPressed) { +// Row { +// icon() +// Spacer(Modifier.size(ButtonDefaults.IconSpacing)) +// } +// } +// } +// AnimatedContent(targetState = isPressed) { + val scale = if (isPressed) 2f else 1f + val alpha = if (isPressed) .5f else 1f +// Box( +// modifier = Modifier +// .alpha(alpha = alpha) +// .scale(scale, scale) +// ) { + content(isPressed) +// } +// } + } +} + +@Composable +private fun InteractionSource.collectIsPressedOrDraggedAsState(): State { + val isPressedOrDragged = remember { mutableStateOf(false) } + val interactions = remember { mutableStateListOf() } + LaunchedEffect(key1 = isPressedOrDragged) { + this@collectIsPressedOrDraggedAsState.interactions.collect { interaction -> + when (interaction) { + is PressInteraction.Press -> { + interactions.add(interaction) + } + + is PressInteraction.Release -> { + interactions.remove(interaction.press) + } + + is PressInteraction.Cancel -> { + interactions.remove(interaction.press) + } + + is DragInteraction.Start -> { + interactions.add(interaction) + } + + is DragInteraction.Stop -> { + interactions.remove(interaction.start) + } + + is DragInteraction.Cancel -> { + interactions.remove(interaction.start) + } + } + isPressedOrDragged.value = interactions.isNotEmpty() + } + } + + return isPressedOrDragged + +} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/OverScroll.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/OverScroll.kt new file mode 100644 index 0000000..231978d --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/OverScroll.kt @@ -0,0 +1,289 @@ +//package com.yunext.kmp.ui.compose +// +//import androidx.compose.animation.core.Animatable +//import androidx.compose.animation.core.AnimationState +//import androidx.compose.animation.core.AnimationVector1D +//import androidx.compose.animation.core.DecayAnimationSpec +//import androidx.compose.animation.core.Spring +//import androidx.compose.animation.core.animateDecay +//import androidx.compose.animation.core.exponentialDecay +//import androidx.compose.animation.core.spring +//import androidx.compose.animation.rememberSplineBasedDecay +//import androidx.compose.foundation.gestures.FlingBehavior +//import androidx.compose.foundation.gestures.ScrollScope +//import androidx.compose.foundation.gestures.ScrollableState +//import androidx.compose.foundation.gestures.scrollable +//import androidx.compose.foundation.lazy.LazyColumn +//import androidx.compose.foundation.lazy.LazyListState +//import androidx.compose.foundation.lazy.LazyRow +//import androidx.compose.runtime.Composable +//import androidx.compose.runtime.Stable +//import androidx.compose.runtime.getValue +//import androidx.compose.runtime.mutableStateOf +//import androidx.compose.runtime.remember +//import androidx.compose.runtime.setValue +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.composed +//import androidx.compose.ui.draw.clipToBounds +//import androidx.compose.ui.geometry.Offset +//import androidx.compose.ui.graphics.graphicsLayer +//import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +//import androidx.compose.ui.input.nestedscroll.NestedScrollDispatcher +//import androidx.compose.ui.input.nestedscroll.NestedScrollSource +//import androidx.compose.ui.input.nestedscroll.nestedScroll +//import androidx.compose.ui.platform.LocalDensity +//import androidx.compose.ui.unit.Velocity +//import kotlinx.coroutines.launch +//import kotlin.math.abs +//import kotlin.math.sign +//import kotlin.math.sqrt +// +///** +// * A parabolic rolling easing curve. +// * +// * When rolling in the same direction, the farther away from 0, the greater the "resistance"; the closer to 0, the smaller the "resistance"; +// * +// * No drag effect is applied when the scrolling direction is opposite to the currently existing overscroll offset +// * +// * Note: when [p] = 50f, its performance should be consistent with iOS +// * @param currentOffset Offset value currently out of bounds +// * @param newOffset The offset of the new scroll +// * @param p Key parameters for parabolic curve calculation +// * @param density Without this param, the unit of offset is pixels, +// * so we need this variable to have the same expectations on different devices. +// */ +//@Stable +//fun parabolaScrollEasing(currentOffset: Float, newOffset: Float, p: Float = 50f, density: Float = 4f): Float { +// val realP = p * density +// val ratio = (realP / (sqrt(realP * abs(currentOffset + newOffset / 2).coerceAtLeast(Float.MIN_VALUE)))).coerceIn(Float.MIN_VALUE, 1f) +// return if (sign(currentOffset) == sign(newOffset)) { +// currentOffset + newOffset * ratio +// } else { +// currentOffset + newOffset +// } +//} +// +//private val DefaultParabolaScrollEasing: (currentOffset: Float, newOffset: Float) -> Float +// @Composable +// get() { +// val density = LocalDensity.current.density +// return { currentOffset, newOffset -> +// parabolaScrollEasing(currentOffset, newOffset, density = density) +// } +// } +// +//private const val OutBoundSpringStiff = 150f +//private const val OutBoundSpringDamp = 0.86f +// +///** +// * @see overScrollOutOfBound +// */ +//fun Modifier.overScrollVertical( +// nestedScrollToParent: Boolean = true, +// scrollEasing: ((currentOffset: Float, newOffset: Float) -> Float)? = null, +// springStiff: Float = OutBoundSpringStiff, +// springDamp: Float = OutBoundSpringDamp, +//): Modifier = composed { overScrollOutOfBound(isVertical = true, nestedScrollToParent, scrollEasing ?: DefaultParabolaScrollEasing, springStiff, springDamp) } +// +///** +// * @see overScrollOutOfBound +// */ +//fun Modifier.overScrollHorizontal( +// nestedScrollToParent: Boolean = true, +// scrollEasing: ((currentOffset: Float, newOffset: Float) -> Float)? = null, +// springStiff: Float = OutBoundSpringStiff, +// springDamp: Float = OutBoundSpringDamp, +//): Modifier = composed { overScrollOutOfBound(isVertical = false, nestedScrollToParent, scrollEasing ?: DefaultParabolaScrollEasing, springStiff, springDamp) } +// +///** +// * OverScroll effect for scrollable Composable . +// * +// * - You should call it before Modifiers with similar semantics such as [Modifier.scrollable], so that nested scrolling can work normally +// * - You should use it with [rememberOverscrollFlingBehavior] +// * @Author: cormor +// * @Email: cangtiansuo@gmail.com +// * @param isVertical is vertical, or horizontal ? +// * @param nestedScrollToParent Whether to dispatch nested scroll events to parent +// * @param scrollEasing U can refer to [DefaultParabolaScrollEasing], The incoming values are the currently existing overscroll Offset +// * and the new offset from the gesture. +// * modify it to cooperate with [springStiff] to customize the sliding damping effect. +// * The current default easing comes from iOS, you don't need to modify it! +// * @param springStiff springStiff for overscroll effect,For better user experience, the new value is not recommended to be higher than[Spring.StiffnessMediumLow] +// * @param springDamp springDamp for overscroll effect,generally do not need to set +// */ +//fun Modifier.overScrollOutOfBound( +// isVertical: Boolean = true, +// nestedScrollToParent: Boolean = true, +// scrollEasing: (currentOffset: Float, newOffset: Float) -> Float, +// springStiff: Float = OutBoundSpringStiff, +// springDamp: Float = OutBoundSpringDamp, +//): Modifier = composed { +// val hasChangedParams = remember(nestedScrollToParent, springStiff, springDamp, isVertical) { Clock.System.now().toEpochMilliseconds() } +// +// val dispatcher = remember(hasChangedParams) { NestedScrollDispatcher() } +// var offset by remember(hasChangedParams) { mutableStateOf(0f) } +// +// val nestedConnection = remember(hasChangedParams) { +// object : NestedScrollConnection { +// /** +// * If the offset is less than this value, we consider the animation to end. +// */ +// val visibilityThreshold = 0.5f +// lateinit var lastFlingAnimator: Animatable +// +// override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { +// if (::lastFlingAnimator.isInitialized && lastFlingAnimator.isRunning) { +// dispatcher.coroutineScope.launch { +// lastFlingAnimator.stop() +// } +// } +// val realAvailable = when { +// nestedScrollToParent -> available - dispatcher.dispatchPreScroll(available, source) +// else -> available +// } +// val realOffset = if (isVertical) realAvailable.y else realAvailable.x +// +// val isSameDirection = sign(realOffset) == sign(offset) +// if (abs(offset) <= visibilityThreshold || isSameDirection) { +// return available - realAvailable +// } +// val offsetAtLast = scrollEasing(offset, realOffset) +// // sign changed, coerce to start scrolling and exit +// return if (sign(offset) != sign(offsetAtLast)) { +// offset = 0f +// if (isVertical) { +// Offset(x = available.x - realAvailable.x, y = available.y - realAvailable.y + realOffset) +// } else { +// Offset(x = available.x - realAvailable.x + realOffset, y = available.y - realAvailable.y) +// } +// } else { +// offset = offsetAtLast +// if (isVertical) { +// Offset(x = available.x - realAvailable.x, y = available.y) +// } else { +// Offset(x = available.x, y = available.y - realAvailable.y) +// } +// } +// } +// +// override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset { +// val realAvailable = when { +// nestedScrollToParent -> available - dispatcher.dispatchPostScroll(consumed, available, source) +// else -> available +// } +// offset = scrollEasing(offset, if (isVertical) realAvailable.y else realAvailable.x) +// return if (isVertical) { +// Offset(x = available.x - realAvailable.x, y = available.y) +// } else { +// Offset(x = available.x, y = available.y - realAvailable.y) +// } +// } +// +// override suspend fun onPreFling(available: Velocity): Velocity { +// if (::lastFlingAnimator.isInitialized && lastFlingAnimator.isRunning) { +// lastFlingAnimator.stop() +// } +// val parentConsumed = when { +// nestedScrollToParent -> dispatcher.dispatchPreFling(available) +// else -> Velocity.Zero +// } +// val realAvailable = available - parentConsumed +// var leftVelocity = if (isVertical) realAvailable.y else realAvailable.x +// +// if (abs(offset) >= visibilityThreshold && sign(leftVelocity) != sign(offset)) { +// lastFlingAnimator = Animatable(offset).apply { +// when { +// leftVelocity < 0 -> updateBounds(lowerBound = 0f) +// leftVelocity > 0 -> updateBounds(upperBound = 0f) +// } +// } +// leftVelocity = lastFlingAnimator.animateTo(0f, spring(springDamp, springStiff, visibilityThreshold), leftVelocity) { +// offset = scrollEasing(offset, value - offset) +// }.endState.velocity +// } +// return if (isVertical) { +// Velocity(parentConsumed.x, y = available.y - leftVelocity) +// } else { +// Velocity(available.x - leftVelocity, y = parentConsumed.y) +// } +// } +// +// override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity { +// val realAvailable = when { +// nestedScrollToParent -> available - dispatcher.dispatchPostFling(consumed, available) +// else -> available +// } +// +// lastFlingAnimator = Animatable(offset) +// lastFlingAnimator.animateTo(0f, spring(springDamp, springStiff, visibilityThreshold), realAvailable.y) { +// offset = scrollEasing(offset, value - offset) +// } +// return if (isVertical) { +// Velocity(x = available.x - realAvailable.x, y = available.y) +// } else { +// Velocity(x = available.x, y = available.y - realAvailable.y) +// } +// } +// } +// } +// +// this +// .clipToBounds() +// .nestedScroll(nestedConnection, dispatcher) +// .graphicsLayer { +// if (isVertical) translationY = offset else translationX = offset +// } +//} +// +///** +// * You should use it with [overScrollVertical] +// * @param decaySpec You can use instead [rememberSplineBasedDecay] +// * @param getScrollState Pass in your [ScrollableState], for [LazyColumn]/[LazyRow] , it's [LazyListState] +// */ +//@Composable +//fun rememberOverscrollFlingBehavior( +// decaySpec: DecayAnimationSpec = exponentialDecay(), +// getScrollState: () -> ScrollableState, +//): FlingBehavior = remember(decaySpec) { +// object : FlingBehavior { +// /** +// * - We should check it every frame of fling +// * - Should stop fling when returning true and return the remaining speed immediately. +// * - Without this detection, scrollBy() will continue to consume velocity, +// * which will cause a velocity error in nestedScroll. +// */ +// private val Float.canNotBeConsumed: Boolean // this is Velocity +// get() { +// val state = getScrollState() +// return !(this < 0 && state.canScrollBackward || this > 0 && state.canScrollForward) +// } +// +// override suspend fun ScrollScope.performFling(initialVelocity: Float): Float { +// if (initialVelocity.canNotBeConsumed) { +// return initialVelocity +// } +// return if (abs(initialVelocity) > 1f) { +// var velocityLeft = initialVelocity +// var lastValue = 0f +// AnimationState( +// initialValue = 0f, +// initialVelocity = initialVelocity, +// ).animateDecay(decaySpec) { +// if (velocityLeft.canNotBeConsumed) { +// cancelAnimation() +// return@animateDecay +// } +// val delta = value - lastValue +// val consumed = scrollBy(delta) +// lastValue = value +// velocityLeft = this.velocity +// // avoid rounding errors and stop if anything is unconsumed +// if (abs(delta - consumed) > 0.5f) this.cancelAnimation() +// } +// velocityLeft +// } else { +// initialVelocity +// } +// } +// } +//} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Previews.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Previews.kt new file mode 100644 index 0000000..444b852 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Previews.kt @@ -0,0 +1,24 @@ +package com.yunext.kmp.ui.compose//package com.yunext.twins.ui.compoents.dialog + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.yunext.kmp.resource.color.China + +@Composable +fun PreviewPart(content: @Composable () -> Unit) { + Box( + Modifier + .fillMaxSize() + .background(China.w_qian_shi_bai) + .padding(16.dp), contentAlignment = Alignment.Center + ) { + content() + } +} + diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/TwinsTitle.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/TwinsTitle.kt new file mode 100644 index 0000000..4db04ad --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/TwinsTitle.kt @@ -0,0 +1,229 @@ +//package com.yunext.kmp.ui.compose +// +//import androidx.compose.foundation.Image +//import androidx.compose.foundation.clickable +//import androidx.compose.foundation.layout.Arrangement +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Column +//import androidx.compose.foundation.layout.PaddingValues +//import androidx.compose.foundation.layout.Row +//import androidx.compose.foundation.layout.Spacer +//import androidx.compose.foundation.layout.fillMaxSize +//import androidx.compose.foundation.layout.fillMaxWidth +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.layout.padding +//import androidx.compose.foundation.layout.requiredWidthIn +//import androidx.compose.foundation.layout.size +//import androidx.compose.foundation.layout.width +//import androidx.compose.foundation.layout.widthIn +//import androidx.compose.foundation.layout.wrapContentSize +//import androidx.compose.foundation.shape.CircleShape +//import androidx.compose.material3.Text +//import androidx.compose.runtime.Composable +//import androidx.compose.runtime.compositionLocalOf +//import androidx.compose.ui.Alignment +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.draw.clip +//import androidx.compose.ui.graphics.Color +//import androidx.compose.ui.graphics.painter.Painter +//import androidx.compose.ui.layout.ContentScale +//import androidx.compose.ui.text.font.FontWeight +//import androidx.compose.ui.text.style.TextOverflow +//import androidx.compose.ui.unit.dp +//import androidx.compose.ui.unit.sp +//import com.yunext.virtual.ui.uidata.DeviceStatus +//import com.yunext.virtual.ui.theme.app_textColor_333333 +//import com.yunext.virtual.ui.theme.app_textColor_666666 +//import com.yunext.virtual.ui.theme.app_textColor_999999 +//import org.jetbrains.compose.resources.ExperimentalResourceApi +//import org.jetbrains.compose.resources.painterResource +// +///** +// * 适配android沉浸式 +// */ +//val LocalPaddingValues = compositionLocalOf { PaddingValues() } +// +//private object TwinsTitleDefaults { +// val height = 44.dp +//} +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsTitle( +// modifier: Modifier = Modifier, +// text: String, +// icon: Painter? = null, +// leftClick: () -> Unit = {}, +// rightClick: (() -> Unit)? = null, +//) { +// Row( +// modifier = modifier.fillMaxWidth().padding(LocalPaddingValues.current) +// .height(TwinsTitleDefaults.height), +// verticalAlignment = Alignment.CenterVertically +// ) { +// // left +// Image( +// painter = painterResource("icon_twins_return_nor.png"), +// contentDescription = "back", +// Modifier +// .clip(CircleShape) +// .clickable { +// leftClick.invoke() +// } +// .applyIcon() +// ) +// +// // +// Row(modifier = Modifier.wrapContentSize().weight(1f)) { +// Text( +// text = text, +// fontSize = 18.sp, +// fontWeight = FontWeight.Bold, +// overflow = TextOverflow.Ellipsis, +// modifier = Modifier +// .align(Alignment.CenterVertically) +// .requiredWidthIn(max = 200.dp), +//// .width(200.dp), +// maxLines = 1 +// ) +// if (icon != null) { +// Spacer(modifier = Modifier.width(2.dp)) +// Image( +// painter = icon,//painterResource(id = icon), +// modifier = Modifier.align(Alignment.CenterVertically), +// contentDescription = "status" +// ) +// } +// +// } +// +// // +// if (rightClick != null) { +// Image( +// painter = painterResource("icon_twins_more_nor.png"),//painterResource(id = R.mipmap.icon_twins_more_nor), +// contentDescription = "more", +// modifier = Modifier +// .clip(CircleShape) +// .clickable { +// rightClick.invoke() +// } +// .applyIcon() +// ) +// } else { +// Box(modifier = Modifier.applyIcon()) +// } +// +// } +// +// +//} +// +//private fun Modifier.applyIcon() = this +// .size(TwinsTitleDefaults.height) +// .padding(10.dp) +// +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsEmptyView() { +// Column( +// modifier = Modifier.fillMaxSize(), +// verticalArrangement = Arrangement.Center, +// horizontalAlignment = Alignment.CenterHorizontally +// ) { +// Image( +// painter = painterResource("ic_app.png"),//painterResource(id = R.mipmap.ic_app), +// contentDescription = null +// ) +// Spacer(modifier = Modifier.height(16.dp)) +// +// Text( +// text = "没有找到相关内容", +// fontSize = 14.sp, +// color = app_textColor_666666 +// ) +// } +//} +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsEmptyViewForDevice() { +// Debug("TwinsHomePage-内容-设备列表-空") +// Column( +// modifier = Modifier.fillMaxSize(), +// verticalArrangement = Arrangement.Center, +// horizontalAlignment = Alignment.CenterHorizontally +// ) { +// Image( +// painter = painterResource("ic_app.png"),//painterResource(id = R.mipmap.ic_app), +// contentDescription = null +// ) +// Spacer(modifier = Modifier.height(16.dp)) +// Text( +// text = "你还没有添加设备", +// fontSize = 16.sp, +// color = app_textColor_333333 +// ) +// Spacer(modifier = Modifier.height(12.dp)) +// Text( +// text = "添加设备,实时查看设备信息", +// fontSize = 12.sp, +// color = app_textColor_999999 +// ) +// } +//} +// +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsDeviceStatus(modifier: Modifier = Modifier, deviceStatus: DeviceStatus) { +// when (deviceStatus) { +// DeviceStatus.GPRSOffLine -> { +// Image( +// painter = painterResource("icon_twins_offline.png"),//id = R.mipmap.icon_twins_offline), +// contentDescription = "gprs_offline", modifier = modifier +// ) +// } +// +// DeviceStatus.GPRSOnLine -> { +// Image( +// painter = painterResource("icon_twins_4g.png"),//id = R.mipmap.icon_twins_4g), +// contentDescription = "wifi", modifier = modifier +// ) +// } +// +// DeviceStatus.WiFiOffLine -> { +// Image( +// painter = painterResource("icon_twins_offline.png"),//id = R.mipmap.icon_twins_offline), +// contentDescription = "wifi", modifier = modifier +// ) +// } +// +// DeviceStatus.WiFiOnLine -> { +// Image( +// painter = painterResource("icon_twins_wifi.png"),//id = R.mipmap.icon_twins_wifi), +// contentDescription = "wifi", modifier = modifier +// ) +// } +// } +//} +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsLabelText(modifier: Modifier = Modifier, text: String) { +// Box(modifier = modifier.widthIn(min = 60.dp, max = 60.dp)) { +// Image( +// painter = painterResource("icon_twins_label_bg.png"),//id = R.mipmap.icon_twins_label_bg), +// contentDescription = "bg", +// modifier = Modifier.matchParentSize(), +// contentScale = ContentScale.FillBounds +// ) +// Text( +// text = text, fontSize = 11.sp, color = Color(0x66666666), modifier = Modifier +// .align( +// Alignment.CenterStart +// ) +// .padding(horizontal = 6.dp) +// ) +// } +//} \ No newline at end of file diff --git a/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Views.kt b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Views.kt new file mode 100644 index 0000000..e5eb681 --- /dev/null +++ b/hdui/src/commonMain/kotlin/com/yunext/kmp/ui/compose/Views.kt @@ -0,0 +1,373 @@ +//package com.yunext.kmp.ui.compose +// +//import androidx.compose.foundation.Image +//import androidx.compose.foundation.background +//import androidx.compose.foundation.border +//import androidx.compose.foundation.clickable +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Spacer +//import androidx.compose.foundation.layout.fillMaxHeight +//import androidx.compose.foundation.layout.fillMaxSize +//import androidx.compose.foundation.layout.fillMaxWidth +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.layout.padding +//import androidx.compose.foundation.layout.size +//import androidx.compose.foundation.layout.width +//import androidx.compose.foundation.layout.wrapContentHeight +//import androidx.compose.foundation.layout.wrapContentSize +//import androidx.compose.foundation.layout.wrapContentWidth +//import androidx.compose.foundation.shape.CircleShape +//import androidx.compose.foundation.shape.RoundedCornerShape +//import androidx.compose.foundation.text.KeyboardActions +//import androidx.compose.foundation.text.KeyboardOptions +//import androidx.compose.material.icons.Icons +//import androidx.compose.material.icons.filled.Add +//import androidx.compose.material3.ExperimentalMaterial3Api +//import androidx.compose.material3.Icon +//import androidx.compose.material3.Surface +//import androidx.compose.material3.Text +//import androidx.compose.material3.TextField +//import androidx.compose.material3.TextFieldDefaults +//import androidx.compose.runtime.Composable +//import androidx.compose.ui.Alignment +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.draw.clip +//import androidx.compose.ui.draw.drawWithContent +//import androidx.compose.ui.graphics.Color +//import androidx.compose.ui.graphics.painter.Painter +//import androidx.compose.ui.layout.ContentScale +//import androidx.compose.ui.text.TextStyle +//import androidx.compose.ui.text.font.FontWeight +//import androidx.compose.ui.text.input.KeyboardType +//import androidx.compose.ui.text.style.TextAlign +//import androidx.compose.ui.unit.dp +//import androidx.compose.ui.unit.sp +//import com.yunext.virtual.ui.theme.Twins +//import com.yunext.virtual.ui.theme.app_appColor +//import com.yunext.virtual.ui.theme.app_background_brush +//import com.yunext.virtual.ui.theme.app_button_brush +//import com.yunext.virtual.ui.theme.app_textColor_999999 +//import org.jetbrains.compose.resources.ExperimentalResourceApi +//import org.jetbrains.compose.resources.painterResource +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun TwinsBackgroundBlock( +// modifier: Modifier = Modifier, +//// painter: Painter = painterResource("icon_twins_4g.png"), +// painter: Painter = painterResource("icon_twins_body_bg.png"),//icon_twins_body_bg.png +// grey: Boolean = false, +//) { +// Debug("TwinsBackgroundBlock") +// if (grey) { +// Spacer( +// modifier = Modifier +// .fillMaxSize() +// .background(app_background_brush) +// ) +// } else { +// Image( +// painter = painter, +// contentScale = ContentScale.Crop, +// contentDescription = "background", +// modifier = modifier.fillMaxWidth() +// ) +// } +//} +// +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun EmptyDeviceBlock(modifier: Modifier = Modifier, painter: Painter = painterResource("icon_twins_no_device.png")) { +// Image( +// painter = painter, +// contentScale = ContentScale.Crop, +// contentDescription = "EmptyDeviceBlock", +// modifier = modifier +// ) +//} +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun EmptyDataBlock(modifier: Modifier = Modifier, painter: Painter = painterResource("icon_twins_no_data.png")) { +// Image( +// painter = painter, +// contentScale = ContentScale.Crop, +// contentDescription = "EmptyDataBlock", +// modifier = modifier +// ) +//} +// +//@OptIn(ExperimentalResourceApi::class) +//@Composable +//fun LabelTextBlock(modifier: Modifier = Modifier,text: String,painter: Painter = painterResource("icon_twins_label_bg.png")) { +// Box(contentAlignment = Alignment.Center, modifier = modifier) { +// Image( +// painter = painter, +// contentDescription = "bg" +// ) +// Text( +// text = text, fontSize = 11.sp, color = Color(0x66666666), modifier = Modifier +// .align( +// Alignment.CenterStart +// ) +// .padding(start = 6.dp) +// ) +// } +//} +// +//@OptIn(ExperimentalMaterial3Api::class) +//@Composable +//fun EditTextBlock( +// modifier: Modifier = Modifier, +// text: String, +// hint: String, +// keyboardOptions: KeyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), +// keyboardActions: KeyboardActions = KeyboardActions(), +// onValueChange: (String) -> Unit, +//) { +// TextField( +// value = text, +// onValueChange = onValueChange, +// keyboardOptions = keyboardOptions, +// keyboardActions = keyboardActions, +// modifier = modifier, +// textStyle = Twins.twins_edit_text.copy(textAlign = TextAlign.End), +// placeholder = { +// Text( +// modifier = Modifier.fillMaxWidth(), +// text = hint, +// style = Twins.twins_edit_text_hint.copy(textAlign = TextAlign.End) +// ) +// }, +// singleLine = true, +// maxLines = 1, +// shape = RoundedCornerShape(12.dp), +// colors = TextFieldDefaults.textFieldColors( +// cursorColor = China.r_luo_xia_hong, +// focusedIndicatorColor = Color.Transparent, +// unfocusedIndicatorColor = Color.Transparent +// +// ) +// ) +//} +// +//@OptIn(ExperimentalMaterial3Api::class) +//@Composable +//fun EditTextCenterBlock( +// modifier: Modifier = Modifier, +// text: String, +// hint: String, +// keyboardOptions: KeyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), +// keyboardActions: KeyboardActions = KeyboardActions(), +// onValueChange: (String) -> Unit, +//) { +// val textAlign = TextAlign.Center +// TextField( +// value = text, +// onValueChange = onValueChange, +// modifier = modifier, +// textStyle = Twins.twins_edit_text.copy(textAlign = textAlign), +// placeholder = { +// Text( +// modifier = Modifier.fillMaxWidth(), +// text = hint, +// style = Twins.twins_edit_text_hint.copy(textAlign = textAlign) +// ) +// }, +// singleLine = true, +// maxLines = 1, +// shape = RoundedCornerShape(12.dp), +// colors = TextFieldDefaults.textFieldColors( +// cursorColor = China.r_luo_xia_hong, +// focusedIndicatorColor = Color.Transparent, +// unfocusedIndicatorColor = Color.Transparent +// +// ), keyboardOptions = keyboardOptions, keyboardActions = keyboardActions +// ) +//} +// +//@Composable +//fun CheckedTextBlock( +// modifier: Modifier = Modifier, +// text: String, +// checked: Boolean, +// onCheckedChanged: (Boolean) -> Unit, +//) { +// val style = if (checked) { +// Twins.twins_title.copy(color = app_appColor) +// } else { +// Twins.twins_title +// } +// val shape = RoundedCornerShape(22.dp) +// Text( +// text = text, +// style = style, +// modifier = modifier +// .clip(shape) +// .run { +// if (checked) { +// this.border(width = 1.dp, color = app_appColor, shape = shape) +// } else { +// this.background(Color(0xfff4f5f7)) +// } +// } +// .clickable { +// onCheckedChanged.invoke(!checked) +// } +// .padding(vertical = 5.dp, horizontal = 16.dp) +// ) +//} +// +// +//@Composable +//fun CommitButtonBlockPreview() { +// CommitButtonBlock("ahhaha", true) { +// +// } +//} +// +//@Composable +//fun CommitButtonBlock2( +// text: String, +// enable: Boolean = true, +// onClick: () -> Unit, +//) { +// Box( +// modifier = Modifier +// .fillMaxWidth() +// .height(48.dp) +// .padding(horizontal = 16.dp) +// .clip(RoundedCornerShape(24.dp)) +// .background(app_button_brush) +// .clickable(enabled = enable) { +// onClick() +// }, contentAlignment = Alignment.Center +// ) { +// Text( +// text = text, +// textAlign = TextAlign.Center, +// style = TextStyle( +// fontSize = 16.sp, +// color = Color(1f, 1f, 1f, if (enable) 1f else .5f), +// fontWeight = FontWeight(400), textAlign = TextAlign.Center, +// ), +// maxLines = 1, +// modifier = Modifier +// +// ) +// } +// +//} +// +//@Composable +//fun CommitButtonBlock( +// text: String, +// enable: Boolean = true, +// onClick: () -> Unit, +//) { +// +// Text( +// text = text, +// //textAlign = TextAlign.Center, +// style = TextStyle( +// fontSize = 16.sp, +// color = Color(1f, 1f, 1f, if (enable) 1f else .5f), +// fontWeight = FontWeight(400), //textAlign = TextAlign.Center, +// ), +// maxLines = 1, +// modifier = Modifier +// .fillMaxWidth() +// .height(48.dp) +// .padding(horizontal = 0.dp) +// .clip(RoundedCornerShape(24.dp)) +// .background(app_button_brush) +// .clickable(enabled = enable) { +// onClick() +// } +// .wrapContentHeight() +// .wrapContentWidth() +// +// +// ) +// +//} +// +//// 文本居中示例 +//@Composable +//private fun TextDemo() { +// Box( +// Modifier +// .background(China.g_zhu_lv) +// .padding(32.dp) +// .size(200.dp) +// ) { +// Text( +// text = "hello !", +// modifier = Modifier +// .height(56.dp) +// .fillMaxWidth() +// .background(China.r_luo_xia_hong) +// .wrapContentHeight() +// .wrapContentWidth(), +//// textAlign = TextAlign.Center +// ) +// } +//} +// +//@Deprecated("delete") +//@Composable +//fun FloatActionBlock(modifier: Modifier = Modifier, onClick: () -> Unit) { +// Box( +// modifier +// .size(58.dp) +// .padding(4.dp) +// ) { +// Surface( +// shadowElevation = 4.dp, modifier = Modifier +// +// .fillMaxSize() +// .clip(CircleShape) +// .drawWithContent { +// drawCircle(app_button_brush) +// drawContent() +// } +// +//// .size(58.dp) +//// .clip(CircleShape) +// +// +//// .background(China.r_luo_xia_hong) +//// , color = blue_1 +// ) { +// Icon( +// Icons.Filled.Add, +// tint = Color.White, +// contentDescription = "add_device", +// modifier = Modifier +// .wrapContentSize() +//// .background(China.g_zhu_lv) +// ) +// +// } +// } +//} +// +//@Composable +//fun DividerBlock(color: Color = app_textColor_999999, horizontal: Boolean = true) { +// Spacer(modifier = Modifier +// .run { +// if (horizontal) { +// this +// .fillMaxWidth() +// .height(.5.dp) +// } else { +// this +// .width(.5.dp) +// .fillMaxHeight() +// +// } +// +// } +// .background(color)) +//} diff --git a/iosApp/DerivedData/ModuleCache.noindex/EYH9XYDI5AKA/ComposeApp-3JGVIRIUZEK4Z.pcm b/iosApp/DerivedData/ModuleCache.noindex/EYH9XYDI5AKA/ComposeApp-3JGVIRIUZEK4Z.pcm index 63487de3d77ae250b3e1f6114714ad4db4b8b941..6e87bb491670c142f91106a03b374ffcf5d4c41d 100644 GIT binary patch delta 2457 zcmc&$e@q+a8NQ2+&k6B&w!Ywp>y~AmYFFAsnuZ?^ zfX0eVXd}m+IzOs zACvmm{@Cd(pPui1pZ9s6_q$K`*|h@Cy9EJGH}*7+$=7jZ_75Ao*zz*2zL;v#she^u z>f8e64A$WFI&B_}UA3}Idos1;b^cI z&~H8Ub@X)b4xlyvgypW;QM4lC-^-Ta9B=YGv{NiJQK)<@gl*#Fys??JY0 zC>gDuPCnKZL(eJ9gvb$@kzc#j=bvmQO+zp19F=!Rh=U`Ime%*~7GHPl`7U4lDqk4B zTXv&`VXJ=gSJ0(CXT;87@{Jkg`*B-K+Q?y8d@@8Oc_!|n#=K12OC^%@I8RT6G&3${ zETma+X_>JU6;FMe=nV)x0pXBQ+^WU*zfe{22(Sy?9-`YWblQo&R>heSqNjxDvkN^P zLbXwFmk`}*qF0?mh&VkT(xgMwJkLPgG*pSwGhQa)p`qLozI!f3CyaCgXJ%P?f~A+T z0ZU@iikA+Q_nZ}~O9bnrPv#vIy39lm@SY`lm*g~w0Tg{ZuFl4j%6;>q|)(4ZXH;Ql7;XgUx*){AeTsD#q9b`&EThprb4svZ; z^-zm8JJ140p7x*xElNAkrf4{Xf1va$EMYNm2xsx@!76i;c$vdVai$J0*Cf$>32k!_ zj^RheG9G`Y#Adh|vrNiWEfL-f53@L}npl~JXP zMRTvyIScINQu(25nBuE-zz+OBuB0K%-FF zk!=r_lB&#C!rEa%Fdhl5V^%jpeDiCsOqo)v1RG$(Ha-(IM{E`;W|@M0y2C2P3@_R0h831TOrCKBvTcSz zpVe=(T#D62eAcV-hN!&cGvABVfP0dnHsXUN>#z+(p6HgQ+X&)zfS-Dser%D!1AB+_RCkRR!^ED z^*VjH)ZZ{*!0!w^#_C>cv=9D~*KZy3D@%&^RlOArf1o7sgLkgL z{k*?no?u=7Zm?fFrPaHR2b2kdWq;30SE7M)N9@C`+6$vP{l+nW!`@=HWw9}{e#D-> zuG1$EDEm$-|8_vR_H4lauRZMB_Zy{88cmx=?9wlE`T;ZJ_kX^J-S8D0P2bR|&tXbC zSHxwCCCt4My~6i@{<~* zvdUBAP0jKuQ9mxwrQU-_waf6UXZZ-^<0Ct;+p*VA^)58>dl<^TWy delta 2394 zcmc&$Z%iBK9lqCh@wp_tcP46}!Dr41S%?}%gTJ7&99Y8N9jnX2hzZ&Xc}wm1z_yv}Rvm}P{ah#)>N#wZSum<+-}lBKJ%Kfkld zlKuO#FSAZ}=jZ*s&+mDk=kB$=KVS1{|C)eV{qX@r$e%hYdm%pV+ItdFUFkh)YEN!N zl^Y=9Kch#3mjQkHU(nZsPmopW7gy2d)oy2lM*$t)pJP~A|# zc8;DX9ZGVZnW`!8uFR&*#}4x+rKqU3owu!jS;xFA6<(9_^j9|?kJ7QO!nz~O4&QjP z=y_N)uR1}f6!JlM<)dd^O_!fQMA_!h<_ff>qfav{Xr~12XI{+^(#}RSmvov;L^Bx4 zpAs}<^_mHuyROqrgtc(K0;Ayv^*lF$wBtJNl8(zn@`oeZ$$Cvj$4w=<381RijO#SB zK$S(x+#YdfKy-QNHePfE#GO{!ZKc~CWNU|2YzxzRr|5S0TO72Y5%_0X5Oj;Tog5Gu(C+KZ9=>k-X_4tTYh2$#{xME+LLXBS;6 z+69b;tSnf8lWteh?N*uesjPI*Y0(`PU3|6x*iX~0vg|!b35ZUI=!(fYzUv@c%0y?@ zgWqz{dbA_LP5Zdfdd;X$JCV>_^l{@p?Fb|i(OyB^=Vjl@X!mKc)!}zJ#dgQPIgyZ^ z2x}%I+6hR($4$xc=!(ijX6;bD zJZ&NS1dRGL@X$eo!#WPYEQ>)_15Uc_4=jwfBx~(i;NZUP7@4b$1jGCRlLe?>Nn^jy*h^M)r%W+a-fuA^ zNP;SRD6?)8!K_I5rVY=4OM63 zo=}v>p-pOguLYK00nK12hD?u?6$f@3$1TQasv==A4yKBS72Dps_+RG^B)OPR6HA%` zsq(l`IqWyZQAMxc5Ko#WE#+(vG)S7lmU3vn&YV~qdb%2!ziM8)B;f@;&ailX8sCp67AngJ*cD~Q2ipNqWPz$nO zlMOBI{YS(pg1RY%f;Gr|xL?9c2|VM)=>Wc^XBxe0XC&D=$m%+a?j`B2|Jg2-$5Muo?BV-TLRnbqW^jjLPX+k3NH9x!W{%C12&R$8cLR9Aj2j`Ztd$LR zyu#u|8@?yum8cvpn0w8}+>khC$@UUUFJ3WqTg=`(Cw$? zO&W$;JYt(_jmIn2->)trT*OL^HS>W`@KHl2^#@wl^x>uGJ4xxU)z-u@w%{)fRB6Yd z&gxSeb@e|}J~LdUF0j`H2I9)pt&OE;->kJtNA(E+?=?`a!ohdd1#Kmroqt}hyZV7( z?W`9H9PsrOCF)aJ@;2zYej@0v)LI9i{#$jO)o&ChFBIy!eqU?#o?$a@t52O_V;w@l zt>-!ieprk;ij#wdIuxq09+~#A1uK9u8%n!AspVA)mPdPue zuH~ko+T+qOw&ZUcO1`ZqG`^Bb4XGRw&`!tvhs)Fs>0^5}iGq}4%vbV}(f uVyL_=1@ISvJa7FnB9ZEaAN|TzdExML=fCz9bU8o7A4CR3g}w*DPW4~S;~ diff --git a/iosApp/DerivedData/ModuleCache.noindex/Session.modulevalidation b/iosApp/DerivedData/ModuleCache.noindex/Session.modulevalidation index f2e89b5..cf909be 100644 --- a/iosApp/DerivedData/ModuleCache.noindex/Session.modulevalidation +++ b/iosApp/DerivedData/ModuleCache.noindex/Session.modulevalidation @@ -1 +1 @@ -1709882413.0931501: Module build session file for module cache at Path(str: "/Users/xiangpengle/Documents/as/kmp/HDVirtuals/iosApp/DerivedData/ModuleCache.noindex") +1710211217.540483: Module build session file for module cache at Path(str: "/Users/xiangpengle/Documents/as/kmp/HDVirtuals/iosApp/DerivedData/ModuleCache.noindex") diff --git a/iosApp/DerivedData/SDKStatCaches.noindex/iphonesimulator17.2-21C52-4f2951bfe8f3cd53c99228b0131e163e.sdkstatcache b/iosApp/DerivedData/SDKStatCaches.noindex/iphonesimulator17.2-21C52-4f2951bfe8f3cd53c99228b0131e163e.sdkstatcache index 560949769ead980abb2d33d78188a37609afb7fe..774a531d08c2f89916ff8a3e50645bd06ce7486a 100644 GIT binary patch delta 76 zcmWN{sS$uM07XIW>v09o42nLG(WI0#fcU+{BB+BlQUv4si862R2GBuGB0~Fs&44?!PaX<@OZ-_QT%jpicd6PWvej!qk ciCh$-6qTq&BU;gkKlEY{qnN}j%+0d;4{9zGumAu6 diff --git a/iosApp/DerivedData/iosApp/info.plist b/iosApp/DerivedData/iosApp/info.plist index 865f164..812deeb 100644 --- a/iosApp/DerivedData/iosApp/info.plist +++ b/iosApp/DerivedData/iosApp/info.plist @@ -3,7 +3,7 @@ LastAccessedDate - 2024-03-08T07:20:12Z + 2024-03-12T02:40:17Z WorkspacePath /Users/xiangpengle/Documents/as/kmp/HDVirtuals/iosApp/iosApp.xcodeproj diff --git a/settings.gradle.kts b/settings.gradle.kts index 10ae52d..d1ef72d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,4 +28,5 @@ include(":hdmqtt") include(":hdcontext") include(":hdhttp") include(":hdble") -include(":hdserial") \ No newline at end of file +include(":hdserial") +include(":hdui") \ No newline at end of file diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 19abfda..705e302 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -39,12 +39,23 @@ kotlin { implementation(projects.hdserial) implementation(projects.hddb) implementation(projects.hdble) + implementation(projects.hdui) + + // voyager + implementation(libs.voyager.navigator) + implementation(libs.voyager.screenModel) + implementation(libs.voyager.bottomSheetNavigator) + implementation(libs.voyager.tabNavigator) + implementation(libs.voyager.transitions) + implementation(libs.voyager.koin) + } androidMain.dependencies { implementation(libs.compose.ui.tooling.preview) implementation(libs.androidx.activity.compose) +// implementation(libs.voyager.hilt) } iosMain.dependencies { diff --git a/shared/src/androidMain/kotlin/com/yunext/virtuals/ui/demo/voyager/hiltNavigation/HiltModule.kt b/shared/src/androidMain/kotlin/com/yunext/virtuals/ui/demo/voyager/hiltNavigation/HiltModule.kt new file mode 100644 index 0000000..07e62b1 --- /dev/null +++ b/shared/src/androidMain/kotlin/com/yunext/virtuals/ui/demo/voyager/hiltNavigation/HiltModule.kt @@ -0,0 +1,27 @@ +//package com.yunext.virtuals.ui.demo.voyager.hiltNavigation +// +//import cafe.adriel.voyager.core.model.ScreenModel +//import cafe.adriel.voyager.hilt.ScreenModelFactory +//import cafe.adriel.voyager.hilt.ScreenModelFactoryKey +//import cafe.adriel.voyager.hilt.ScreenModelKey +//import dagger.Binds +//import dagger.Module +//import dagger.hilt.InstallIn +//import dagger.hilt.android.components.ActivityComponent +//import dagger.multibindings.IntoMap +// +//@Module +//@InstallIn(ActivityComponent::class) +//abstract class HiltModule { +// @Binds +// @IntoMap +// @ScreenModelKey(HiltListScreenModel::class) +// abstract fun bindHiltScreenModel(hiltListScreenModel: HiltListScreenModel): ScreenModel +// +// @Binds +// @IntoMap +// @ScreenModelFactoryKey(HiltDetailsScreenModel.Factory::class) +// abstract fun bindHiltDetailsScreenModelFactory( +// hiltDetailsScreenModelFactory: HiltDetailsScreenModel.Factory +// ): ScreenModelFactory +//} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/VoyagerDemoApp.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/VoyagerDemoApp.kt new file mode 100644 index 0000000..a6cb7a0 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/VoyagerDemoApp.kt @@ -0,0 +1,16 @@ +package com.yunext.virtuals.ui.demo.voyager + +import androidx.compose.runtime.Composable +import com.yunext.virtuals.ui.demo.voyager.basicNavigationScreen.BasicNavigationScreen +import com.yunext.virtuals.ui.demo.voyager.bottomSheetNavigation.BottomSheetNavigationScreen +import com.yunext.virtuals.ui.demo.voyager.nestedNavigation.NestedNavigationScreen +import com.yunext.virtuals.ui.demo.voyager.tabNavigation.TabNavigationScreen + +@Composable +fun VoyagerDemoApp() { + BasicNavigationScreen() +// BottomSheetNavigationScreen() +// KoinScreen() +// TabNavigationScreen() + NestedNavigationScreen() +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/basicNavigationScreen/VoyagerDemo.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/basicNavigationScreen/VoyagerDemo.kt new file mode 100644 index 0000000..af0c117 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/basicNavigationScreen/VoyagerDemo.kt @@ -0,0 +1,118 @@ +package com.yunext.virtuals.ui.demo.voyager.basicNavigationScreen + +import com.yunext.kmp.common.logger.HDLogger +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.lifecycle.LifecycleEffect +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.uniqueScreenKey +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.navigator.currentOrThrow + +private const val TAG = "VoyagerDemo" + +@Composable +fun BasicNavigationScreen() { + Navigator(screen = BasicNavigationScreen(index = 0), onBackPressed = { + HDLogger.d(TAG, "screen : $it") + true + }) +} + +data class BasicNavigationScreen( + val index: Int, + val wrapContent: Boolean = false, +) : Screen { + + override val key = uniqueScreenKey + + @Composable + override fun Content() { + LifecycleEffect( + onStarted = { HDLogger.d(TAG, "Start screen #$index") }, + onDisposed = { HDLogger.d(TAG, "Dispose screen #$index") } + ) + + val navigator = LocalNavigator.currentOrThrow + + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.run { + if (wrapContent) { + padding(vertical = 16.dp).wrapContentHeight() + } else { + fillMaxSize() + } + } + ) { + Text( + text = "Screen #$index", + style = MaterialTheme.typography.h5 + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Row( + modifier = Modifier.padding(16.dp) + ) { + Button( + enabled = navigator.canPop, + onClick = navigator::pop, + modifier = Modifier.weight(.5f) + ) { + Text(text = "Pop") + } + + Spacer(modifier = Modifier.weight(.1f)) + + Button( + onClick = { navigator.push(BasicNavigationScreen(index.inc(), wrapContent)) }, + modifier = Modifier.weight(.5f) + ) { + Text(text = "Push") + } + + Spacer(modifier = Modifier.weight(.1f)) + + Button( + onClick = { + navigator.replace( + BasicNavigationScreen( + index.inc(), + wrapContent + ) + ) + }, + modifier = Modifier.weight(.5f) + ) { + Text(text = "Replace") + } + } + + LazyColumn( + modifier = Modifier.height(100.dp)//.weight(1f) + ) { + items(100) { + Text("Item #$it") + } + } + } + } +} + diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/bottomSheetNavigation/BackScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/bottomSheetNavigation/BackScreen.kt new file mode 100644 index 0000000..8d67652 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/bottomSheetNavigation/BackScreen.kt @@ -0,0 +1,46 @@ +package com.yunext.virtuals.ui.demo.voyager.bottomSheetNavigation + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.Button +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator +import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator +import com.yunext.kmp.resource.color.China +import com.yunext.kmp.ui.compose.hdBorder +import com.yunext.kmp.ui.compose.xplBackground +import com.yunext.virtuals.ui.demo.voyager.basicNavigationScreen.BasicNavigationScreen + +class BackScreen : Screen { + + @Composable + override fun Content() { + val bottomSheetNavigator = LocalBottomSheetNavigator.current + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize().hdBorder().xplBackground { China.g_zhu_lv } + ) { + Button( + onClick = { bottomSheetNavigator.show(BasicNavigationScreen(index = 0, wrapContent = true)) } + ) { + Text(text = "Show BottomSheet") + } + } + } +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun BottomSheetNavigationScreen() { + BottomSheetNavigator { + Navigator(BackScreen()) + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreen.kt new file mode 100644 index 0000000..a446453 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreen.kt @@ -0,0 +1,21 @@ +//package com.yunext.virtuals.ui.demo.voyager.integration +// +//import androidx.compose.runtime.Composable +//import cafe.adriel.voyager.core.screen.Screen +//import cafe.adriel.voyager.core.screen.ScreenKey +//import cafe.adriel.voyager.core.screen.uniqueScreenKey +//import cafe.adriel.voyager.koin.getScreenModel +//import com.yunext.virtuals.ui.demo.voyager.ListContent +// +//class KoinScreen : Screen { +// +// override val key: ScreenKey = uniqueScreenKey +// +// @Composable +// override fun Content() { +// val screenModel = getScreenModel() +// +// ListContent(screenModel.items) +// } +//} + diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreenModel.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreenModel.kt new file mode 100644 index 0000000..c19ee46 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/integration/KoinScreenModel.kt @@ -0,0 +1,9 @@ +//package com.yunext.virtuals.ui.demo.voyager.integration +// +//import cafe.adriel.voyager.core.model.ScreenModel +//import com.yunext.virtuals.ui.demo.voyager.sampleItems +// +//class KoinScreenModel : ScreenModel { +// +// val items = sampleItems +//} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/nestedNavigation/NestednavigationScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/nestedNavigation/NestednavigationScreen.kt new file mode 100644 index 0000000..584ee79 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/nestedNavigation/NestednavigationScreen.kt @@ -0,0 +1,64 @@ +package com.yunext.virtuals.ui.demo.voyager.nestedNavigation + + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.navigator.CurrentScreen +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.navigator.NavigatorContent +import com.yunext.kmp.resource.color.China +import com.yunext.virtuals.ui.demo.voyager.basicNavigationScreen.BasicNavigationScreen + + +@Composable +fun NestedNavigationScreen() { + NestedNavigation(backgroundColor = China.g_zhu_lv) { + CurrentScreen() + NestedNavigation(backgroundColor = China.r_luo_xia_hong) { + CurrentScreen() + NestedNavigation(backgroundColor = China.h_gu_huang) { navigator -> + CurrentScreen() + Button( + onClick = { navigator.popUntilRoot() }, + modifier = Modifier.padding(bottom = 16.dp) + ) { + Text(text = "Pop Until Root") + } + } + } + } +} + +@Composable +private fun NestedNavigation( + backgroundColor: Color, + content: NavigatorContent = { CurrentScreen() }, +) { + Navigator( + screen = BasicNavigationScreen(index = 0, wrapContent = true) + ) { navigator -> + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .padding(16.dp) + .background(backgroundColor) + ) { + Text( + text = "Level #${navigator.level}", + modifier = Modifier.padding(8.dp) + ) + content(navigator) + } + } +} diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/sampleItems.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/sampleItems.kt new file mode 100644 index 0000000..b8c5c44 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/sampleItems.kt @@ -0,0 +1,76 @@ +//package com.yunext.virtuals.ui.demo.voyager +// +//import androidx.compose.foundation.clickable +//import androidx.compose.foundation.layout.Arrangement +//import androidx.compose.foundation.layout.Box +//import androidx.compose.foundation.layout.Column +//import androidx.compose.foundation.layout.Spacer +//import androidx.compose.foundation.layout.fillMaxSize +//import androidx.compose.foundation.layout.height +//import androidx.compose.foundation.lazy.LazyColumn +//import androidx.compose.foundation.lazy.itemsIndexed +//import androidx.compose.material.Button +//import androidx.compose.material.CircularProgressIndicator +//import androidx.compose.material.ExperimentalMaterialApi +//import androidx.compose.material.ListItem +//import androidx.compose.material.MaterialTheme +//import androidx.compose.material.Text +//import androidx.compose.runtime.Composable +//import androidx.compose.ui.Alignment +//import androidx.compose.ui.Modifier +//import androidx.compose.ui.unit.dp +//import com.yunext.kmp.common.util.hdUUID +// +//val sampleItems: List +// get() = (0..99).map { "Item #$it | ${hdUUID(16).substringBefore('-')}" } +// +//@Composable +//fun LoadingContent() { +// Box( +// contentAlignment = Alignment.Center, +// modifier = Modifier.fillMaxSize() +// ) { +// CircularProgressIndicator() +// } +//} +// +//@OptIn(ExperimentalMaterialApi::class) +//@Composable +//fun ListContent(items: List, onClick: ((Int) -> Unit)? = null) { +// LazyColumn { +// itemsIndexed(items) { index, item -> +// ListItem( +// text = { Text(text = item) }, +// modifier = if (onClick == null) Modifier else Modifier.clickable { onClick(index) } +// ) +// } +// } +//} +// +//@Composable +//fun DetailsContent(instance: Any, item: String, onClick: () -> Unit) { +// Column( +// verticalArrangement = Arrangement.Center, +// horizontalAlignment = Alignment.CenterHorizontally, +// modifier = Modifier.fillMaxSize() +// ) { +// Text( +// text = item, +// style = MaterialTheme.typography.h5 +// ) +// +// Spacer(modifier = Modifier.height(16.dp)) +// +// Text( +// text = instance.toString().substringAfterLast('.'), +// style = MaterialTheme.typography.body2 +// ) +// +// Spacer(modifier = Modifier.height(16.dp)) +// +// Button( +// onClick = onClick, +// content = { Text(text = "Back") } +// ) +// } +//} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/FavoritesTab.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/FavoritesTab.kt new file mode 100644 index 0000000..a3e8954 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/FavoritesTab.kt @@ -0,0 +1,31 @@ +package com.yunext.virtuals.ui.demo.voyager.tabNavigation + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Favorite +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions + +object FavoritesTab : Tab { + + override val options: TabOptions + @Composable + get() { + val icon = rememberVectorPainter(Icons.Default.Favorite) + + return remember { + TabOptions( + index = 1u, + title = "Favorites", + icon = icon + ) + } + } + + @Composable + override fun Content() { + TabContent() + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/HomeTab.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/HomeTab.kt new file mode 100644 index 0000000..0bbf64a --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/HomeTab.kt @@ -0,0 +1,31 @@ +package com.yunext.virtuals.ui.demo.voyager.tabNavigation + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions + +object HomeTab : Tab { + + override val options: TabOptions + @Composable + get() { + val icon = rememberVectorPainter(Icons.Default.Home) + + return remember { + TabOptions( + index = 0u, + title = "Home", + icon = icon + ) + } + } + + @Composable + override fun Content() { + TabContent() + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/ProfileTab.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/ProfileTab.kt new file mode 100644 index 0000000..030c1b8 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/ProfileTab.kt @@ -0,0 +1,31 @@ +package com.yunext.virtuals.ui.demo.voyager.tabNavigation + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Person +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabOptions + +object ProfileTab : Tab { + + override val options: TabOptions + @Composable + get() { + val icon = rememberVectorPainter(Icons.Default.Person) + + return remember { + TabOptions( + index = 2u, + title = "Profile", + icon = icon + ) + } + } + + @Composable + override fun Content() { + TabContent() + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabContent.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabContent.kt new file mode 100644 index 0000000..8b204bf --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabContent.kt @@ -0,0 +1,72 @@ +package com.yunext.virtuals.ui.demo.voyager.tabNavigation + +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.lifecycle.LifecycleEffect +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.navigator.tab.LocalTabNavigator +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.transitions.SlideTransition +import com.yunext.kmp.common.logger.HDLogger +import com.yunext.virtuals.ui.demo.voyager.basicNavigationScreen.BasicNavigationScreen + +@Composable +fun Tab.TabContent() { + val tabTitle = options.title + + LifecycleEffect( + onStarted = { HDLogger.d("Navigator", "Start tab $tabTitle") }, + onDisposed = { HDLogger.d("Navigator", "Dispose tab $tabTitle") } + ) + + Navigator(BasicNavigationScreen(index = 0)) { navigator -> + SlideTransition(navigator) { screen -> + Column { + InnerTabNavigation() + screen.Content() + HDLogger.d("Navigator", "Last Event: ${navigator.lastEvent}") + } + } + } +} + +@Composable +private fun InnerTabNavigation() { + Row( + modifier = Modifier.padding(16.dp) + ) { + TabNavigationButton(HomeTab) + + Spacer(modifier = Modifier.weight(.05f)) + + TabNavigationButton(FavoritesTab) + + Spacer(modifier = Modifier.weight(.05f)) + + TabNavigationButton(ProfileTab) + } +} + +@Composable +private fun RowScope.TabNavigationButton( + tab: Tab +) { + val tabNavigator = LocalTabNavigator.current + + Button( + enabled = tabNavigator.current.key != tab.key, + onClick = { tabNavigator.current = tab }, + modifier = Modifier.weight(1f) + ) { + Text(text = tab.options.title) + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabNavigationScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabNavigationScreen.kt new file mode 100644 index 0000000..e43b53b --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/demo/voyager/tabNavigation/TabNavigationScreen.kt @@ -0,0 +1,58 @@ +package com.yunext.virtuals.ui.demo.voyager.tabNavigation + +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material.BottomNavigation +import androidx.compose.material.BottomNavigationItem +import androidx.compose.material.Icon +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.navigator.tab.CurrentTab +import cafe.adriel.voyager.navigator.tab.LocalTabNavigator +import cafe.adriel.voyager.navigator.tab.Tab +import cafe.adriel.voyager.navigator.tab.TabDisposable +import cafe.adriel.voyager.navigator.tab.TabNavigator + +@Composable +fun TabNavigationScreen() { + + TabNavigator( + HomeTab, + tabDisposable = { + TabDisposable( + navigator = it, + tabs = listOf(HomeTab, FavoritesTab, ProfileTab) + ) + } + ) { tabNavigator -> + Scaffold( + topBar = { + TopAppBar( + title = { Text(text = tabNavigator.current.options.title) } + ) + }, + content = { + CurrentTab() + }, + bottomBar = { + BottomNavigation { + TabNavigationItem(HomeTab) + TabNavigationItem(FavoritesTab) + TabNavigationItem(ProfileTab) + } + } + ) + } +} + +@Composable +private fun RowScope.TabNavigationItem(tab: Tab) { + val tabNavigator = LocalTabNavigator.current + + BottomNavigationItem( + selected = tabNavigator.current.key == tab.key, + onClick = { tabNavigator.current = tab }, + icon = { Icon(painter = tab.options.icon!!, contentDescription = tab.options.title) } + ) +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/DemoScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/DemoScreen.kt index 76f8bcc..a29ce94 100644 --- a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/DemoScreen.kt +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/DemoScreen.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -24,12 +25,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import com.yunext.kmp.common.util.hdMD5 -import com.yunext.kmp.common.util.hdRandomString +import com.yunext.kmp.common.util.hdUUID import com.yunext.kmp.context.hdContext import com.yunext.kmp.db.datasource.DemoDataSource import com.yunext.kmp.db.datasource.impl.DemoDataSourceImpl import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import com.yunext.kmp.http.testKtor @Composable fun DemoScreen() { @@ -44,7 +46,9 @@ fun DemoScreen() { Text( text, style = TextStyle(color = Color.White), - modifier = Modifier.padding(12.dp, 8.dp).weight(1f) + modifier = Modifier.padding(12.dp, 8.dp) + .verticalScroll(rememberScrollState()) + .weight(1f) ) LibModuleDemo(listLibModules) { module -> when (module) { @@ -54,7 +58,7 @@ fun DemoScreen() { HDCommon -> { coroutineScope.launch { - text = "md:${hdMD5(text)} ,random:${hdRandomString(4)}" + text = "md:${hdMD5(text)} ,random:${hdUUID(4)}" } } @@ -85,7 +89,14 @@ fun DemoScreen() { } HDHttp -> { - text = "todo ${module.moduleName}" + coroutineScope.launch { + text = "start test http" + delay(2000) + text = "http ..." + val http = testKtor() + delay(2000) + text = "http result:${http}" + } } HDMqtt -> { @@ -109,7 +120,7 @@ fun DemoScreen() { Button(onClick = { coroutineScope.launch { - text = "md:${hdMD5(text)} ,random:${hdRandomString(4)}" + text = "md:${hdMD5(text)} ,random:${hdUUID(4)}" } }) { Text("hdcommon") diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/SplashScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/SplashScreen.kt new file mode 100644 index 0000000..d4d41ce --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/SplashScreen.kt @@ -0,0 +1,47 @@ +package com.yunext.virtuals.ui.screen + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.Text +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 androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import com.yunext.virtuals.ui.screen.devicelist.DeviceListScreen +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +internal class SplashScreen : Screen { + + @Composable + override fun Content() { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + var show by remember { + mutableStateOf(false) + } + val navigator = LocalNavigator.currentOrThrow + LaunchedEffect(Unit) { + launch { + delay(1000) + show = true + delay(1000) + navigator.replace(DeviceListScreen()) + } + } + AnimatedVisibility(show) { + Text("欢迎使用孪生App", modifier = Modifier.wrapContentSize()) + } + } + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/VoyagerApp.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/VoyagerApp.kt new file mode 100644 index 0000000..7d4e5ec --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/VoyagerApp.kt @@ -0,0 +1,16 @@ +package com.yunext.virtuals.ui.screen + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.navigator.Navigator +import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior + + +@Composable +fun VoyagerApp() { + Navigator( + screen = SplashScreen(), + disposeBehavior = NavigatorDisposeBehavior(), + onBackPressed = { + true + }) +} diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/adddevice/AddDeviceScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/adddevice/AddDeviceScreen.kt new file mode 100644 index 0000000..1a6a465 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/adddevice/AddDeviceScreen.kt @@ -0,0 +1,14 @@ +package com.yunext.virtuals.ui.screen.adddevice + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class AddDeviceScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/configwifi/ConfigWiFiScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/configwifi/ConfigWiFiScreen.kt new file mode 100644 index 0000000..9974260 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/configwifi/ConfigWiFiScreen.kt @@ -0,0 +1,14 @@ +package com.yunext.virtuals.ui.screen.configwifi + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class ConfigWiFiScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailScreen.kt new file mode 100644 index 0000000..5350be4 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailScreen.kt @@ -0,0 +1,14 @@ +package com.yunext.virtuals.ui.screen.devicedetail + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class DeviceDetailScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubEventScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubEventScreen.kt new file mode 100644 index 0000000..0677133 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubEventScreen.kt @@ -0,0 +1,12 @@ +package com.yunext.virtuals.ui.screen.devicedetail + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen + +class DeviceDetailSubEventScreen :Screen { + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubPropertityScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubPropertityScreen.kt new file mode 100644 index 0000000..f15fce9 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubPropertityScreen.kt @@ -0,0 +1,13 @@ +package com.yunext.virtuals.ui.screen.devicedetail + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen + +class DeviceDetailSubPropertityScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubServiceScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubServiceScreen.kt new file mode 100644 index 0000000..4b04e5f --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicedetail/DeviceDetailSubServiceScreen.kt @@ -0,0 +1,13 @@ +package com.yunext.virtuals.ui.screen.devicedetail + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen + +class DeviceDetailSubServiceScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicelist/DeviceListScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicelist/DeviceListScreen.kt new file mode 100644 index 0000000..124a275 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/devicelist/DeviceListScreen.kt @@ -0,0 +1,14 @@ +package com.yunext.virtuals.ui.screen.devicelist + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class DeviceListScreen :Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/logger/LoggerScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/logger/LoggerScreen.kt new file mode 100644 index 0000000..0b6013f --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/logger/LoggerScreen.kt @@ -0,0 +1,13 @@ +package com.yunext.virtuals.ui.screen.logger + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class LoggerScreen : Screen { + + @Composable + override fun Content() { + + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/setting/SettingScreen.kt b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/setting/SettingScreen.kt new file mode 100644 index 0000000..ecbaf35 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/yunext/virtuals/ui/screen/setting/SettingScreen.kt @@ -0,0 +1,14 @@ +package com.yunext.virtuals.ui.screen.setting + +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey + +class SettingScreen : Screen { + + + @Composable + override fun Content() { + + } +} \ No newline at end of file