Skip to content

Commit

Permalink
Preparations for CLI
Browse files Browse the repository at this point in the history
- Upload client to Maven
- Add CLI login flow
  • Loading branch information
DRSchlaubi committed Jun 3, 2023
1 parent 83c6dfc commit f09c2cf
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 29 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Maven CI

on:
push:
tags:
- '**'

jobs:
publish:
name: Publish To Maven
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 19
- name: Build plugin
uses: gradle/gradle-build-action@v2
env:
JFROG_USER: ${{ secrets.JFROG_USER }}
JFROG_PASSWORD: ${{ secrets.JFROG_PASSWORD }}
SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
SIGNING_PASSWORD: ${{ secrets.GPG_SIGNING_PASSWORD }}
with:
arguments: publish
12 changes: 11 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/strings/DeStrings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ val DeStrings = Strings(
loginSuccessful = "Anmeldung erfolgreich!",
logo = "Stell dir unser logo vor",
loginSuccessfulDescription = "Du hast dich erfolgreich angemeldet, hab Spaß und kauf keine Apple Produkte",
starOnGithub = "Bewerte uns auf GitHub"
starOnGithub = "Bewerte uns auf GitHub",
cliLoginExplainer = "Bitte führe diesen Befehl aus um dich anzumelden"
)
3 changes: 2 additions & 1 deletion app/shared/src/commonMain/kotlin/strings/EnStrings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ val EnStrings = Strings(
loginSuccessful = "Login Successful",
logo = "Imagine our logo being here",
loginSuccessfulDescription = "You signed in successfully, you can close this tab now and please don't buy Apple Products",
starOnGithub = "Star us on GitHub"
starOnGithub = "Star us on GitHub",
cliLoginExplainer = "Please run this command to log in"
)
1 change: 1 addition & 0 deletions app/shared/src/commonMain/kotlin/strings/Strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ data class Strings(
val loginSuccessful: String,
val logo: String,
val loginSuccessfulDescription: String,
val cliLoginExplainer: String,
val starOnGithub: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,50 @@ package dev.schlaubi.tonbrett.app.web

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import dev.schlaubi.tonbrett.app.ColorScheme
import dev.schlaubi.tonbrett.app.strings.LocalStrings
import dev.schlaubi.tonbrett.common.authServerPort
import io.ktor.client.fetch.*
import kotlinx.browser.window
import kotlinx.coroutines.await
import kotlinx.coroutines.delay
import mu.KotlinLogging
import org.w3c.dom.url.URLSearchParams
import kotlin.time.Duration.Companion.seconds

private val LOG = KotlinLogging.logger { }

@Composable
fun AuthorizationScreen() {
fun AuthorizationScreen(cli: Boolean) {
val strings = LocalStrings.current
LaunchedEffect(Unit) {
val token = URLSearchParams(window.location.search).get("token") ?: error("Missing token")
try {
fetch("http://localhost:$authServerPort/login?token=$token", object : RequestInit {
override var method: String? = "POST"
}).await()
} catch (e: Throwable) {
LOG.error(e) { "Could not propagate token" }
val token = remember { URLSearchParams(window.location.search).get("token") ?: error("Missing token") }
if (!cli) {
LaunchedEffect(Unit) {
try {
fetch("http://localhost:$authServerPort/login?token=$token", object : RequestInit {
override var method: String? = "POST"
}).await()
} catch (e: Throwable) {
LOG.error(e) { "Could not propagate token" }
}
}
}
BoxWithConstraints(Modifier.fillMaxSize().background(ColorScheme.container)) {
Expand Down Expand Up @@ -68,21 +73,83 @@ fun AuthorizationScreen() {
Spacer(Modifier.padding(vertical = 15.dp))
Text(strings.logo, modifier = Modifier.width(64.dp), fontSize = 16.sp)
Spacer(Modifier.padding(vertical = 7.dp))
Text(
strings.loginSuccessfulDescription,
fontSize = 24.sp
)
val text = if(cli) {
strings.cliLoginExplainer
} else {
strings.loginSuccessfulDescription
}
Text(text, fontSize = 24.sp)
Spacer(Modifier.padding(vertical = 7.dp))
if (cli) {
BoxWithConstraints(
Modifier.background(ColorScheme.container, RoundedCornerShape(4.dp))
.fillMaxWidth()
.height(32.dp)
.padding(horizontal = 15.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxHeight()
) {
Text(
token,
maxLines = 1,
modifier = Modifier.horizontalScroll(rememberScrollState())
)
}
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier.zIndex(2f).fillMaxWidth()
) {
CopyButton("tonbrett-cli login --auth-token=token")
}
}
}
Divider(Modifier.padding(vertical = 15.dp).fillMaxWidth(), thickness = 2.dp)
Text(
strings.starOnGithub,
fontSize = 24.sp,
color = Color.Blue,
modifier = Modifier.clickable {
window.location.href = "https://github.com/DRSchlaubi/Tonbrett"
})
}
)
}
}
}
}
}
}

