mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat(wifi-provision): add mPWRD-OS branding and disclaimer banner (#4978)
This commit is contained in:
parent
51251ab16a
commit
fc86c696cd
8 changed files with 67 additions and 13 deletions
|
|
@ -77,7 +77,7 @@ class ProcessRadioResponseUseCaseTest {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertTrue(result is RadioResponseResult.Metadata)
|
assertTrue(result is RadioResponseResult.Metadata)
|
||||||
assertEquals("2.5.0", (result as RadioResponseResult.Metadata).metadata.firmware_version)
|
assertEquals("2.5.0", result.metadata.firmware_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -99,7 +99,7 @@ class ProcessRadioResponseUseCaseTest {
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertTrue(result is RadioResponseResult.CannedMessages)
|
assertTrue(result is RadioResponseResult.CannedMessages)
|
||||||
assertEquals("Hello World", (result as RadioResponseResult.CannedMessages).messages)
|
assertEquals("Hello World", result.messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -133,7 +133,7 @@ class ProcessRadioResponseUseCaseTest {
|
||||||
)
|
)
|
||||||
val result = useCase(packet, 123, setOf(42))
|
val result = useCase(packet, 123, setOf(42))
|
||||||
assertTrue(result is RadioResponseResult.Owner)
|
assertTrue(result is RadioResponseResult.Owner)
|
||||||
assertEquals("Owner", (result as RadioResponseResult.Owner).user.long_name)
|
assertEquals("Owner", result.user.long_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -186,7 +186,7 @@ class ProcessRadioResponseUseCaseTest {
|
||||||
)
|
)
|
||||||
val result = useCase(packet, 123, setOf(42))
|
val result = useCase(packet, 123, setOf(42))
|
||||||
assertTrue(result is RadioResponseResult.ChannelResponse)
|
assertTrue(result is RadioResponseResult.ChannelResponse)
|
||||||
assertEquals("Main", (result as RadioResponseResult.ChannelResponse).channel.settings?.name)
|
assertEquals("Main", result.channel.settings?.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ByteArray.toByteString() = okio.ByteString.of(*this)
|
private fun ByteArray.toByteString() = okio.ByteString.of(*this)
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
|
|
@ -940,7 +940,7 @@
|
||||||
<string name="pax_metrics_log">PAX Metrics</string>
|
<string name="pax_metrics_log">PAX Metrics</string>
|
||||||
<string name="pax">PAX</string>
|
<string name="pax">PAX</string>
|
||||||
<string name="no_pax_metrics_logs">No PAX metrics available.</string>
|
<string name="no_pax_metrics_logs">No PAX metrics available.</string>
|
||||||
<string name="wifi_devices">WiFi Devices</string>
|
<string name="wifi_devices">Wi-Fi Provisioning for mPWRD-OS</string>
|
||||||
<string name="ble_devices">Bluetooth Devices</string>
|
<string name="ble_devices">Bluetooth Devices</string>
|
||||||
<string name="bluetooth_paired_devices">Paired devices</string>
|
<string name="bluetooth_paired_devices">Paired devices</string>
|
||||||
<string name="connected_device">Connected Device</string>
|
<string name="connected_device">Connected Device</string>
|
||||||
|
|
@ -1327,8 +1327,9 @@
|
||||||
|
|
||||||
<string name="connect">Connect</string>
|
<string name="connect">Connect</string>
|
||||||
<string name="done">Done</string>
|
<string name="done">Done</string>
|
||||||
<string name="wifi_provisioning">WiFi Provisioning</string>
|
<string name="wifi_provisioning">Wi-Fi Provisioning for mPWRD-OS</string>
|
||||||
<string name="wifi_provision_description">Provision WiFi credentials to your Meshtastic device via Bluetooth.</string>
|
<string name="wifi_provision_description">Provision Wi-Fi credentials to your mPWRD-OS device via Bluetooth.</string>
|
||||||
|
<string name="wifi_provision_mpwrd_disclaimer">Learn more about the mPWRD-OS project\nhttps://github.com/mPWRD-OS</string>
|
||||||
<string name="wifi_provision_scanning_ble">Searching for device…</string>
|
<string name="wifi_provision_scanning_ble">Searching for device…</string>
|
||||||
<string name="wifi_provision_device_found">Device found</string>
|
<string name="wifi_provision_device_found">Device found</string>
|
||||||
<string name="wifi_provision_device_found_detail">Ready to scan for WiFi networks.</string>
|
<string name="wifi_provision_device_found_detail">Ready to scan for WiFi networks.</string>
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,8 @@ class CoTXmlTest {
|
||||||
|
|
||||||
assertEquals("b-t-f", roundTripped.type)
|
assertEquals("b-t-f", roundTripped.type)
|
||||||
assertNotNull(roundTripped.chat)
|
assertNotNull(roundTripped.chat)
|
||||||
assertEquals("Hello World", roundTripped.chat?.message)
|
assertEquals("Hello World", roundTripped.chat.message)
|
||||||
assertEquals("Alice", roundTripped.chat?.senderCallsign)
|
assertEquals("Alice", roundTripped.chat.senderCallsign)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── XML escaping ─────────────────────────────────────────────────────────
|
// ── XML escaping ─────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ class TAKPacketConversionTest {
|
||||||
assertEquals(85, cot.status?.battery)
|
assertEquals(85, cot.status?.battery)
|
||||||
|
|
||||||
assertNotNull(cot.track)
|
assertNotNull(cot.track)
|
||||||
assertEquals(5.0, cot.track?.speed)
|
assertEquals(5.0, cot.track.speed)
|
||||||
assertEquals(90.0, cot.track?.course)
|
assertEquals(90.0, cot.track.course)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
|
||||||
```
|
```
|
||||||
<!--endregion-->
|
<!--endregion-->
|
||||||
|
|
||||||
## WiFi Provisioning System
|
## WiFi Provisioning System — for mPWRD-OS
|
||||||
|
|
||||||
The `:feature:wifi-provision` module provides BLE-based WiFi provisioning for Meshtastic devices using the Nymea network manager protocol. It scans for provisioning-capable devices, retrieves available WiFi networks, and applies credentials — all over BLE via the Kable multiplatform library.
|
The `:feature:wifi-provision` module provides BLE-based WiFi provisioning for [mPWRD-OS](https://github.com/mPWRD-OS/mPWRD-OS) devices using the Nymea network manager protocol. mPWRD-OS is a community project that combines Armbian and Meshtastic for Linux-native mesh networking hardware. This module scans for provisioning-capable devices, retrieves available WiFi networks, and applies credentials — all over BLE via the Kable multiplatform library.
|
||||||
|
|
||||||
### Architecture
|
### Architecture
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -346,3 +346,13 @@ private fun NetworkRowLongSsidPreview() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// mPWRD-OS disclaimer banner
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@PreviewLightDark
|
||||||
|
@Composable
|
||||||
|
private fun MpwrdDisclaimerBannerPreview() {
|
||||||
|
AppTheme { Surface { Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) { MpwrdDisclaimerBanner() } } }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import androidx.compose.animation.expandVertically
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.shrinkVertically
|
import androidx.compose.animation.shrinkVertically
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
|
@ -38,6 +39,7 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
|
@ -77,6 +79,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
|
|
@ -86,6 +89,7 @@ import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import org.koin.compose.viewmodel.koinViewModel
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
import org.meshtastic.core.resources.Res
|
import org.meshtastic.core.resources.Res
|
||||||
|
|
@ -93,6 +97,7 @@ import org.meshtastic.core.resources.apply
|
||||||
import org.meshtastic.core.resources.back
|
import org.meshtastic.core.resources.back
|
||||||
import org.meshtastic.core.resources.cancel
|
import org.meshtastic.core.resources.cancel
|
||||||
import org.meshtastic.core.resources.hide_password
|
import org.meshtastic.core.resources.hide_password
|
||||||
|
import org.meshtastic.core.resources.img_mpwrd_logo
|
||||||
import org.meshtastic.core.resources.password
|
import org.meshtastic.core.resources.password
|
||||||
import org.meshtastic.core.resources.show_password
|
import org.meshtastic.core.resources.show_password
|
||||||
import org.meshtastic.core.resources.wifi_provision_available_networks
|
import org.meshtastic.core.resources.wifi_provision_available_networks
|
||||||
|
|
@ -100,6 +105,7 @@ import org.meshtastic.core.resources.wifi_provision_connect_failed
|
||||||
import org.meshtastic.core.resources.wifi_provision_description
|
import org.meshtastic.core.resources.wifi_provision_description
|
||||||
import org.meshtastic.core.resources.wifi_provision_device_found
|
import org.meshtastic.core.resources.wifi_provision_device_found
|
||||||
import org.meshtastic.core.resources.wifi_provision_device_found_detail
|
import org.meshtastic.core.resources.wifi_provision_device_found_detail
|
||||||
|
import org.meshtastic.core.resources.wifi_provision_mpwrd_disclaimer
|
||||||
import org.meshtastic.core.resources.wifi_provision_no_networks
|
import org.meshtastic.core.resources.wifi_provision_no_networks
|
||||||
import org.meshtastic.core.resources.wifi_provision_scan_failed
|
import org.meshtastic.core.resources.wifi_provision_scan_failed
|
||||||
import org.meshtastic.core.resources.wifi_provision_scan_networks
|
import org.meshtastic.core.resources.wifi_provision_scan_networks
|
||||||
|
|
@ -110,6 +116,7 @@ import org.meshtastic.core.resources.wifi_provision_signal_strength
|
||||||
import org.meshtastic.core.resources.wifi_provision_ssid_label
|
import org.meshtastic.core.resources.wifi_provision_ssid_label
|
||||||
import org.meshtastic.core.resources.wifi_provision_ssid_placeholder
|
import org.meshtastic.core.resources.wifi_provision_ssid_placeholder
|
||||||
import org.meshtastic.core.resources.wifi_provisioning
|
import org.meshtastic.core.resources.wifi_provisioning
|
||||||
|
import org.meshtastic.core.ui.component.AutoLinkText
|
||||||
import org.meshtastic.feature.wifiprovision.WifiProvisionError
|
import org.meshtastic.feature.wifiprovision.WifiProvisionError
|
||||||
import org.meshtastic.feature.wifiprovision.WifiProvisionUiState
|
import org.meshtastic.feature.wifiprovision.WifiProvisionUiState
|
||||||
import org.meshtastic.feature.wifiprovision.WifiProvisionUiState.Phase
|
import org.meshtastic.feature.wifiprovision.WifiProvisionUiState.Phase
|
||||||
|
|
@ -164,6 +171,8 @@ fun WifiProvisionScreen(
|
||||||
Spacer(Modifier.height(4.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MpwrdDisclaimerBanner()
|
||||||
|
|
||||||
Crossfade(targetState = screenKey(uiState), label = "wifi_provision") { key ->
|
Crossfade(targetState = screenKey(uiState), label = "wifi_provision") { key ->
|
||||||
when (key) {
|
when (key) {
|
||||||
ScreenKey.ConnectingBle -> ScanningBleContent()
|
ScreenKey.ConnectingBle -> ScanningBleContent()
|
||||||
|
|
@ -481,6 +490,40 @@ internal fun NetworkRow(network: WifiNetwork, isSelected: Boolean, onClick: () -
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// mPWRD-OS disclaimer banner
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private const val MPWRD_LOGO_SIZE_DP = 40
|
||||||
|
|
||||||
|
/** Branded disclaimer banner shown at the top of the provisioning screen. */
|
||||||
|
@Composable
|
||||||
|
internal fun MpwrdDisclaimerBanner() {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerHigh),
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(12.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
|
verticalAlignment = Alignment.Top,
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(Res.drawable.img_mpwrd_logo),
|
||||||
|
contentDescription = "mPWRD-OS",
|
||||||
|
modifier = Modifier.size(MPWRD_LOGO_SIZE_DP.dp).clip(RoundedCornerShape(8.dp)),
|
||||||
|
)
|
||||||
|
AutoLinkText(
|
||||||
|
text = stringResource(Res.string.wifi_provision_mpwrd_disclaimer),
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Shared layout wrapper for centered status screens
|
// Shared layout wrapper for centered status screens
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue