mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
fix(shared): keep dense transfer QR codes scannable
This commit is contained in:
@@ -37,8 +37,8 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.FilterQuality
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -59,7 +59,6 @@ import com.vnidrop.app.ui.state.progressForReceiver
|
||||
import com.vnidrop.app.ui.theme.LocalVniDropColors
|
||||
import org.jetbrains.compose.resources.decodeToImageBitmap
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import qrcode.QRCode
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import vnidrop.shared.generated.resources.*
|
||||
@@ -247,7 +246,7 @@ internal fun TransferSharePanel(
|
||||
val renderedBitmap by produceState(qrBitmap, ticket, qrBitmap) {
|
||||
if (value == null) {
|
||||
value = withContext(Dispatchers.Default) {
|
||||
runCatching { QRCode.ofSquares().withSize(8).build(ticket).renderToBytes().decodeToImageBitmap() }.getOrNull()
|
||||
runCatching { buildTransferQrCode(ticket).renderToBytes().decodeToImageBitmap() }.getOrNull()
|
||||
}
|
||||
value?.let { onQrRendered(ticket, it) }
|
||||
}
|
||||
@@ -259,7 +258,12 @@ internal fun TransferSharePanel(
|
||||
color = Color.White,
|
||||
) {
|
||||
if (renderedQr != null) {
|
||||
Image(renderedQr, null, Modifier.padding(14.dp).fillMaxSize().clip(RoundedCornerShape(8.dp)))
|
||||
Image(
|
||||
bitmap = renderedQr,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(14.dp).fillMaxSize(),
|
||||
filterQuality = FilterQuality.None,
|
||||
)
|
||||
} else {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CircularProgressIndicator() }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.vnidrop.app.feature.send
|
||||
|
||||
import qrcode.QRCode
|
||||
import qrcode.raw.ErrorCorrectionLevel
|
||||
|
||||
private const val QrCellSize = 8
|
||||
private const val QrQuietZoneModules = 4
|
||||
// qrcode-kotlin 4.5.0 falls back to version 40 above version 20's byte capacity.
|
||||
private val QrLowErrorCorrectionByteCapacities = intArrayOf(
|
||||
17, 32, 53, 78, 106, 134, 154, 192, 230, 271,
|
||||
321, 367, 425, 458, 520, 586, 644, 718, 792, 858,
|
||||
929, 1003, 1091, 1171, 1273, 1367, 1465, 1528, 1628, 1732,
|
||||
1840, 1952, 2068, 2188, 2303, 2431, 2563, 2699, 2809, 2953,
|
||||
)
|
||||
|
||||
internal fun buildTransferQrCode(ticket: String): QRCode =
|
||||
QRCode.ofSquares()
|
||||
.withSize(QrCellSize)
|
||||
.withInnerSpacing(0)
|
||||
.withMargin(QrQuietZoneModules * QrCellSize)
|
||||
.withErrorCorrectionLevel(ErrorCorrectionLevel.LOW)
|
||||
.withInformationDensity(transferQrInformationDensity(ticket))
|
||||
.build(ticket)
|
||||
|
||||
internal fun transferQrInformationDensity(ticket: String): Int {
|
||||
val byteCount = ticket.encodeToByteArray().size
|
||||
val index = QrLowErrorCorrectionByteCapacities.indexOfFirst { byteCount <= it }
|
||||
return if (index >= 0) index + 1 else throw IllegalArgumentException("The invitation is too large for a QR code")
|
||||
}
|
||||
Reference in New Issue
Block a user