Repository: Automattic/pocket-casts-android
File: automotive/src/main/java/au/com/shiftyjelly/pocketcasts/compose/QrPainter.kt (Kotlin)

Code before:
import androidx.compose.ui.unit.dp
import androidx.core.graphics.createBitmap
import androidx.core.graphics.set
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber

private sealed class QrState {
    object Loading : QrState()
    data class Success(val bitmap: Bitmap) : QrState()
    object Error : QrState()
}

@Composable
fun rememberQrPainter(
    content: String,
    size: Dp = 300.dp,
): Painter {
    val density = LocalDensity.current
    val sizePx = with(density) { size.roundToPx() }

    var qrState by remember(content, sizePx) {
        mutableStateOf<QrState>(QrState.Loading)
    }

    LaunchedEffect(content, sizePx) {
        qrState = QrState.Loading

        launch(Dispatchers.IO) {
            try {
                if (content.isBlank()) {
                    qrState = QrState.Error
                    return@launch
                }

                val qrCodeWriter = QRCodeWriter()
                val encodeHints = mutableMapOf<EncodeHintType, Any?>().apply {
                    this[EncodeHintType.MARGIN] = 0
                    this[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
                }

                val bitMatrix = qrCodeWriter.encode(
                    content,
                    BarcodeFormat.QR_CODE,
                    sizePx,
                    sizePx,
                    encodeHints,

Review comment (suggestion):
💡 this and the `LaunchedEffect` could be replaced with a single `produceState<QrState>` 
https://developer.android.com/develop/ui/compose/side-effects

Code after:
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import timber.log.Timber

private sealed class QrState {
    object Loading : QrState()
    data class Success(val bitmap: Bitmap) : QrState()
    object Error : QrState()
}

@Composable
fun rememberQrPainter(
    content: String,
    size: Dp = 300.dp,
): Painter {
    val density = LocalDensity.current
    val sizePx = with(density) { size.roundToPx() }

    val qrState by produceState<QrState>(QrState.Loading, content, sizePx) {
        launch(Dispatchers.IO) {
            try {
                if (content.isBlank()) {
                    value = QrState.Error
                    return@launch
                }

                val qrCodeWriter = QRCodeWriter()
                val encodeHints = mutableMapOf<EncodeHintType, Any?>().apply {
                    this[EncodeHintType.MARGIN] = 0
                    this[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
                }

                val bitMatrix = qrCodeWriter.encode(
                    content,
                    BarcodeFormat.QR_CODE,
                    sizePx,
                    sizePx,
                    encodeHints,
                )

                val newBitmap = createBitmap(bitMatrix.width, bitMatrix.height)

                for (x in 0 until bitMatrix.width) {
                    for (y in 0 until bitMatrix.height) {
                        val shouldColorPixel = bitMatrix[x, y]
                        val color = if (shouldColorPixel) Color.WHITE else Color.BLACK
                        newBitmap[x, y] = color