From 1ffc73026d92fdef99da3f16202746379a4e84fc Mon Sep 17 00:00:00 2001 From: Sasikanth Miriyampalli Date: Thu, 21 Sep 2023 14:49:19 +0530 Subject: [PATCH] [WIP] --- .../hisp/dhis/common/screens/SwitchScreen.kt | 33 ++----------- .../component/internal/qr/QrCodeGenerator.kt | 31 ++++++++++++ .../ui/designsystem/component/QrCodeBlock.kt | 47 +++++++++++++++++++ .../component/internal/qr/QrCodeGenerator.kt | 27 +++++++++++ .../component/internal/qr/QrCodeGenerator.kt | 45 ++++++++++++++++++ 5 files changed, 154 insertions(+), 29 deletions(-) create mode 100644 designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/QrCodeBlock.kt create mode 100644 designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt create mode 100644 designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SwitchScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SwitchScreen.kt index d76bf7860..0e2c71580 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SwitchScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/SwitchScreen.kt @@ -1,41 +1,16 @@ package org.hisp.dhis.common.screens -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable 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 org.hisp.dhis.mobile.ui.designsystem.component.ColumnComponentContainer -import org.hisp.dhis.mobile.ui.designsystem.component.RowComponentContainer -import org.hisp.dhis.mobile.ui.designsystem.component.SubTitle -import org.hisp.dhis.mobile.ui.designsystem.component.Switch -import org.hisp.dhis.mobile.ui.designsystem.component.Title -import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing +import org.hisp.dhis.mobile.ui.designsystem.component.QrCodeBlock @Composable fun SwitchScreen() { ColumnComponentContainer { - Title("Switches") - SubTitle("Toggled enabled and disabled switch") - var switchOne by remember { mutableStateOf(true) } - var switchTwo by remember { mutableStateOf(true) } - var switchThree by remember { mutableStateOf(false) } - var switchFour by remember { mutableStateOf(false) } - - RowComponentContainer { - Switch(isChecked = switchOne, onCheckedChange = { switchOne = !it }) - Switch(isChecked = switchTwo, onCheckedChange = { switchTwo = !it }, enabled = false) - } - - Spacer(Modifier.size(Spacing.Spacing6)) - SubTitle("Untoggled enabled and disabled switch") - - RowComponentContainer { - Switch(isChecked = switchThree, onCheckedChange = { switchThree = !it }) - Switch(isChecked = switchFour, onCheckedChange = { switchFour = !it }, enabled = false) - } + QrCodeBlock( + data = "QR code value", + ) } } diff --git a/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt b/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt new file mode 100644 index 000000000..654dee3ef --- /dev/null +++ b/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt @@ -0,0 +1,31 @@ +package org.hisp.dhis.mobile.ui.designsystem.component.internal.qr + +import android.graphics.Bitmap +import android.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType +import com.google.zxing.qrcode.QRCodeWriter + +actual class QrCodeGenerator { + + actual fun generate(data: String): ImageBitmap { + val writer = QRCodeWriter() + val bitMatrix = writer.encode(data, BarcodeFormat.QR_CODE, 512, 512, mapOf(Pair(EncodeHintType.MARGIN, 1))) + val width = bitMatrix.width + val height = bitMatrix.height + + val pixels = IntArray(width * height) + for (y in 0 until height) { + for (x in 0 until width) { + pixels[y * width + x] = if (bitMatrix[x, y]) Color.BLACK else Color.WHITE + } + } + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + bitmap.setPixels(pixels, 0, width, 0, 0, width, height) + + return bitmap.asImageBitmap() + } +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/QrCodeBlock.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/QrCodeBlock.kt new file mode 100644 index 000000000..dea8b9450 --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/QrCodeBlock.kt @@ -0,0 +1,47 @@ +package org.hisp.dhis.mobile.ui.designsystem.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import org.hisp.dhis.mobile.ui.designsystem.component.internal.qr.rememberQrCodeGenerator +import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing +import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor + +@Composable +fun QrCodeBlock( + data: String, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier.padding(vertical = Spacing.Spacing16), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + val qrCode by rememberQrCodeGenerator(data) + // TODO: Extract out a size to a constants file? + Box(Modifier.size(240.dp)) { + qrCode?.let { bitmap -> + Image( + bitmap = bitmap, + contentDescription = null, + modifier = Modifier.matchParentSize(), + contentScale = ContentScale.FillBounds, + ) + } + } + Text( + text = data, + style = MaterialTheme.typography.titleMedium, + color = TextColor.OnSurface, + ) + } +} diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt new file mode 100644 index 000000000..b93864562 --- /dev/null +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt @@ -0,0 +1,27 @@ +package org.hisp.dhis.mobile.ui.designsystem.component.internal.qr + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.ImageBitmap + +@Composable +fun rememberQrCodeGenerator(value: String): State { + val qrCodeGenerator = LocalQrCodeGenerator.current + val result = remember(value) { mutableStateOf(null) } + + LaunchedEffect(value) { + result.value = qrCodeGenerator.generate(value) + } + + return result +} + +expect class QrCodeGenerator() { + fun generate(data: String): ImageBitmap +} + +val LocalQrCodeGenerator = staticCompositionLocalOf { QrCodeGenerator() } diff --git a/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt b/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt new file mode 100644 index 000000000..be80dfb2e --- /dev/null +++ b/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/internal/qr/QrCodeGenerator.kt @@ -0,0 +1,45 @@ +package org.hisp.dhis.mobile.ui.designsystem.component.internal.qr + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.toComposeImageBitmap +import com.google.zxing.BarcodeFormat +import com.google.zxing.EncodeHintType +import com.google.zxing.qrcode.QRCodeWriter +import java.awt.image.BufferedImage + +actual class QrCodeGenerator { + + private val colorBlack = 0xFF000000.toInt() + private val colorWhite = 0xFFFFFFFF.toInt() + + actual fun generate(data: String): ImageBitmap { + val writer = QRCodeWriter() + val bitMatrix = writer.encode( + data, + BarcodeFormat.QR_CODE, + 512, + 512, + mapOf( + Pair( + EncodeHintType.MARGIN, + 1, + ), + ), + ) + val width = bitMatrix.width + val height = bitMatrix.height + + val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) + + val pixels = IntArray(width * height) + for (y in 0 until height) { + for (x in 0 until width) { + pixels[y * width + x] = if (bitMatrix[x, y]) colorBlack else colorWhite + } + } + + image.setRGB(0, 0, width, height, pixels, 0, width) + + return image.toComposeImageBitmap() + } +}