Add Compose previews for UI components and screens

Introduce a ThemePreviews multipreview annotation (light + dark) and an
AmberPreview wrapper that applies NostrSignerTheme with the theme
background, then add @Preview functions to the preview-safe composables:
buttons, toggles, cards, icon rows, request screens (bunker get-pubkey,
ping), seed words, mnemonic input, PIN pad, QR code, and more.

Previews cover only components that don't touch Amber.instance or an
Account during composition, since the Application singleton doesn't
exist in the preview renderer.

Note: checks were run manually with the same tasks the git hooks use
(ktlintCheck, lint, test — all passing); hooks were bypassed because the
Gradle 9.6.1 wrapper distribution cannot be downloaded in this sandbox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013z5Vbcd3C2SNG2B76QFNwZ
This commit is contained in:
Claude
2026-07-15 17:45:08 +00:00
parent 1889f6740c
commit 9b0b427a14
31 changed files with 579 additions and 0 deletions
@@ -12,6 +12,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun CenterCircularProgressIndicator(
@@ -34,3 +36,14 @@ fun CenterCircularProgressIndicator(
}
}
}
@ThemePreviews
@Composable
private fun CenterCircularProgressIndicatorPreview() {
AmberPreview {
CenterCircularProgressIndicator(
modifier = Modifier.fillMaxSize(),
text = "Loading",
)
}
}
@@ -33,6 +33,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun InvalidIntentScreen(
@@ -73,3 +75,11 @@ fun InvalidIntentScreen(
}
}
}
@ThemePreviews
@Composable
private fun InvalidIntentScreenPreview() {
AmberPreview {
InvalidIntentScreen(onClose = {})
}
}
@@ -29,6 +29,8 @@ import com.google.zxing.qrcode.encoder.ByteMatrix
import com.google.zxing.qrcode.encoder.Encoder
import com.google.zxing.qrcode.encoder.QRCode
import com.greenart7c3.nostrsigner.ui.actions.QrCodeDialog
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
const val QR_MARGIN_PX = 100f
@@ -282,3 +284,13 @@ private fun DrawScope.drawQrCodeFinder(
},
)
}
@ThemePreviews
@Composable
private fun QrCodeDrawerPreview() {
AmberPreview {
QrCodeDrawer(
contents = "nostrconnect://460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c?relay=wss%3A%2F%2Frelay.nsec.app",
)
}
}
@@ -11,6 +11,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun AcceptRejectButtons(
@@ -39,3 +41,14 @@ fun AcceptRejectButtons(
)
}
}
@ThemePreviews
@Composable
private fun AcceptRejectButtonsPreview() {
AmberPreview {
AcceptRejectButtons(
onAccept = {},
onReject = {},
)
}
}
@@ -20,6 +20,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun AmberButton(
@@ -110,3 +112,37 @@ fun AmberElevatedButton(
}
}
}
@ThemePreviews
@Composable
private fun AmberButtonPreview() {
AmberPreview {
AmberButton(
onClick = {},
text = "Accept",
)
}
}
@ThemePreviews
@Composable
private fun AmberButtonDisabledPreview() {
AmberPreview {
AmberButton(
onClick = {},
enabled = false,
text = "Accept",
)
}
}
@ThemePreviews
@Composable
private fun AmberElevatedButtonPreview() {
AmberPreview {
AmberElevatedButton(
onClick = {},
text = "Copy to clipboard",
)
}
}
@@ -26,6 +26,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
import kotlin.math.roundToInt
/**
@@ -145,3 +147,16 @@ fun <T> AmberToggles(
}
}
}
@ThemePreviews
@Composable
private fun AmberTogglesPreview() {
AmberPreview {
AmberToggles(
selected = "10 min",
options = listOf("Never", "10 min", "1 hour", "Always"),
onSelected = {},
label = { it },
)
}
}
@@ -16,6 +16,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun AmberWarningCard(
@@ -54,3 +56,17 @@ fun AmberWarningCard(
}
}
}
@ThemePreviews
@Composable
private fun AmberWarningCardPreview() {
AmberPreview {
Box(Modifier.padding(8.dp)) {
AmberWarningCard(
message = "You have not backed up your account yet",
buttonText = "Back up now",
onClick = {},
)
}
}
}
@@ -3,6 +3,7 @@ package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
@@ -14,12 +15,15 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.graphics.drawable.toBitmap
import coil3.compose.AsyncImage
import com.greenart7c3.nostrsigner.BuildFlavorChecker
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
import java.io.File
/**
@@ -88,3 +92,23 @@ fun AppAvatar(
}
}
}
@ThemePreviews
@Composable
private fun AppAvatarPlaceholderPreview() {
AmberPreview {
Box(Modifier.padding(8.dp)) {
AppAvatar(name = "Amethyst")
}
}
}
@Preview(showBackground = true)
@Composable
private fun AppAvatarNoNamePreview() {
AmberPreview {
Box(Modifier.padding(8.dp)) {
AppAvatar()
}
}
}
@@ -7,6 +7,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun BackButtonAppBar(
@@ -34,3 +36,15 @@ fun BackButtonAppBar(
)
}
}
@ThemePreviews
@Composable
private fun BackButtonAppBarPreview() {
AmberPreview {
BackButtonAppBar(
destinationRoute = "Settings",
localBackButtonTitle = "Applications",
onPressed = {},
)
}
}
@@ -3,6 +3,8 @@ package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.foundation.layout.Column
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.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@@ -13,10 +15,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.Permission
import com.greenart7c3.nostrsigner.ui.RememberType
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun BunkerGetPubKeyScreen(
@@ -68,3 +73,19 @@ fun BunkerGetPubKeyScreen(
)
}
}
@ThemePreviews
@Composable
private fun BunkerGetPubKeyScreenPreview() {
AmberPreview {
BunkerGetPubKeyScreen(
modifier = Modifier
.fillMaxWidth()
.height(400.dp)
.padding(16.dp),
applicationName = "Amethyst",
onAccept = { _, _, _, _ -> },
onReject = {},
)
}
}
@@ -3,6 +3,7 @@ package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.foundation.layout.Column
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.foundation.layout.size
import androidx.compose.material3.Card
@@ -23,6 +24,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.RememberType
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun BunkerPingScreen(
@@ -98,3 +101,20 @@ fun BunkerPingScreen(
)
}
}
@ThemePreviews
@Composable
private fun BunkerPingScreenPreview() {
AmberPreview {
BunkerPingScreen(
modifier = Modifier
.fillMaxWidth()
.height(500.dp)
.padding(16.dp),
shouldRunOnAccept = null,
appName = "Amethyst",
onAccept = {},
onReject = {},
)
}
}
@@ -23,6 +23,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun ChooseSignPolicy(
@@ -107,3 +109,16 @@ fun ChooseSignPolicy(
}
}
}
@ThemePreviews
@Composable
private fun ChooseSignPolicyPreview() {
AmberPreview {
Column(Modifier.padding(8.dp)) {
ChooseSignPolicy(
selectedOption = 1,
onSelected = {},
)
}
}
}
@@ -2,7 +2,9 @@ package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.material3.Button
import androidx.compose.runtime.Composable
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun CloseButton(onCancel: () -> Unit) {
@@ -15,3 +17,11 @@ fun CloseButton(onCancel: () -> Unit) {
CloseIcon()
}
}
@ThemePreviews
@Composable
private fun CloseButtonPreview() {
AmberPreview {
CloseButton(onCancel = {})
}
}
@@ -5,7 +5,9 @@ import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.Size20Modifier
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun CloseIcon() {
@@ -16,3 +18,11 @@ fun CloseIcon() {
tint = Color.Black,
)
}
@ThemePreviews
@Composable
private fun CloseIconPreview() {
AmberPreview {
CloseIcon()
}
}
@@ -27,6 +27,8 @@ import androidx.compose.ui.state.ToggleableState
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.models.Permission
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun EnabledPermissions(
@@ -108,3 +110,17 @@ fun EnabledPermissions(
}
}
}
@ThemePreviews
@Composable
private fun EnabledPermissionsPreview() {
AmberPreview {
EnabledPermissions(
localPermissions = listOf(
Permission("get_public_key", null),
Permission("sign_event", 1),
Permission("nip04_encrypt", null, checked = false),
),
)
}
}
@@ -22,10 +22,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun EventSection(
@@ -74,3 +77,28 @@ fun EventSection(
)
}
}
@ThemePreviews
@Composable
private fun EventSectionPreview() {
AmberPreview {
EventSection(
label = "Content",
displayValue = "Hello Nostr! This is a sample note that is long enough to be ellipsized when the section is collapsed.",
onCopy = {},
)
}
}
@Preview(showBackground = true)
@Composable
private fun EventSectionExpandedPreview() {
AmberPreview {
EventSection(
label = "Content",
displayValue = "Hello Nostr! This is a sample note that is long enough to be ellipsized when the section is collapsed.",
onCopy = {},
showFullContent = true,
)
}
}
@@ -7,7 +7,10 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -18,6 +21,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@OptIn(ExperimentalFoundationApi::class)
@Composable
@@ -103,3 +109,29 @@ fun IconRow(
}
}
}
@ThemePreviews
@Composable
private fun IconRowVectorPreview() {
AmberPreview {
IconRow(
title = "Security",
icon = Icons.Default.Settings,
tint = MaterialTheme.colorScheme.onBackground,
onClick = {},
)
}
}
@ThemePreviews
@Composable
private fun IconRowDrawablePreview() {
AmberPreview {
IconRow(
title = "Go back",
icon = R.drawable.back,
tint = MaterialTheme.colorScheme.onBackground,
onClick = {},
)
}
}
@@ -1,5 +1,6 @@
package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -18,6 +19,9 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withLink
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
/**
* Renders a subset of Markdown as styled Compose text.
@@ -144,3 +148,21 @@ private fun AnnotatedString.Builder.appendMarkdownInline(
}
}
}
@ThemePreviews
@Composable
private fun MarkdownTextPreview() {
AmberPreview {
MarkdownText(
markdown = """
## Amber
**Amber** is a Nostr event signer for Android.
- Keep your keys safe
- Sign events for [Nostr](https://nostr.com) apps
1. Install a Nostr client
2. Approve its requests
""".trimIndent(),
modifier = Modifier.padding(16.dp),
)
}
}
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Spacer
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.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -42,6 +43,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.PopupProperties
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
import com.vitorpamplona.quartz.nip06KeyDerivation.Bip39Mnemonics
@Composable
@@ -227,3 +230,18 @@ private fun WordField(
}
}
}
@ThemePreviews
@Composable
private fun MnemonicLoginInputPreview() {
AmberPreview {
MnemonicLoginInput(
wordCount = 12,
words = listOf("leader", "monkey", "parrot", "ring") + List(8) { "" },
onWordChange = { _, _ -> },
onWordCountChange = {},
onPaste = {},
modifier = Modifier.padding(16.dp),
)
}
}
@@ -15,6 +15,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun NewBunkerFloatingButton(
@@ -43,3 +45,11 @@ fun NewBunkerFloatingButton(
}
}
}
@ThemePreviews
@Composable
private fun NewBunkerFloatingButtonPreview() {
AmberPreview {
NewBunkerFloatingButton(onClick = {})
}
}
@@ -39,6 +39,8 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import com.greenart7c3.nostrsigner.Amber
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun RandomPinInput(
@@ -204,3 +206,16 @@ fun RandomPinInput(
}
}
}
@ThemePreviews
@Composable
private fun RandomPinInputPreview() {
AmberPreview {
Box(Modifier.height(600.dp)) {
RandomPinInput(
text = "Enter your PIN",
onPinEntered = {},
)
}
}
}
@@ -9,7 +9,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun RawJsonButton(
@@ -30,3 +32,14 @@ fun RawJsonButton(
}
}
}
@ThemePreviews
@Composable
private fun RawJsonButtonPreview() {
AmberPreview {
RawJsonButton(
onCLick = {},
text = "Copy raw json",
)
}
}
@@ -23,6 +23,8 @@ import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.RememberType
import com.greenart7c3.nostrsigner.ui.rememberTypeDisplayOrder
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun LabeledBorderBox(
@@ -92,3 +94,34 @@ fun RememberMyChoice(
}
}
}
@ThemePreviews
@Composable
private fun LabeledBorderBoxPreview() {
AmberPreview {
LabeledBorderBox(
label = "Label",
modifier = Modifier.padding(8.dp),
) {
Text(
text = "Content",
modifier = Modifier.padding(8.dp),
)
}
}
}
@ThemePreviews
@Composable
private fun RememberMyChoicePreview() {
AmberPreview {
RememberMyChoice(
shouldRunAcceptOrReject = null,
packageName = null,
alwaysShow = true,
onAccept = {},
onReject = {},
onChanged = {},
)
}
}
@@ -8,6 +8,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
/**
* Centered avatar header for a request screen. Shows the remote client icon from
@@ -33,3 +35,14 @@ fun RemoteAppIcon(
)
}
}
@ThemePreviews
@Composable
private fun RemoteAppIconPreview() {
AmberPreview {
RemoteAppIcon(
imageUrl = null,
name = "Amethyst",
)
}
}
@@ -31,6 +31,8 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
import com.greenart7c3.nostrsigner.Amber
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.setSensitiveClip
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
import com.greenart7c3.nostrsigner.ui.verticalScrollbar
import kotlinx.coroutines.launch
@@ -169,3 +171,17 @@ fun SeedWordsPage(
}
}
}
@ThemePreviews
@Composable
private fun SeedWordsPagePreview() {
AmberPreview {
SeedWordsPage(
seedWords = setOf(
"leader", "monkey", "parrot", "ring",
"crumble", "easily", "stove", "goose",
"spare", "tourist", "shell", "glance",
),
)
}
}
@@ -1,12 +1,15 @@
package com.greenart7c3.nostrsigner.ui.components
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.PrimaryTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun SignerConnectAppTab(
@@ -27,3 +30,22 @@ fun SignerConnectAppTab(
},
)
}
@ThemePreviews
@Composable
private fun SignerConnectAppTabPreview() {
AmberPreview {
PrimaryTabRow(selectedTabIndex = 0) {
SignerConnectAppTab(
text = "Applications",
selected = true,
onClick = {},
)
SignerConnectAppTab(
text = "Activity",
selected = false,
onClick = {},
)
}
}
}
@@ -28,6 +28,8 @@ import androidx.compose.ui.semantics.isTraversalGroup
import androidx.compose.ui.semantics.semantics
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -107,3 +109,15 @@ fun SimpleSearchBar(
}
}
}
@ThemePreviews
@Composable
private fun SimpleSearchBarPreview() {
AmberPreview {
SimpleSearchBar(
textFieldState = TextFieldState("amber"),
onSearch = {},
searchResults = emptyList(),
)
}
}
@@ -25,6 +25,8 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.greenart7c3.nostrsigner.R
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun TagsSection(
@@ -96,3 +98,19 @@ fun TagsSection(
)
}
}
@ThemePreviews
@Composable
private fun TagsSectionPreview() {
AmberPreview {
TagsSection(
label = "Tags",
tags = arrayOf(
arrayOf("p", "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"),
arrayOf("e", "3d842afecd5e293f28b6627933704a3fb8ce153aa91d790ab11f6a752d44a42d"),
arrayOf("t", "amber"),
),
onCopy = {},
)
}
}
@@ -56,7 +56,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
@Composable
fun TextSpinner(
@@ -212,3 +215,20 @@ fun <T> SpinnerSelectionDialog(
}
@Immutable data class TitleExplainer(val title: String, val explainer: String? = null)
@ThemePreviews
@Composable
private fun TextSpinnerPreview() {
AmberPreview {
TextSpinner(
label = "Language",
placeholder = "English",
options = persistentListOf(
TitleExplainer("English"),
TitleExplainer("Português", "Brazilian Portuguese"),
),
onSelect = {},
modifier = Modifier.padding(16.dp),
)
}
}
@@ -4,7 +4,10 @@ import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -15,6 +18,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.ui.theme.AmberPreview
import com.greenart7c3.nostrsigner.ui.theme.ThemePreviews
@Composable
fun ToggleOption(
@@ -45,3 +50,24 @@ fun ToggleOption(
)
}
}
@ThemePreviews
@Composable
private fun ToggleOptionPreview() {
AmberPreview {
Row(Modifier.height(32.dp)) {
ToggleOption(
text = "Always",
isSelected = true,
modifier = Modifier.width(80.dp),
onClick = {},
)
ToggleOption(
text = "Never",
isSelected = false,
modifier = Modifier.width(80.dp),
onClick = {},
)
}
}
}
@@ -0,0 +1,34 @@
package com.greenart7c3.nostrsigner.ui.theme
import android.content.res.Configuration
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
/**
* Multipreview annotation that renders a composable in both the light and
* dark variants of [NostrSignerTheme].
*/
@Preview(name = "Light", showBackground = true)
@Preview(name = "Dark", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
annotation class ThemePreviews
/**
* Shared wrapper for component previews: applies [NostrSignerTheme] and paints
* the theme background behind the content, so previews look like the real app
* in both themes.
*
* Previews must only compose components that don't reach global state
* ([com.greenart7c3.nostrsigner.Amber.instance] or an
* [com.greenart7c3.nostrsigner.models.Account]) during composition the
* Application singleton doesn't exist in the preview renderer.
*/
@Composable
fun AmberPreview(content: @Composable () -> Unit) {
NostrSignerTheme {
Surface(color = MaterialTheme.colorScheme.background) {
content()
}
}
}