@Composable
fun CopyButton(text: String) {
var copied by remember { mutableStateOf(false) }

if (copied) {
LaunchedEffect(copied) {
delay(3.seconds)
copied = false
}
}

Surface(
color = ColorScheme.secondaryContainer, shape = RoundedCornerShape(4.dp),
modifier = Modifier
.fillMaxHeight()
.padding(vertical = 3.dp)
) {
IconButton(
{
window.navigator.clipboard.writeText(text)
copied = true
}
) {
val icon = if (copied) {
Icons.Default.Check
} else {
Icons.Default.ContentCopy
}
Icon(icon, null, tint = ColorScheme.textColor)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fun main() {
} else if (path.subList(1, 3) == listOf("deeplink", "login")){
onWasmReady {
CanvasBasedWindow(title) {
AuthorizationScreen()
AuthorizationScreen(url.parameters["cli"]?.toBoolean() ?: false)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ plugins {
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.android.library) apply false
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
alias(libs.plugins.kotlin.android) apply false
}

allprojects {
Expand Down
28 changes: 28 additions & 0 deletions buildSrc/src/main/kotlin/published-module.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import org.gradle.kotlin.dsl.`maven-publish`
import org.gradle.kotlin.dsl.signing
import java.util.Base64

plugins {
`maven-publish`
signing
}

publishing {
repositories {
maven("https://schlaubi.jfrog.io/artifactory/mikbot/") {
credentials {
username = System.getenv("JFROG_USER")
password = System.getenv("JFROG_PASSWORD")
}
}
}
}

signing {
val key = System.getenv("SIGNING_KEY")
val password = System.getenv("SIGNING_PASSWORD")
if(key != null && password != null) {
useInMemoryPgpKeys(String(Base64.getDecoder().decode(key)), password)
sign(publishing.publications)
}
}
10 changes: 10 additions & 0 deletions client/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("multiplatform")
id("com.android.library")
`published-module`
}

repositories {
Expand Down Expand Up @@ -34,6 +35,9 @@ kotlin {
iosSimulatorArm64()
iosX64()
iosArm64()
macosArm64()
macosX64()
mingwX64()

sourceSets {
commonMain {
Expand Down Expand Up @@ -64,6 +68,12 @@ kotlin {
implementation(libs.ktor.client.okhttp)
}
}

named("mingwMain") {
dependencies {
implementation(libs.ktor.client.winhttp)
}
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
`published-module`
}

@OptIn(ExperimentalKotlinGradlePluginApi::class)
Expand All @@ -24,6 +25,9 @@ kotlin {
iosSimulatorArm64()
iosX64()
iosArm64()
macosArm64()
macosX64()
mingwX64()

sourceSets {
commonMain {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package dev.schlaubi.tonbrett.common.util

internal actual fun String.codePoints(): Sequence<Int> = emptySequence()
public actual fun String.codePoints(): Sequence<Int> = emptySequence()
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class Route {
public enum class Type(public val redirectTo: String) {
WEB("/soundboard/ui/login?token="),
APP("/soundboard/deeplink/login?token="),
CLI("/soundboard/deeplink/login?cli=true&token="),
MOBILE_APP("tonbrett://login?token=")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package dev.schlaubi.tonbrett.common.util
import kotlin.jvm.JvmName
import dev.schlaubi.tonbrett.common.util.codePoints as commonCodePoints

internal expect fun String.codePoints(): Sequence<Int>
public expect fun String.codePoints(): Sequence<Int>
internal fun formatEmojiUnicode(input: String) = input.commonCodePoints()
// twemoji seems to use variant selectors weirdly
.filterIndexed { index, it ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.schlaubi.tonbrett.common.util

internal actual fun String.codePoints(): Sequence<Int> = buildList(length) {
public actual fun String.codePoints(): Sequence<Int> = buildList(length) {
var i = 0
while (isNotEmpty()) {
val point = asDynamic().codePointAt(i++) as Int?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import kotlin.streams.asSequence

// Member is not MPP
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
internal actual fun String.codePoints(): Sequence<Int> =
public actual fun String.codePoints(): Sequence<Int> =
codePoints().asSequence()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package dev.schlaubi.tonbrett.common.util

public actual fun String.codePoints(): Sequence<Int> = TODO("Refactor emoji handling")
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ktor-server-auth-jwt = { group = "io.ktor", name = "ktor-server-auth-jwt", versi
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" }
ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" }
ktor-client-winhttp = { group = "io.ktor", name = "ktor-client-winhttp", version.ref = "ktor" }
ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" }
ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
Expand All @@ -54,6 +55,7 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const
mdc-android = { group = "com.google.android.material", name = "material", version = "1.9.0" }
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
mikbot = { id = "dev.schlaubi.mikbot.gradle-plugin", version.ref = "mikbot" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
Expand Down

0 comments on commit f09c2cf

Please sign in to comment.