DEV Community

Cover image for QRKit — QRCode Generator in Compose Multiplatform for Android and iOS
Mobile innovation Network
Mobile innovation Network

Posted on

QRKit — QRCode Generator in Compose Multiplatform for Android and iOS

QRKit is a Kotlin Multiplatform library for Qr Generator in your Android or iOS App.

Installation

Add the dependency to your build.gradle.kts file:

commonMain.dependencies {
    implementation("network.chaintech:qr-kit:1.0.2")
}
Enter fullscreen mode Exit fullscreen mode

Example

QRCodeImage(
    url: String,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null,
    filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
    onSuccess: (ImageBitmap) -> Unit = { qrImage -> },
    onFailure: (String) -> Unit = { message -> }
)
Enter fullscreen mode Exit fullscreen mode
  • url: The URL of the QR code image to be displayed.
  • contentDescription: A textual description of the image content for accessibility purposes. It's optional.
  • modifier: Modifier for modifying the layout of the QR code image.
  • alignment: Alignment of the QR code image within its layout bounds. Default is Alignment.Center.
  • contentScale: The scale strategy for fitting the QR code image content within its layout bounds. Default is ContentScale.Fit.
  • alpha: The opacity of the QR code image, ranging from 0.0 (fully transparent) to 1.0 (fully opaque). Default is DefaultAlpha.
  • colorFilter: A color filter to apply to the QR code image. Default is null.
  • filterQuality: The quality of the filtering applied to the QR code image. Default is DrawScope.DefaultFilterQuality.
  • onSuccess: Callback invoked when the QR code image is successfully loaded and decoded, passing the decoded ImageBitmap as a parameter.
  • onFailure: Callback invoked when there's a failure during loading or decoding the QR code image, passing an error message as a parameter.

Usage

@Composable
fun QrGeneratorCompose(paddingValues: PaddingValues) {
    val scope = rememberCoroutineScope()
    var inputText by rememberSaveable { mutableStateOf("") }
    var isInputTextError by rememberSaveable { mutableStateOf(false) }
    val generatedQRCode = remember { mutableStateOf<ImageBitmap?>(null) }
    val focusManager = LocalFocusManager.current
    val snackBarHostState = LocalSnackBarHostState.current

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier
            .fillMaxSize()
            .padding(paddingValues)
            .padding(horizontal = 16.dp)
            .padding(top = 22.dp)
            .verticalScroll(rememberScrollState())
    ) {
        QRCodeImage(
            url = "https://www.google.com/",
            contentScale = ContentScale.Fit,
            contentDescription = "QR Code",
            modifier = Modifier
                .size(150.dp),
            onSuccess = { qrImage ->

            },
            onFailure = {
                scope.launch {
                    snackBarHostState.showSnackbar("Something went wrong")
                }
            }
        )

        OutlinedTextField(
            value = inputText,
            onValueChange = {
                inputText = it
                isInputTextError = inputText.isBlank()
            },
            label = { Text("Please enter text", style = MaterialTheme.typography.titleMedium) },
            textStyle = MaterialTheme.typography.bodyLarge,
            singleLine = false,
            isError = isInputTextError,
            modifier = Modifier.padding(top = 14.dp).fillMaxWidth(),
            shape = RoundedCornerShape(10),
            trailingIcon = {
                if (isInputTextError) {
                    Icon(
                        imageVector = Icons.Default.Error,
                        contentDescription = "Error",
                        tint = Color.Red
                    )
                }
            }
        )
        Spacer(modifier = Modifier.height(22.dp))
        Button(
            onClick = {
                if (inputText.isBlank()) {
                    isInputTextError = true
                    return@Button
                } else {
                    focusManager.clearFocus()
                    generateQrCode(
                        inputText,
                        onSuccess = { info, qrCode ->
                            generatedQRCode.value = qrCode
                        },
                        onFailure = {
                            scope.launch {
                                snackBarHostState.showSnackbar("Something went wrong")
                            }
                        }
                    )
                }
            },
            modifier = Modifier
                .fillMaxWidth()
                .height(54.dp),
            colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF007AFF)),
            shape = RoundedCornerShape(25)
        ) {
            Text(
                text = "Generate code",
                style = MaterialTheme.typography.bodyLarge,
                color = Color.White
            )
        }
        generatedQRCode.value?.let { qrCode ->
            QRCodeViewer(qrCode)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
@Composable
fun QRCodeViewer(qrCode: ImageBitmap) {
    var isLoading by rememberSaveable { mutableStateOf(true) }
    LaunchedEffect(Unit) {
        delay(500)
        isLoading = false
    }

    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize()
            .padding(vertical = 22.dp),
    ) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .background(Color.White)
                .border(BorderStroke(3.dp, Color.Black))
                .size(250.dp)
        ) {
            if (isLoading) {
                QRCodeShimmer()
                return@Column
            }

            Image(
                bitmap = qrCode,
                contentScale = ContentScale.Fit,
                contentDescription = "QR Code",
                modifier = Modifier
                    .fillMaxSize(1f)
            )
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
@Composable
fun QRCodeShimmer() {
    val shimmerColorShades = listOf(
        Color.Gray.copy(0.5f),
        Color.LightGray.copy(0.2f),
        Color.Gray.copy(0.5f),
    )

    val transition = rememberInfiniteTransition()
    val transitionAnim by transition.animateFloat(
        initialValue = 0f,
        targetValue = 1000f,
        animationSpec = infiniteRepeatable(
            tween(durationMillis = 1200, easing = FastOutSlowInEasing),
            RepeatMode.Reverse
        )
    )

    val brush = Brush.linearGradient(
        colors = shimmerColorShades,
        start = Offset(10f, 10f),
        end = Offset(transitionAnim, transitionAnim)
    )

    Surface(
        color = Color.Transparent,
        modifier = Modifier.alpha(.3f)
    ) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier.size(300.dp)
        ) {
            Spacer(
                modifier = Modifier
                    .fillMaxSize()
                    .background(brush = brush)
            )
            Spacer(
                modifier = Modifier
                    .fillMaxSize(.8f)
                    .background(brush = brush)
            )
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Final Demo:

QRKit

Conclusion

Integrating a QR code generator library enhances functionality, streamlines processes, and improves user experience in your application.

https://github.com/ChainTechNetwork/QRKitComposeMultiplatform.git

Happy coding ❤

Connect with us 👇

Top comments (0)