QRKit — QRCode Generator in Compose Multiplatform

ssvaghasiya
Mobile Innovation Network
4 min readApr 19, 2024

QRKit is a Kotlin Multiplatform library for Qr Generator in your Android, iOS & Desktop App.

Installation

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

commonMain.dependencies {
implementation("network.chaintech:qr-kit:1.0.6")
}

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 -> }
)
  • 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)
}
}
}
@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)
)
}
}
}
@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)
)
}
}
}

Final Demo:

For QRCode Scanner follow below link:

https://medium.com/mobile-innovation-network/qrkit-barcode-scanning-in-compose-multiplatform-for-android-and-ios-77cf5d84f719

Conclusion

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

Happy coding ❤

--

--