kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
`ConnectionsScreen` available BLE devices (#3298)
rodzic
526ca9b854
commit
502e417338
|
@ -25,23 +25,18 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.rememberScrollState
|
||||
import androidx.compose.foundation.selection.selectable
|
||||
import androidx.compose.foundation.selection.selectableGroup
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Language
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
|
@ -49,14 +44,12 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.geeksville.mesh.ConfigProtos
|
||||
|
@ -118,7 +111,8 @@ fun ConnectionsScreen(
|
|||
val regionUnset = config.lora.region == ConfigProtos.Config.LoRaConfig.RegionCode.UNSET
|
||||
val bluetoothRssi by connectionsViewModel.bluetoothRssi.collectAsStateWithLifecycle()
|
||||
|
||||
val bleDevices by scanModel.bleDevicesForUi.collectAsStateWithLifecycle()
|
||||
val bondedBleDevices by scanModel.bleDevicesForUi.collectAsStateWithLifecycle()
|
||||
val scannedBleDevices by scanModel.scanResult.observeAsState(emptyMap())
|
||||
val discoveredTcpDevices by scanModel.discoveredTcpDevicesForUi.collectAsStateWithLifecycle()
|
||||
val recentTcpDevices by scanModel.recentTcpDevicesForUi.collectAsStateWithLifecycle()
|
||||
val usbDevices by scanModel.usbDevicesForUi.collectAsStateWithLifecycle()
|
||||
|
@ -152,15 +146,6 @@ fun ConnectionsScreen(
|
|||
}
|
||||
}
|
||||
|
||||
// State for the device scan dialog
|
||||
var showScanDialog by remember { mutableStateOf(false) }
|
||||
val scanResults by scanModel.scanResult.observeAsState(emptyMap())
|
||||
|
||||
// Observe scan results to show the dialog
|
||||
if (scanResults.isNotEmpty()) {
|
||||
showScanDialog = true
|
||||
}
|
||||
|
||||
LaunchedEffect(connectionState, regionUnset) {
|
||||
when (connectionState) {
|
||||
ConnectionState.CONNECTED -> {
|
||||
|
@ -245,7 +230,11 @@ fun ConnectionsScreen(
|
|||
DeviceType.BLE -> {
|
||||
BLEDevices(
|
||||
connectionState = connectionState,
|
||||
btDevices = bleDevices,
|
||||
bondedDevices = bondedBleDevices,
|
||||
availableDevices =
|
||||
scannedBleDevices.values.toList().filterNot { available ->
|
||||
bondedBleDevices.any { it.address == available.address }
|
||||
},
|
||||
selectedDevice = selectedDevice,
|
||||
scanModel = scanModel,
|
||||
bluetoothEnabled = bluetoothState.enabled,
|
||||
|
@ -280,7 +269,7 @@ fun ConnectionsScreen(
|
|||
val showWarningNotPaired =
|
||||
!connectionState.isConnected() &&
|
||||
!hasShownNotPairedWarning &&
|
||||
bleDevices.none { it is DeviceListEntry.Ble && it.bonded }
|
||||
bondedBleDevices.none { it is DeviceListEntry.Ble && it.bonded }
|
||||
if (showWarningNotPaired) {
|
||||
Text(
|
||||
text = stringResource(R.string.warning_not_paired),
|
||||
|
@ -294,55 +283,6 @@ fun ConnectionsScreen(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compose Device Scan Dialog
|
||||
if (showScanDialog) {
|
||||
Dialog(
|
||||
onDismissRequest = {
|
||||
showScanDialog = false
|
||||
scanModel.clearScanResults()
|
||||
},
|
||||
) {
|
||||
Surface(shape = MaterialTheme.shapes.medium) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(
|
||||
text = "Select a Bluetooth device",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
modifier = Modifier.padding(bottom = 16.dp),
|
||||
)
|
||||
Column(modifier = Modifier.selectableGroup()) {
|
||||
scanResults.values.forEach { device ->
|
||||
Row(
|
||||
modifier =
|
||||
Modifier.fillMaxWidth()
|
||||
.selectable(
|
||||
selected = false, // No pre-selection in this dialog
|
||||
onClick = {
|
||||
scanModel.onSelected(device)
|
||||
scanModel.clearScanResults()
|
||||
showScanDialog = false
|
||||
},
|
||||
)
|
||||
.padding(vertical = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(text = device.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
TextButton(
|
||||
onClick = {
|
||||
scanModel.clearScanResults()
|
||||
showScanDialog = false
|
||||
},
|
||||
) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.fillMaxWidth().padding(8.dp)) {
|
||||
|
|
|
@ -69,7 +69,8 @@ import org.meshtastic.core.ui.component.TitledCard
|
|||
@Composable
|
||||
fun BLEDevices(
|
||||
connectionState: ConnectionState,
|
||||
btDevices: List<DeviceListEntry>,
|
||||
bondedDevices: List<DeviceListEntry>,
|
||||
availableDevices: List<DeviceListEntry>,
|
||||
selectedDevice: String,
|
||||
scanModel: BTScanModel,
|
||||
bluetoothEnabled: Boolean,
|
||||
|
@ -153,7 +154,7 @@ fun BLEDevices(
|
|||
}
|
||||
}
|
||||
|
||||
if (btDevices.isEmpty()) {
|
||||
if (bondedDevices.isEmpty() && availableDevices.isEmpty()) {
|
||||
EmptyStateContent(
|
||||
imageVector = Icons.Rounded.BluetoothDisabled,
|
||||
text =
|
||||
|
@ -165,18 +166,19 @@ fun BLEDevices(
|
|||
actionButton = scanButton,
|
||||
)
|
||||
} else {
|
||||
TitledCard(title = stringResource(R.string.bluetooth_paired_devices)) {
|
||||
btDevices.forEach { device ->
|
||||
val connected =
|
||||
connectionState == ConnectionState.CONNECTED && device.fullAddress == selectedDevice
|
||||
DeviceListItem(
|
||||
connected = connected,
|
||||
device = device,
|
||||
onSelect = { scanModel.onSelected(device) },
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
bondedDevices.Section(
|
||||
title = stringResource(R.string.bluetooth_paired_devices),
|
||||
connectionState = connectionState,
|
||||
selectedDevice = selectedDevice,
|
||||
onSelect = scanModel::onSelected,
|
||||
)
|
||||
|
||||
availableDevices.Section(
|
||||
title = stringResource(R.string.bluetooth_available_devices),
|
||||
connectionState = connectionState,
|
||||
selectedDevice = selectedDevice,
|
||||
onSelect = scanModel::onSelected,
|
||||
)
|
||||
|
||||
scanButton()
|
||||
}
|
||||
|
@ -213,3 +215,25 @@ private fun checkPermissionsAndScan(
|
|||
permissionsState.launchMultiplePermissionRequest()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun List<DeviceListEntry>.Section(
|
||||
title: String,
|
||||
connectionState: ConnectionState,
|
||||
selectedDevice: String,
|
||||
onSelect: (DeviceListEntry) -> Unit,
|
||||
) {
|
||||
if (isNotEmpty()) {
|
||||
TitledCard(title = title) {
|
||||
forEach { device ->
|
||||
val connected = connectionState == ConnectionState.CONNECTED && device.fullAddress == selectedDevice
|
||||
DeviceListItem(
|
||||
connected = connected,
|
||||
device = device,
|
||||
onSelect = { onSelect(device) },
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -821,7 +821,8 @@
|
|||
<string name="no_pax_metrics_logs">No PAX metrics logs available.</string>
|
||||
<string name="wifi_devices">WiFi Devices</string>
|
||||
<string name="ble_devices">BLE Devices</string>
|
||||
<string name="bluetooth_paired_devices">Paired Devices</string>
|
||||
<string name="bluetooth_paired_devices">Paired devices</string>
|
||||
<string name="bluetooth_available_devices">Available devices</string>
|
||||
<string name="connected_device">Connected Device</string>
|
||||
|
||||
<string name="routing_error_rate_limit_exceeded">Rate Limit Exceeded. Please try again later.</string>
|
||||
|
|
Ładowanie…
Reference in New Issue