diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index deb53fc..7db8219 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -69,6 +69,8 @@ kotlin { implementation(libs.ktor.client.core) implementation(libs.ktor.client.resources) + + implementation(libs.procyk.compose.qrcode) } desktopMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/in/procyk/shin/App.kt similarity index 83% rename from composeApp/src/commonMain/kotlin/App.kt rename to composeApp/src/commonMain/kotlin/in/procyk/shin/App.kt index 4ea4408..ee69f6b 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/in/procyk/shin/App.kt @@ -1,6 +1,7 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.Image import androidx.compose.foundation.hoverable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsHoveredAsState @@ -14,8 +15,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.input.key.* import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.text.* import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign @@ -23,6 +27,9 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import `in`.procyk.compose.qrcode.QrData +import `in`.procyk.compose.qrcode.options.* +import `in`.procyk.compose.qrcode.rememberQrCodePainter import io.ktor.client.* import io.ktor.client.plugins.* import io.ktor.client.plugins.resources.* @@ -60,9 +67,13 @@ fun App() { enter = expandVertically(expandFrom = Alignment.Top), exit = shrinkVertically(shrinkTowards = Alignment.Top), ) { - Column { - Spacer(Modifier.height(16.dp)) - response?.let { uri -> + response?.let { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp, alignment = Alignment.CenterVertically) + ) { + val uri by remember(it) { mutableStateOf(it.normalizeAsHttpUrl()) } + Spacer(Modifier.height(16.dp)) val color = MaterialTheme.colors.primary val annotatedString = remember(uri, color) { buildAnnotatedString { @@ -89,6 +100,7 @@ fun App() { } } val clipboardManager = LocalClipboardManager.current + val localUriHandler = LocalUriHandler.current val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() ClickableText( @@ -102,11 +114,18 @@ fun App() { .getStringAnnotations(URL_TAG, position, position) .single() .let { - val url = it.item.normalizeAsHttpUrl() - clipboardManager.setText(AnnotatedString(url)) + clipboardManager.setText(AnnotatedString(uri)) + localUriHandler.openUri(uri) } } ) + Spacer(Modifier.height(16.dp)) + QrCode(uri) + Button( + onClick = { clipboardManager.setText(AnnotatedString(uri)) }, + ) { + Text("Copy to Clipboard") + } } } } @@ -148,6 +167,31 @@ private fun ShortenRequest( } } +@Composable +private fun QrCode(url: String) { + val primaryColor = MaterialTheme.colors.primary + val secondaryColor = MaterialTheme.colors.secondary + val painter = rememberQrCodePainter( + data = QrData.text(url), + ) { + shapes { + ball = QrBallShape.circle() + darkPixel = QrPixelShape.roundCorners() + frame = QrFrameShape.roundCorners(.25f) + } + colors { + dark = QrBrush.brush { + Brush.linearGradient( + 0f to secondaryColor, + 1f to primaryColor, + end = Offset(it, it) + ) + } + } + } + Image(painter, "QR code") +} + @Composable private fun ShortenRequestElements( client: HttpClient, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 667eb98..26d4e07 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ kotlin = "1.9.21" ktor-server = "2.3.8" ktor-client = "3.0.0-wasm2" koin = "3.6.0-wasm-alpha2" +procyk-compose = "1.6.0-alpha01.1" logback = "1.4.14" postgres = "42.7.1" dotenv = "6.4.1" @@ -52,6 +53,7 @@ ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "kto ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor-client" } ktor-client-resources = { module = "io.ktor:ktor-client-resources", version.ref = "ktor-client" } koin-ktor = { module = "io.insert-koin:koin-ktor", version.ref = "koin" } +procyk-compose-qrcode = { module = "in.procyk.compose:qr-code", version.ref = "procyk-compose" } postgres = { module = "org.postgresql:postgresql", version.ref = "postgres" } dotenv = { module = "io.github.cdimascio:dotenv-kotlin", version.ref = "dotenv" }