mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Refactor map layer management and navigation infrastructure (#4921)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
b608a04ca4
commit
a005231d94
142 changed files with 5408 additions and 3090 deletions
|
|
@ -89,6 +89,7 @@ import org.meshtastic.core.database.entity.FirmwareRelease
|
|||
import org.meshtastic.core.database.entity.FirmwareReleaseType
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.UiText
|
||||
import org.meshtastic.core.resources.back
|
||||
import org.meshtastic.core.resources.cancel
|
||||
import org.meshtastic.core.resources.chirpy
|
||||
|
|
@ -713,7 +714,11 @@ private fun ProgressContent(
|
|||
|
||||
Spacer(Modifier.height(24.dp))
|
||||
|
||||
Text(progressState.message, style = MaterialTheme.typography.titleMedium, textAlign = TextAlign.Center)
|
||||
Text(
|
||||
progressState.message.asString(),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
val details = progressState.details
|
||||
if (details != null) {
|
||||
|
|
@ -829,7 +834,7 @@ private fun VerificationFailedState(onRetry: () -> Unit, onIgnore: () -> Unit) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ErrorState(error: String, onRetry: () -> Unit) {
|
||||
private fun ErrorState(error: UiText, onRetry: () -> Unit) {
|
||||
Icon(
|
||||
MeshtasticIcons.Dangerous,
|
||||
contentDescription = null,
|
||||
|
|
@ -838,7 +843,7 @@ private fun ErrorState(error: String, onRetry: () -> Unit) {
|
|||
)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
Text(
|
||||
stringResource(Res.string.firmware_update_error, error),
|
||||
stringResource(Res.string.firmware_update_error, error.asString()),
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.meshtastic.core.database.entity.FirmwareRelease
|
|||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.UiText
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
import org.meshtastic.core.resources.firmware_update_nordic_failed
|
||||
import org.meshtastic.core.resources.firmware_update_not_found_in_release
|
||||
|
|
@ -68,7 +69,11 @@ class NordicDfuHandler(
|
|||
.replace(Regex(":?\\s*%1\\\$d%?"), "")
|
||||
.trim()
|
||||
|
||||
updateState(FirmwareUpdateState.Downloading(ProgressState(message = downloadingMsg, progress = 0f)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = UiText.DynamicString(downloadingMsg), progress = 0f),
|
||||
),
|
||||
)
|
||||
|
||||
if (firmwareUri != null) {
|
||||
initiateDfu(target, hardware, firmwareUri, updateState)
|
||||
|
|
@ -79,14 +84,18 @@ class NordicDfuHandler(
|
|||
val percent = (progress * PERCENT_MAX).toInt()
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = downloadingMsg, progress = progress, details = "$percent%"),
|
||||
ProgressState(
|
||||
message = UiText.DynamicString(downloadingMsg),
|
||||
progress = progress,
|
||||
details = "$percent%",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (firmwareFile == null) {
|
||||
val errorMsg = getString(Res.string.firmware_update_not_found_in_release, hardware.displayName)
|
||||
updateState(FirmwareUpdateState.Error(errorMsg))
|
||||
updateState(FirmwareUpdateState.Error(UiText.DynamicString(errorMsg)))
|
||||
null
|
||||
} else {
|
||||
initiateDfu(target, hardware, CommonUri.parse("file://$firmwareFile"), updateState)
|
||||
|
|
@ -98,7 +107,7 @@ class NordicDfuHandler(
|
|||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.e(e) { "Nordic DFU Update failed" }
|
||||
val errorMsg = getString(Res.string.firmware_update_nordic_failed)
|
||||
updateState(FirmwareUpdateState.Error(e.message ?: errorMsg))
|
||||
updateState(FirmwareUpdateState.Error(UiText.DynamicString(e.message ?: errorMsg)))
|
||||
null
|
||||
}
|
||||
|
||||
|
|
@ -108,8 +117,9 @@ class NordicDfuHandler(
|
|||
firmwareUri: CommonUri,
|
||||
updateState: (FirmwareUpdateState) -> Unit,
|
||||
) {
|
||||
val startingMsg = getString(Res.string.firmware_update_starting_service)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(startingMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(ProgressState(UiText.Resource(Res.string.firmware_update_starting_service))),
|
||||
)
|
||||
|
||||
// n = Nordic (Legacy prefix handling in mesh service)
|
||||
radioController.setDeviceAddress("n")
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.meshtastic.core.model.DeviceHardware
|
|||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.UiText
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
import org.meshtastic.core.resources.firmware_update_rebooting
|
||||
import org.meshtastic.core.resources.firmware_update_retrieval_failed
|
||||
|
|
@ -56,11 +57,14 @@ class UsbUpdateHandler(
|
|||
.replace(Regex(":?\\s*%1\\\$d%?"), "")
|
||||
.trim()
|
||||
|
||||
updateState(FirmwareUpdateState.Downloading(ProgressState(message = downloadingMsg, progress = 0f)))
|
||||
|
||||
val rebootingMsg = getString(Res.string.firmware_update_rebooting)
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = UiText.DynamicString(downloadingMsg), progress = 0f),
|
||||
),
|
||||
)
|
||||
|
||||
if (firmwareUri != null) {
|
||||
val rebootingMsg = UiText.Resource(Res.string.firmware_update_rebooting)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(rebootingMsg)))
|
||||
val myNodeNum = nodeRepository.myNodeInfo.value?.myNodeNum ?: 0
|
||||
radioController.rebootToDfu(myNodeNum)
|
||||
|
|
@ -74,22 +78,28 @@ class UsbUpdateHandler(
|
|||
val percent = (progress * PERCENT_MAX).toInt()
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = downloadingMsg, progress = progress, details = "$percent%"),
|
||||
ProgressState(
|
||||
message = UiText.DynamicString(downloadingMsg),
|
||||
progress = progress,
|
||||
details = "$percent%",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (firmwareFile == null) {
|
||||
val retrievalFailedMsg = getString(Res.string.firmware_update_retrieval_failed)
|
||||
updateState(FirmwareUpdateState.Error(retrievalFailedMsg))
|
||||
updateState(FirmwareUpdateState.Error(UiText.DynamicString(retrievalFailedMsg)))
|
||||
null
|
||||
} else {
|
||||
val rebootingMsg = UiText.Resource(Res.string.firmware_update_rebooting)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(rebootingMsg)))
|
||||
val myNodeNum = nodeRepository.myNodeInfo.value?.myNodeNum ?: 0
|
||||
radioController.rebootToDfu(myNodeNum)
|
||||
delay(REBOOT_DELAY)
|
||||
|
||||
updateState(FirmwareUpdateState.AwaitingFileSave(firmwareFile, java.io.File(firmwareFile).name))
|
||||
val fileName = java.io.File(firmwareFile).name
|
||||
updateState(FirmwareUpdateState.AwaitingFileSave(firmwareFile, fileName))
|
||||
firmwareFile
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +108,7 @@ class UsbUpdateHandler(
|
|||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.e(e) { "USB Update failed" }
|
||||
val usbFailedMsg = getString(Res.string.firmware_update_usb_failed)
|
||||
updateState(FirmwareUpdateState.Error(e.message ?: usbFailedMsg))
|
||||
updateState(FirmwareUpdateState.Error(UiText.DynamicString(e.message ?: usbFailedMsg)))
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.meshtastic.core.model.DeviceHardware
|
|||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.UiText
|
||||
import org.meshtastic.core.resources.firmware_update_connecting_attempt
|
||||
import org.meshtastic.core.resources.firmware_update_downloading_percent
|
||||
import org.meshtastic.core.resources.firmware_update_erasing
|
||||
|
|
@ -163,18 +164,19 @@ class Esp32OtaUpdateHandler(
|
|||
throw e
|
||||
} catch (e: OtaProtocolException.HashRejected) {
|
||||
Logger.e(e) { "ESP32 OTA: Hash rejected by device" }
|
||||
val msg = getString(Res.string.firmware_update_hash_rejected)
|
||||
updateState(FirmwareUpdateState.Error(msg))
|
||||
updateState(FirmwareUpdateState.Error(UiText.Resource(Res.string.firmware_update_hash_rejected)))
|
||||
null
|
||||
} catch (e: OtaProtocolException) {
|
||||
Logger.e(e) { "ESP32 OTA: Protocol error" }
|
||||
val msg = getString(Res.string.firmware_update_ota_failed, e.message ?: "")
|
||||
updateState(FirmwareUpdateState.Error(msg))
|
||||
updateState(
|
||||
FirmwareUpdateState.Error(UiText.Resource(Res.string.firmware_update_ota_failed, e.message ?: "")),
|
||||
)
|
||||
null
|
||||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
Logger.e(e) { "ESP32 OTA: Unexpected error" }
|
||||
val msg = getString(Res.string.firmware_update_ota_failed, e.message ?: "")
|
||||
updateState(FirmwareUpdateState.Error(msg))
|
||||
updateState(
|
||||
FirmwareUpdateState.Error(UiText.Resource(Res.string.firmware_update_ota_failed, e.message ?: "")),
|
||||
)
|
||||
null
|
||||
}
|
||||
|
||||
|
|
@ -186,12 +188,20 @@ class Esp32OtaUpdateHandler(
|
|||
): String? {
|
||||
val downloadingMsg =
|
||||
getString(Res.string.firmware_update_downloading_percent, 0).replace(Regex(":?\\s*%1\\\$d%?"), "").trim()
|
||||
updateState(FirmwareUpdateState.Downloading(ProgressState(message = downloadingMsg, progress = 0f)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = UiText.DynamicString(downloadingMsg), progress = 0f),
|
||||
),
|
||||
)
|
||||
return firmwareRetriever.retrieveEsp32Firmware(release, hardware) { progress ->
|
||||
val percent = (progress * PERCENT_MAX).toInt()
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = downloadingMsg, progress = progress, details = "$percent%"),
|
||||
ProgressState(
|
||||
message = UiText.DynamicString(downloadingMsg),
|
||||
progress = progress,
|
||||
details = "$percent%",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -234,11 +244,18 @@ class Esp32OtaUpdateHandler(
|
|||
val downloadingMsg =
|
||||
getString(Res.string.firmware_update_downloading_percent, 0).replace(Regex(":?\\s*%1\\\$d%?"), "").trim()
|
||||
|
||||
updateState(FirmwareUpdateState.Downloading(ProgressState(message = downloadingMsg, progress = 0f)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = UiText.DynamicString(downloadingMsg), progress = 0f),
|
||||
),
|
||||
)
|
||||
|
||||
return if (firmwareUri != null) {
|
||||
val extractingMsg = getString(Res.string.firmware_update_extracting)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(message = extractingMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(
|
||||
ProgressState(message = UiText.Resource(Res.string.firmware_update_extracting)),
|
||||
),
|
||||
)
|
||||
getFirmwareFromUri(firmwareUri)
|
||||
} else {
|
||||
val firmwareFile =
|
||||
|
|
@ -246,14 +263,21 @@ class Esp32OtaUpdateHandler(
|
|||
val percent = (progress * PERCENT_MAX).toInt()
|
||||
updateState(
|
||||
FirmwareUpdateState.Downloading(
|
||||
ProgressState(message = downloadingMsg, progress = progress, details = "$percent%"),
|
||||
ProgressState(
|
||||
message = UiText.DynamicString(downloadingMsg),
|
||||
progress = progress,
|
||||
details = "$percent%",
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (firmwareFile == null) {
|
||||
val errorMsg = getString(Res.string.firmware_update_not_found_in_release, hardware.displayName)
|
||||
updateState(FirmwareUpdateState.Error(errorMsg))
|
||||
updateState(
|
||||
FirmwareUpdateState.Error(
|
||||
UiText.Resource(Res.string.firmware_update_not_found_in_release, hardware.displayName),
|
||||
),
|
||||
)
|
||||
null
|
||||
} else {
|
||||
firmwareFile
|
||||
|
|
@ -267,13 +291,17 @@ class Esp32OtaUpdateHandler(
|
|||
updateState: (FirmwareUpdateState) -> Unit,
|
||||
): Boolean {
|
||||
// Show "waiting for reboot" state before first connection attempt
|
||||
val waitingMsg = getString(Res.string.firmware_update_waiting_reboot)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(waitingMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(ProgressState(UiText.Resource(Res.string.firmware_update_waiting_reboot))),
|
||||
)
|
||||
|
||||
for (i in 1..attempts) {
|
||||
try {
|
||||
val connectingMsg = getString(Res.string.firmware_update_connecting_attempt, i, attempts)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(connectingMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(
|
||||
ProgressState(UiText.Resource(Res.string.firmware_update_connecting_attempt, i, attempts)),
|
||||
),
|
||||
)
|
||||
transport.connect().getOrThrow()
|
||||
return true
|
||||
} catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
|
||||
|
|
@ -294,21 +322,25 @@ class Esp32OtaUpdateHandler(
|
|||
) {
|
||||
val file = java.io.File(firmwareFile)
|
||||
// Step 5: Start OTA
|
||||
val startingOtaMsg = getString(Res.string.firmware_update_starting_ota)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(startingOtaMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(ProgressState(UiText.Resource(Res.string.firmware_update_starting_ota))),
|
||||
)
|
||||
transport
|
||||
.startOta(sizeBytes = file.length(), sha256Hash = sha256Hash) { status ->
|
||||
when (status) {
|
||||
OtaHandshakeStatus.Erasing -> {
|
||||
val erasingMsg = getString(Res.string.firmware_update_erasing)
|
||||
updateState(FirmwareUpdateState.Processing(ProgressState(erasingMsg)))
|
||||
updateState(
|
||||
FirmwareUpdateState.Processing(
|
||||
ProgressState(UiText.Resource(Res.string.firmware_update_erasing)),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.getOrThrow()
|
||||
|
||||
// Step 6: Stream
|
||||
val uploadingMsg = getString(Res.string.firmware_update_uploading)
|
||||
val uploadingMsg = UiText.Resource(Res.string.firmware_update_uploading)
|
||||
updateState(FirmwareUpdateState.Updating(ProgressState(uploadingMsg, 0f)))
|
||||
val firmwareData = file.readBytes()
|
||||
val chunkSize =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue