Remove mutable state from AmberBunkerRequest and IntentData

Replaces MutableState<Boolean> (checked) and MutableState<RememberType>
(rememberType) fields in AmberBunkerRequest and IntentData with plain
immutable values. UI state is now managed in MultiEventScreenIntents
via a SnapshotStateMap (checkedStates) and a mutableStateOf (rememberType),
keeping Compose state out of pure data models and fixing data class
semantics (copy/equals/hashCode).

https://claude.ai/code/session_01PRSKjmFms1Tj1QJ5FhfqZm
This commit is contained in:
Claude
2026-03-20 11:44:52 +00:00
parent f760e67c8d
commit d97e87b89c
9 changed files with 125 additions and 100 deletions
@@ -1,8 +1,5 @@
package com.greenart7c3.nostrsigner.models
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.greenart7c3.nostrsigner.ui.RememberType
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest
@@ -22,8 +19,6 @@ data class AmberBunkerRequest(
val name: String,
val signedEvent: Event?,
val encryptedData: EncryptedDataKind?,
val checked: MutableState<Boolean> = mutableStateOf(true),
val rememberType: MutableState<RememberType> = mutableStateOf(RememberType.NEVER),
val encryptionType: EncryptionType,
val isNostrConnectUri: Boolean,
)
@@ -1,7 +1,5 @@
package com.greenart7c3.nostrsigner.models
import androidx.compose.runtime.MutableState
import com.greenart7c3.nostrsigner.ui.RememberType
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.HexKey
@@ -16,8 +14,6 @@ data class IntentData(
val returnType: ReturnType,
val permissions: List<Permission>?,
val currentAccount: String,
val checked: MutableState<Boolean>,
val rememberType: MutableState<RememberType>,
val route: String?,
val event: Event?,
val encryptedData: EncryptedDataKind?,
@@ -8,7 +8,6 @@ import android.net.Uri
import android.provider.Browser
import android.util.Log
import android.widget.Toast
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.Clipboard
import androidx.compose.ui.text.intl.Locale
@@ -173,8 +172,6 @@ object IntentUtils {
returnType = returnType,
permissions = listOf(),
currentAccount = Hex.decode(signedEvent.pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = signedEvent,
encryptedData = null,
@@ -219,8 +216,6 @@ object IntentUtils {
returnType = returnType,
permissions = listOf(),
currentAccount = Hex.decode(pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = encryptedDataKind,
@@ -238,8 +233,6 @@ object IntentUtils {
returnType = returnType,
permissions = listOf(),
currentAccount = "",
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = null,
@@ -257,8 +250,6 @@ object IntentUtils {
returnType = returnType,
permissions = listOf(),
currentAccount = "",
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = null,
@@ -359,8 +350,6 @@ object IntentUtils {
returnType = returnType,
permissions = permissions?.map { Permission(it.type.trim(), it.kind, it.checked) },
currentAccount = npub ?: Hex.decode(signed.pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = signed,
encryptedData = null,
@@ -411,8 +400,6 @@ object IntentUtils {
returnType = returnType,
permissions = permissions?.map { Permission(it.type.trim(), it.kind, it.checked) },
currentAccount = npub ?: Hex.decode(pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = encryptedDataKind,
@@ -435,8 +422,6 @@ object IntentUtils {
returnType = returnType,
permissions = permissions?.map { Permission(it.type.trim(), it.kind, it.checked) },
currentAccount = npub ?: Hex.decode(pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = null,
@@ -459,8 +444,6 @@ object IntentUtils {
returnType = returnType,
permissions = permissions?.map { Permission(it.type.trim(), it.kind, it.checked) },
currentAccount = npub ?: Hex.decode(pubKey).toNpub(),
checked = mutableStateOf(true),
rememberType = mutableStateOf(RememberType.NEVER),
route = route,
event = null,
encryptedData = null,
@@ -1,10 +1,17 @@
package com.greenart7c3.nostrsigner.service
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.greenart7c3.nostrsigner.models.AmberBunkerRequest
import com.greenart7c3.nostrsigner.models.IntentData
import com.greenart7c3.nostrsigner.ui.RememberType
object MultiEventScreenIntents {
var intents = listOf<IntentData>()
var bunkerRequests = listOf<AmberBunkerRequest>()
var appName = ""
val checkedStates = mutableStateMapOf<String, Boolean>()
var rememberType by mutableStateOf(RememberType.NEVER)
}
@@ -56,7 +56,7 @@ fun SeeDetailsScreen(
.weight(1f)
.verticalScroll(rememberScrollState()),
) {
var rememberType by remember { mutableStateOf(MultiEventScreenIntents.intents.firstOrNull()?.rememberType?.value ?: MultiEventScreenIntents.bunkerRequests.first().rememberType.value) }
var rememberType by remember { mutableStateOf(MultiEventScreenIntents.rememberType) }
val type = if (MultiEventScreenIntents.intents.isNotEmpty()) {
MultiEventScreenIntents.intents.first().type
} else {
@@ -96,15 +96,14 @@ fun SeeDetailsScreen(
onReject = {},
onChanged = {
rememberType = it
MultiEventScreenIntents.intents.forEach { intent ->
intent.rememberType.value = rememberType
}
MultiEventScreenIntents.rememberType = it
},
packageName = null,
)
}
MultiEventScreenIntents.intents.forEach { intent ->
val intentChecked = MultiEventScreenIntents.checkedStates[intent.id] ?: true
Card(
Modifier
.padding(4.dp),
@@ -118,13 +117,13 @@ fun SeeDetailsScreen(
modifier = Modifier
.fillMaxWidth()
.clickable {
intent.checked.value = !intent.checked.value
MultiEventScreenIntents.checkedStates[intent.id] = !intentChecked
},
) {
Checkbox(
checked = intent.checked.value,
checked = intentChecked,
onCheckedChange = { _ ->
intent.checked.value = !intent.checked.value
MultiEventScreenIntents.checkedStates[intent.id] = !intentChecked
},
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
@@ -163,13 +162,14 @@ fun SeeDetailsScreen(
.weight(1f)
.padding(vertical = 8.dp),
text = data.ifBlank { message },
color = if (intent.checked.value) Color.Unspecified else Color.Gray,
color = if (intentChecked) Color.Unspecified else Color.Gray,
)
}
}
}
MultiEventScreenIntents.bunkerRequests.forEach { bunkerRequest ->
val bunkerChecked = MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] ?: true
Card(
Modifier
.padding(4.dp),
@@ -183,13 +183,13 @@ fun SeeDetailsScreen(
modifier = Modifier
.fillMaxWidth()
.clickable {
bunkerRequest.checked.value = !bunkerRequest.checked.value
MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] = !bunkerChecked
},
) {
Checkbox(
checked = bunkerRequest.checked.value,
checked = bunkerChecked,
onCheckedChange = { _ ->
bunkerRequest.checked.value = !bunkerRequest.checked.value
MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] = !bunkerChecked
},
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
@@ -228,7 +228,7 @@ fun SeeDetailsScreen(
.weight(1f)
.padding(vertical = 8.dp),
text = data.ifBlank { message },
color = if (bunkerRequest.checked.value) Color.Unspecified else Color.Gray,
color = if (bunkerChecked) Color.Unspecified else Color.Gray,
)
}
}
@@ -53,6 +53,7 @@ import com.greenart7c3.nostrsigner.service.AmberUtils
import com.greenart7c3.nostrsigner.service.ApplicationNameCache
import com.greenart7c3.nostrsigner.service.BunkerRequestUtils
import com.greenart7c3.nostrsigner.service.EventNotificationConsumer
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.service.toShortenHex
import com.greenart7c3.nostrsigner.ui.RememberType
@@ -82,6 +83,12 @@ fun BunkerMultiEventHomeScreen(
var relayAuthScope by remember { mutableStateOf(RelayAuthScope.SPECIFIC) }
var appName by remember { mutableStateOf(ApplicationNameCache.names["$localAccount-$key"] ?: key.toShortenHex()) }
LaunchedEffect(Unit) {
MultiEventScreenIntents.checkedStates.clear()
MultiEventScreenIntents.rememberType = RememberType.NEVER
bunkerRequests.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = true }
}
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
localAccount = LocalPreferences.loadFromEncryptedStorage(
@@ -116,8 +123,8 @@ fun BunkerMultiEventHomeScreen(
SigningAs(accountParam)
val allCheckedState = when {
bunkerRequests.all { it.checked.value } -> ToggleableState.On
bunkerRequests.none { it.checked.value } -> ToggleableState.Off
bunkerRequests.all { MultiEventScreenIntents.checkedStates[it.request.id] ?: true } -> ToggleableState.On
bunkerRequests.none { MultiEventScreenIntents.checkedStates[it.request.id] ?: true } -> ToggleableState.Off
else -> ToggleableState.Indeterminate
}
Row(
@@ -126,14 +133,14 @@ fun BunkerMultiEventHomeScreen(
.fillMaxWidth()
.clickable {
val newValue = allCheckedState != ToggleableState.On
bunkerRequests.forEach { it.checked.value = newValue }
bunkerRequests.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = newValue }
},
) {
TriStateCheckbox(
state = allCheckedState,
onClick = {
val newValue = allCheckedState != ToggleableState.On
bunkerRequests.forEach { it.checked.value = newValue }
bunkerRequests.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = newValue }
},
)
Text(stringResource(R.string.select_deselect_all))
@@ -145,7 +152,15 @@ fun BunkerMultiEventHomeScreen(
.verticalScroll(rememberScrollState()),
) {
bunkerRequests.forEach { bunkerRequest ->
BunkerRequestCard(context = context, bunkerRequest = bunkerRequest)
BunkerRequestCard(
context = context,
bunkerRequest = bunkerRequest,
checked = MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] ?: true,
onToggleChecked = {
val current = MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] ?: true
MultiEventScreenIntents.checkedStates[bunkerRequest.request.id] = !current
},
)
}
}
@@ -184,9 +199,7 @@ fun BunkerMultiEventHomeScreen(
onReject = {},
onChanged = {
rememberType = it
bunkerRequests.forEach { bunkerRequest ->
bunkerRequest.rememberType.value = rememberType
}
MultiEventScreenIntents.rememberType = it
},
packageName = packageName,
)
@@ -247,7 +260,8 @@ fun BunkerMultiEventHomeScreen(
permissions = mutableListOf(),
)
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
val isChecked = MultiEventScreenIntents.checkedStates[request.request.id] ?: true
if (rememberType != RememberType.NEVER && isChecked) {
val rejectKind = if (request.request is BunkerRequestSign) request.request.event.kind else null
val rejectRelay = if (request.request is BunkerRequestSign && request.request.event.kind == 22242) {
if (relayAuthScope == RelayAuthScope.ALL) {
@@ -272,7 +286,7 @@ fun BunkerMultiEventHomeScreen(
BunkerRequestUtils.getTypeFromBunker(request.request),
rejectKind,
false,
request.rememberType.value,
rememberType,
thisAccount,
relay = rejectRelay,
)
@@ -345,10 +359,12 @@ fun BunkerMultiEventHomeScreen(
permissions = mutableListOf(),
)
val isChecked = MultiEventScreenIntents.checkedStates[request.request.id] ?: true
if (request.request is BunkerRequestSign) {
val localEvent = request.signedEvent!!
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
val signRelay = if (localEvent.kind == 22242) {
if (relayAuthScope == RelayAuthScope.ALL) {
"*"
@@ -372,7 +388,7 @@ fun BunkerMultiEventHomeScreen(
signerType = SignerType.SIGN_EVENT,
kind = localEvent.kind,
value = true,
rememberType = request.rememberType.value,
rememberType = rememberType,
account = thisAccount,
relay = signRelay,
)
@@ -387,7 +403,7 @@ fun BunkerMultiEventHomeScreen(
type = SignerType.SIGN_EVENT.toString(),
kind = localEvent.kind,
time = TimeUtils.now(),
accepted = request.checked.value,
accepted = isChecked,
content = localEvent.toJson(),
),
thisAccount.npub,
@@ -395,7 +411,7 @@ fun BunkerMultiEventHomeScreen(
BunkerRequestUtils.remove(request.request.id)
if (request.checked.value) {
if (isChecked) {
BunkerRequestUtils.sendBunkerResponse(
context,
thisAccount,
@@ -416,14 +432,14 @@ fun BunkerMultiEventHomeScreen(
)
}
} else if (request.request.method == "sign_message") {
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
AmberUtils.acceptOrRejectPermission(
application,
localKey,
SignerType.SIGN_MESSAGE,
null,
true,
request.rememberType.value,
rememberType,
thisAccount,
)
}
@@ -436,7 +452,7 @@ fun BunkerMultiEventHomeScreen(
SignerType.SIGN_MESSAGE.toString(),
null,
TimeUtils.now(),
request.checked.value,
isChecked,
content = request.request.params.first(),
),
thisAccount.npub,
@@ -445,7 +461,7 @@ fun BunkerMultiEventHomeScreen(
val signedMessage = thisAccount.signString(request.request.params.first())
BunkerRequestUtils.remove(request.request.id)
if (request.checked.value) {
if (isChecked) {
BunkerRequestUtils.sendBunkerResponse(
context,
thisAccount,
@@ -476,14 +492,14 @@ fun BunkerMultiEventHomeScreen(
SignerType.CONNECT.toString(),
null,
TimeUtils.now(),
request.checked.value,
isChecked,
content = "",
),
thisAccount.npub,
)
BunkerRequestUtils.remove(request.request.id)
if (request.checked.value) {
if (isChecked) {
BunkerRequestUtils.sendBunkerResponse(
context,
thisAccount,
@@ -506,14 +522,14 @@ fun BunkerMultiEventHomeScreen(
}
} else {
val type = BunkerRequestUtils.getTypeFromBunker(request.request)
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
AmberUtils.acceptOrRejectPermission(
application,
localKey,
type,
null,
true,
request.rememberType.value,
rememberType,
thisAccount,
)
}
@@ -527,7 +543,7 @@ fun BunkerMultiEventHomeScreen(
type.toString(),
null,
TimeUtils.now(),
request.checked.value,
isChecked,
content = if (type == SignerType.NIP04_DECRYPT || type == SignerType.NIP44_DECRYPT || type == SignerType.DECRYPT_ZAP_EVENT) {
request.encryptedData?.result ?: ""
} else {
@@ -539,7 +555,7 @@ fun BunkerMultiEventHomeScreen(
val signature = request.encryptedData?.result ?: continue
BunkerRequestUtils.remove(request.request.id)
if (request.checked.value) {
if (isChecked) {
BunkerRequestUtils.sendBunkerResponse(
context,
thisAccount,
@@ -572,7 +588,12 @@ fun BunkerMultiEventHomeScreen(
}
@Composable
private fun BunkerRequestCard(context: Context, bunkerRequest: AmberBunkerRequest) {
private fun BunkerRequestCard(
context: Context,
bunkerRequest: AmberBunkerRequest,
checked: Boolean,
onToggleChecked: () -> Unit,
) {
val type = BunkerRequestUtils.getTypeFromBunker(bunkerRequest.request)
var showDetails by remember { mutableStateOf(false) }
val hasDetails = (type == SignerType.SIGN_EVENT && bunkerRequest.signedEvent != null) ||
@@ -655,11 +676,11 @@ private fun BunkerRequestCard(context: Context, bunkerRequest: AmberBunkerReques
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { bunkerRequest.checked.value = !bunkerRequest.checked.value },
.clickable { onToggleChecked() },
) {
Checkbox(
checked = bunkerRequest.checked.value,
onCheckedChange = { bunkerRequest.checked.value = !bunkerRequest.checked.value },
checked = checked,
onCheckedChange = { onToggleChecked() },
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
),
@@ -671,7 +692,7 @@ private fun BunkerRequestCard(context: Context, bunkerRequest: AmberBunkerReques
) {
Text(
text = label,
color = if (bunkerRequest.checked.value) Color.Unspecified else Color.Gray,
color = if (checked) Color.Unspecified else Color.Gray,
)
if (preview.isNotBlank()) {
Text(
@@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -66,14 +67,14 @@ fun BunkerPermissionCard(
.fillMaxWidth()
.clickable {
acceptEventsGroup[index].value = !acceptEventsGroup[index].value
item.second.forEach { it.checked.value = acceptEventsGroup[index].value }
item.second.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = acceptEventsGroup[index].value }
},
) {
Checkbox(
checked = acceptEventsGroup[index].value,
onCheckedChange = { _ ->
acceptEventsGroup[index].value = !acceptEventsGroup[index].value
item.second.forEach { it.checked.value = acceptEventsGroup[index].value }
item.second.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = acceptEventsGroup[index].value }
},
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
@@ -134,7 +135,7 @@ fun BunkerPermissionCard(
)
}
if (acceptEventsGroup[index].value) {
val selected = item.second.filter { it.checked.value }.size
val selected = item.second.filter { MultiEventScreenIntents.checkedStates[it.request.id] ?: true }.size
val total = item.second.size
Row(
Modifier
@@ -55,6 +55,7 @@ import com.greenart7c3.nostrsigner.models.SignerType
import com.greenart7c3.nostrsigner.models.TagArrayEncryptedDataKind
import com.greenart7c3.nostrsigner.service.AmberUtils
import com.greenart7c3.nostrsigner.service.ApplicationNameCache
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
import com.greenart7c3.nostrsigner.service.model.AmberEvent
import com.greenart7c3.nostrsigner.service.toShortenHex
import com.greenart7c3.nostrsigner.ui.RememberType
@@ -82,6 +83,12 @@ fun IntentMultiEventHomeScreen(
var rememberType by remember { mutableStateOf(RememberType.NEVER) }
var relayAuthScope by remember { mutableStateOf(RelayAuthScope.SPECIFIC) }
LaunchedEffect(Unit) {
MultiEventScreenIntents.checkedStates.clear()
MultiEventScreenIntents.rememberType = RememberType.NEVER
intents.forEach { MultiEventScreenIntents.checkedStates[it.id] = true }
}
LaunchedEffect(Unit) {
launch(Dispatchers.IO) {
localAccount = LocalPreferences.loadFromEncryptedStorage(
@@ -124,8 +131,8 @@ fun IntentMultiEventHomeScreen(
SigningAs(accountParam)
val allCheckedState = when {
intents.all { it.checked.value } -> ToggleableState.On
intents.none { it.checked.value } -> ToggleableState.Off
intents.all { MultiEventScreenIntents.checkedStates[it.id] ?: true } -> ToggleableState.On
intents.none { MultiEventScreenIntents.checkedStates[it.id] ?: true } -> ToggleableState.Off
else -> ToggleableState.Indeterminate
}
Row(
@@ -134,14 +141,14 @@ fun IntentMultiEventHomeScreen(
.fillMaxWidth()
.clickable {
val newValue = allCheckedState != ToggleableState.On
intents.forEach { it.checked.value = newValue }
intents.forEach { MultiEventScreenIntents.checkedStates[it.id] = newValue }
},
) {
TriStateCheckbox(
state = allCheckedState,
onClick = {
val newValue = allCheckedState != ToggleableState.On
intents.forEach { it.checked.value = newValue }
intents.forEach { MultiEventScreenIntents.checkedStates[it.id] = newValue }
},
)
Text(stringResource(R.string.select_deselect_all))
@@ -153,7 +160,15 @@ fun IntentMultiEventHomeScreen(
.verticalScroll(rememberScrollState()),
) {
intents.forEach { intent ->
IntentRequestCard(context = context, intent = intent)
IntentRequestCard(
context = context,
intent = intent,
checked = MultiEventScreenIntents.checkedStates[intent.id] ?: true,
onToggleChecked = {
val current = MultiEventScreenIntents.checkedStates[intent.id] ?: true
MultiEventScreenIntents.checkedStates[intent.id] = !current
},
)
}
}
@@ -192,9 +207,7 @@ fun IntentMultiEventHomeScreen(
onReject = {},
onChanged = {
rememberType = it
intents.forEach { intent ->
intent.rememberType.value = rememberType
}
MultiEventScreenIntents.rememberType = it
},
packageName = packageName,
)
@@ -250,7 +263,8 @@ fun IntentMultiEventHomeScreen(
permissions = mutableListOf(),
)
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
val isChecked = MultiEventScreenIntents.checkedStates[intentData.id] ?: true
if (rememberType != RememberType.NEVER && isChecked) {
val rejectKind = if (intentData.type == SignerType.SIGN_EVENT) intentData.event?.kind else null
val rejectRelay = if (intentData.type == SignerType.SIGN_EVENT && intentData.event?.kind == 22242) {
if (relayAuthScope == RelayAuthScope.ALL) {
@@ -275,7 +289,7 @@ fun IntentMultiEventHomeScreen(
intentData.type,
rejectKind,
false,
intentData.rememberType.value,
rememberType,
thisAccount,
relay = rejectRelay,
)
@@ -356,10 +370,12 @@ fun IntentMultiEventHomeScreen(
closeApp = false
}
val isChecked = MultiEventScreenIntents.checkedStates[intentData.id] ?: true
if (intentData.type == SignerType.SIGN_EVENT) {
val localEvent = intentData.event!!
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
val signRelay = if (localEvent.kind == 22242) {
if (relayAuthScope == RelayAuthScope.ALL) {
"*"
@@ -383,7 +399,7 @@ fun IntentMultiEventHomeScreen(
intentData.type,
localEvent.kind,
true,
intentData.rememberType.value,
rememberType,
thisAccount,
relay = signRelay,
)
@@ -398,13 +414,13 @@ fun IntentMultiEventHomeScreen(
intentData.type.toString(),
localEvent.kind,
TimeUtils.now(),
intentData.checked.value,
isChecked,
content = localEvent.toJson(),
),
thisAccount.npub,
)
if (intentData.checked.value) {
if (isChecked) {
results.add(
Result(
null,
@@ -432,14 +448,14 @@ fun IntentMultiEventHomeScreen(
)
}
} else if (intentData.type == SignerType.SIGN_MESSAGE) {
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
AmberUtils.acceptOrRejectPermission(
application,
localKey,
intentData.type,
null,
true,
intentData.rememberType.value,
rememberType,
thisAccount,
)
}
@@ -452,14 +468,14 @@ fun IntentMultiEventHomeScreen(
intentData.type.toString(),
null,
TimeUtils.now(),
intentData.checked.value,
isChecked,
content = intentData.data,
),
thisAccount.npub,
)
val signedMessage = thisAccount.signString(intentData.data)
if (intentData.checked.value) {
if (isChecked) {
results.add(
Result(
null,
@@ -471,14 +487,14 @@ fun IntentMultiEventHomeScreen(
)
}
} else {
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
if (rememberType != RememberType.NEVER && isChecked) {
AmberUtils.acceptOrRejectPermission(
application,
localKey,
intentData.type,
null,
true,
intentData.rememberType.value,
rememberType,
thisAccount,
)
}
@@ -492,7 +508,7 @@ fun IntentMultiEventHomeScreen(
intentData.type.toString(),
null,
TimeUtils.now(),
intentData.checked.value,
isChecked,
content = if (intentData.type == SignerType.NIP04_DECRYPT || intentData.type == SignerType.NIP44_DECRYPT || intentData.type == SignerType.DECRYPT_ZAP_EVENT) {
intentData.encryptedData?.result ?: ""
} else {
@@ -503,7 +519,7 @@ fun IntentMultiEventHomeScreen(
)
val signature = intentData.encryptedData?.result ?: continue
if (intentData.checked.value) {
if (isChecked) {
results.add(
Result(
null,
@@ -533,7 +549,12 @@ fun IntentMultiEventHomeScreen(
}
@Composable
private fun IntentRequestCard(context: Context, intent: IntentData) {
private fun IntentRequestCard(
context: Context,
intent: IntentData,
checked: Boolean,
onToggleChecked: () -> Unit,
) {
val type = intent.type
var showDetails by remember { mutableStateOf(false) }
val hasDetails = (type == SignerType.SIGN_EVENT && intent.event != null) ||
@@ -615,11 +636,11 @@ private fun IntentRequestCard(context: Context, intent: IntentData) {
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { intent.checked.value = !intent.checked.value },
.clickable { onToggleChecked() },
) {
Checkbox(
checked = intent.checked.value,
onCheckedChange = { intent.checked.value = !intent.checked.value },
checked = checked,
onCheckedChange = { onToggleChecked() },
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
),
@@ -631,7 +652,7 @@ private fun IntentRequestCard(context: Context, intent: IntentData) {
) {
Text(
text = label,
color = if (intent.checked.value) Color.Unspecified else Color.Gray,
color = if (checked) Color.Unspecified else Color.Gray,
)
if (preview.isNotBlank()) {
Text(
@@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -66,14 +67,14 @@ fun PermissionCard(
.fillMaxWidth()
.clickable {
acceptEventsGroup[index].value = !acceptEventsGroup[index].value
item.second.forEach { it.checked.value = acceptEventsGroup[index].value }
item.second.forEach { MultiEventScreenIntents.checkedStates[it.id] = acceptEventsGroup[index].value }
},
) {
Checkbox(
checked = acceptEventsGroup[index].value,
onCheckedChange = { _ ->
acceptEventsGroup[index].value = !acceptEventsGroup[index].value
item.second.forEach { it.checked.value = acceptEventsGroup[index].value }
item.second.forEach { MultiEventScreenIntents.checkedStates[it.id] = acceptEventsGroup[index].value }
},
colors = CheckboxDefaults.colors().copy(
uncheckedBorderColor = Color.Gray,
@@ -134,7 +135,7 @@ fun PermissionCard(
)
}
if (acceptEventsGroup[index].value) {
val selected = item.second.filter { it.checked.value }.size
val selected = item.second.filter { MultiEventScreenIntents.checkedStates[it.id] ?: true }.size
val total = item.second.size
Row(
Modifier