mirror of
https://github.com/atsunatsu/Look4Sat.git
synced 2026-10-02 03:15:37 +00:00
fix: logbook mode display + bottom-sheet dialogs
- displayMode no longer trusts a stale submode for non-MFSK modes: FM/CW/SSB records (including ones persisted with the old default submode=FT4) now show their real mode; only MODE=MFSK uses the FT4 submode. QsoRecord defaults changed mode=MFSK->FM, submode=FT4->''. - LoTW report bridge sets submode=FT4 for MODE=MFSK so confirmations still match local FT4 records. - Logbook and LoTW upload config dialogs now use SharedDialog (bottom-sheet), matching the LoTW confirmed-grids dialog style.
This commit is contained in:
1 parent
e606afb0f3
commit
238511aa78
7 files changed
+136
-120
No files matched your search
+94
-95
@@ -21,15 +21,12 @@ import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -46,7 +43,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.rtbishop.look4sat.core.domain.repository.LoTWCertificate
|
||||
import com.rtbishop.look4sat.core.domain.repository.LoTWStation
|
||||
import com.rtbishop.look4sat.core.presentation.CardButton
|
||||
import com.rtbishop.look4sat.core.presentation.R
|
||||
import com.rtbishop.look4sat.core.presentation.SharedDialog
|
||||
|
||||
@Composable
|
||||
fun LoTWUploadCard(
|
||||
@@ -103,102 +102,102 @@ fun LoTWUploadConfigDialog(
|
||||
}
|
||||
}.getOrNull() ?: uri.lastPathSegment.orEmpty()
|
||||
|
||||
AlertDialog(
|
||||
SharedDialog(
|
||||
title = stringResource(R.string.prefs_lotw_upload_title),
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(R.string.prefs_lotw_upload_title)) },
|
||||
text = {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
if (busy) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
CircularProgressIndicator(modifier = Modifier.height(20.dp), strokeWidth = 2.dp)
|
||||
Text(stringResource(R.string.prefs_lotw_upload_busy), fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
if (certificate == null) {
|
||||
Text(stringResource(R.string.prefs_lotw_upload_cert_hint), fontSize = 13.sp)
|
||||
Button(
|
||||
onClick = { filePicker.launch(arrayOf("*/*")) },
|
||||
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) {
|
||||
Text(stringResource(R.string.prefs_lotw_upload_remove), fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
Text(stringResource(R.string.prefs_lotw_upload_station_title), style = MaterialTheme.typography.titleSmall)
|
||||
// Grid field accepts a comma-separated multi-grid set (e.g. "OL62,OL72").
|
||||
onCancel = onDismiss,
|
||||
onAccept = null
|
||||
) {
|
||||
if (busy) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
CircularProgressIndicator(modifier = Modifier.height(20.dp), strokeWidth = 2.dp)
|
||||
Text(stringResource(R.string.prefs_lotw_upload_busy), fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
if (certificate == null) {
|
||||
Text(stringResource(R.string.prefs_lotw_upload_cert_hint), fontSize = 13.sp)
|
||||
CardButton(
|
||||
onClick = { filePicker.launch(arrayOf("*/*")) },
|
||||
text = stringResource(R.string.prefs_lotw_upload_import),
|
||||
isEnabled = !busy,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
selectedFile?.let { uri ->
|
||||
Text(
|
||||
text = displayName(uri),
|
||||
fontSize = 12.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = grid,
|
||||
onValueChange = { grid = it.uppercase() },
|
||||
label = { Text(stringResource(R.string.prefs_lotw_upload_grid), fontSize = 13.sp) },
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
label = { Text(stringResource(R.string.prefs_lotw_upload_password), fontSize = 13.sp) },
|
||||
singleLine = true,
|
||||
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(capitalization = KeyboardCapitalization.Characters),
|
||||
visualTransformation = PasswordVisualTransformation(),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
CardButton(
|
||||
onClick = {
|
||||
val bytes = runCatching {
|
||||
context.contentResolver.openInputStream(uri)?.use { it.readBytes() }
|
||||
}.getOrNull()
|
||||
if (bytes != null && bytes.isNotEmpty()) {
|
||||
onImport(bytes, password.toCharArray())
|
||||
password = ""
|
||||
selectedFile = null
|
||||
}
|
||||
},
|
||||
text = stringResource(R.string.prefs_lotw_upload_import_confirm),
|
||||
isEnabled = password.isNotBlank() && !busy,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
OutlinedTextField(
|
||||
value = cqZone,
|
||||
onValueChange = { cqZone = it },
|
||||
label = { Text("CQZ", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = ituZone,
|
||||
onValueChange = { ituZone = it },
|
||||
label = { Text("ITUZ", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = iota,
|
||||
onValueChange = { iota = it.uppercase() },
|
||||
label = { Text("IOTA", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = { onSaveStation(LoTWStation(grid, cqZone, ituZone, "", "", iota)) },
|
||||
enabled = grid.isNotBlank() && !busy
|
||||
) { Text(stringResource(R.string.prefs_lotw_upload_save)) }
|
||||
},
|
||||
dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.prefs_lotw_upload_close)) } }
|
||||
)
|
||||
} else {
|
||||
Text(stringResource(R.string.prefs_lotw_upload_cert_info, certificate.callsign, certificate.dxcc, certificate.expires), fontSize = 13.sp)
|
||||
OutlinedButton(onClick = onRemove, enabled = !busy) {
|
||||
Text(stringResource(R.string.prefs_lotw_upload_remove), fontSize = 13.sp)
|
||||
}
|
||||
}
|
||||
Text(stringResource(R.string.prefs_lotw_upload_station_title), style = MaterialTheme.typography.titleSmall)
|
||||
// Grid field accepts a comma-separated multi-grid set (e.g. "OL62,OL72").
|
||||
OutlinedTextField(
|
||||
value = grid,
|
||||
onValueChange = { grid = it.uppercase() },
|
||||
label = { Text(stringResource(R.string.prefs_lotw_upload_grid), fontSize = 13.sp) },
|
||||
singleLine = true,
|
||||
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(capitalization = KeyboardCapitalization.Characters),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
OutlinedTextField(
|
||||
value = cqZone,
|
||||
onValueChange = { cqZone = it },
|
||||
label = { Text("CQZ", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = ituZone,
|
||||
onValueChange = { ituZone = it },
|
||||
label = { Text("ITUZ", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = iota,
|
||||
onValueChange = { iota = it.uppercase() },
|
||||
label = { Text("IOTA", fontSize = 12.sp) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
CardButton(
|
||||
onClick = { onSaveStation(LoTWStation(grid, cqZone, ituZone, "", "", iota)) },
|
||||
text = stringResource(R.string.prefs_lotw_upload_save),
|
||||
isEnabled = grid.isNotBlank() && !busy,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
+18
-19
@@ -14,17 +14,15 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -36,6 +34,7 @@ import androidx.compose.ui.unit.sp
|
||||
import com.rtbishop.look4sat.core.domain.logbook.QsoRecord
|
||||
import com.rtbishop.look4sat.core.domain.logbook.displayMode
|
||||
import com.rtbishop.look4sat.core.presentation.R
|
||||
import com.rtbishop.look4sat.core.presentation.SharedDialog
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
@@ -65,25 +64,25 @@ fun LogbookDialog(
|
||||
onDismiss: () -> Unit,
|
||||
onDelete: (Long) -> Unit
|
||||
) {
|
||||
AlertDialog(
|
||||
SharedDialog(
|
||||
title = stringResource(R.string.prefs_logbook_title),
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(R.string.prefs_logbook_title)) },
|
||||
text = {
|
||||
if (records.isEmpty()) {
|
||||
Text(stringResource(R.string.prefs_logbook_empty), fontSize = 14.sp)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
items(records, key = { it.id }) { record ->
|
||||
LogbookRow(record, onDelete = { onDelete(record.id) })
|
||||
}
|
||||
onCancel = onDismiss,
|
||||
onAccept = null
|
||||
) {
|
||||
if (records.isEmpty()) {
|
||||
Text(stringResource(R.string.prefs_logbook_empty), fontSize = 14.sp)
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxWidth().heightIn(max = 420.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
items(records, key = { it.id }) { record ->
|
||||
LogbookRow(record, onDelete = { onDelete(record.id) })
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.prefs_logbook_close)) } }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
Reference in new issue
Block a user