diff --git a/core/presentation/src/main/res/values-zh/strings.xml b/core/presentation/src/main/res/values-zh/strings.xml
index 49097479..2cc39e27 100644
--- a/core/presentation/src/main/res/values-zh/strings.xml
+++ b/core/presentation/src/main/res/values-zh/strings.xml
@@ -202,6 +202,7 @@
导入你的 TrustedQSL .p12 证书(与 TQSL 同款)用于签名上传通联。密码仅加密保存在手机本地。
证书密码
选择 .p12 文件
+ 导入
%1$s · DXCC %2$d · 有效期至 %3$s
移除证书
台址
diff --git a/core/presentation/src/main/res/values/strings.xml b/core/presentation/src/main/res/values/strings.xml
index ca8c90be..a51eb2aa 100644
--- a/core/presentation/src/main/res/values/strings.xml
+++ b/core/presentation/src/main/res/values/strings.xml
@@ -233,6 +233,7 @@
Import your TrustedQSL .p12 certificate (same one you use in TQSL) to sign and upload QSOs. The password is stored encrypted on this device only.
Certificate password
Choose .p12 file
+ Import
%1$s · DXCC %2$d · expires %3$s
Remove certificate
Station location
diff --git a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/LoTWUploadConfigDialog.kt b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/LoTWUploadConfigDialog.kt
index d76e0e7e..f3599c1c 100644
--- a/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/LoTWUploadConfigDialog.kt
+++ b/feature/settings/src/main/java/com/rtbishop/look4sat/feature/settings/LoTWUploadConfigDialog.kt
@@ -9,6 +9,8 @@
*/
package com.rtbishop.look4sat.feature.settings
+import android.net.Uri
+import android.provider.OpenableColumns
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable
@@ -39,6 +41,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.rtbishop.look4sat.core.domain.repository.LoTWCertificate
@@ -82,24 +85,24 @@ fun LoTWUploadConfigDialog(
onSaveStation: (LoTWStation) -> Unit
) {
var password by remember { mutableStateOf("") }
+ var selectedFile by remember { mutableStateOf(null) }
var grid by remember { mutableStateOf(station?.grid.orEmpty()) }
var cqZone by remember { mutableStateOf(station?.cqZone.orEmpty()) }
var ituZone by remember { mutableStateOf(station?.ituZone.orEmpty()) }
var iota by remember { mutableStateOf(station?.iota.orEmpty()) }
val context = LocalContext.current
+ // Pick the file first, then ask for the password — matches normal usage.
val filePicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
- if (uri != null && password.isNotBlank()) {
- val bytes = runCatching {
- context.contentResolver.openInputStream(uri)?.use { it.readBytes() }
- }.getOrNull()
- if (bytes != null && bytes.isNotEmpty()) {
- onImport(bytes, password.toCharArray())
- password = ""
- }
- }
+ if (uri != null) selectedFile = uri
}
+ fun displayName(uri: Uri): String = runCatching {
+ context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
+ if (cursor.moveToFirst()) cursor.getString(0) else null
+ }
+ }.getOrNull() ?: uri.lastPathSegment.orEmpty()
+
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.prefs_lotw_upload_title)) },
@@ -113,19 +116,42 @@ fun LoTWUploadConfigDialog(
}
if (certificate == null) {
Text(stringResource(R.string.prefs_lotw_upload_cert_hint), fontSize = 13.sp)
- OutlinedTextField(
- value = password,
- onValueChange = { password = it },
- label = { Text(stringResource(R.string.prefs_lotw_upload_password), fontSize = 13.sp) },
- singleLine = true,
- visualTransformation = PasswordVisualTransformation(),
- modifier = Modifier.fillMaxWidth()
- )
Button(
onClick = { filePicker.launch(arrayOf("*/*")) },
- enabled = password.isNotBlank() && !busy,
+ enabled = !busy,
modifier = Modifier.fillMaxWidth()
) { Text(stringResource(R.string.prefs_lotw_upload_import), fontSize = 13.sp) }
+ selectedFile?.let { uri ->
+ Text(
+ text = displayName(uri),
+ fontSize = 12.sp,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ color = MaterialTheme.colorScheme.primary
+ )
+ OutlinedTextField(
+ value = password,
+ onValueChange = { password = it },
+ label = { Text(stringResource(R.string.prefs_lotw_upload_password), fontSize = 13.sp) },
+ singleLine = true,
+ visualTransformation = PasswordVisualTransformation(),
+ modifier = Modifier.fillMaxWidth()
+ )
+ Button(
+ onClick = {
+ val bytes = runCatching {
+ context.contentResolver.openInputStream(uri)?.use { it.readBytes() }
+ }.getOrNull()
+ if (bytes != null && bytes.isNotEmpty()) {
+ onImport(bytes, password.toCharArray())
+ password = ""
+ selectedFile = null
+ }
+ },
+ enabled = password.isNotBlank() && !busy,
+ modifier = Modifier.fillMaxWidth()
+ ) { Text(stringResource(R.string.prefs_lotw_upload_import_confirm), fontSize = 13.sp) }
+ }
} else {
Text(stringResource(R.string.prefs_lotw_upload_cert_info, certificate.callsign, certificate.dxcc, certificate.expires), fontSize = 13.sp)
OutlinedButton(onClick = onRemove, enabled = !busy) {