feat: show clear error when p12 certificate import fails

The import previously swallowed all exceptions silently. Now the upload
config dialog shows a specific message for: wrong password, expired
certificate, invalid file, and unknown failures.
This commit is contained in:
atsunatsu committed 2026-09-25 23:50:48 +08:00
1 parent bc5a8e4bba
commit d8d0825f54
6 files changed
+38 -3

No files matched your search

@@ -78,6 +78,7 @@ fun LoTWUploadConfigDialog(
certificate: LoTWCertificate?,
station: LoTWStation?,
busy: Boolean,
error: LoTWUploadError?,
onDismiss: () -> Unit,
onImport: (ByteArray, CharArray) -> Unit,
onRemove: () -> Unit,
@@ -122,6 +123,20 @@ fun LoTWUploadConfigDialog(
isEnabled = !busy,
modifier = Modifier.fillMaxWidth()
)
error?.let {
Text(
text = stringResource(
when (it) {
LoTWUploadError.PASSWORD -> R.string.prefs_lotw_upload_error_password
LoTWUploadError.EXPIRED -> R.string.prefs_lotw_upload_error_expired
LoTWUploadError.INVALID_FILE -> R.string.prefs_lotw_upload_error_invalid
LoTWUploadError.UNKNOWN -> R.string.prefs_lotw_upload_error_unknown
}
),
color = MaterialTheme.colorScheme.error,
fontSize = 12.sp
)
}
selectedFile?.let { uri ->
Text(
text = displayName(uri),
@@ -273,6 +273,7 @@ private fun SettingsScreen(uiState: SettingsState, onAction: (SettingsAction) ->
certificate = uiState.lotwCertificate,
station = uiState.lotwStation,
busy = uiState.lotwUploadBusy,
error = uiState.lotwUploadError,
onDismiss = { dialogs.lotwUpload = false },
onImport = { bytes, password -> onAction(SettingsAction.ImportLoTWCertificate(bytes, password)) },
onRemove = { onAction(SettingsAction.RemoveLoTWCertificate) },
@@ -75,6 +75,8 @@ data class SettingsState(
/** LoTW upload station location (null when unset). */
val lotwStation: com.rtbishop.look4sat.core.domain.repository.LoTWStation? = null,
val lotwUploadBusy: Boolean = false,
/** Last certificate import outcome; shown inside the upload config dialog. */
val lotwUploadError: LoTWUploadError? = null,
/** 指南针校准精度等级 (校准对话框进度条). */
val compassAccuracy: CompassAccuracy = CompassAccuracy.UNRELIABLE,
/** 校正后航向(度, 含磁偏角+手动偏置), 校准对话框实时显示. */
@@ -91,6 +93,8 @@ sealed interface LoTWError {
data class Network(val detail: String) : LoTWError
}
enum class LoTWUploadError { PASSWORD, INVALID_FILE, EXPIRED, UNKNOWN }
sealed interface SettingsAction {
// Position
data object SetGpsPosition : SettingsAction
@@ -354,12 +354,19 @@ class SettingsViewModel(
private fun importLoTWCertificate(bytes: ByteArray, password: CharArray) {
viewModelScope.launch {
_uiState.update { it.copy(lotwUploadBusy = true) }
_uiState.update { it.copy(lotwUploadBusy = true, lotwUploadError = null) }
try {
val cert = lotwUploadRepository.importCertificate(bytes, password)
_uiState.update { it.copy(lotwCertificate = cert, lotwUploadBusy = false) }
_uiState.update { it.copy(lotwCertificate = cert, lotwUploadBusy = false, lotwUploadError = null) }
} catch (e: com.rtbishop.look4sat.core.domain.repository.LoTWOperationException) {
val error = when (e.reason) {
com.rtbishop.look4sat.core.domain.repository.LoTWProblem.CERTIFICATE_PASSWORD -> LoTWUploadError.PASSWORD
com.rtbishop.look4sat.core.domain.repository.LoTWProblem.CERTIFICATE_EXPIRED -> LoTWUploadError.EXPIRED
else -> LoTWUploadError.INVALID_FILE
}
_uiState.update { it.copy(lotwUploadBusy = false, lotwUploadError = error) }
} catch (_: Exception) {
_uiState.update { it.copy(lotwUploadBusy = false) }
_uiState.update { it.copy(lotwUploadBusy = false, lotwUploadError = LoTWUploadError.UNKNOWN) }
}
}
}