previous PR fixes
This commit is contained in:
@@ -5,6 +5,7 @@ plugins {
|
||||
alias(libs.plugins.androidLibrary)
|
||||
alias(libs.plugins.jetbrainsComposeCompiler)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.mokoResources)
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -75,6 +76,10 @@ kotlin {
|
||||
|
||||
// Immutable collections
|
||||
api(libs.kotlinx.collections.immutable)
|
||||
|
||||
// Moko Resources for KMP string resources
|
||||
api(libs.moko.resources)
|
||||
api(libs.moko.resources.compose)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,3 +129,8 @@ kotlin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiplatformResources {
|
||||
resourcesPackage.set("com.vitorpamplona.amethyst.commons")
|
||||
resourcesClassName.set("SharedRes")
|
||||
}
|
||||
|
||||
+17
-7
@@ -34,6 +34,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.SharedRes
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
/**
|
||||
* A centered loading state with a progress indicator and message.
|
||||
@@ -67,8 +69,10 @@ fun EmptyState(
|
||||
modifier: Modifier = Modifier,
|
||||
description: String? = null,
|
||||
onRefresh: (() -> Unit)? = null,
|
||||
refreshLabel: String = "Refresh",
|
||||
refreshLabel: String? = null,
|
||||
) {
|
||||
val actualRefreshLabel = refreshLabel ?: stringResource(SharedRes.strings.action_refresh)
|
||||
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
@@ -90,7 +94,7 @@ fun EmptyState(
|
||||
if (onRefresh != null) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
OutlinedButton(onClick = onRefresh) {
|
||||
Text(refreshLabel)
|
||||
Text(actualRefreshLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,8 +108,10 @@ fun ErrorState(
|
||||
message: String,
|
||||
modifier: Modifier = Modifier,
|
||||
onRetry: (() -> Unit)? = null,
|
||||
retryLabel: String = "Try Again",
|
||||
retryLabel: String? = null,
|
||||
) {
|
||||
val actualRetryLabel = retryLabel ?: stringResource(SharedRes.strings.action_try_again)
|
||||
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
@@ -119,7 +125,7 @@ fun ErrorState(
|
||||
if (onRetry != null) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Button(onClick = onRetry) {
|
||||
Text(retryLabel)
|
||||
Text(actualRetryLabel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,11 +137,13 @@ fun ErrorState(
|
||||
@Composable
|
||||
fun FeedEmptyState(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = "Feed is empty",
|
||||
title: String? = null,
|
||||
onRefresh: (() -> Unit)? = null,
|
||||
) {
|
||||
val actualTitle = title ?: stringResource(SharedRes.strings.feed_empty)
|
||||
|
||||
EmptyState(
|
||||
title = title,
|
||||
title = actualTitle,
|
||||
modifier = modifier,
|
||||
onRefresh = onRefresh,
|
||||
)
|
||||
@@ -150,8 +158,10 @@ fun FeedErrorState(
|
||||
modifier: Modifier = Modifier,
|
||||
onRetry: (() -> Unit)? = null,
|
||||
) {
|
||||
val formattedMessage = stringResource(SharedRes.strings.error_loading_feed).format(errorMessage)
|
||||
|
||||
ErrorState(
|
||||
message = "Error loading feed: $errorMessage",
|
||||
message = formattedMessage,
|
||||
modifier = modifier,
|
||||
onRetry = onRetry,
|
||||
)
|
||||
|
||||
+8
-6
@@ -28,6 +28,8 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.SharedRes
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
/**
|
||||
* Generic placeholder screen with title and description.
|
||||
@@ -58,8 +60,8 @@ fun PlaceholderScreen(
|
||||
@Composable
|
||||
fun SearchPlaceholder(modifier: Modifier = Modifier) {
|
||||
PlaceholderScreen(
|
||||
title = "Search",
|
||||
description = "Search for users, notes, and hashtags.",
|
||||
title = stringResource(SharedRes.strings.screen_search_title),
|
||||
description = stringResource(SharedRes.strings.screen_search_description),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
@@ -70,8 +72,8 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) {
|
||||
@Composable
|
||||
fun MessagesPlaceholder(modifier: Modifier = Modifier) {
|
||||
PlaceholderScreen(
|
||||
title = "Messages",
|
||||
description = "Your encrypted direct messages will appear here.",
|
||||
title = stringResource(SharedRes.strings.screen_messages_title),
|
||||
description = stringResource(SharedRes.strings.screen_messages_description),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
@@ -82,8 +84,8 @@ fun MessagesPlaceholder(modifier: Modifier = Modifier) {
|
||||
@Composable
|
||||
fun NotificationsPlaceholder(modifier: Modifier = Modifier) {
|
||||
PlaceholderScreen(
|
||||
title = "Notifications",
|
||||
description = "Mentions, replies, and reactions will appear here.",
|
||||
title = stringResource(SharedRes.strings.screen_notifications_title),
|
||||
description = stringResource(SharedRes.strings.screen_notifications_description),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Login & Auth -->
|
||||
<string name="login_title">Welcome to Amethyst</string>
|
||||
<string name="login_subtitle">Sign in to your Nostr account</string>
|
||||
<string name="login_subtitle_desktop">A Nostr client for desktop</string>
|
||||
<string name="login_card_title">Login with your Nostr key</string>
|
||||
<string name="login_card_subtitle">Use nsec for full access or npub for read-only</string>
|
||||
<string name="login_with_key">Login with Key</string>
|
||||
<string name="login_button">Login</string>
|
||||
<string name="login_generate_new">Generate New Key</string>
|
||||
<string name="login_generate_button">Generate New</string>
|
||||
<string name="login_key_hint">Enter your private key (nsec) or public key (npub)</string>
|
||||
<string name="login_key_label">nsec or npub</string>
|
||||
<string name="login_key_placeholder">nsec1... or npub1...</string>
|
||||
<string name="login_show_key">Show key</string>
|
||||
<string name="login_hide_key">Hide key</string>
|
||||
|
||||
<!-- New Key Warning -->
|
||||
<string name="new_key_warning_title">IMPORTANT: Save your keys!</string>
|
||||
<string name="new_key_warning_message">Your secret key (nsec) is the ONLY way to access your account. If you lose it, your account is gone forever. Save it somewhere safe!</string>
|
||||
<string name="new_key_public_label">Public Key (shareable):</string>
|
||||
<string name="new_key_secret_label">Secret Key (NEVER share this!):</string>
|
||||
<string name="new_key_continue_button">I've saved my keys, continue</string>
|
||||
|
||||
<!-- Common Actions -->
|
||||
<string name="action_copy">Copy</string>
|
||||
<string name="action_paste">Paste</string>
|
||||
<string name="action_cancel">Cancel</string>
|
||||
<string name="action_ok">OK</string>
|
||||
<string name="action_save">Save</string>
|
||||
<string name="action_delete">Delete</string>
|
||||
<string name="action_share">Share</string>
|
||||
|
||||
<!-- Errors -->
|
||||
<string name="error_invalid_key">Invalid key format. Please check and try again.</string>
|
||||
<string name="error_network">Network error. Please check your connection.</string>
|
||||
<string name="error_generic">An error occurred. Please try again.</string>
|
||||
|
||||
<!-- Loading & Empty States -->
|
||||
<string name="action_refresh">Refresh</string>
|
||||
<string name="action_try_again">Try Again</string>
|
||||
<string name="feed_empty">Feed is empty</string>
|
||||
<string name="error_loading_feed">Error loading feed: %s</string>
|
||||
|
||||
<!-- Placeholder Screens -->
|
||||
<string name="screen_search_title">Search</string>
|
||||
<string name="screen_search_description">Search for users, notes, and hashtags.</string>
|
||||
<string name="screen_messages_title">Messages</string>
|
||||
<string name="screen_messages_description">Your encrypted direct messages will appear here.</string>
|
||||
<string name="screen_notifications_title">Notifications</string>
|
||||
<string name="screen_notifications_description">Mentions, replies, and reactions will appear here.</string>
|
||||
</resources>
|
||||
+23
-3
@@ -41,6 +41,9 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.SharedRes
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
/**
|
||||
* Text field for entering Nostr keys (nsec or npub) with visibility toggle.
|
||||
@@ -50,8 +53,8 @@ fun KeyInputField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
label: String = "nsec or npub",
|
||||
placeholder: String = "nsec1... or npub1...",
|
||||
label: String = stringResource(SharedRes.strings.login_key_label),
|
||||
placeholder: String = stringResource(SharedRes.strings.login_key_placeholder),
|
||||
errorMessage: String? = null,
|
||||
) {
|
||||
var showKey by remember { mutableStateOf(false) }
|
||||
@@ -73,7 +76,7 @@ fun KeyInputField(
|
||||
IconButton(onClick = { showKey = !showKey }) {
|
||||
Icon(
|
||||
if (showKey) Icons.Default.VisibilityOff else Icons.Default.Visibility,
|
||||
contentDescription = if (showKey) "Hide key" else "Show key",
|
||||
contentDescription = if (showKey) stringResource(SharedRes.strings.login_hide_key) else stringResource(SharedRes.strings.login_show_key),
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -108,3 +111,20 @@ fun SelectableKeyText(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun KeyInputFieldPreview() {
|
||||
KeyInputField(
|
||||
value = "nsec1example1234567890",
|
||||
onValueChange = {},
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun SelectableKeyTextPreview() {
|
||||
SelectableKeyText(
|
||||
key = "npub1example1234567890abcdefghijklmnopqrstuvwxyz1234567890",
|
||||
)
|
||||
}
|
||||
|
||||
+16
-4
@@ -43,6 +43,9 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.SharedRes
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
/**
|
||||
* Login card with Nostr key input field and action buttons.
|
||||
@@ -60,8 +63,8 @@ fun LoginCard(
|
||||
onGenerateNew: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
cardWidth: Dp = 400.dp,
|
||||
title: String = "Login with your Nostr key",
|
||||
subtitle: String = "Use nsec for full access or npub for read-only",
|
||||
title: String = stringResource(SharedRes.strings.login_card_title),
|
||||
subtitle: String = stringResource(SharedRes.strings.login_card_subtitle),
|
||||
) {
|
||||
var keyInput by remember { mutableStateOf("") }
|
||||
var errorMessage by remember { mutableStateOf<String?>(null) }
|
||||
@@ -118,16 +121,25 @@ fun LoginCard(
|
||||
modifier = Modifier.weight(1f),
|
||||
enabled = keyInput.isNotBlank(),
|
||||
) {
|
||||
Text("Login")
|
||||
Text(stringResource(SharedRes.strings.login_button))
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
onClick = onGenerateNew,
|
||||
modifier = Modifier.weight(1f),
|
||||
) {
|
||||
Text("Generate New")
|
||||
Text(stringResource(SharedRes.strings.login_generate_button))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun LoginCardPreview() {
|
||||
LoginCard(
|
||||
onLogin = { Result.success(Unit) },
|
||||
onGenerateNew = {},
|
||||
)
|
||||
}
|
||||
|
||||
+18
-6
@@ -36,6 +36,9 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.commons.SharedRes
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
/**
|
||||
* Warning card displayed after generating a new Nostr key pair.
|
||||
@@ -66,7 +69,7 @@ fun NewKeyWarningCard(
|
||||
modifier = Modifier.padding(24.dp),
|
||||
) {
|
||||
Text(
|
||||
"IMPORTANT: Save your keys!",
|
||||
stringResource(SharedRes.strings.new_key_warning_title),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = Color.Red,
|
||||
)
|
||||
@@ -74,8 +77,7 @@ fun NewKeyWarningCard(
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
"Your secret key (nsec) is the ONLY way to access your account. " +
|
||||
"If you lose it, your account is gone forever. Save it somewhere safe!",
|
||||
stringResource(SharedRes.strings.new_key_warning_message),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
@@ -83,7 +85,7 @@ fun NewKeyWarningCard(
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
"Public Key (shareable):",
|
||||
stringResource(SharedRes.strings.new_key_public_label),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -93,7 +95,7 @@ fun NewKeyWarningCard(
|
||||
|
||||
nsec?.let { secretKey ->
|
||||
Text(
|
||||
"Secret Key (NEVER share this!):",
|
||||
stringResource(SharedRes.strings.new_key_secret_label),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = Color.Red,
|
||||
)
|
||||
@@ -106,8 +108,18 @@ fun NewKeyWarningCard(
|
||||
onClick = onContinue,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text("I've saved my keys, continue")
|
||||
Text(stringResource(SharedRes.strings.new_key_continue_button))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun NewKeyWarningCardPreview() {
|
||||
NewKeyWarningCard(
|
||||
npub = "npub1example1234567890abcdefghijklmnopqrstuvwxyz",
|
||||
nsec = "nsec1example1234567890abcdefghijklmnopqrstuvwxyz",
|
||||
onContinue = {},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user