Link new device using QrCode.

This commit is contained in:
Benoit Marty
2025-12-04 10:52:26 +01:00
committed by Benoit Marty
parent 028741d81c
commit fd446e98dd
94 changed files with 4431 additions and 36 deletions

View File

@@ -19,4 +19,5 @@ dependencies {
implementation(libs.androidx.camera.view)
implementation(libs.androidx.camera.camera2)
implementation(libs.zxing.cpp)
implementation(libs.google.zxing)
}

View File

@@ -31,6 +31,7 @@ import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.LocalLifecycleOwner
@@ -117,7 +118,13 @@ fun QrCodeCameraView(
.background(color = ElementTheme.colors.bgSubtlePrimary),
contentAlignment = Alignment.Center,
) {
Text("CameraView")
Text(
text = buildString {
append("CameraView\n")
append(if (isScanning) "scanning" else "frozen")
},
textAlign = TextAlign.Center,
)
}
} else {
AndroidView(

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.qrcode
import android.graphics.Bitmap
import android.graphics.Color
import androidx.annotation.ColorInt
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
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 androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntSize
import com.google.zxing.BarcodeFormat
import com.google.zxing.common.BitMatrix
import com.google.zxing.qrcode.QRCodeWriter
import io.element.android.libraries.designsystem.modifiers.squareSize
import io.element.android.libraries.designsystem.utils.ForceMaxBrightness
private fun String.toBitMatrix(size: Int): BitMatrix {
return QRCodeWriter().encode(
this,
BarcodeFormat.QR_CODE,
size,
size,
)
}
private fun BitMatrix.toBitmap(
@ColorInt backgroundColor: Int = Color.WHITE,
@ColorInt foregroundColor: Int = Color.BLACK,
): Bitmap {
val colorBuffer = IntArray(width * height)
var rowOffset = 0
for (y in 0 until height) {
for (x in 0 until width) {
val arrayIndex = x + rowOffset
colorBuffer[arrayIndex] = if (get(x, y)) foregroundColor else backgroundColor
}
rowOffset += width
}
return Bitmap.createBitmap(colorBuffer, width, height, Bitmap.Config.ARGB_8888)
}
@Composable
fun QrCodeImage(
data: String,
forceMaxBrightness: Boolean = true,
modifier: Modifier = Modifier,
) {
if (forceMaxBrightness) {
ForceMaxBrightness()
}
var size by remember { mutableStateOf(IntSize.Zero) }
Box(
modifier = modifier
.squareSize()
.onSizeChanged {
size = it
},
) {
val image = remember(data, size) {
val sideSide = maxOf(size.width, size.height).coerceAtLeast(128)
data.toBitMatrix(sideSide).toBitmap().asImageBitmap()
}
Image(
contentDescription = null,
bitmap = image,
)
}
}
@Composable
@Preview
internal fun QrCodeViewPreview() {
QrCodeImage(
modifier = Modifier.fillMaxHeight(),
data = "RANDOM_QRCODE_DATA",
)
}