refactor: add connections sheet
This commit is contained in:
Generated
+2
@@ -3,6 +3,7 @@
|
|||||||
<words>
|
<words>
|
||||||
<w>Aead</w>
|
<w>Aead</w>
|
||||||
<w>Nbits</w>
|
<w>Nbits</w>
|
||||||
|
<w>Nostr</w>
|
||||||
<w>Tink</w>
|
<w>Tink</w>
|
||||||
<w>amboss</w>
|
<w>amboss</w>
|
||||||
<w>hkdf</w>
|
<w>hkdf</w>
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
<w>msat</w>
|
<w>msat</w>
|
||||||
<w>satoshis</w>
|
<w>satoshis</w>
|
||||||
<w>sats</w>
|
<w>sats</w>
|
||||||
|
<w>snackbar</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
||||||
@@ -16,11 +16,43 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.bitcointxoko.gudariwallet.api.NwcNewBudget
|
import com.bitcointxoko.gudariwallet.api.NwcNewBudget
|
||||||
import java.text.SimpleDateFormat
|
import java.time.LocalDateTime
|
||||||
import java.util.Calendar
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
// ── Add connection bottom sheet ──────────────────────────────────────────────
|
@Stable
|
||||||
|
private class AddConnectionState {
|
||||||
|
var description by mutableStateOf("")
|
||||||
|
var selectedPermissions by mutableStateOf(
|
||||||
|
ALL_PERMISSIONS.filter { it.default }.map { it.serverKey }.toSet()
|
||||||
|
)
|
||||||
|
var neverExpires by mutableStateOf(false)
|
||||||
|
var expiry: LocalDateTime by mutableStateOf(
|
||||||
|
LocalDateTime.now().plusDays(30).withSecond(0).withNano(0)
|
||||||
|
)
|
||||||
|
var showDatePicker by mutableStateOf(false)
|
||||||
|
var showTimePicker by mutableStateOf(false)
|
||||||
|
var nextBudgetId by mutableIntStateOf(0)
|
||||||
|
var budgets by mutableStateOf(emptyList<BudgetDraft>())
|
||||||
|
|
||||||
|
// Converts the LocalDateTime expiry to a Unix epoch in seconds (#10)
|
||||||
|
fun expiryEpochSeconds(): Long =
|
||||||
|
expiry.atZone(ZoneId.systemDefault()).toEpochSecond()
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
description = ""
|
||||||
|
selectedPermissions = ALL_PERMISSIONS.filter { it.default }.map { it.serverKey }.toSet()
|
||||||
|
neverExpires = false
|
||||||
|
expiry = LocalDateTime.now().plusDays(30).withSecond(0).withNano(0)
|
||||||
|
showDatePicker = false
|
||||||
|
showTimePicker = false
|
||||||
|
nextBudgetId = 0
|
||||||
|
budgets = emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Sheet ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -35,76 +67,59 @@ internal fun NwcAddConnectionSheet(
|
|||||||
onDismiss : () -> Unit
|
onDismiss : () -> Unit
|
||||||
) {
|
) {
|
||||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
|
val state = remember { AddConnectionState() } // #9
|
||||||
|
|
||||||
var description by remember { mutableStateOf("") }
|
if (state.showDatePicker) {
|
||||||
var selectedPermissions by remember {
|
val initialMillis = state.expiry
|
||||||
mutableStateOf(ALL_PERMISSIONS.filter { it.default }.map { it.serverKey }.toSet())
|
.atZone(ZoneId.systemDefault())
|
||||||
}
|
.toInstant()
|
||||||
var neverExpires by remember { mutableStateOf(false) }
|
.toEpochMilli()
|
||||||
|
|
||||||
val defaultExpiry = remember {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
add(Calendar.DAY_OF_YEAR, 30)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var expiryCalendar by remember { mutableStateOf(defaultExpiry) }
|
|
||||||
var showDatePicker by remember { mutableStateOf(false) }
|
|
||||||
var showTimePicker by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
// ── Budget list state ────────────────────────────────────────────────────
|
|
||||||
var nextBudgetId by remember { mutableIntStateOf(0) }
|
|
||||||
var budgets by remember { mutableStateOf(emptyList<BudgetDraft>()) }
|
|
||||||
|
|
||||||
// ── Date picker dialog ───────────────────────────────────────────────────
|
|
||||||
if (showDatePicker) {
|
|
||||||
val datePickerState = rememberDatePickerState(
|
val datePickerState = rememberDatePickerState(
|
||||||
initialSelectedDateMillis = expiryCalendar.timeInMillis
|
initialSelectedDateMillis = initialMillis
|
||||||
)
|
)
|
||||||
DatePickerDialog(
|
DatePickerDialog(
|
||||||
onDismissRequest = { showDatePicker = false },
|
onDismissRequest = { state.showDatePicker = false },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
datePickerState.selectedDateMillis?.let { millis ->
|
datePickerState.selectedDateMillis?.let { millis ->
|
||||||
expiryCalendar = (expiryCalendar.clone() as Calendar).apply {
|
val picked = java.time.Instant
|
||||||
val picked = Calendar.getInstance().apply { timeInMillis = millis }
|
.ofEpochMilli(millis)
|
||||||
set(Calendar.YEAR, picked.get(Calendar.YEAR))
|
.atZone(ZoneId.systemDefault())
|
||||||
set(Calendar.MONTH, picked.get(Calendar.MONTH))
|
.toLocalDate()
|
||||||
set(Calendar.DAY_OF_MONTH, picked.get(Calendar.DAY_OF_MONTH))
|
state.expiry = state.expiry
|
||||||
}
|
.withYear(picked.year)
|
||||||
|
.withMonth(picked.monthValue)
|
||||||
|
.withDayOfMonth(picked.dayOfMonth)
|
||||||
}
|
}
|
||||||
showDatePicker = false
|
state.showDatePicker = false
|
||||||
}) { Text("OK") }
|
}) { Text("OK") }
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton(onClick = { showDatePicker = false }) { Text("Cancel") }
|
TextButton(onClick = { state.showDatePicker = false }) { Text("Cancel") }
|
||||||
}
|
}
|
||||||
) { DatePicker(state = datePickerState) }
|
) { DatePicker(state = datePickerState) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Time picker dialog ───────────────────────────────────────────────────
|
if (state.showTimePicker) {
|
||||||
if (showTimePicker) {
|
|
||||||
val timePickerState = rememberTimePickerState(
|
val timePickerState = rememberTimePickerState(
|
||||||
initialHour = expiryCalendar.get(Calendar.HOUR_OF_DAY),
|
initialHour = state.expiry.hour,
|
||||||
initialMinute = expiryCalendar.get(Calendar.MINUTE),
|
initialMinute = state.expiry.minute,
|
||||||
is24Hour = true
|
is24Hour = true
|
||||||
)
|
)
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showTimePicker = false },
|
onDismissRequest = { state.showTimePicker = false },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
expiryCalendar = (expiryCalendar.clone() as Calendar).apply {
|
state.expiry = state.expiry
|
||||||
set(Calendar.HOUR_OF_DAY, timePickerState.hour)
|
.withHour(timePickerState.hour)
|
||||||
set(Calendar.MINUTE, timePickerState.minute)
|
.withMinute(timePickerState.minute)
|
||||||
set(Calendar.SECOND, 0)
|
.withSecond(0)
|
||||||
set(Calendar.MILLISECOND, 0)
|
.withNano(0)
|
||||||
}
|
state.showTimePicker = false
|
||||||
showTimePicker = false
|
|
||||||
}) { Text("OK") }
|
}) { Text("OK") }
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton(onClick = { showTimePicker = false }) { Text("Cancel") }
|
TextButton(onClick = { state.showTimePicker = false }) { Text("Cancel") }
|
||||||
},
|
},
|
||||||
text = { TimePicker(state = timePickerState) }
|
text = { TimePicker(state = timePickerState) }
|
||||||
)
|
)
|
||||||
@@ -129,8 +144,8 @@ internal fun NwcAddConnectionSheet(
|
|||||||
|
|
||||||
// ── Description ──────────────────────────────────────────────────
|
// ── Description ──────────────────────────────────────────────────
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = description,
|
value = state.description,
|
||||||
onValueChange = { description = it },
|
onValueChange = { state.description = it },
|
||||||
label = { Text("Label (e.g. Amethyst, Bitrefill)") },
|
label = { Text("Label (e.g. Amethyst, Bitrefill)") },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
@@ -144,13 +159,12 @@ internal fun NwcAddConnectionSheet(
|
|||||||
Text(text = "Expires", style = MaterialTheme.typography.bodyMedium)
|
Text(text = "Expires", style = MaterialTheme.typography.bodyMedium)
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
|
|
||||||
if (!neverExpires) {
|
if (!state.neverExpires) {
|
||||||
val dateLabel = remember(expiryCalendar) {
|
val dateLabel = remember(state.expiry) {
|
||||||
SimpleDateFormat("dd MMM yyyy", Locale.getDefault())
|
DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.getDefault()).format(state.expiry)
|
||||||
.format(expiryCalendar.time)
|
|
||||||
}
|
}
|
||||||
SuggestionChip(
|
SuggestionChip(
|
||||||
onClick = { showDatePicker = true },
|
onClick = { state.showDatePicker = true },
|
||||||
label = { Text(dateLabel, style = MaterialTheme.typography.bodySmall) },
|
label = { Text(dateLabel, style = MaterialTheme.typography.bodySmall) },
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -161,15 +175,11 @@ internal fun NwcAddConnectionSheet(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
val timeLabel = remember(expiryCalendar) {
|
val timeLabel = remember(state.expiry) {
|
||||||
String.format(
|
DateTimeFormatter.ofPattern("HH:mm", Locale.getDefault()).format(state.expiry)
|
||||||
"%02d:%02d",
|
|
||||||
expiryCalendar.get(Calendar.HOUR_OF_DAY),
|
|
||||||
expiryCalendar.get(Calendar.MINUTE)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
SuggestionChip(
|
SuggestionChip(
|
||||||
onClick = { showTimePicker = true },
|
onClick = { state.showTimePicker = true },
|
||||||
label = { Text(timeLabel, style = MaterialTheme.typography.bodySmall) },
|
label = { Text(timeLabel, style = MaterialTheme.typography.bodySmall) },
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -183,13 +193,12 @@ internal fun NwcAddConnectionSheet(
|
|||||||
|
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = neverExpires,
|
checked = state.neverExpires,
|
||||||
onCheckedChange = { neverExpires = it }
|
onCheckedChange = { state.neverExpires = it }
|
||||||
)
|
)
|
||||||
Text(text = "Never", style = MaterialTheme.typography.bodyMedium)
|
Text(text = "Never", style = MaterialTheme.typography.bodyMedium)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Budgets ──────────────────────────────────────────────────────
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@@ -202,8 +211,8 @@ internal fun NwcAddConnectionSheet(
|
|||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
budgets = budgets + BudgetDraft(id = nextBudgetId)
|
state.budgets += BudgetDraft(id = state.nextBudgetId)
|
||||||
nextBudgetId++
|
state.nextBudgetId++
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -216,16 +225,18 @@ internal fun NwcAddConnectionSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
budgets.forEach { draft ->
|
state.budgets.forEach { draft ->
|
||||||
BudgetRow(
|
key(draft.id) {
|
||||||
draft = draft,
|
BudgetRow(
|
||||||
onChange = { updated ->
|
draft = draft,
|
||||||
budgets = budgets.map { if (it.id == draft.id) updated else it }
|
onChange = { updated ->
|
||||||
},
|
state.budgets = state.budgets.map { if (it.id == draft.id) updated else it }
|
||||||
onRemove = {
|
},
|
||||||
budgets = budgets.filter { it.id != draft.id }
|
onRemove = {
|
||||||
}
|
state.budgets = state.budgets.filter { it.id != draft.id }
|
||||||
)
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Permissions ──────────────────────────────────────────────────
|
// ── Permissions ──────────────────────────────────────────────────
|
||||||
@@ -235,39 +246,41 @@ internal fun NwcAddConnectionSheet(
|
|||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
ALL_PERMISSIONS.forEach { perm ->
|
ALL_PERMISSIONS.forEach { perm ->
|
||||||
val checked = perm.serverKey in selectedPermissions
|
key(perm.serverKey) {
|
||||||
Row(
|
val checked = perm.serverKey in state.selectedPermissions
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
verticalAlignment = Alignment.CenterVertically
|
||||||
Checkbox(
|
) {
|
||||||
checked = checked,
|
Checkbox(
|
||||||
onCheckedChange = { on ->
|
checked = checked,
|
||||||
selectedPermissions = if (on)
|
onCheckedChange = { on ->
|
||||||
selectedPermissions + perm.serverKey
|
state.selectedPermissions = if (on)
|
||||||
else
|
state.selectedPermissions + perm.serverKey
|
||||||
selectedPermissions - perm.serverKey
|
else
|
||||||
}
|
state.selectedPermissions - perm.serverKey
|
||||||
)
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
)
|
||||||
Text(text = perm.displayLabel, style = MaterialTheme.typography.bodyMedium)
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text(text = perm.displayLabel, style = MaterialTheme.typography.bodyMedium)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Create button ────────────────────────────────────────────────
|
// ── Create button ─────────────────────────────────────────────────
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
val expiresAtSecs = if (neverExpires) 0L
|
val expiresAtSecs = if (state.neverExpires) 0L
|
||||||
else expiryCalendar.timeInMillis / 1000L
|
else state.expiryEpochSeconds() // #10
|
||||||
val validBudgets = budgets.mapNotNull { it.toNwcNewBudget() }
|
val validBudgets = state.budgets.mapNotNull { it.toNwcNewBudget() }
|
||||||
onCreate(
|
onCreate(
|
||||||
description.trim().ifBlank { "Unnamed" },
|
state.description.trim().ifBlank { "Unnamed" },
|
||||||
selectedPermissions.toList(),
|
state.selectedPermissions.toList(),
|
||||||
expiresAtSecs,
|
expiresAtSecs,
|
||||||
validBudgets
|
validBudgets
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
enabled = selectedPermissions.isNotEmpty() && !isCreating,
|
enabled = state.selectedPermissions.isNotEmpty() && !isCreating,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
if (isCreating) {
|
if (isCreating) {
|
||||||
@@ -284,7 +297,7 @@ internal fun NwcAddConnectionSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Budget row ───────────────────────────────────────────────────────────────
|
// ── Budget row ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -294,8 +307,6 @@ private fun BudgetRow(
|
|||||||
onRemove : () -> Unit
|
onRemove : () -> Unit
|
||||||
) {
|
) {
|
||||||
var dropdownExpanded by remember { mutableStateOf(false) }
|
var dropdownExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
// Shared height for both fields so they are always flush
|
|
||||||
val fieldHeight = 64.dp
|
val fieldHeight = 64.dp
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
@@ -310,36 +321,30 @@ private fun BudgetRow(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
// ── Amount field ─────────────────────────────────────────────────
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = draft.amountSats,
|
value = draft.amountSats,
|
||||||
onValueChange = { onChange(draft.copy(amountSats = it.filter(Char::isDigit))) },
|
onValueChange = { onChange(draft.copy(amountSats = it.filter(Char::isDigit))) },
|
||||||
label = { Text("Sats") },
|
label = { Text("Sats") },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||||
modifier = Modifier
|
modifier = Modifier.weight(1f).height(fieldHeight)
|
||||||
.weight(1f)
|
|
||||||
.height(fieldHeight)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ── Refresh-window dropdown ──────────────────────────────────────
|
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
expanded = dropdownExpanded,
|
expanded = dropdownExpanded,
|
||||||
onExpandedChange = { dropdownExpanded = it },
|
onExpandedChange = { dropdownExpanded = it },
|
||||||
modifier = Modifier
|
modifier = Modifier.weight(1f).height(fieldHeight)
|
||||||
.weight(1f)
|
|
||||||
.height(fieldHeight)
|
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = draft.refreshWindow.label,
|
value = draft.refreshWindow.label,
|
||||||
onValueChange = {},
|
onValueChange = {},
|
||||||
readOnly = true,
|
readOnly = true,
|
||||||
label = { Text("Resets") },
|
label = { Text("Resets") },
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = dropdownExpanded)
|
ExposedDropdownMenuDefaults.TrailingIcon(expanded = dropdownExpanded)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.menuAnchor()
|
.menuAnchor(type = ExposedDropdownMenuAnchorType.PrimaryNotEditable, enabled = true)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(fieldHeight)
|
.height(fieldHeight)
|
||||||
)
|
)
|
||||||
@@ -359,7 +364,6 @@ private fun BudgetRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Remove button ────────────────────────────────────────────────
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onRemove,
|
onClick = onRemove,
|
||||||
modifier = Modifier.size(fieldHeight)
|
modifier = Modifier.size(fieldHeight)
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ fun NwcScreen(
|
|||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
// ── Shared refresh lambda (item #13) ──────────────────────────────────────
|
|
||||||
val refresh = { viewModel.loadConnections(includeExpired = true) }
|
val refresh = { viewModel.loadConnections(includeExpired = true) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -57,7 +56,7 @@ fun NwcScreen(
|
|||||||
|
|
||||||
PullToRefreshBox(
|
PullToRefreshBox(
|
||||||
isRefreshing = isRefreshing,
|
isRefreshing = isRefreshing,
|
||||||
onRefresh = refresh, // ← was loadConnections(includeExpired = true)
|
onRefresh = refresh,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(innerPadding)
|
.padding(innerPadding)
|
||||||
@@ -72,7 +71,7 @@ fun NwcScreen(
|
|||||||
is NwcUiState.Error -> {
|
is NwcUiState.Error -> {
|
||||||
NwcErrorContent(
|
NwcErrorContent(
|
||||||
message = state.message,
|
message = state.message,
|
||||||
onRetry = refresh, // ← was loadConnections(includeExpired = true)
|
onRetry = refresh,
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -121,9 +120,9 @@ fun NwcScreen(
|
|||||||
expiresAt = expiresAt,
|
expiresAt = expiresAt,
|
||||||
budgets = budgets
|
budgets = budgets
|
||||||
)
|
)
|
||||||
viewModel.closeAddSheet() // ← was openAddSheet()
|
viewModel.closeAddSheet()
|
||||||
},
|
},
|
||||||
onDismiss = { viewModel.closeAddSheet() } // ← was openAddSheet()
|
onDismiss = { viewModel.closeAddSheet() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +147,7 @@ fun NwcScreen(
|
|||||||
text = { Text("This will permanently revoke this Nostr Wallet Connect key. Any app using it will lose access.") },
|
text = { Text("This will permanently revoke this Nostr Wallet Connect key. Any app using it will lose access.") },
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { viewModel.confirmDelete() } // ← was deleteConnection(pubkey) + cancelDelete()
|
onClick = { viewModel.confirmDelete() }
|
||||||
) { Text("Remove", color = MaterialTheme.colorScheme.error) }
|
) { Text("Remove", color = MaterialTheme.colorScheme.error) }
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
|
|||||||
Reference in New Issue
Block a user