From f5cc7cf4ad9413407c61dd9d9ee0761124acadfe Mon Sep 17 00:00:00 2001 From: andrekir Date: Sun, 18 Aug 2024 10:23:10 -0300 Subject: [PATCH] feat(NetworkConfig): add QR code scan for WiFi credentials closes #1192 --- .../config/NetworkConfigItemList.kt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt index 86d60bce0..26d30f2d2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt @@ -1,10 +1,16 @@ package com.geeksville.mesh.ui.components.config +import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Button import androidx.compose.material.Divider +import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -15,6 +21,7 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import com.geeksville.mesh.ConfigProtos.Config.NetworkConfig import com.geeksville.mesh.copy import com.geeksville.mesh.ui.components.DropDownPreference @@ -24,6 +31,8 @@ import com.geeksville.mesh.ui.components.EditTextPreference import com.geeksville.mesh.ui.components.PreferenceCategory import com.geeksville.mesh.ui.components.PreferenceFooter import com.geeksville.mesh.ui.components.SwitchPreference +import com.journeyapps.barcodescanner.ScanContract +import com.journeyapps.barcodescanner.ScanOptions @Composable fun NetworkConfigItemList( @@ -34,6 +43,33 @@ fun NetworkConfigItemList( val focusManager = LocalFocusManager.current var networkInput by rememberSaveable { mutableStateOf(networkConfig) } + fun extractWifiCredentials(qrCode: String) = Regex("""WIFI:S:(.*?);.*?P:(.*?);""") + .find(qrCode)?.destructured + ?.let { (ssid, password) -> ssid to password } + ?: (null to null) + + val barcodeLauncher = rememberLauncherForActivityResult(ScanContract()) { result -> + if (result.contents != null) { + val (ssid, psk) = extractWifiCredentials(result.contents) + if (ssid != null && psk != null) { + networkInput = networkInput.copy { wifiSsid = ssid } + networkInput = networkInput.copy { wifiPsk = psk } + } else { + // TODO show: "Invalid WiFi Credential QR code format" + } + } + } + + fun zxingScan() { + val zxingScan = ScanOptions().apply { + setCameraId(0) + setPrompt("") + setBeepEnabled(false) + setDesiredBarcodeFormats(ScanOptions.QR_CODE) + } + barcodeLauncher.launch(zxingScan) + } + LazyColumn( modifier = Modifier.fillMaxSize() ) { @@ -71,6 +107,18 @@ fun NetworkConfigItemList( onValueChanged = { networkInput = networkInput.copy { wifiPsk = it } }) } + item { + Button( + onClick = { zxingScan() }, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp) + .height(48.dp), + ) { + Text(text = "Scan WiFi QR code") + } + } + item { EditTextPreference(title = "NTP server", value = networkInput.ntpServer,