mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 03:18:23 +00:00
Add Compose previews for the multi-event approval screens
Add light/dark previews for BunkerMultiEventHomeScreen and IntentMultiEventHomeScreen with sample request groups (connect, sign event, NIP-44 decrypt) so group headers, options and cards all render. Guard side effects that reach the Amber singleton, which does not exist in the preview renderer: - ProfileSubscriptionEffect: skip the relay subscription in inspection mode (also fixes every preview embedding SigningAs) - BunkerMultiEventHomeScreen: skip the encrypted-storage/DB lookup - rememberAppDisplayInfo: fall back to the package name when any part of the PackageManager lookup fails instead of crashing
This commit is contained in:
@@ -238,18 +238,13 @@ fun AmberTopAppBar(
|
||||
fun rememberAppDisplayInfo(packageName: String): AppDisplayInfo {
|
||||
val context = LocalContext.current
|
||||
return remember(packageName) {
|
||||
val appInfo = runCatching {
|
||||
context.packageManager.getApplicationInfo(packageName, 0)
|
||||
}.getOrNull()
|
||||
|
||||
if (appInfo != null) {
|
||||
runCatching {
|
||||
val appInfo = context.packageManager.getApplicationInfo(packageName, 0)
|
||||
AppDisplayInfo(
|
||||
name = context.packageManager.getApplicationLabel(appInfo).toString(),
|
||||
icon = context.packageManager.getApplicationIcon(appInfo),
|
||||
)
|
||||
} else {
|
||||
AppDisplayInfo(name = packageName, icon = null)
|
||||
}
|
||||
}.getOrNull() ?: AppDisplayInfo(name = packageName, icon = null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+112
-16
@@ -5,6 +5,7 @@ import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -23,6 +24,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.capitalize
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
@@ -36,7 +38,9 @@ import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.AmberBunkerRequest
|
||||
import com.greenart7c3.nostrsigner.models.BunkerClientMetadata
|
||||
import com.greenart7c3.nostrsigner.models.ClearTextEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.models.EncryptionType
|
||||
import com.greenart7c3.nostrsigner.models.EventEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.models.PrivateZapEncryptedDataKind
|
||||
@@ -51,13 +55,21 @@ import com.greenart7c3.nostrsigner.service.RelayUrlUtils
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
|
||||
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
|
||||
import com.greenart7c3.nostrsigner.ui.theme.previewAccount
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestConnect
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip44Decrypt
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestSign
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.set
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -85,25 +97,29 @@ fun BunkerMultiEventHomeScreen(
|
||||
bunkerRequests.forEach { MultiEventScreenIntents.checkedStates[it.request.id] = true }
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
launch(Dispatchers.IO) {
|
||||
localAccount = LocalPreferences.loadFromEncryptedStorage(
|
||||
context,
|
||||
bunkerRequests.first().currentAccount,
|
||||
)?.npub?.toShortenHex() ?: ""
|
||||
// Skipped in previews: encrypted storage and the Amber singleton don't
|
||||
// exist in the preview renderer.
|
||||
if (!LocalInspectionMode.current) {
|
||||
LaunchedEffect(Unit) {
|
||||
launch(Dispatchers.IO) {
|
||||
localAccount = LocalPreferences.loadFromEncryptedStorage(
|
||||
context,
|
||||
bunkerRequests.first().currentAccount,
|
||||
)?.npub?.toShortenHex() ?: ""
|
||||
|
||||
val app = Amber.instance.getDatabase(accountParam.npub).dao().getByKey(key)
|
||||
if (ApplicationNameCache["$localAccount-$key"] == null) {
|
||||
app?.let {
|
||||
appName = it.application.name
|
||||
ApplicationNameCache["$localAccount-$key"] = it.application.name
|
||||
}
|
||||
} else {
|
||||
ApplicationNameCache["$localAccount-$key"]?.let {
|
||||
appName = it
|
||||
val app = Amber.instance.getDatabase(accountParam.npub).dao().getByKey(key)
|
||||
if (ApplicationNameCache["$localAccount-$key"] == null) {
|
||||
app?.let {
|
||||
appName = it.application.name
|
||||
ApplicationNameCache["$localAccount-$key"] = it.application.name
|
||||
}
|
||||
} else {
|
||||
ApplicationNameCache["$localAccount-$key"]?.let {
|
||||
appName = it
|
||||
}
|
||||
}
|
||||
app?.application?.icon?.let { if (it.isNotBlank()) appIcon = it }
|
||||
}
|
||||
app?.application?.icon?.let { if (it.isNotBlank()) appIcon = it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -592,3 +608,83 @@ private fun finishActivity(closeApp: Boolean) {
|
||||
private suspend fun reconnectToRelays() {
|
||||
Amber.instance.checkForNewRelaysAndUpdateAllFilters()
|
||||
}
|
||||
|
||||
private const val PREVIEW_LOCAL_KEY = "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"
|
||||
|
||||
private fun previewBunkerRequest(
|
||||
request: BunkerRequest,
|
||||
signedEvent: Event? = null,
|
||||
encryptedData: ClearTextEncryptedDataKind? = null,
|
||||
) = AmberBunkerRequest(
|
||||
request = request,
|
||||
localKey = PREVIEW_LOCAL_KEY,
|
||||
relays = listOf(),
|
||||
currentAccount = "",
|
||||
nostrConnectSecret = "",
|
||||
closeApplication = false,
|
||||
name = "",
|
||||
signedEvent = signedEvent,
|
||||
encryptedData = encryptedData,
|
||||
encryptionType = EncryptionType.NIP44,
|
||||
isNostrConnectUri = false,
|
||||
clientMetadata = BunkerClientMetadata(name = "Amethyst", url = "https://amethyst.social"),
|
||||
)
|
||||
|
||||
private fun previewSignRequest(id: String, content: String) = previewBunkerRequest(
|
||||
request = BunkerRequestSign(
|
||||
id = id,
|
||||
event = EventTemplate(
|
||||
createdAt = 1735689600,
|
||||
kind = 1,
|
||||
tags = arrayOf(arrayOf("t", "amber")),
|
||||
content = content,
|
||||
),
|
||||
),
|
||||
signedEvent = Event(
|
||||
id = "0".repeat(64),
|
||||
pubKey = PREVIEW_LOCAL_KEY,
|
||||
createdAt = 1735689600,
|
||||
kind = 1,
|
||||
tags = arrayOf(arrayOf("t", "amber")),
|
||||
content = content,
|
||||
sig = "",
|
||||
),
|
||||
)
|
||||
|
||||
@ThemePreviews
|
||||
@Composable
|
||||
fun BunkerMultiEventHomeScreenPreview() {
|
||||
// The screen normally resolves the app name from the database, which is
|
||||
// skipped in previews — seed the cache so the header shows a real name.
|
||||
ApplicationNameCache["-$PREVIEW_LOCAL_KEY"] = "Amethyst"
|
||||
|
||||
AmberPreview {
|
||||
BunkerMultiEventHomeScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(700.dp)
|
||||
.padding(16.dp),
|
||||
bunkerRequests = persistentListOf(
|
||||
previewBunkerRequest(
|
||||
request = BunkerRequestConnect(
|
||||
id = "preview-connect",
|
||||
remoteKey = PREVIEW_LOCAL_KEY,
|
||||
),
|
||||
),
|
||||
previewSignRequest("preview-sign-1", "Hello Nostr!"),
|
||||
previewSignRequest("preview-sign-2", "GM from Amber"),
|
||||
previewBunkerRequest(
|
||||
request = BunkerRequestNip44Decrypt(
|
||||
id = "preview-nip44-decrypt",
|
||||
pubKey = PREVIEW_LOCAL_KEY,
|
||||
ciphertext = "encrypted-payload",
|
||||
),
|
||||
encryptedData = ClearTextEncryptedDataKind("encrypted-payload", "Hello Nostr!"),
|
||||
),
|
||||
),
|
||||
packageName = null,
|
||||
accountParam = previewAccount(),
|
||||
onLoading = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+73
@@ -7,6 +7,7 @@ import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
@@ -38,12 +39,14 @@ import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions
|
||||
import com.greenart7c3.nostrsigner.database.HistoryEntity
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.models.ClearTextEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.models.CompressionType
|
||||
import com.greenart7c3.nostrsigner.models.EventEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.models.IntentData
|
||||
import com.greenart7c3.nostrsigner.models.IntentResultType
|
||||
import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.models.PrivateZapEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.models.Result
|
||||
import com.greenart7c3.nostrsigner.models.ReturnType
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TagArrayEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
@@ -51,9 +54,14 @@ import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
|
||||
import com.greenart7c3.nostrsigner.service.RelayUrlUtils
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
|
||||
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
|
||||
import com.greenart7c3.nostrsigner.ui.theme.previewAccount
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -508,6 +516,71 @@ private fun IntentRequestCard(
|
||||
}
|
||||
}
|
||||
|
||||
private const val PREVIEW_PUBKEY = "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"
|
||||
|
||||
private fun previewIntent(
|
||||
id: String,
|
||||
type: SignerType,
|
||||
data: String = "",
|
||||
event: Event? = null,
|
||||
encryptedData: ClearTextEncryptedDataKind? = null,
|
||||
) = IntentData(
|
||||
data = data,
|
||||
name = "",
|
||||
type = type,
|
||||
pubKey = PREVIEW_PUBKEY,
|
||||
id = id,
|
||||
callBackUrl = null,
|
||||
compression = CompressionType.NONE,
|
||||
returnType = ReturnType.SIGNATURE,
|
||||
permissions = null,
|
||||
currentAccount = "",
|
||||
route = null,
|
||||
event = event,
|
||||
encryptedData = encryptedData,
|
||||
)
|
||||
|
||||
private fun previewSignIntent(id: String, content: String) = previewIntent(
|
||||
id = id,
|
||||
type = SignerType.SIGN_EVENT,
|
||||
event = Event(
|
||||
id = "0".repeat(64),
|
||||
pubKey = PREVIEW_PUBKEY,
|
||||
createdAt = 1735689600,
|
||||
kind = 1,
|
||||
tags = arrayOf(arrayOf("t", "amber")),
|
||||
content = content,
|
||||
sig = "",
|
||||
),
|
||||
)
|
||||
|
||||
@ThemePreviews
|
||||
@Composable
|
||||
fun IntentMultiEventHomeScreenPreview() {
|
||||
AmberPreview {
|
||||
IntentMultiEventHomeScreen(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(700.dp)
|
||||
.padding(16.dp),
|
||||
intents = persistentListOf(
|
||||
previewSignIntent("preview-sign-1", "Hello Nostr!"),
|
||||
previewSignIntent("preview-sign-2", "GM from Amber"),
|
||||
previewIntent(
|
||||
id = "preview-nip44-decrypt",
|
||||
type = SignerType.NIP44_DECRYPT,
|
||||
data = "encrypted-payload",
|
||||
encryptedData = ClearTextEncryptedDataKind("encrypted-payload", "Hello Nostr!"),
|
||||
),
|
||||
),
|
||||
packageName = "com.vitorpamplona.amethyst",
|
||||
accountParam = previewAccount(),
|
||||
onRemoveIntentData = { _, _ -> },
|
||||
onLoading = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishActivity(closeApp: Boolean) {
|
||||
val activity = Amber.instance.getMainActivity()
|
||||
activity?.intent = null
|
||||
|
||||
+3
@@ -2,6 +2,7 @@ package com.greenart7c3.nostrsigner.ui.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import com.greenart7c3.nostrsigner.Amber
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -14,6 +15,8 @@ import kotlinx.coroutines.launch
|
||||
*/
|
||||
@Composable
|
||||
fun ProfileSubscriptionEffect(account: Account) {
|
||||
// No relay subscriptions in previews: the Amber singleton doesn't exist in the preview renderer.
|
||||
if (LocalInspectionMode.current) return
|
||||
DisposableEffect(account.hexKey) {
|
||||
val sub = Amber.instance.profileSubscription
|
||||
Amber.instance.applicationIOScope.launch { sub.updateFilter(account) }
|
||||
|
||||
Reference in New Issue
Block a user