From d2b0fe6dde5d16c24fa54a71254166357213cf31 Mon Sep 17 00:00:00 2001 From: storytellerF <34095089+storytellerF@users.noreply.github.com> Date: Sun, 20 Oct 2024 10:15:24 +0800 Subject: [PATCH] feat: client-cli --- cli/build.gradle.kts | 4 - client-cli/build.gradle.kts | 12 ++ client-cli/src/main/kotlin/example/main.kt | 173 +++++++++++++++++++++ gradle/libs.versions.toml | 2 + settings.gradle.kts | 3 +- 5 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 client-cli/build.gradle.kts create mode 100644 client-cli/src/main/kotlin/example/main.kt diff --git a/cli/build.gradle.kts b/cli/build.gradle.kts index 9ec5732..c19d0ff 100644 --- a/cli/build.gradle.kts +++ b/cli/build.gradle.kts @@ -6,10 +6,6 @@ plugins { group = "com.storyteller_f" version = "unspecified" -repositories { - mavenCentral() -} - dependencies { implementation(projects.shared) testImplementation(kotlin("test")) diff --git a/client-cli/build.gradle.kts b/client-cli/build.gradle.kts new file mode 100644 index 0000000..d8b3ccd --- /dev/null +++ b/client-cli/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + alias(libs.plugins.kotlinJvm) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) + application +} +application { + mainClass.set("example.MainKt") +} +dependencies { + implementation(libs.mosaic.runtime) +} diff --git a/client-cli/src/main/kotlin/example/main.kt b/client-cli/src/main/kotlin/example/main.kt new file mode 100644 index 0000000..d2751a6 --- /dev/null +++ b/client-cli/src/main/kotlin/example/main.kt @@ -0,0 +1,173 @@ +package example + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import com.jakewharton.mosaic.LocalTerminal +import com.jakewharton.mosaic.layout.background +import com.jakewharton.mosaic.layout.height +import com.jakewharton.mosaic.layout.size +import com.jakewharton.mosaic.modifier.Modifier +import com.jakewharton.mosaic.runMosaicBlocking +import com.jakewharton.mosaic.text.SpanStyle +import com.jakewharton.mosaic.text.buildAnnotatedString +import com.jakewharton.mosaic.text.withStyle +import com.jakewharton.mosaic.ui.Box +import com.jakewharton.mosaic.ui.Color +import com.jakewharton.mosaic.ui.Column +import com.jakewharton.mosaic.ui.ColumnScope +import com.jakewharton.mosaic.ui.Filler +import com.jakewharton.mosaic.ui.Row +import com.jakewharton.mosaic.ui.Spacer +import com.jakewharton.mosaic.ui.Text +import com.jakewharton.mosaic.ui.TextStyle +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.delay + +private val BrightGreen = Color(100, 255, 100) +private val BrightBlue = Color(60, 140, 230) + +fun main() = runMosaicBlocking { + Column { + val terminal = LocalTerminal.current + Text( + buildAnnotatedString { + append("\uD83D\uDDA5\uFE0F") + append(" ") + append("Terminal(") + withStyle(SpanStyle(color = BrightGreen)) { + append("width=") + } + withStyle( + SpanStyle( + color = BrightBlue, + textStyle = TextStyle.Bold + TextStyle.Underline, + ), + ) { + append(terminal.size.width.toString()) + } + append(", ") + withStyle(SpanStyle(color = BrightGreen)) { + append("height=") + } + withStyle( + SpanStyle( + color = BrightBlue, + textStyle = TextStyle.Bold + TextStyle.Underline, + ), + ) { + append(terminal.size.height.toString()) + } + append(")") + append(" ") + append("\uD83D\uDDA5\uFE0F") + }, + ) + Spacer(modifier = Modifier.height(1)) + GradientsBlock() + } + + LaunchedEffect(Unit) { + awaitCancellation() + } +} + +@Suppress("UnusedReceiverParameter") // instead of ignore rule: compose:multiple-emitters-check +@Composable +private fun ColumnScope.GradientsBlock() { + val screenHalfWidth = LocalTerminal.current.size.width / 2 + var gradientWidth by remember { mutableIntStateOf(0) } + val gradientWidthDiff by remember(screenHalfWidth) { + derivedStateOf { (screenHalfWidth - gradientWidth) / 5 } + } + Gradient( + repeatedWord = "Red", + width = gradientWidth, + textColorProvider = { percent -> Color(1.0f - percent, 0.0f, 0.0f) }, + backgroundColorProvider = { percent -> Color(percent, 0.0f, 0.0f) }, + ) + Gradient( + repeatedWord = "Yellow", + width = gradientWidth, + textColorProvider = { percent -> Color(1.0f - percent, 1.0f - percent, 0.0f) }, + backgroundColorProvider = { percent -> Color(percent, percent, 0.0f) }, + ) + Gradient( + repeatedWord = "Green", + width = gradientWidth, + textColorProvider = { percent -> Color(0.0f, 1.0f - percent, 0.0f) }, + backgroundColorProvider = { percent -> Color(0.0f, percent, 0.0f) }, + ) + Gradient( + repeatedWord = "Cyan", + width = gradientWidth, + textColorProvider = { percent -> Color(0.0f, 1.0f - percent, 1.0f - percent) }, + backgroundColorProvider = { percent -> Color(0.0f, percent, percent) }, + ) + Gradient( + repeatedWord = "Blue", + width = gradientWidth, + textColorProvider = { percent -> Color(0.0f, 0.0f, 1.0f - percent) }, + backgroundColorProvider = { percent -> Color(0.0f, 0.0f, percent) }, + ) + Gradient( + repeatedWord = "Magenta", + width = gradientWidth, + textColorProvider = { percent -> Color(1.0f - percent, 0.0f, 1.0f - percent) }, + backgroundColorProvider = { percent -> Color(percent, 0.0f, percent) }, + ) + LaunchedEffect(screenHalfWidth) { + while (true) { + delay(100L) + gradientWidth += gradientWidthDiff + } + } +} + +@Composable +private fun Gradient( + repeatedWord: String, + width: Int, + textColorProvider: (percent: Float) -> Color, + backgroundColorProvider: (percent: Float) -> Color, +) { + var textBias by remember { mutableIntStateOf(0) } + Box { + Row { + var wordCharIndex = textBias + repeat(width) { index -> + if (wordCharIndex == repeatedWord.length) { + wordCharIndex = 0 + } + Filler( + char = repeatedWord[wordCharIndex], + foreground = textColorProvider.invoke(index / width.toFloat()), + modifier = Modifier.size(1), + ) + wordCharIndex++ + } + } + Row { + repeat(width) { index -> + Spacer( + modifier = Modifier + .size(1) + .background(backgroundColorProvider.invoke(index / width.toFloat())), + ) + } + } + } + LaunchedEffect(Unit) { + while (true) { + delay(200L) + textBias-- + if (textBias < 0) { + textBias = repeatedWord.length - 1 + } + } + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3d4bd6b..f2e3aab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ kotlinxCoroutinesCore = "1.9.0" kotlinxDatetime = "0.6.0" ktomlCore = "0.5.1" luceneCore = "9.11.1" +mosaicRuntime = "0.14.0" multiplatformCryptoLibsodiumBindings = "0.9.2" multiplatformMarkdownRenderer = "0.25.0" napier = "2.7.1" @@ -72,6 +73,7 @@ lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.r lucene-analysis-common = { module = "org.apache.lucene:lucene-analysis-common", version.ref = "luceneCore" } lucene-core = { module = "org.apache.lucene:lucene-core", version.ref = "luceneCore" } lucene-queryparser = { module = "org.apache.lucene:lucene-queryparser", version.ref = "luceneCore" } +mosaic-runtime = { module = "com.jakewharton.mosaic:mosaic-runtime", version.ref = "mosaicRuntime" } multiplatform-crypto-libsodium-bindings = { module = "com.ionspin.kotlin:multiplatform-crypto-libsodium-bindings", version.ref = "multiplatformCryptoLibsodiumBindings" } multiplatform-markdown-renderer = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "multiplatformMarkdownRenderer" } multiplatform-markdown-renderer-coil3 = { module = "com.mikepenz:multiplatform-markdown-renderer-coil3", version.ref = "multiplatformMarkdownRenderer" } diff --git a/settings.gradle.kts b/settings.gradle.kts index c780606..4a33986 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -43,4 +43,5 @@ include(":cli") include(":backend") include(":client-lib") include(":bot-lib") -include(":builtin-bot") \ No newline at end of file +include(":builtin-bot") +include(":client-cli") \ No newline at end of file