diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 6038af56e7..886a0dfe3e 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -285,6 +285,48 @@ Quartz uses expect/actual for platform-specific implementations (e.g. crypto backed by `secp256k1-kmp-jni-android` on Android and `secp256k1-kmp-jni-jvm` on JVM). See `/kotlin-multiplatform` for the expect/actual and source-set patterns. +## Strings + +**MANDATORY: every new user-visible string goes in `commonsUI` Compose resources**, +`commonsUI/src/commonMain/composeResources/values/strings.xml` — **never** in +`amethyst/src/main/res/values/strings.xml`, even for an Android-only screen. A +screen cannot move to `commonsUI` (or be rendered by Desktop) while its labels +live in Android `res/`, and every key added there has to be migrated back out +later. (The 2026-09-22 move emptied Android `res/` down to ~190 keys; the next two +features put 447 back.) + +- Reference it as `Res.string.my_key` / `Res.plurals.my_key`, importing + `com.vitorpamplona.amethyst.commons.resources.Res` **and** the per-key accessor + `com.vitorpamplona.amethyst.commons.resources.my_key` (Compose resources generates + each key as an extension property). +- Read it with `stringRes(Res.string.x)` / `pluralStringRes(Res.plurals.x, n, …)` + in composition — the app-side `ui.stringRes` overloads delegate to the + commonsUI bridge (`commons/ui/StringRes.kt`), so one import serves both kinds. +- Outside composition there is **no blocking accessor**: use `loadStringRes(…)` + from a coroutine (or make the function `suspend`), or resolve the label in + composition and pass it down as a `String`. A `runBlocking` bridge is ruled out. +- Hold a string reference as `StringResource` / `PluralStringResource`, not a + `@StringRes Int`. +- Format arguments must be positional (`%1$s`, `%2$d`) — compose-resources does + not format bare `%s`/`%d`. +- Escaping is not Android's: write `'` and `"` bare (no `\'`), and never wrap a + value in quotes to keep its whitespace. `.claude/hooks/compose_escaping_check.py` + checks this before a push. + +The **only** strings that stay in Android `res/` are the ones a platform API +reads synchronously under a deadline, where a `suspend` read cannot run: a +foreground service's `startForeground` notification, a notification channel +created during service startup, PiP `RemoteAction`s, napplet capability labels +read in the sandbox process, and `AndroidManifest.xml` / `res/xml` references. +Most of those are *copies* of a key that also lives in `commonsUI`. See +`commons/plans/2026-09-22-strings-to-compose-resources.md` ("the +synchronous-platform tier"). If you think a new string belongs in that tier, +say why in the PR. + +To move keys that already landed in Android `res/`, use +`tools/strings-migrate/migrate.py `. It moves every locale byte-for-byte, +so Crowdin sees a pure move. Then repoint `R.string.x` → `Res.string.x`. + ## Icons The Material Symbols font bundled at diff --git a/.claude/hooks/compose_escaping_check.py b/.claude/hooks/compose_escaping_check.py index cd9b054eef..b5721481ae 100755 --- a/.claude/hooks/compose_escaping_check.py +++ b/.claude/hooks/compose_escaping_check.py @@ -27,6 +27,9 @@ Repair with: idempotent, quote-unwrapping is not, and a second unwrap strips the real display quotes from values like `import_follows_tips`. +Raw line breaks and tabs inside a value are the whitespace half of the same +mismatch: aapt collapsed them, Compose renders them (the same repair fixes them). + Only the Compose catalog is scanned. In an Android res tree the same escaping is correct and must be left alone. """ @@ -41,6 +44,10 @@ CATALOG = "*/src/*/composeResources/values*/strings.xml" # Compose resolves those itself. ANDROID_ESCAPE = re.compile(r"(?]*>(.*?)", re.S) +LAYOUT_WS = re.compile(r"[\r\n\t]") def find_violations(root: Path): @@ -52,6 +59,13 @@ def find_violations(root: Path): n = len(TOOLS_ATTR.findall(text)) if n: found[path]["tools: attribute"] += n + n = sum( + 1 + for m in STRING_TEXT.finditer(text) + if "/strings.xml` | | **commonsUI** (KMP Compose resources, shared by Android + Desktop) | `commonsUI/src/commonMain/composeResources/values/strings.xml` | `commonsUI/src/commonMain/composeResources/values-/strings.xml` | +**New keys go in the `commonsUI` tree, always.** The amethyst tree is frozen at +the small synchronous-platform tier (foreground-service and notification-channel +text, PiP actions, napplet capability labels, manifest references). If you find +a new feature key in it, it belongs in `commonsUI`. Move it with +`tools/strings-migrate/migrate.py` rather than translating it where it is. See +"Strings" in `.claude/CLAUDE.md`. + The `commonsUI` tree appeared when shared event-renderer composables were extracted out of `amethyst/` into `commons/` — now `commonsUI/` since the UI split (Compose Multiplatform `stringResource`). It is **not** a copy of the amethyst tree — the vast majority of its keys are commons-only; only a small handful overlap. Every diff/count/translate command below works on either tree by swapping the base path — **run the whole technique once per tree** and report them separately (each maps to its own Crowdin file, so the counts should reconcile against two different Crowdin UI numbers). **Locale-qualifier caveat:** `commons` uses the same region-qualified locale dirs as amethyst for our four targets (`values-cs`, `values-de-rDE`, `values-sv-rSE`, `values-pt-rBR`), but the *full* set of locale dirs differs between trees. Enumerate `values-*` under each tree's own base rather than assuming they match. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index 3e0c5f6a6e..934226f2c8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -1154,7 +1154,7 @@ class AppModules( // Local store for posts the user has scheduled to publish later. Backed by a // single JSON file under the app's private filesDir; read by ScheduledPostWorker. val scheduledPostStore = - ScheduledPostStore(File(appContext.filesDir, ScheduledPostStore.FILE_NAME)) + ScheduledPostStore(File(appContext.filesDir, ScheduledPostStore.FILE_NAME).path) // Organizes cache clearing val trimmingService by diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt index 5db9dcbbd4..f7f574dbd6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/actions/EditPostView.kt @@ -78,6 +78,7 @@ import com.vitorpamplona.amethyst.commons.resources.lightning_create_and_add_inv import com.vitorpamplona.amethyst.commons.resources.lightning_invoice import com.vitorpamplona.amethyst.commons.resources.what_s_on_your_mind import com.vitorpamplona.amethyst.commons.richtext.RichTextParser +import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.PostingTopBar @@ -98,7 +99,6 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromFiles import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery import com.vitorpamplona.amethyst.ui.components.BechLink import com.vitorpamplona.amethyst.ui.components.LoadUrlPreview -import com.vitorpamplona.amethyst.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.note.creators.invoice.InvoiceRequest import com.vitorpamplona.amethyst.ui.note.creators.uploads.ImageVideoDescription diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt index 2f8261e466..176ba467b5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/AmethystRichText.kt @@ -52,6 +52,12 @@ import com.vitorpamplona.amethyst.commons.richtext.RichTextViewerState import com.vitorpamplona.amethyst.commons.richtext.SecretEmoji import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment +import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail +import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone +import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.richtext.LocalRichTextInteractions diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt deleted file mode 100644 index 6e25f4be6b..0000000000 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableEmail.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2025 Vitor Pamplona - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the - * Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package com.vitorpamplona.amethyst.ui.components - -import android.content.ActivityNotFoundException -import android.content.Context -import android.content.Intent -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary -import kotlinx.coroutines.CancellationException - -@Composable -fun ClickableEmail(email: String) { - val stripped = email.replaceFirst("mailto:", "") - val context = LocalContext.current - - ClickableTextPrimary( - text = stripped, - onClick = { runCatching { context.sendMail(stripped) } }, - ) -} - -fun Context.sendMail( - to: String, - subject: String? = null, -) { - try { - val intent = Intent(Intent.ACTION_SEND) - intent.type = "vnd.android.cursor.item/email" // or "message/rfc822" - intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to)) - if (subject != null) { - intent.putExtra(Intent.EXTRA_SUBJECT, subject) - } - startActivity(intent) - } catch (e: ActivityNotFoundException) { - // TODO: Handle case where no email app is available - } catch (t: Throwable) { - if (t is CancellationException) throw t - // TODO: Handle potential other type of exceptions - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt index 8935486076..714fc0af02 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ConcordInviteCard.kt @@ -49,6 +49,7 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.concord_home_title import com.vitorpamplona.amethyst.commons.resources.concord_invite_card_join import com.vitorpamplona.amethyst.commons.resources.concord_invite_card_subtitle +import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt index cda380757e..e2a636f8c7 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RelayGroupCard.kt @@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_invite_onl import com.vitorpamplona.amethyst.commons.resources.relay_group_badge_private import com.vitorpamplona.amethyst.commons.resources.relay_group_member_count import com.vitorpamplona.amethyst.commons.resources.relay_group_open +import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.pluralStringRes diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index ede5174be2..bfa2899272 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -102,6 +102,12 @@ import com.vitorpamplona.amethyst.commons.richtext.Segment import com.vitorpamplona.amethyst.commons.richtext.VideoSegment import com.vitorpamplona.amethyst.commons.richtext.WithdrawSegment import com.vitorpamplona.amethyst.commons.ui.components.AnimatedBorderTextCornerRadius +import com.vitorpamplona.amethyst.commons.ui.components.ClickableBuzzInviteLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableConcordInviteLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableEmail +import com.vitorpamplona.amethyst.commons.ui.components.ClickablePhone +import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayGroupLink +import com.vitorpamplona.amethyst.commons.ui.components.ClickableRelayUrl import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.NowhereLinkCard diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt index ce29dc0daf..85dc9c6610 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/FeedContentStateView.kt @@ -35,6 +35,8 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt index b9580ea8ba..d0d7daa8c5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/WatchScrollToTop.kt @@ -21,52 +21,11 @@ package com.vitorpamplona.amethyst.ui.feeds import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.commons.feeds.FeedContentState -import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.CardFeedContentState -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map - -@Composable -fun WatchScrollToTop( - feedContentState: FeedContentState, - listState: LazyListState, -) { - val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && feedContentState.scrollToTopPending) { - listState.scrollToItem(index = 0) - feedContentState.sentToTop() - } - } -} - -@Composable -fun WatchScrollToTop( - feedContentState: FeedContentState, - listState: LazyGridState, -) { - val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && feedContentState.scrollToTopPending) { - listState.scrollToItem(index = 0) - feedContentState.sentToTop() - } - } -} @Composable fun WatchScrollToTop( @@ -82,166 +41,3 @@ fun WatchScrollToTop( } } } - -@Composable -fun WatchScrollToTop( - videoFeedContentState: FeedContentState, - pagerState: PagerState, -) { - val scrollToTop by videoFeedContentState.scrollToTop.collectAsStateWithLifecycle() - - LaunchedEffect(scrollToTop) { - if (scrollToTop > 0 && videoFeedContentState.scrollToTopPending) { - pagerState.scrollToPage(page = 0) - videoFeedContentState.sentToTop() - } - } -} - -/** - * Keeps the user pinned to index 0 when new items prepend to a feed, but - * only if they were already at the very top right before the update. - * - * Why this is non-trivial: every feed uses stable `key = item.idHex` in - * its lazy list, which makes Compose preserve the visual anchor across - * data changes. When N items prepend, the user's previously-visible - * top item is still on screen but its index is now N — so - * `firstVisibleItemIndex` shifts from 0 to N without any user gesture. - * A naive `if (firstVisibleItemIndex <= 1) scrollToItem(0)` check inside - * `LaunchedEffect(items.firstOrNull())` therefore fails as soon as more - * than one item arrives in the same batch. - * - * The trick: track "was at top" continuously via [snapshotFlow], but - * only flip it from true → false when [LazyListState.isScrollInProgress] - * is true (i.e. the user is actively scrolling). Compose's keyed-item - * shift after a data update does not set that flag — only real touch - * gestures and `animate*` calls do — so data-driven index shifts can - * never poison the cached value. When [firstItemKey] changes (head of - * the list moved), if the cached value is still true, snap back to 0 - * with an instant (non-animated) scroll so the prepend appears as - * in-place growth rather than a visible jump-then-scroll. - * - * Most callers should not invoke this directly: [SaveableFeedContentState], - * [SaveableGridFeedContentState], and the analogous wrappers in - * `ui/screen/FeedView.kt` already apply auto-stick to every feed they - * own. Invoke the explicit overload only when the listState is - * constructed outside one of those wrappers, or when the key that - * should trigger the snap is not the default `items.list[0].idHex` - * (e.g. notifications, chats, or feeds keyed on something other than a - * Note's hex id). - */ -@Composable -fun StickToTopOnPrepend( - listState: LazyListState, - firstItemKey: Any?, -) { - stickToTopOnPrepend( - stateKey = listState, - firstItemKey = firstItemKey, - initialAtTop = { - listState.firstVisibleItemIndex == 0 && listState.firstVisibleItemScrollOffset == 0 - }, - sampler = { - snapshotFlow { - listState.firstVisibleItemIndex == 0 && listState.firstVisibleItemScrollOffset == 0 - } - }, - isScrollInProgress = { listState.isScrollInProgress }, - firstVisibleItemIndex = { listState.firstVisibleItemIndex }, - scrollToTop = { listState.scrollToItem(0) }, - ) -} - -@Composable -fun StickToTopOnPrepend( - gridState: LazyGridState, - firstItemKey: Any?, -) { - stickToTopOnPrepend( - stateKey = gridState, - firstItemKey = firstItemKey, - initialAtTop = { - gridState.firstVisibleItemIndex == 0 && gridState.firstVisibleItemScrollOffset == 0 - }, - sampler = { - snapshotFlow { - gridState.firstVisibleItemIndex == 0 && gridState.firstVisibleItemScrollOffset == 0 - } - }, - isScrollInProgress = { gridState.isScrollInProgress }, - firstVisibleItemIndex = { gridState.firstVisibleItemIndex }, - scrollToTop = { gridState.scrollToItem(0) }, - ) -} - -/** - * Auto-stick wired straight to a [FeedContentState]: derives the head - * key from `feedContent → Loaded.feed → list.firstOrNull()?.idHex` so - * callers don't have to collect the inner feed flow themselves. Used - * by the Saveable* wrappers; suitable for any Note-keyed feed. - */ -@Composable -fun StickToTopOnPrepend( - feedContentState: FeedContentState, - listState: LazyListState, -) { - StickToTopOnPrepend(listState, rememberFirstItemIdHex(feedContentState)) -} - -@Composable -fun StickToTopOnPrepend( - feedContentState: FeedContentState, - gridState: LazyGridState, -) { - StickToTopOnPrepend(gridState, rememberFirstItemIdHex(feedContentState)) -} - -@OptIn(ExperimentalCoroutinesApi::class) -@Composable -private fun rememberFirstItemIdHex(feedContentState: FeedContentState): String? { - val flow = - remember(feedContentState) { - feedContentState.feedContent.flatMapLatest { state -> - when (state) { - is FeedState.Loaded -> state.feed.map { it.list.firstOrNull()?.idHex } - else -> flowOf(null) - } - } - } - val key by flow.collectAsStateWithLifecycle(initialValue = null) - return key -} - -@Composable -private fun stickToTopOnPrepend( - stateKey: Any, - firstItemKey: Any?, - initialAtTop: () -> Boolean, - sampler: () -> Flow, - isScrollInProgress: () -> Boolean, - firstVisibleItemIndex: () -> Int, - scrollToTop: suspend () -> Unit, -) { - // Plain holder instead of mutableStateOf — we only read this inside - // effects, never in composition, so we don't need snapshot tracking. - // Seed from the actual restored scroll position: when the user returns - // to a feed via rememberForeverLazyListState, the saved offset is - // already in place, and a hardcoded `true` would mis-snap them to 0. - val wasAtTop = remember(stateKey) { booleanArrayOf(initialAtTop()) } - - LaunchedEffect(stateKey) { - sampler().collect { atTop -> - if (atTop) { - wasAtTop[0] = true - } else if (isScrollInProgress()) { - wasAtTop[0] = false - } - } - } - - LaunchedEffect(firstItemKey) { - if (firstItemKey != null && wasAtTop[0] && firstVisibleItemIndex() > 0) { - scrollToTop() - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt similarity index 77% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt index 5abf8308cf..1f49f5ac52 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayout.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/ChatHeaderLayoutPreview.kt @@ -20,16 +20,10 @@ */ package com.vitorpamplona.amethyst.ui.layouts -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.combinedClickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.ListItem import androidx.compose.material3.Text @@ -38,20 +32,19 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_banner +import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble +import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.NewItemsBubble import com.vitorpamplona.quartz.utils.TimeUtils private const val PREVIEW_AUTHOR = "This is my author" @@ -136,43 +129,3 @@ fun ChannelNamePreview() { } } } - -@OptIn(ExperimentalFoundationApi::class) -@Composable -fun ChatHeaderLayout( - channelPicture: @Composable () -> Unit, - firstRow: @Composable RowScope.() -> Unit, - secondRow: @Composable RowScope.() -> Unit, - onClick: () -> Unit, - onLongClick: (() -> Unit)? = null, -) { - Row( - modifier = - Modifier - .combinedClickable(onClick = onClick, onLongClick = onLongClick) - .padding(10.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - Box(Size55Modifier) { channelPicture() } - - Spacer(modifier = DoubleHorzSpacer) - - Column( - modifier = Modifier.fillMaxWidth(), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - firstRow() - } - - Spacer(modifier = Height4dpModifier) - - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - secondRow() - } - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt similarity index 72% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt rename to amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt index 167bbc4a51..2f26c2e73e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayout.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/LeftPictureLayoutPreview.kt @@ -21,18 +21,11 @@ package com.vitorpamplona.amethyst.ui.layouts import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale @@ -43,10 +36,10 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.profile_banner +import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.note.LikeIcon import com.vitorpamplona.amethyst.commons.ui.note.ZappedIcon import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.QuoteBorder import com.vitorpamplona.amethyst.commons.ui.theme.Size16Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size20Modifier @@ -104,47 +97,3 @@ fun LeftPictureLayoutPreviewCard() { onBottomRow = { Text("This is my Moderator List") }, ) } - -@Composable -fun LeftPictureLayout( - onImage: @Composable () -> Unit, - onTitleRow: @Composable RowScope.() -> Unit, - onDescription: @Composable () -> Unit, - onBottomRow: @Composable RowScope.() -> Unit, - imageFraction: Float = 0.25f, -) { - Row(Modifier.aspectRatio(ratio = 1 / imageFraction)) { - Column( - modifier = Modifier.fillMaxWidth(imageFraction).aspectRatio(ratio = 1f), - ) { - onImage() - } - - Spacer(modifier = DoubleHorzSpacer) - - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.SpaceBetween, - ) { - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - onTitleRow() - } - - Row( - modifier = Modifier.fillMaxWidth().weight(1f), - ) { - onDescription() - } - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - ) { - onBottomRow() - } - } - } -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt new file mode 100644 index 0000000000..f4529fc097 --- /dev/null +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemPreview.kt @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.layouts.listItem + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment.Companion.CenterVertically +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.tooling.preview.Preview +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.profile_banner +import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble +import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem +import com.vitorpamplona.amethyst.commons.ui.stringRes +import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness +import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier +import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier +import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn +import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo +import com.vitorpamplona.amethyst.ui.painterRes +import com.vitorpamplona.quartz.utils.TimeUtils + +private const val PREVIEW_AUTHOR = "This is my author" +private const val PREVIEW_MESSAGE = "This is a message from this person" + +@Composable +@Preview +fun ChannelNamePreview() { + ThemeComparisonColumn { + Column { + ChatHeaderLayout( + channelPicture = { + Image( + painter = painterRes(R.drawable.github, 1), + contentDescription = stringRes(id = Res.string.profile_banner), + contentScale = ContentScale.FillWidth, + ) + }, + firstRow = { + Text(PREVIEW_AUTHOR, Modifier.weight(1f)) + TimeAgo(TimeUtils.now()) + }, + secondRow = { + Text(PREVIEW_MESSAGE, Modifier.weight(1f)) + NewItemsBubble() + }, + onClick = {}, + ) + + HorizontalDivider(thickness = DividerThickness) + + SlimListItem( + headlineContent = { + Row(verticalAlignment = CenterVertically) { + Text(PREVIEW_AUTHOR, Modifier.weight(1f)) + TimeAgo(TimeUtils.now()) + } + }, + supportingContent = { + Row(verticalAlignment = CenterVertically) { + Text(PREVIEW_MESSAGE, Modifier.weight(1f)) + Spacer(modifier = Height4dpModifier) + NewItemsBubble() + } + }, + leadingContent = { + Image( + painter = painterRes(R.drawable.github, 2), + contentDescription = stringRes(id = Res.string.profile_banner), + contentScale = ContentScale.FillWidth, + modifier = Size55Modifier, + ) + }, + ) + + HorizontalDivider(thickness = DividerThickness) + + ListItem( + headlineContent = { + Row(verticalAlignment = CenterVertically) { + Text(PREVIEW_AUTHOR, Modifier.weight(1f)) + TimeAgo(TimeUtils.now()) + } + }, + supportingContent = { + Row(verticalAlignment = CenterVertically) { + Text(PREVIEW_MESSAGE, Modifier.weight(1f)) + Spacer(modifier = Height4dpModifier) + NewItemsBubble() + } + }, + leadingContent = { + Image( + painter = painterRes(R.drawable.github, 2), + contentDescription = stringRes(id = Res.string.profile_banner), + contentScale = ContentScale.FillWidth, + modifier = Size55Modifier, + ) + }, + ) + + HorizontalDivider(thickness = DividerThickness) + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt index 46771e5f29..f002b59bef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/UserCompose.kt @@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.commons.resources.follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_follow import com.vitorpamplona.amethyst.commons.resources.login_with_a_private_key_to_be_able_to_unfollow import com.vitorpamplona.amethyst.commons.resources.read_only_user +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ShowUserButton import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp @@ -51,7 +52,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.service.relayClient.reqCommand.account.observeAccountIsHiddenUser import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserAboutMe import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserIsFollowing -import com.vitorpamplona.amethyst.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt index bb78a2b1b1..e2aedac116 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/notify/AudienceSheet.kt @@ -88,6 +88,7 @@ import com.vitorpamplona.amethyst.commons.resources.discover_follows import com.vitorpamplona.amethyst.commons.resources.follow_sets import com.vitorpamplona.amethyst.commons.resources.num_selected import com.vitorpamplona.amethyst.commons.resources.select_all +import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness @@ -95,7 +96,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size24dp import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.commons.ui.theme.warningColor -import com.vitorpamplona.amethyst.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.note.creators.userSuggestions.ShowUserSuggestionList diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt index b13c5e1386..ee8e180270 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/userSuggestions/ShowUserSuggestionList.kt @@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.nip05DnsIdentifiers.Nip05State import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.user_suggestion_in_this_chat +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.Font14SP @@ -60,7 +61,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.NIP05IconSize import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.nip05 import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderNIP05VerifiedSymbol import com.vitorpamplona.amethyst.ui.note.UsernameDisplay diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt index 6554cdcabe..ad2b1c3ea5 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/zapsplits/ForwardZapTo.kt @@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.commons.resources.zap_split_explainer import com.vitorpamplona.amethyst.commons.resources.zap_split_search_and_add_user import com.vitorpamplona.amethyst.commons.resources.zap_split_search_and_add_user_placeholder import com.vitorpamplona.amethyst.commons.resources.zap_split_title +import com.vitorpamplona.amethyst.commons.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.IZapField import com.vitorpamplona.amethyst.commons.ui.note.creators.zapsplits.ZapSplitIcon import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -55,7 +56,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.actions.MentionPreservingInputTransformation import com.vitorpamplona.amethyst.ui.actions.UrlUserTagOutputTransformation -import com.vitorpamplona.amethyst.ui.components.OutlinedThinPaddingTextField import com.vitorpamplona.amethyst.ui.note.BaseUserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt index 421549ffb6..bcb73b461a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/FeedView.kt @@ -35,14 +35,14 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.viewmodels.FeedViewModel import com.vitorpamplona.amethyst.ui.feeds.FeedLoaded import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.feeds.StickToTopOnPrepend -import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @Composable diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt index 880e12de22..4ed610bed1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/UserFeedView.kt @@ -35,11 +35,11 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.ui.note.UserCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt index dd46388f4d..a62a265f18 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountFeedContentStates.kt @@ -22,13 +22,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.content.ComponentCallbacks2 import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.feeds.ChannelFeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.model.Note import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.feeds.ChannelFeedContentState import com.vitorpamplona.amethyst.ui.screen.TopNavFilterState import com.vitorpamplona.amethyst.ui.screen.loggedIn.articles.dal.ArticlesFeedFilter import com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.dal.BadgesFeedFilter diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt index bb977a4184..769c911ae4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictCards.kt @@ -43,17 +43,57 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.backups.BackupEventType import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict import com.vitorpamplona.amethyst.commons.model.navigation.Route +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.backup_card_accept +import com.vitorpamplona.amethyst.commons.resources.backup_card_and_added +import com.vitorpamplona.amethyst.commons.resources.backup_card_and_blocked +import com.vitorpamplona.amethyst.commons.resources.backup_card_and_followed +import com.vitorpamplona.amethyst.commons.resources.backup_card_and_joined +import com.vitorpamplona.amethyst.commons.resources.backup_card_and_muted +import com.vitorpamplona.amethyst.commons.resources.backup_card_app_settings +import com.vitorpamplona.amethyst.commons.resources.backup_card_concord_emptied +import com.vitorpamplona.amethyst.commons.resources.backup_card_concord_rewritten +import com.vitorpamplona.amethyst.commons.resources.backup_card_dm_relays_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_feeds_removed +import com.vitorpamplona.amethyst.commons.resources.backup_card_follows_dropped +import com.vitorpamplona.amethyst.commons.resources.backup_card_hashtags_unfollowed +import com.vitorpamplona.amethyst.commons.resources.backup_card_indexer_relays_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_key_package_relays_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_leave_chats +import com.vitorpamplona.amethyst.commons.resources.backup_card_leave_communities +import com.vitorpamplona.amethyst.commons.resources.backup_card_leave_groups +import com.vitorpamplona.amethyst.commons.resources.backup_card_leave_rooms +import com.vitorpamplona.amethyst.commons.resources.backup_card_mutes_visible +import com.vitorpamplona.amethyst.commons.resources.backup_card_nip65_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_nutzap_key_removed +import com.vitorpamplona.amethyst.commons.resources.backup_card_nutzap_key_replaced +import com.vitorpamplona.amethyst.commons.resources.backup_card_nutzap_mints_removed +import com.vitorpamplona.amethyst.commons.resources.backup_card_offers_removed +import com.vitorpamplona.amethyst.commons.resources.backup_card_payment_targets_removed +import com.vitorpamplona.amethyst.commons.resources.backup_card_places_unfollowed +import com.vitorpamplona.amethyst.commons.resources.backup_card_private_outbox_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_profile_lost_fields +import com.vitorpamplona.amethyst.commons.resources.backup_card_relay_feeds_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_search_relays_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_trust_services_changed +import com.vitorpamplona.amethyst.commons.resources.backup_card_trusted_lost +import com.vitorpamplona.amethyst.commons.resources.backup_card_unblocked +import com.vitorpamplona.amethyst.commons.resources.backup_card_wallet_emptied +import com.vitorpamplona.amethyst.commons.resources.backup_card_wallet_rewritten +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_count_added +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_count_changed +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_count_removed +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_title +import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.note.timeAgoNoDot @@ -79,6 +119,9 @@ import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListDiff import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataDiff import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListDiff import com.vitorpamplona.quartz.nipB1Bolt12Zaps.offer.Bolt12OfferListDiff +import org.jetbrains.compose.resources.PluralStringResource +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.pluralStringResource /** * Cards at the top of Home's feed, one per open [ReplaceableBackupConflict]: the user @@ -125,34 +168,34 @@ private fun headlineOf( when (diff) { // Counted, not "shrank": a version that drops 3 follows and adds 100 still raises // a conflict, and calling that a shrink contradicts the card's own bar. - is ContactListDiff -> plural(R.plurals.backup_card_follows_dropped, diff.follows.removed.size) - is MuteListDiff -> plural(R.plurals.backup_card_mutes_visible, diff.publicMutes.removed.size) - is MetadataDiff -> plural(R.plurals.backup_card_profile_lost_fields, counts.removed) - is AdvertisedRelayListDiff -> plural(R.plurals.backup_card_nip65_lost, diff.relays.removed.size) + is ContactListDiff -> plural(Res.plurals.backup_card_follows_dropped, diff.follows.removed.size) + is MuteListDiff -> plural(Res.plurals.backup_card_mutes_visible, diff.publicMutes.removed.size) + is MetadataDiff -> plural(Res.plurals.backup_card_profile_lost_fields, counts.removed) + is AdvertisedRelayListDiff -> plural(Res.plurals.backup_card_nip65_lost, diff.relays.removed.size) is RelayListDiff -> relayListHeadline(conflict.eventType, diff.relays.removed.size) - is ChannelListDiff -> plural(R.plurals.backup_card_leave_chats, diff.channels.removed.size) - is CommunityListDiff -> plural(R.plurals.backup_card_leave_communities, diff.communities.removed.size) - is EphemeralChatListDiff -> plural(R.plurals.backup_card_leave_rooms, diff.rooms.removed.size) - is SimpleGroupListDiff -> plural(R.plurals.backup_card_leave_groups, diff.groups.removed.size) - is FavoriteAlgoFeedsListDiff -> plural(R.plurals.backup_card_feeds_removed, diff.feeds.removed.size) - is HashtagListDiff -> plural(R.plurals.backup_card_hashtags_unfollowed, diff.hashtags.removed.size) - is GeohashListDiff -> plural(R.plurals.backup_card_places_unfollowed, diff.geohashes.removed.size) - is TrustProviderListDiff -> plural(R.plurals.backup_card_trust_services_changed, diff.providers.removed.size + diff.providers.changed.size) + is ChannelListDiff -> plural(Res.plurals.backup_card_leave_chats, diff.channels.removed.size) + is CommunityListDiff -> plural(Res.plurals.backup_card_leave_communities, diff.communities.removed.size) + is EphemeralChatListDiff -> plural(Res.plurals.backup_card_leave_rooms, diff.rooms.removed.size) + is SimpleGroupListDiff -> plural(Res.plurals.backup_card_leave_groups, diff.groups.removed.size) + is FavoriteAlgoFeedsListDiff -> plural(Res.plurals.backup_card_feeds_removed, diff.feeds.removed.size) + is HashtagListDiff -> plural(Res.plurals.backup_card_hashtags_unfollowed, diff.hashtags.removed.size) + is GeohashListDiff -> plural(Res.plurals.backup_card_places_unfollowed, diff.geohashes.removed.size) + is TrustProviderListDiff -> plural(Res.plurals.backup_card_trust_services_changed, diff.providers.removed.size + diff.providers.changed.size) is NutzapInfoDiff -> when { - diff.p2pkPubkey?.after == null && diff.p2pkPubkey != null -> stringRes(R.string.backup_card_nutzap_key_removed) - diff.p2pkPubkey != null -> stringRes(R.string.backup_card_nutzap_key_replaced) - else -> plural(R.plurals.backup_card_nutzap_mints_removed, diff.mints.removed.size) + diff.p2pkPubkey?.after == null && diff.p2pkPubkey != null -> stringRes(Res.string.backup_card_nutzap_key_removed) + diff.p2pkPubkey != null -> stringRes(Res.string.backup_card_nutzap_key_replaced) + else -> plural(Res.plurals.backup_card_nutzap_mints_removed, diff.mints.removed.size) } - is PaymentTargetsDiff -> plural(R.plurals.backup_card_payment_targets_removed, diff.targets.removed.size) - is Bolt12OfferListDiff -> plural(R.plurals.backup_card_offers_removed, diff.offers.removed.size) - is CashuWalletDiff -> encryptedHeadline(R.string.backup_card_wallet_emptied, R.string.backup_card_wallet_rewritten, diff.wallet) - is ConcordCommunityListDiff -> encryptedHeadline(R.string.backup_card_concord_emptied, R.string.backup_card_concord_rewritten, diff.communities) - is AppSpecificDataDiff -> stringRes(R.string.backup_card_app_settings) + is PaymentTargetsDiff -> plural(Res.plurals.backup_card_payment_targets_removed, diff.targets.removed.size) + is Bolt12OfferListDiff -> plural(Res.plurals.backup_card_offers_removed, diff.offers.removed.size) + is CashuWalletDiff -> encryptedHeadline(Res.string.backup_card_wallet_emptied, Res.string.backup_card_wallet_rewritten, diff.wallet) + is ConcordCommunityListDiff -> encryptedHeadline(Res.string.backup_card_concord_emptied, Res.string.backup_card_concord_rewritten, diff.communities) + is AppSpecificDataDiff -> stringRes(Res.string.backup_card_app_settings) else -> null } // A headline counting removed items reads wrong when only encrypted items were lost. - if (specific.isNullOrEmpty()) return stringRes(R.string.backup_conflict_title, stringRes(eventTypeName(conflict.eventType))) + if (specific.isNullOrEmpty()) return stringRes(Res.string.backup_conflict_title, stringRes(eventTypeName(conflict.eventType))) // Headlines lead with the loss; what the other app added to the same list is said too, // so a list that dropped 3 and gained 40 doesn't read as if it only shrank. The wording // follows the headline's: following people, muting, joining chats, blocking relays. @@ -160,11 +203,11 @@ private fun headlineOf( if (added <= 0) return specific val tail = when { - diff is ContactListDiff -> R.plurals.backup_card_and_followed - diff is MuteListDiff -> R.plurals.backup_card_and_muted - diff is ChannelListDiff || diff is CommunityListDiff || diff is EphemeralChatListDiff || diff is SimpleGroupListDiff -> R.plurals.backup_card_and_joined - conflict.eventType == BackupEventType.BLOCKED_RELAYS -> R.plurals.backup_card_and_blocked - else -> R.plurals.backup_card_and_added + diff is ContactListDiff -> Res.plurals.backup_card_and_followed + diff is MuteListDiff -> Res.plurals.backup_card_and_muted + diff is ChannelListDiff || diff is CommunityListDiff || diff is EphemeralChatListDiff || diff is SimpleGroupListDiff -> Res.plurals.backup_card_and_joined + conflict.eventType == BackupEventType.BLOCKED_RELAYS -> Res.plurals.backup_card_and_blocked + else -> Res.plurals.backup_card_and_added } return pluralStringResource(tail, added, specific, added) } @@ -208,7 +251,7 @@ private fun relayListHasHeadline(type: BackupEventType): Boolean = /** The count's plural, or "" when nothing of that kind was removed. */ @Composable private fun plural( - id: Int, + id: PluralStringResource, count: Int, ): String = if (count > 0) pluralStringResource(id, count, count) else "" @@ -218,21 +261,21 @@ private fun relayListHeadline( removed: Int, ): String = when (type) { - BackupEventType.DM_RELAYS -> plural(R.plurals.backup_card_dm_relays_lost, removed) - BackupEventType.KEY_PACKAGE_RELAYS -> plural(R.plurals.backup_card_key_package_relays_lost, removed) - BackupEventType.SEARCH_RELAYS -> plural(R.plurals.backup_card_search_relays_lost, removed) - BackupEventType.INDEXER_RELAYS -> plural(R.plurals.backup_card_indexer_relays_lost, removed) - BackupEventType.RELAY_FEEDS -> plural(R.plurals.backup_card_relay_feeds_lost, removed) - BackupEventType.PRIVATE_OUTBOX_RELAYS -> plural(R.plurals.backup_card_private_outbox_lost, removed) - BackupEventType.TRUSTED_RELAYS -> plural(R.plurals.backup_card_trusted_lost, removed) - BackupEventType.BLOCKED_RELAYS -> plural(R.plurals.backup_card_unblocked, removed) + BackupEventType.DM_RELAYS -> plural(Res.plurals.backup_card_dm_relays_lost, removed) + BackupEventType.KEY_PACKAGE_RELAYS -> plural(Res.plurals.backup_card_key_package_relays_lost, removed) + BackupEventType.SEARCH_RELAYS -> plural(Res.plurals.backup_card_search_relays_lost, removed) + BackupEventType.INDEXER_RELAYS -> plural(Res.plurals.backup_card_indexer_relays_lost, removed) + BackupEventType.RELAY_FEEDS -> plural(Res.plurals.backup_card_relay_feeds_lost, removed) + BackupEventType.PRIVATE_OUTBOX_RELAYS -> plural(Res.plurals.backup_card_private_outbox_lost, removed) + BackupEventType.TRUSTED_RELAYS -> plural(Res.plurals.backup_card_trusted_lost, removed) + BackupEventType.BLOCKED_RELAYS -> plural(Res.plurals.backup_card_unblocked, removed) else -> "" } @Composable private fun encryptedHeadline( - emptied: Int, - rewritten: Int, + emptied: StringResource, + rewritten: StringResource, change: ContentChange, ): String = if (change == ContentChange.CLEARED) stringRes(emptied) else stringRes(rewritten) @@ -262,7 +305,7 @@ private fun LeadConflictCard( Column(Modifier.weight(1f)) { Text(headlineOf(conflict, counts), style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.Bold, maxLines = 3, overflow = TextOverflow.Ellipsis) Text( - stringRes(R.string.backup_review_changed_by_other_app, timeAgoNoDot(conflict.cause.createdAt)), + stringRes(Res.string.backup_review_changed_by_other_app, timeAgoNoDot(conflict.cause.createdAt)), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.placeholderText, ) @@ -296,9 +339,9 @@ private fun LeadConflictCard( private fun CountChips(counts: ConflictCounts) { val tones = conflictTones() Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - if (counts.removed > 0) StatusTag(stringRes(R.string.backup_conflict_count_removed, counts.removed.toString()), tones.removed) - if (counts.added > 0) StatusTag(stringRes(R.string.backup_conflict_count_added, counts.added.toString()), tones.added) - if (counts.changed > 0) StatusTag(stringRes(R.string.backup_conflict_count_changed, counts.changed.toString()), tones.changed) + if (counts.removed > 0) StatusTag(stringRes(Res.string.backup_conflict_count_removed, counts.removed.toString()), tones.removed) + if (counts.added > 0) StatusTag(stringRes(Res.string.backup_conflict_count_added, counts.added.toString()), tones.added) + if (counts.changed > 0) StatusTag(stringRes(Res.string.backup_conflict_count_changed, counts.changed.toString()), tones.changed) } } @@ -342,6 +385,6 @@ private fun AcceptButton(onAccept: () -> Unit) { modifier = Modifier.height(36.dp), contentPadding = PaddingValues(horizontal = 14.dp), ) { - Text(stringRes(R.string.backup_card_accept), fontWeight = FontWeight.SemiBold) + Text(stringRes(Res.string.backup_card_accept), fontWeight = FontWeight.SemiBold) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt index 419bd3b2a2..1916f09286 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictEventViews.kt @@ -62,7 +62,6 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict @@ -70,6 +69,67 @@ import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor import com.vitorpamplona.amethyst.commons.model.nip29RelayGroups.RelayGroupChannel +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.backup_entry_hashtag +import com.vitorpamplona.amethyst.commons.resources.backup_entry_mint +import com.vitorpamplona.amethyst.commons.resources.backup_entry_nutzap_key +import com.vitorpamplona.amethyst.commons.resources.backup_entry_person +import com.vitorpamplona.amethyst.commons.resources.backup_entry_profile_field +import com.vitorpamplona.amethyst.commons.resources.backup_entry_thread +import com.vitorpamplona.amethyst.commons.resources.backup_entry_word +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_about +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_banner +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_birthday +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_bot +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_clink_offer +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_display_name +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_lud06 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_lud16 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_name +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_nip05 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_picture +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_pronouns +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_website +import com.vitorpamplona.amethyst.commons.resources.backup_review_demoted_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_dropped_count +import com.vitorpamplona.amethyst.commons.resources.backup_review_dropped_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_gone +import com.vitorpamplona.amethyst.commons.resources.backup_review_inbox +import com.vitorpamplona.amethyst.commons.resources.backup_review_inbox_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_joined +import com.vitorpamplona.amethyst.commons.resources.backup_review_kept_count +import com.vitorpamplona.amethyst.commons.resources.backup_review_key_removed +import com.vitorpamplona.amethyst.commons.resources.backup_review_key_replaced +import com.vitorpamplona.amethyst.commons.resources.backup_review_key_warning +import com.vitorpamplona.amethyst.commons.resources.backup_review_left +import com.vitorpamplona.amethyst.commons.resources.backup_review_left_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_names_and_more +import com.vitorpamplona.amethyst.commons.resources.backup_review_new +import com.vitorpamplona.amethyst.commons.resources.backup_review_new_count +import com.vitorpamplona.amethyst.commons.resources.backup_review_new_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_newly_muted +import com.vitorpamplona.amethyst.commons.resources.backup_review_not_set +import com.vitorpamplona.amethyst.commons.resources.backup_review_nothing_here +import com.vitorpamplona.amethyst.commons.resources.backup_review_outbox +import com.vitorpamplona.amethyst.commons.resources.backup_review_outbox_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_added_body +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_added_title +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_changed_body +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_changed_title +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_wiped_body +import com.vitorpamplona.amethyst.commons.resources.backup_review_private_wiped_title +import com.vitorpamplona.amethyst.commons.resources.backup_review_renamed +import com.vitorpamplona.amethyst.commons.resources.backup_review_renamed_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_saved +import com.vitorpamplona.amethyst.commons.resources.backup_review_search_people +import com.vitorpamplona.amethyst.commons.resources.backup_review_tab_dropped +import com.vitorpamplona.amethyst.commons.resources.backup_review_tab_edited +import com.vitorpamplona.amethyst.commons.resources.backup_review_tab_new +import com.vitorpamplona.amethyst.commons.resources.backup_review_units_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted +import com.vitorpamplona.amethyst.commons.resources.backup_review_unmuted_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_was_named +import com.vitorpamplona.amethyst.commons.resources.backup_review_words_and_hashtags import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings @@ -111,6 +171,7 @@ import com.vitorpamplona.quartz.nip61Nutzaps.info.tags.NutzapMintTag import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListDiff import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent import com.vitorpamplona.quartz.nip65RelayList.tags.AdvertisedRelayType +import org.jetbrains.compose.resources.StringResource private const val GRID_COLUMNS = 4 private const val PEOPLE_PREVIEW = 6 @@ -168,7 +229,7 @@ private fun LazyListScope.followListItems( item(key = "follow-hero", contentType = "hero") { val tones = conflictTones() Column(Pad.padding(top = 8.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) { - HeroCounts(stringRes(R.string.backup_review_saved), saved, stringRes(R.string.backup_review_new), new) + HeroCounts(stringRes(Res.string.backup_review_saved), saved, stringRes(Res.string.backup_review_new), new) SplitBar( listOf( BarSegment(saved - dropped, tones.kept), @@ -177,9 +238,9 @@ private fun LazyListScope.followListItems( ), ) Row(horizontalArrangement = Arrangement.spacedBy(14.dp)) { - LegendItem(tones.kept, stringRes(R.string.backup_review_kept_count, (saved - dropped).toString())) - LegendItem(tones.removed, stringRes(R.string.backup_review_dropped_count, dropped.toString())) - LegendItem(tones.added, stringRes(R.string.backup_review_new_count, gained.toString())) + LegendItem(tones.kept, stringRes(Res.string.backup_review_kept_count, (saved - dropped).toString())) + LegendItem(tones.removed, stringRes(Res.string.backup_review_dropped_count, dropped.toString())) + LegendItem(tones.added, stringRes(Res.string.backup_review_new_count, gained.toString())) } } } @@ -188,9 +249,9 @@ private fun LazyListScope.followListItems( ReviewTabs( labels = listOf( - stringRes(R.string.backup_review_tab_dropped, dropped.toString()), - stringRes(R.string.backup_review_tab_new, gained.toString()), - stringRes(R.string.backup_review_tab_edited, edited.toString()), + stringRes(Res.string.backup_review_tab_dropped, dropped.toString()), + stringRes(Res.string.backup_review_tab_new, gained.toString()), + stringRes(Res.string.backup_review_tab_edited, edited.toString()), ), selected = ui.tab, onSelect = { @@ -223,7 +284,7 @@ private fun LazyListScope.followListItems( if (filtered.isEmpty()) { item(key = "follow-empty", contentType = "note") { - DetailText(stringRes(R.string.backup_review_nothing_here), Pad.padding(vertical = 24.dp)) + DetailText(stringRes(Res.string.backup_review_nothing_here), Pad.padding(vertical = 24.dp)) } } } @@ -359,7 +420,7 @@ private fun PeopleSearch( singleLine = true, shape = RoundedCornerShape(14.dp), leadingIcon = { Icon(symbol = MaterialSymbols.Search, contentDescription = null) }, - placeholder = { Text(stringRes(R.string.backup_review_search_people, count.toString())) }, + placeholder = { Text(stringRes(Res.string.backup_review_search_people, count.toString())) }, ) } @@ -388,15 +449,15 @@ private fun LazyListScope.muteListItems( Icon(symbol = MaterialSymbols.Shield, contentDescription = null, tint = tones.removed, modifier = Modifier.size(44.dp)) Column { Text( - stringRes(R.string.backup_review_unmuted, removed.size.toString()), + stringRes(Res.string.backup_review_unmuted, removed.size.toString()), fontSize = 30.sp, lineHeight = 32.sp, fontWeight = FontWeight.Bold, color = tones.removed, ) - Text(stringRes(R.string.backup_review_unmuted_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) + Text(stringRes(Res.string.backup_review_unmuted_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) if (added.isNotEmpty()) { - Text(stringRes(R.string.backup_review_newly_muted, added.size.toString()), style = MaterialTheme.typography.bodySmall, color = tones.added) + Text(stringRes(Res.string.backup_review_newly_muted, added.size.toString()), style = MaterialTheme.typography.bodySmall, color = tones.added) } } } @@ -406,17 +467,17 @@ private fun LazyListScope.muteListItems( item(key = "mute-tiles", contentType = "tiles") { val tones = conflictTones() Row(Pad.padding(top = 12.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { - StatTile("−${people.size}", stringRes(R.string.backup_entry_person), tones.removed, Modifier.weight(1f)) - StatTile("−${words.size}", stringRes(R.string.backup_entry_word), tones.removed, Modifier.weight(1f)) - StatTile("−${hashtags.size}", stringRes(R.string.backup_entry_hashtag), tones.removed, Modifier.weight(1f)) - StatTile("−${threads.size}", stringRes(R.string.backup_entry_thread), tones.removed, Modifier.weight(1f)) + StatTile("−${people.size}", stringRes(Res.string.backup_entry_person), tones.removed, Modifier.weight(1f)) + StatTile("−${words.size}", stringRes(Res.string.backup_entry_word), tones.removed, Modifier.weight(1f)) + StatTile("−${hashtags.size}", stringRes(Res.string.backup_entry_hashtag), tones.removed, Modifier.weight(1f)) + StatTile("−${threads.size}", stringRes(Res.string.backup_entry_thread), tones.removed, Modifier.weight(1f)) } } if (people.isNotEmpty()) { item(key = "mute-people", contentType = "facepile") { Column(Pad.padding(top = 18.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { - SectionCaption(stringRes(R.string.backup_entry_person)) + SectionCaption(stringRes(Res.string.backup_entry_person)) FacePile(people, accountViewModel) { ui.showAllPeople = !ui.showAllPeople } } } @@ -427,7 +488,7 @@ private fun LazyListScope.muteListItems( item(key = "mute-words", contentType = "pills") { val tones = conflictTones() Column(Pad.padding(top = 18.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { - SectionCaption(stringRes(R.string.backup_review_words_and_hashtags)) + SectionCaption(stringRes(Res.string.backup_review_words_and_hashtags)) FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { (words.map { "\"$it\"" } + hashtags).forEach { StruckPill(it, tones.removed) } } @@ -436,7 +497,7 @@ private fun LazyListScope.muteListItems( } if (threads.isNotEmpty()) { - item(key = "mute-threads-caption", contentType = "caption") { SectionCaption(stringRes(R.string.backup_entry_thread), Pad.padding(top = 18.dp)) } + item(key = "mute-threads-caption", contentType = "caption") { SectionCaption(stringRes(Res.string.backup_entry_thread), Pad.padding(top = 18.dp)) } items(threads, key = { "mute-thread-$it" }, contentType = { "note" }) { id -> LoadNote(id) { note -> if (note != null) { @@ -463,7 +524,7 @@ private fun FacePile( val names = people.take(2).map { observedName(it, accountViewModel) } val summary = if (people.size > 2) { - stringRes(R.string.backup_review_names_and_more, names.joinToString(", "), (people.size - 2).toString()) + stringRes(Res.string.backup_review_names_and_more, names.joinToString(", "), (people.size - 2).toString()) } else { names.joinToString(", ") } @@ -564,9 +625,9 @@ internal fun PrivateItemsCard( val tones = conflictTones() val (title, body) = when (change) { - ContentChange.CLEARED -> R.string.backup_review_private_wiped_title to R.string.backup_review_private_wiped_body - ContentChange.ADDED -> R.string.backup_review_private_added_title to R.string.backup_review_private_added_body - else -> R.string.backup_review_private_changed_title to R.string.backup_review_private_changed_body + ContentChange.CLEARED -> Res.string.backup_review_private_wiped_title to Res.string.backup_review_private_wiped_body + ContentChange.ADDED -> Res.string.backup_review_private_added_title to Res.string.backup_review_private_added_body + else -> Res.string.backup_review_private_changed_title to Res.string.backup_review_private_changed_body } Row( modifier @@ -592,28 +653,28 @@ internal fun PrivateItemsCard( // --------------------------------------------------------------------------------------- private class ProfileField( - val labelRes: Int, + val labelRes: StringResource, val change: ValueChange, val isImage: Boolean = false, ) private fun profileFields(diff: MetadataDiff): List = listOfNotNull( - diff.picture?.let { ProfileField(R.string.backup_profile_field_picture, it, isImage = true) }, - diff.banner?.let { ProfileField(R.string.backup_profile_field_banner, it, isImage = true) }, - diff.name?.let { ProfileField(R.string.backup_profile_field_name, it) }, - diff.displayName?.let { ProfileField(R.string.backup_profile_field_display_name, it) }, - diff.about?.let { ProfileField(R.string.backup_profile_field_about, it) }, - diff.nip05?.let { ProfileField(R.string.backup_profile_field_nip05, it) }, - diff.website?.let { ProfileField(R.string.backup_profile_field_website, it) }, - diff.lud16?.let { ProfileField(R.string.backup_profile_field_lud16, it) }, - diff.lud06?.let { ProfileField(R.string.backup_profile_field_lud06, it) }, - diff.clinkOffer?.let { ProfileField(R.string.backup_profile_field_clink_offer, it) }, - diff.pronouns?.let { ProfileField(R.string.backup_profile_field_pronouns, it) }, - diff.bot?.let { ProfileField(R.string.backup_profile_field_bot, ValueChange(it.before?.toString(), it.after?.toString())) }, + diff.picture?.let { ProfileField(Res.string.backup_profile_field_picture, it, isImage = true) }, + diff.banner?.let { ProfileField(Res.string.backup_profile_field_banner, it, isImage = true) }, + diff.name?.let { ProfileField(Res.string.backup_profile_field_name, it) }, + diff.displayName?.let { ProfileField(Res.string.backup_profile_field_display_name, it) }, + diff.about?.let { ProfileField(Res.string.backup_profile_field_about, it) }, + diff.nip05?.let { ProfileField(Res.string.backup_profile_field_nip05, it) }, + diff.website?.let { ProfileField(Res.string.backup_profile_field_website, it) }, + diff.lud16?.let { ProfileField(Res.string.backup_profile_field_lud16, it) }, + diff.lud06?.let { ProfileField(Res.string.backup_profile_field_lud06, it) }, + diff.clinkOffer?.let { ProfileField(Res.string.backup_profile_field_clink_offer, it) }, + diff.pronouns?.let { ProfileField(Res.string.backup_profile_field_pronouns, it) }, + diff.bot?.let { ProfileField(Res.string.backup_profile_field_bot, ValueChange(it.before?.toString(), it.after?.toString())) }, diff.birthday?.let { ProfileField( - R.string.backup_profile_field_birthday, + Res.string.backup_profile_field_birthday, ValueChange( it.before?.let { b -> listOfNotNull(b.year, b.month, b.day).joinToString("-") }, it.after?.let { a -> listOfNotNull(a.year, a.month, a.day).joinToString("-") }, @@ -636,8 +697,8 @@ private fun LazyListScope.profileItems( item(key = "profile-cards", contentType = "profile-cards") { val tones = conflictTones() Row(Pad.padding(top = 8.dp), horizontalArrangement = Arrangement.spacedBy(10.dp)) { - MiniProfileCard(saved, pubKey, stringRes(R.string.backup_review_saved), MaterialTheme.colorScheme.outlineVariant, accountViewModel, Modifier.weight(1f)) - MiniProfileCard(incoming, pubKey, stringRes(R.string.backup_review_new), tones.removed.copy(alpha = 0.5f), accountViewModel, Modifier.weight(1f)) + MiniProfileCard(saved, pubKey, stringRes(Res.string.backup_review_saved), MaterialTheme.colorScheme.outlineVariant, accountViewModel, Modifier.weight(1f)) + MiniProfileCard(incoming, pubKey, stringRes(Res.string.backup_review_new), tones.removed.copy(alpha = 0.5f), accountViewModel, Modifier.weight(1f)) } } @@ -656,7 +717,7 @@ private fun LazyListScope.profileItems( } } // Linked identities and fields this app doesn't model use the generic sections. - genericDiffItems(buildRows(presentation, skipGroups = setOf(R.string.backup_entry_profile_field)), accountViewModel, nav) + genericDiffItems(buildRows(presentation, skipGroups = setOf(Res.string.backup_entry_profile_field)), accountViewModel, nav) } @Composable @@ -735,10 +796,10 @@ private fun FlowRowDiff( FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(6.dp), itemVerticalAlignment = Alignment.CenterVertically) { if (before != null) DiffChip(clip(before), tones.removed, struck = true) when { - after == null -> StatusTag(stringRes(R.string.backup_review_gone), tones.removed) + after == null -> StatusTag(stringRes(Res.string.backup_review_gone), tones.removed) before == null -> { DiffChip(clip(after), tones.added, struck = false) - StatusTag(stringRes(R.string.backup_review_new_tag), tones.added) + StatusTag(stringRes(Res.string.backup_review_new_tag), tones.added) } else -> { Text("→", color = MaterialTheme.colorScheme.placeholderText) @@ -779,7 +840,7 @@ private fun ImageThumb( contentAlignment = Alignment.Center, ) { if (url == null) { - Text(stringRes(R.string.backup_review_not_set), style = MaterialTheme.typography.labelSmall, color = color) + Text(stringRes(Res.string.backup_review_not_set), style = MaterialTheme.typography.labelSmall, color = color) } else { MyAsyncImage( imageUrl = url, @@ -843,14 +904,14 @@ private fun LazyListScope.nip65Items( val outbox = lane(saved, new, writes) val inbox = lane(saved, new, reads) - laneItems("outbox", stringRes = R.string.backup_review_outbox, subRes = R.string.backup_review_outbox_explainer, rows = outbox, nav = nav) - laneItems("inbox", stringRes = R.string.backup_review_inbox, subRes = R.string.backup_review_inbox_explainer, rows = inbox, nav = nav) + laneItems("outbox", stringRes = Res.string.backup_review_outbox, subRes = Res.string.backup_review_outbox_explainer, rows = outbox, nav = nav) + laneItems("inbox", stringRes = Res.string.backup_review_inbox, subRes = Res.string.backup_review_inbox_explainer, rows = inbox, nav = nav) } private fun LazyListScope.laneItems( key: String, - stringRes: Int, - subRes: Int, + stringRes: StringResource, + subRes: StringResource, rows: List, nav: INav, ) { @@ -873,9 +934,9 @@ private fun LaneRelayRow( val (color, tag) = when (row.state) { LaneState.KEPT -> tones.kept to null - LaneState.DROPPED -> tones.removed to R.string.backup_review_dropped_tag - LaneState.ADDED -> tones.added to R.string.backup_review_new_tag - LaneState.DEMOTED -> tones.changed to R.string.backup_review_demoted_tag + LaneState.DROPPED -> tones.removed to Res.string.backup_review_dropped_tag + LaneState.ADDED -> tones.added to Res.string.backup_review_new_tag + LaneState.DEMOTED -> tones.changed to Res.string.backup_review_demoted_tag } Row( Pad @@ -933,12 +994,12 @@ private fun LazyListScope.nutzapItems( ) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { Icon(symbol = MaterialSymbols.Key, contentDescription = null, tint = tones.changed) - Text(stringRes(if (key.after == null) R.string.backup_review_key_removed else R.string.backup_review_key_replaced), style = MaterialTheme.typography.titleSmall) + Text(stringRes(if (key.after == null) Res.string.backup_review_key_removed else Res.string.backup_review_key_replaced), style = MaterialTheme.typography.titleSmall) } Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) { - KeyColumn(key.before, stringRes(R.string.backup_review_saved), tones.kept) + KeyColumn(key.before, stringRes(Res.string.backup_review_saved), tones.kept) Text("→", fontSize = 24.sp, color = MaterialTheme.colorScheme.placeholderText, modifier = Modifier.padding(horizontal = 18.dp)) - KeyColumn(key.after, stringRes(R.string.backup_review_new), tones.changed) + KeyColumn(key.after, stringRes(Res.string.backup_review_new), tones.changed) } if (key.after != null) { Row( @@ -950,7 +1011,7 @@ private fun LazyListScope.nutzapItems( horizontalArrangement = Arrangement.spacedBy(8.dp), ) { Icon(symbol = MaterialSymbols.Warning, contentDescription = null, tint = tones.changed, modifier = Modifier.size(18.dp)) - Text(stringRes(R.string.backup_review_key_warning), style = MaterialTheme.typography.bodySmall, color = tones.changed) + Text(stringRes(Res.string.backup_review_key_warning), style = MaterialTheme.typography.bodySmall, color = tones.changed) } } } @@ -976,10 +1037,10 @@ private fun LazyListScope.nutzapItems( } + diff.mints.added.map { Triple(it.mintUrl, it.units.joinToString(), LaneState.ADDED) } if (mintRows.isNotEmpty()) { - item(key = "nutzap-mints", contentType = "caption") { SectionCaption(stringRes(R.string.backup_entry_mint), Pad.padding(top = 18.dp, bottom = 6.dp)) } + item(key = "nutzap-mints", contentType = "caption") { SectionCaption(stringRes(Res.string.backup_entry_mint), Pad.padding(top = 18.dp, bottom = 6.dp)) } items(mintRows, key = { "mint-" + it.first }, contentType = { "mint" }) { (url, units, state) -> MintRow(url, units, state) } } - genericDiffItems(buildRows(presentation, skipGroups = setOf(R.string.backup_entry_mint, R.string.backup_entry_nutzap_key)), accountViewModel, nav) + genericDiffItems(buildRows(presentation, skipGroups = setOf(Res.string.backup_entry_mint, Res.string.backup_entry_nutzap_key)), accountViewModel, nav) } @Composable @@ -993,7 +1054,7 @@ private fun KeyColumn( KeyFingerprint(hex, color) } else { Box(Modifier.size(96.dp).clip(RoundedCornerShape(18.dp)).border(2.dp, color, RoundedCornerShape(18.dp)), contentAlignment = Alignment.Center) { - Text(stringRes(R.string.backup_review_not_set), style = MaterialTheme.typography.labelSmall, color = color) + Text(stringRes(Res.string.backup_review_not_set), style = MaterialTheme.typography.labelSmall, color = color) } } StatusTag(label, color) @@ -1010,9 +1071,9 @@ private fun MintRow( val (color, tag) = when (state) { LaneState.KEPT -> MaterialTheme.colorScheme.onSurface to null - LaneState.DROPPED -> tones.removed to R.string.backup_review_dropped_tag - LaneState.ADDED -> tones.added to R.string.backup_review_new_tag - LaneState.DEMOTED -> tones.changed to R.string.backup_review_units_tag + LaneState.DROPPED -> tones.removed to Res.string.backup_review_dropped_tag + LaneState.ADDED -> tones.added to Res.string.backup_review_new_tag + LaneState.DEMOTED -> tones.changed to Res.string.backup_review_units_tag } Row( Pad @@ -1083,21 +1144,21 @@ private fun LazyListScope.groupItems( StatTile( diff.groups.removed.size .toString(), - stringRes(R.string.backup_review_left), + stringRes(Res.string.backup_review_left), tones.removed, Modifier.weight(1f), ) StatTile( diff.groups.added.size .toString(), - stringRes(R.string.backup_review_joined), + stringRes(Res.string.backup_review_joined), tones.added, Modifier.weight(1f), ) StatTile( diff.groups.changed.size .toString(), - stringRes(R.string.backup_review_renamed), + stringRes(Res.string.backup_review_renamed), tones.changed, Modifier.weight(1f), ) @@ -1165,7 +1226,7 @@ private fun GroupTileContent( Column { Text(name, style = MaterialTheme.typography.titleSmall, maxLines = 1, overflow = TextOverflow.Ellipsis) Text( - tile.oldName?.let { stringRes(R.string.backup_review_was_named, it) } ?: tile.group.relayUrl + tile.oldName?.let { stringRes(Res.string.backup_review_was_named, it) } ?: tile.group.relayUrl .removePrefix("wss://") .removeSuffix("/"), style = MaterialTheme.typography.labelSmall, @@ -1176,9 +1237,9 @@ private fun GroupTileContent( } } when (tile.state) { - LaneState.DROPPED -> StatusTag(stringRes(R.string.backup_review_left_tag), tones.removed, Modifier.align(Alignment.TopEnd)) - LaneState.ADDED -> StatusTag(stringRes(R.string.backup_review_new_tag), tones.added, Modifier.align(Alignment.TopEnd)) - LaneState.DEMOTED -> StatusTag(stringRes(R.string.backup_review_renamed_tag), tones.changed, Modifier.align(Alignment.TopEnd)) + LaneState.DROPPED -> StatusTag(stringRes(Res.string.backup_review_left_tag), tones.removed, Modifier.align(Alignment.TopEnd)) + LaneState.ADDED -> StatusTag(stringRes(Res.string.backup_review_new_tag), tones.added, Modifier.align(Alignment.TopEnd)) + LaneState.DEMOTED -> StatusTag(stringRes(Res.string.backup_review_renamed_tag), tones.changed, Modifier.align(Alignment.TopEnd)) LaneState.KEPT -> {} } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt index 55473cce27..b2e854c06b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictListViews.kt @@ -48,13 +48,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -63,6 +61,53 @@ import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflic import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.backup_review_allowed_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_concord_body +import com.vitorpamplona.amethyst.commons.resources.backup_review_demoted_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_dropped_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_encrypted_added +import com.vitorpamplona.amethyst.commons.resources.backup_review_encrypted_changed +import com.vitorpamplona.amethyst.commons.resources.backup_review_encrypted_cleared +import com.vitorpamplona.amethyst.commons.resources.backup_review_feed +import com.vitorpamplona.amethyst.commons.resources.backup_review_hashtags_you_follow +import com.vitorpamplona.amethyst.commons.resources.backup_review_joined +import com.vitorpamplona.amethyst.commons.resources.backup_review_kept +import com.vitorpamplona.amethyst.commons.resources.backup_review_left +import com.vitorpamplona.amethyst.commons.resources.backup_review_left_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_listed_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_moved_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_new +import com.vitorpamplona.amethyst.commons.resources.backup_review_new_count_caption +import com.vitorpamplona.amethyst.commons.resources.backup_review_new_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_newly_blocked +import com.vitorpamplona.amethyst.commons.resources.backup_review_no_longer_blocked +import com.vitorpamplona.amethyst.commons.resources.backup_review_offer +import com.vitorpamplona.amethyst.commons.resources.backup_review_offers_gone +import com.vitorpamplona.amethyst.commons.resources.backup_review_payment_targets_gone +import com.vitorpamplona.amethyst.commons.resources.backup_review_payments_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_places_gone +import com.vitorpamplona.amethyst.commons.resources.backup_review_places_you_follow +import com.vitorpamplona.amethyst.commons.resources.backup_review_receiving_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_saved +import com.vitorpamplona.amethyst.commons.resources.backup_review_searching_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_service +import com.vitorpamplona.amethyst.commons.resources.backup_review_service_followers +import com.vitorpamplona.amethyst.commons.resources.backup_review_service_rank +import com.vitorpamplona.amethyst.commons.resources.backup_review_service_topics +import com.vitorpamplona.amethyst.commons.resources.backup_review_services_changed +import com.vitorpamplona.amethyst.commons.resources.backup_review_services_changed_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_still_blocked +import com.vitorpamplona.amethyst.commons.resources.backup_review_storing_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_topics_gone +import com.vitorpamplona.amethyst.commons.resources.backup_review_trust_warning +import com.vitorpamplona.amethyst.commons.resources.backup_review_trusted_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_unblocked +import com.vitorpamplona.amethyst.commons.resources.backup_review_unblocked_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_review_untrusted_tag +import com.vitorpamplona.amethyst.commons.resources.backup_review_wallet_body +import com.vitorpamplona.amethyst.commons.resources.backup_type_communities +import com.vitorpamplona.amethyst.commons.resources.backup_type_public_chats import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings @@ -118,6 +163,9 @@ import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListEve import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent import com.vitorpamplona.quartz.nipB1Bolt12Zaps.offer.Bolt12OfferListDiff import com.vitorpamplona.quartz.nipB1Bolt12Zaps.offer.Bolt12OfferListEvent +import org.jetbrains.compose.resources.PluralStringResource +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.pluralStringResource /** * Per-event layouts for the account's other lists: each relay list framed by what it is @@ -142,8 +190,8 @@ internal fun LazyListScope.listDiffItems( is TrustProviderListDiff -> trustProviderItems(diff, conflict, accountViewModel, nav) is PaymentTargetsDiff -> paymentTargetItems(diff, conflict) is Bolt12OfferListDiff -> offerItems(diff, conflict) - is CashuWalletDiff -> encryptedOnlyItems(MaterialSymbols.AccountBalanceWallet, diff.wallet, R.string.backup_review_wallet_body) - is ConcordCommunityListDiff -> encryptedOnlyItems(MaterialSymbols.Groups, diff.communities, R.string.backup_review_concord_body) + is CashuWalletDiff -> encryptedOnlyItems(MaterialSymbols.AccountBalanceWallet, diff.wallet, Res.string.backup_review_wallet_body) + is ConcordCommunityListDiff -> encryptedOnlyItems(MaterialSymbols.Groups, diff.communities, Res.string.backup_review_concord_body) else -> return false } return true @@ -193,15 +241,15 @@ private fun fateColor(fate: ItemFate): Color { private fun LazyListScope.countTiles( items: List>, - removedCaption: Int, - addedCaption: Int, + removedCaption: StringResource, + addedCaption: StringResource, ) { item(key = "count-tiles", contentType = "tiles") { val tones = conflictTones() Row(Pad.padding(top = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { StatTile(items.count { it.second == ItemFate.DROPPED }.toString(), stringRes(removedCaption), tones.removed, Modifier.weight(1f)) StatTile(items.count { it.second == ItemFate.ADDED }.toString(), stringRes(addedCaption), tones.added, Modifier.weight(1f)) - StatTile(items.count { it.second == ItemFate.KEPT || it.second == ItemFate.CHANGED }.toString(), stringRes(R.string.backup_review_kept), tones.kept, Modifier.weight(1f)) + StatTile(items.count { it.second == ItemFate.KEPT || it.second == ItemFate.CHANGED }.toString(), stringRes(Res.string.backup_review_kept), tones.kept, Modifier.weight(1f)) } } } @@ -218,20 +266,20 @@ private fun LazyListScope.privateItemsCard(change: ContentChange) { /** How a relay list's rows are presented: its icon and what a kept or dropped relay is called. */ private class RelayFraming( val icon: MaterialSymbol, - val keptTag: Int, - val droppedTag: Int = R.string.backup_review_dropped_tag, + val keptTag: StringResource, + val droppedTag: StringResource = Res.string.backup_review_dropped_tag, ) private fun framingOf(type: BackupEventType): RelayFraming = when (type) { - BackupEventType.DM_RELAYS -> RelayFraming(MaterialSymbols.Mail, R.string.backup_review_receiving_tag) - BackupEventType.KEY_PACKAGE_RELAYS -> RelayFraming(MaterialSymbols.Key, R.string.backup_review_listed_tag) - BackupEventType.SEARCH_RELAYS -> RelayFraming(MaterialSymbols.Search, R.string.backup_review_searching_tag) - BackupEventType.INDEXER_RELAYS -> RelayFraming(MaterialSymbols.Dns, R.string.backup_review_listed_tag) - BackupEventType.RELAY_FEEDS -> RelayFraming(MaterialSymbols.CellTower, R.string.backup_review_listed_tag) - BackupEventType.PRIVATE_OUTBOX_RELAYS -> RelayFraming(MaterialSymbols.Lock, R.string.backup_review_storing_tag) - BackupEventType.TRUSTED_RELAYS -> RelayFraming(MaterialSymbols.Shield, R.string.backup_review_trusted_tag, R.string.backup_review_untrusted_tag) - else -> RelayFraming(MaterialSymbols.Dns, R.string.backup_review_listed_tag) + BackupEventType.DM_RELAYS -> RelayFraming(MaterialSymbols.Mail, Res.string.backup_review_receiving_tag) + BackupEventType.KEY_PACKAGE_RELAYS -> RelayFraming(MaterialSymbols.Key, Res.string.backup_review_listed_tag) + BackupEventType.SEARCH_RELAYS -> RelayFraming(MaterialSymbols.Search, Res.string.backup_review_searching_tag) + BackupEventType.INDEXER_RELAYS -> RelayFraming(MaterialSymbols.Dns, Res.string.backup_review_listed_tag) + BackupEventType.RELAY_FEEDS -> RelayFraming(MaterialSymbols.CellTower, Res.string.backup_review_listed_tag) + BackupEventType.PRIVATE_OUTBOX_RELAYS -> RelayFraming(MaterialSymbols.Lock, Res.string.backup_review_storing_tag) + BackupEventType.TRUSTED_RELAYS -> RelayFraming(MaterialSymbols.Shield, Res.string.backup_review_trusted_tag, Res.string.backup_review_untrusted_tag) + else -> RelayFraming(MaterialSymbols.Dns, Res.string.backup_review_listed_tag) } private fun savedRelaysOf(event: Event): List = @@ -277,8 +325,8 @@ private fun RelayFateRow( when (fate) { ItemFate.KEPT -> framing.keptTag ItemFate.DROPPED -> framing.droppedTag - ItemFate.ADDED -> R.string.backup_review_new_tag - ItemFate.CHANGED -> R.string.backup_review_demoted_tag + ItemFate.ADDED -> Res.string.backup_review_new_tag + ItemFate.CHANGED -> Res.string.backup_review_demoted_tag } Row( Pad @@ -320,14 +368,14 @@ private fun LazyListScope.blockedRelayItems( Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(16.dp)) { Icon(symbol = MaterialSymbols.LockOpen, contentDescription = null, tint = tones.changed, modifier = Modifier.size(44.dp)) Column { - Text(stringRes(R.string.backup_review_unblocked, unblocked.size.toString()), fontSize = 30.sp, lineHeight = 32.sp, fontWeight = FontWeight.Bold, color = tones.changed) - Text(stringRes(R.string.backup_review_unblocked_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) + Text(stringRes(Res.string.backup_review_unblocked, unblocked.size.toString()), fontSize = 30.sp, lineHeight = 32.sp, fontWeight = FontWeight.Bold, color = tones.changed) + Text(stringRes(Res.string.backup_review_unblocked_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) } } } } if (unblocked.isNotEmpty()) { - item(key = "unblocked-caption", contentType = "caption") { SectionCaption(stringRes(R.string.backup_review_no_longer_blocked), Pad.padding(top = 18.dp)) } + item(key = "unblocked-caption", contentType = "caption") { SectionCaption(stringRes(Res.string.backup_review_no_longer_blocked), Pad.padding(top = 18.dp)) } items(unblocked, key = { "unblocked-" + it.url }, contentType = { "relay-row" }) { url -> val tones = conflictTones() Row( @@ -346,12 +394,12 @@ private fun LazyListScope.blockedRelayItems( Icon(symbol = MaterialSymbols.LockOpen, contentDescription = null, tint = tones.changed, modifier = Modifier.size(18.dp)) } Text(url.url.removePrefix("wss://").removeSuffix("/"), modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.SemiBold, maxLines = 1, overflow = TextOverflow.Ellipsis) - StatusTag(stringRes(R.string.backup_review_allowed_tag), tones.changed) + StatusTag(stringRes(Res.string.backup_review_allowed_tag), tones.changed) } } } if (newlyBlocked.isNotEmpty()) { - item(key = "newly-blocked-caption", contentType = "caption") { SectionCaption(stringRes(R.string.backup_review_newly_blocked), Pad.padding(top = 18.dp)) } + item(key = "newly-blocked-caption", contentType = "caption") { SectionCaption(stringRes(Res.string.backup_review_newly_blocked), Pad.padding(top = 18.dp)) } items(newlyBlocked, key = { "newly-blocked-" + it.url }, contentType = { "relay-row" }) { url -> RelayFateRow(url, ItemFate.ADDED, framingOf(BackupEventType.BLOCKED_RELAYS), nav) } @@ -359,7 +407,7 @@ private fun LazyListScope.blockedRelayItems( if (stillBlocked.isNotEmpty()) { item(key = "still-blocked", contentType = "chips") { Column(Pad.padding(top = 18.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { - SectionCaption(stringRes(R.string.backup_review_still_blocked)) + SectionCaption(stringRes(Res.string.backup_review_still_blocked)) FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) { stillBlocked.forEach { url -> Row( @@ -392,7 +440,7 @@ private fun LazyListScope.spaceGrid( key: (T) -> String, content: @Composable (T, ItemFate, Modifier) -> Unit, ) { - countTiles(items, R.string.backup_review_left, R.string.backup_review_joined) + countTiles(items, Res.string.backup_review_left, Res.string.backup_review_joined) items(items.chunked(2), key = { keyPrefix + key(it.first().first) }, contentType = { "space-row" }) { row -> Row(Pad.padding(top = 10.dp).fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp)) { row.forEach { (item, fate) -> content(item, fate, Modifier.weight(1f)) } @@ -436,9 +484,9 @@ private fun SpaceTile( } val tag = when (fate) { - ItemFate.DROPPED -> R.string.backup_review_left_tag to tones.removed - ItemFate.ADDED -> R.string.backup_review_new_tag to tones.added - ItemFate.CHANGED -> R.string.backup_review_moved_tag to tones.changed + ItemFate.DROPPED -> Res.string.backup_review_left_tag to tones.removed + ItemFate.ADDED -> Res.string.backup_review_new_tag to tones.added + ItemFate.CHANGED -> Res.string.backup_review_moved_tag to tones.changed ItemFate.KEPT -> null } tag?.let { (res, color) -> StatusTag(stringRes(res), color, Modifier.align(Alignment.TopEnd)) } @@ -459,7 +507,7 @@ private fun LazyListScope.publicChatItems( val current = state?.channel ?: channel SpaceTile( name = current.toBestDisplayName(), - subtitle = stringRes(R.string.backup_type_public_chats), + subtitle = stringRes(Res.string.backup_type_public_chats), robot = tag.eventId, picture = channel.profilePicture(), fate = fate, @@ -525,7 +573,7 @@ private fun AddressableSpaceTile( } SpaceTile( name = name ?: address.dTag.ifBlank { address.toValue().toShortDisplay() }, - subtitle = stringRes(if (address.kind == AppDefinitionEvent.KIND) R.string.backup_review_feed else R.string.backup_type_communities), + subtitle = stringRes(if (address.kind == AppDefinitionEvent.KIND) Res.string.backup_review_feed else Res.string.backup_type_communities), robot = address.toValue(), picture = picture, fate = fate, @@ -543,7 +591,7 @@ private fun LazyListScope.ephemeralRoomItems( ) { val saved = (conflict.saved as? EphemeralChatListEvent)?.publicRooms().orEmpty() val rooms = fates(saved, diff.rooms) { it } - countTiles(rooms, R.string.backup_review_left, R.string.backup_review_joined) + countTiles(rooms, Res.string.backup_review_left, Res.string.backup_review_joined) items(rooms, key = { "room-" + it.first.toKey() }, contentType = { "room-row" }) { (room, fate) -> RoomRow(room, fate, nav) } privateItemsCard(diff.privateItems) } @@ -582,8 +630,8 @@ private fun RoomRow( ) } when (fate) { - ItemFate.DROPPED -> StatusTag(stringRes(R.string.backup_review_left_tag), color) - ItemFate.ADDED -> StatusTag(stringRes(R.string.backup_review_new_tag), color) + ItemFate.DROPPED -> StatusTag(stringRes(Res.string.backup_review_left_tag), color) + ItemFate.ADDED -> StatusTag(stringRes(Res.string.backup_review_new_tag), color) else -> {} } } @@ -602,11 +650,11 @@ private fun LazyListScope.topicItems( nav: INav, ) { val topics = fates(saved, diff) { it.lowercase() } - countTiles(topics, if (isPlace) R.string.backup_review_places_gone else R.string.backup_review_topics_gone, R.string.backup_review_new_count_caption) + countTiles(topics, if (isPlace) Res.string.backup_review_places_gone else Res.string.backup_review_topics_gone, Res.string.backup_review_new_count_caption) item(key = "topic-cloud", contentType = "cloud") { val tones = conflictTones() Column(Pad.padding(top = 18.dp), verticalArrangement = Arrangement.spacedBy(10.dp)) { - SectionCaption(stringRes(if (isPlace) R.string.backup_review_places_you_follow else R.string.backup_review_hashtags_you_follow)) + SectionCaption(stringRes(if (isPlace) Res.string.backup_review_places_you_follow else Res.string.backup_review_hashtags_you_follow)) FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), itemVerticalAlignment = Alignment.CenterVertically) { topics.forEach { (topic, fate) -> val color = fateColor(fate) @@ -706,15 +754,15 @@ private fun LazyListScope.trustProviderItems( Icon(symbol = MaterialSymbols.Group, contentDescription = null, tint = tones.changed) } Column { - Text(stringRes(R.string.backup_review_services_changed, affected.toString(), services.size.toString()), fontSize = 24.sp, lineHeight = 28.sp, fontWeight = FontWeight.Bold) - Text(stringRes(R.string.backup_review_services_changed_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) + Text(stringRes(Res.string.backup_review_services_changed, affected.toString(), services.size.toString()), fontSize = 24.sp, lineHeight = 28.sp, fontWeight = FontWeight.Bold) + Text(stringRes(Res.string.backup_review_services_changed_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) } } } } item(key = "trust-header", contentType = "table-header") { Row(Pad.padding(top = 16.dp, bottom = 4.dp).padding(horizontal = 12.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { - listOf(R.string.backup_review_service, R.string.backup_review_saved, R.string.backup_review_new).forEachIndexed { index, res -> + listOf(Res.string.backup_review_service, Res.string.backup_review_saved, Res.string.backup_review_new).forEachIndexed { index, res -> Text(stringRes(res).uppercase(), Modifier.weight(if (index == 0) 1.1f else 1f), style = MaterialTheme.typography.labelSmall, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.placeholderText) } } @@ -732,7 +780,7 @@ private fun LazyListScope.trustProviderItems( horizontalArrangement = Arrangement.spacedBy(8.dp), ) { Icon(symbol = MaterialSymbols.Warning, contentDescription = null, tint = tones.changed, modifier = Modifier.size(18.dp)) - Text(stringRes(R.string.backup_review_trust_warning), style = MaterialTheme.typography.bodySmall, color = tones.changed) + Text(stringRes(Res.string.backup_review_trust_warning), style = MaterialTheme.typography.bodySmall, color = tones.changed) } } privateItemsCard(diff.privateItems) @@ -771,9 +819,9 @@ private fun ServiceTableRow( @Composable private fun serviceLabel(type: String): String = when (type) { - "rank" -> stringRes(R.string.backup_review_service_rank) - "followers" -> stringRes(R.string.backup_review_service_followers) - "t" -> stringRes(R.string.backup_review_service_topics) + "rank" -> stringRes(Res.string.backup_review_service_rank) + "followers" -> stringRes(Res.string.backup_review_service_followers) + "t" -> stringRes(Res.string.backup_review_service_topics) else -> type.replace('_', ' ').replaceFirstChar { it.uppercase() } } @@ -826,7 +874,7 @@ private fun LazyListScope.paymentTargetItems( ) { val saved = (conflict.saved as? PaymentTargetsEvent)?.paymentTargets().orEmpty() val targets = fates(saved, diff.targets) { it } - moneyHero(targets.count { it.second == ItemFate.DROPPED }, R.plurals.backup_review_payment_targets_gone) + moneyHero(targets.count { it.second == ItemFate.DROPPED }, Res.plurals.backup_review_payment_targets_gone) items(targets, key = { "target-" + it.first.type + ":" + it.first.authority }, contentType = { "money-row" }) { (target, fate) -> PaymentTargetRow(target, fate) } } @@ -836,15 +884,15 @@ private fun LazyListScope.offerItems( ) { val saved = (conflict.saved as? Bolt12OfferListEvent)?.offers().orEmpty() val offers = fates(saved, diff.offers) { it } - moneyHero(offers.count { it.second == ItemFate.DROPPED }, R.plurals.backup_review_offers_gone) + moneyHero(offers.count { it.second == ItemFate.DROPPED }, Res.plurals.backup_review_offers_gone) items(offers, key = { "offer-" + it.first }, contentType = { "money-row" }) { (offer, fate) -> - MoneyRow(stringRes(R.string.backup_review_offer), offer.toShortDisplay(prefixSize = 4), fate) + MoneyRow(stringRes(Res.string.backup_review_offer), offer.toShortDisplay(prefixSize = 4), fate) } } private fun LazyListScope.moneyHero( dropped: Int, - headline: Int, + headline: PluralStringResource, ) { item(key = "money-hero", contentType = "hero") { val tones = conflictTones() @@ -856,7 +904,7 @@ private fun LazyListScope.moneyHero( } Column { Text(pluralStringResource(headline, dropped, dropped), fontSize = 24.sp, lineHeight = 28.sp, fontWeight = FontWeight.Bold, color = color) - Text(stringRes(R.string.backup_review_payments_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) + Text(stringRes(Res.string.backup_review_payments_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText) } } } @@ -902,8 +950,8 @@ private fun MoneyRow( ) } when (fate) { - ItemFate.DROPPED -> StatusTag(stringRes(R.string.backup_review_dropped_tag), color) - ItemFate.ADDED -> StatusTag(stringRes(R.string.backup_review_new_tag), color) + ItemFate.DROPPED -> StatusTag(stringRes(Res.string.backup_review_dropped_tag), color) + ItemFate.ADDED -> StatusTag(stringRes(Res.string.backup_review_new_tag), color) else -> {} } } @@ -916,15 +964,15 @@ private fun MoneyRow( private fun LazyListScope.encryptedOnlyItems( icon: MaterialSymbol, change: ContentChange, - body: Int, + body: StringResource, ) { item(key = "encrypted-hero", contentType = "hero") { val tones = conflictTones() val (color, headline) = when (change) { - ContentChange.CLEARED -> tones.removed to R.string.backup_review_encrypted_cleared - ContentChange.ADDED -> tones.added to R.string.backup_review_encrypted_added - else -> tones.changed to R.string.backup_review_encrypted_changed + ContentChange.CLEARED -> tones.removed to Res.string.backup_review_encrypted_cleared + ContentChange.ADDED -> tones.added to Res.string.backup_review_encrypted_added + else -> tones.changed to Res.string.backup_review_encrypted_changed } Column(Pad.padding(top = 8.dp), verticalArrangement = Arrangement.spacedBy(14.dp)) { TintedPanel(color.copy(alpha = 0.12f)) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictPresentation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictPresentation.kt index 58195a5d31..0b4bb8af80 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictPresentation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictPresentation.kt @@ -23,9 +23,98 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.backups import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalResources -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.backups.BackupEventType +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_relay_read_only +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_relay_read_write +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_relay_write_only +import com.vitorpamplona.amethyst.commons.resources.backup_entry_algo_feed +import com.vitorpamplona.amethyst.commons.resources.backup_entry_chat_room +import com.vitorpamplona.amethyst.commons.resources.backup_entry_community +import com.vitorpamplona.amethyst.commons.resources.backup_entry_hashtag +import com.vitorpamplona.amethyst.commons.resources.backup_entry_identity_claim +import com.vitorpamplona.amethyst.commons.resources.backup_entry_location +import com.vitorpamplona.amethyst.commons.resources.backup_entry_mint +import com.vitorpamplona.amethyst.commons.resources.backup_entry_nutzap_key +import com.vitorpamplona.amethyst.commons.resources.backup_entry_offer +import com.vitorpamplona.amethyst.commons.resources.backup_entry_other +import com.vitorpamplona.amethyst.commons.resources.backup_entry_payment_target +import com.vitorpamplona.amethyst.commons.resources.backup_entry_person +import com.vitorpamplona.amethyst.commons.resources.backup_entry_profile_field +import com.vitorpamplona.amethyst.commons.resources.backup_entry_public_chat +import com.vitorpamplona.amethyst.commons.resources.backup_entry_relay +import com.vitorpamplona.amethyst.commons.resources.backup_entry_relay_group +import com.vitorpamplona.amethyst.commons.resources.backup_entry_thread +import com.vitorpamplona.amethyst.commons.resources.backup_entry_trust_provider +import com.vitorpamplona.amethyst.commons.resources.backup_entry_word +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_about +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_banner +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_birthday +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_bot +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_clink_offer +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_display_name +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_lud06 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_lud16 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_name +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_nip05 +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_picture +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_pronouns +import com.vitorpamplona.amethyst.commons.resources.backup_profile_field_website +import com.vitorpamplona.amethyst.commons.resources.backup_type_app_settings +import com.vitorpamplona.amethyst.commons.resources.backup_type_app_settings_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_blocked_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_blocked_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_bolt12_offers +import com.vitorpamplona.amethyst.commons.resources.backup_type_bolt12_offers_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_cashu_wallet +import com.vitorpamplona.amethyst.commons.resources.backup_type_cashu_wallet_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_communities +import com.vitorpamplona.amethyst.commons.resources.backup_type_communities_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_concord_communities +import com.vitorpamplona.amethyst.commons.resources.backup_type_concord_communities_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_dm_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_dm_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_ephemeral_chats +import com.vitorpamplona.amethyst.commons.resources.backup_type_ephemeral_chats_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_favorite_algo_feeds +import com.vitorpamplona.amethyst.commons.resources.backup_type_favorite_algo_feeds_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_follow_list +import com.vitorpamplona.amethyst.commons.resources.backup_type_follow_list_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_geohashes +import com.vitorpamplona.amethyst.commons.resources.backup_type_geohashes_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_hashtags +import com.vitorpamplona.amethyst.commons.resources.backup_type_hashtags_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_indexer_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_indexer_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_key_package_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_key_package_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_mute_list +import com.vitorpamplona.amethyst.commons.resources.backup_type_mute_list_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_nutzap_info +import com.vitorpamplona.amethyst.commons.resources.backup_type_nutzap_info_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_other +import com.vitorpamplona.amethyst.commons.resources.backup_type_other_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_outbox_inbox_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_outbox_inbox_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_payment_targets +import com.vitorpamplona.amethyst.commons.resources.backup_type_payment_targets_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_private_outbox_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_private_outbox_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_profile +import com.vitorpamplona.amethyst.commons.resources.backup_type_profile_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_public_chats +import com.vitorpamplona.amethyst.commons.resources.backup_type_public_chats_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_relay_feeds +import com.vitorpamplona.amethyst.commons.resources.backup_type_relay_feeds_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_relay_groups +import com.vitorpamplona.amethyst.commons.resources.backup_type_relay_groups_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_search_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_search_relays_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_trust_providers +import com.vitorpamplona.amethyst.commons.resources.backup_type_trust_providers_explainer +import com.vitorpamplona.amethyst.commons.resources.backup_type_trusted_relays +import com.vitorpamplona.amethyst.commons.resources.backup_type_trusted_relays_explainer +import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListDiff import com.vitorpamplona.quartz.experimental.ephemChat.chat.RoomId import com.vitorpamplona.quartz.experimental.ephemChat.list.EphemeralChatListDiff @@ -61,6 +150,7 @@ import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListDiff import com.vitorpamplona.quartz.nip78AppData.AppSpecificDataDiff import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListDiff import com.vitorpamplona.quartz.nipB1Bolt12Zaps.offer.Bolt12OfferListDiff +import org.jetbrains.compose.resources.StringResource private const val MAX_VALUE_LENGTH = 80 @@ -168,7 +258,7 @@ sealed interface ReviewItem { /** One labelled group of differences (people, relays, profile fields…) of a conflict. */ @Immutable class DiffGroup( - val label: Int, + val label: StringResource, val removed: List, val added: List, val changed: List, @@ -189,7 +279,7 @@ class DiffPresentation( /** A group from a [ListDiff] of an event's parsed items. */ private fun listGroup( - label: Int, + label: StringResource, diff: ListDiff, item: (T) -> ReviewItem, change: (ItemChange) -> ReviewItem, @@ -197,7 +287,7 @@ private fun listGroup( /** A group whose items can't change, only be added or removed (hashtags, plain relays…). */ private fun listGroup( - label: Int, + label: StringResource, diff: ListDiff, item: (T) -> ReviewItem, ) = listGroup(label, diff, item) { item(it.after) } @@ -212,7 +302,7 @@ private inline fun ListDiff<*>.only() = /** A group from single-valued fields: a field set only after is added, only before is removed. */ private fun fieldGroup( - label: Int, + label: StringResource, fields: List?>>, ): DiffGroup { val removed = mutableListOf() @@ -242,14 +332,53 @@ private fun arrow( */ @Composable fun rememberPresentation(diff: EventDiff): DiffPresentation { - val resources = LocalResources.current - return remember(diff, resources) { presentationOf(diff) { resources.getString(it) } } + // Compose resources resolve only in composition (or suspended), so the labels + // [presentationOf] writes into item text are resolved here and handed in. Only the + // diff types that write labels get any, so the rest pay for no resource reads. The + // map compares by value: a recomposition with the same locale keeps the cached result. + val labels = labelsWrittenBy(diff).associateWith { stringRes(it) } + return remember(diff, labels) { presentationOf(diff) { labels.getValue(it) } } } -/** Turns each event's own diff into typed, labelled groups. [str] resolves the labels. */ +/** Every label [presentationOf] resolves through its `str` parameter for [diff]. */ +internal fun labelsWrittenBy(diff: EventDiff): List = + when (diff) { + is MetadataDiff -> PROFILE_FIELD_LABELS + is AdvertisedRelayListDiff -> RELAY_MARKER_LABELS + else -> emptyList() + } + +private val PROFILE_FIELD_LABELS = + listOf( + Res.string.backup_profile_field_name, + Res.string.backup_profile_field_display_name, + Res.string.backup_profile_field_about, + Res.string.backup_profile_field_picture, + Res.string.backup_profile_field_banner, + Res.string.backup_profile_field_website, + Res.string.backup_profile_field_nip05, + Res.string.backup_profile_field_lud16, + Res.string.backup_profile_field_lud06, + Res.string.backup_profile_field_clink_offer, + Res.string.backup_profile_field_pronouns, + Res.string.backup_profile_field_birthday, + Res.string.backup_profile_field_bot, + ) + +private val RELAY_MARKER_LABELS = + listOf( + Res.string.backup_conflict_relay_read_write, + Res.string.backup_conflict_relay_read_only, + Res.string.backup_conflict_relay_write_only, + ) + +/** + * Turns each event's own diff into typed, labelled groups. [str] resolves the labels; a + * label it asks for must be in [labelsWrittenBy] for that diff type. + */ fun presentationOf( diff: EventDiff, - str: (Int) -> String, + str: (StringResource) -> String, ): DiffPresentation { val (groups, content) = when (diff) { @@ -258,31 +387,31 @@ fun presentationOf( val bot = diff.bot?.let { ValueChange(it.before?.toString(), it.after?.toString()) } listOf( fieldGroup( - R.string.backup_entry_profile_field, + Res.string.backup_entry_profile_field, listOf( - str(R.string.backup_profile_field_name) to diff.name, - str(R.string.backup_profile_field_display_name) to diff.displayName, - str(R.string.backup_profile_field_about) to diff.about, - str(R.string.backup_profile_field_picture) to diff.picture, - str(R.string.backup_profile_field_banner) to diff.banner, - str(R.string.backup_profile_field_website) to diff.website, - str(R.string.backup_profile_field_nip05) to diff.nip05, - str(R.string.backup_profile_field_lud16) to diff.lud16, - str(R.string.backup_profile_field_lud06) to diff.lud06, - str(R.string.backup_profile_field_clink_offer) to diff.clinkOffer, - str(R.string.backup_profile_field_pronouns) to diff.pronouns, - str(R.string.backup_profile_field_birthday) to birthday, - str(R.string.backup_profile_field_bot) to bot, + str(Res.string.backup_profile_field_name) to diff.name, + str(Res.string.backup_profile_field_display_name) to diff.displayName, + str(Res.string.backup_profile_field_about) to diff.about, + str(Res.string.backup_profile_field_picture) to diff.picture, + str(Res.string.backup_profile_field_banner) to diff.banner, + str(Res.string.backup_profile_field_website) to diff.website, + str(Res.string.backup_profile_field_nip05) to diff.nip05, + str(Res.string.backup_profile_field_lud16) to diff.lud16, + str(Res.string.backup_profile_field_lud06) to diff.lud06, + str(Res.string.backup_profile_field_clink_offer) to diff.clinkOffer, + str(Res.string.backup_profile_field_pronouns) to diff.pronouns, + str(Res.string.backup_profile_field_birthday) to birthday, + str(Res.string.backup_profile_field_bot) to bot, ), ), listGroup( - R.string.backup_entry_identity_claim, + Res.string.backup_entry_identity_claim, diff.identityClaims, { ReviewItem.Text(it.platformIdentity()) }, { ReviewItem.Text(it.after.platformIdentity(), arrow(it.before.proof, it.after.proof)) }, ), listGroup( - R.string.backup_entry_other, + Res.string.backup_entry_other, diff.otherFields, { ReviewItem.Text(it.first, clip(it.second)) }, { ReviewItem.Text(it.after.first, clip(it.before.second) + " → " + clip(it.after.second)) }, @@ -292,7 +421,7 @@ fun presentationOf( is ContactListDiff -> listOf( listGroup( - R.string.backup_entry_person, + Res.string.backup_entry_person, diff.follows, { ReviewItem.Person(it.pubKey, it.petname) }, { @@ -308,32 +437,32 @@ fun presentationOf( ) to ContentChange.NONE is MuteListDiff -> listOf( - listGroup(R.string.backup_entry_person, diff.publicMutes.only(), { ReviewItem.Person(it.pubKey) }), - listGroup(R.string.backup_entry_word, diff.publicMutes.only(), { ReviewItem.Text("\"" + it.word + "\"") }), - listGroup(R.string.backup_entry_hashtag, diff.publicMutes.only(), { ReviewItem.Text("#" + it.hashtag) }), - listGroup(R.string.backup_entry_thread, diff.publicMutes.only(), { ReviewItem.Thread(it.eventId) }), + listGroup(Res.string.backup_entry_person, diff.publicMutes.only(), { ReviewItem.Person(it.pubKey) }), + listGroup(Res.string.backup_entry_word, diff.publicMutes.only(), { ReviewItem.Text("\"" + it.word + "\"") }), + listGroup(Res.string.backup_entry_hashtag, diff.publicMutes.only(), { ReviewItem.Text("#" + it.hashtag) }), + listGroup(Res.string.backup_entry_thread, diff.publicMutes.only(), { ReviewItem.Thread(it.eventId) }), ) to diff.privateItems is AdvertisedRelayListDiff -> { val types = mapOf( - AdvertisedRelayType.BOTH to str(R.string.backup_conflict_relay_read_write), - AdvertisedRelayType.READ to str(R.string.backup_conflict_relay_read_only), - AdvertisedRelayType.WRITE to str(R.string.backup_conflict_relay_write_only), + AdvertisedRelayType.BOTH to str(Res.string.backup_conflict_relay_read_write), + AdvertisedRelayType.READ to str(Res.string.backup_conflict_relay_read_only), + AdvertisedRelayType.WRITE to str(Res.string.backup_conflict_relay_write_only), ) listOf( listGroup( - R.string.backup_entry_relay, + Res.string.backup_entry_relay, diff.relays, { ReviewItem.Relay(it.relayUrl, types[it.type]) }, { ReviewItem.Relay(it.after.relayUrl, arrow(types[it.before.type], types[it.after.type])) }, ), ) to ContentChange.NONE } - is RelayListDiff -> listOf(listGroup(R.string.backup_entry_relay, diff.relays, { ReviewItem.Relay(it) })) to diff.privateRelays + is RelayListDiff -> listOf(listGroup(Res.string.backup_entry_relay, diff.relays, { ReviewItem.Relay(it) })) to diff.privateRelays is ChannelListDiff -> listOf( listGroup( - R.string.backup_entry_public_chat, + Res.string.backup_entry_public_chat, diff.channels, { ReviewItem.PublicChat(it.eventId) }, { ReviewItem.PublicChat(it.after.eventId, arrow(it.before.relay?.url, it.after.relay?.url)) }, @@ -342,28 +471,28 @@ fun presentationOf( is CommunityListDiff -> listOf( listGroup( - R.string.backup_entry_community, + Res.string.backup_entry_community, diff.communities, { ReviewItem.Addressable(it.address) }, { ReviewItem.Addressable(it.after.address, arrow(it.before.relayHint?.url, it.after.relayHint?.url)) }, ), ) to diff.privateItems - is HashtagListDiff -> listOf(listGroup(R.string.backup_entry_hashtag, diff.hashtags, { ReviewItem.Text("#$it") })) to diff.privateItems - is GeohashListDiff -> listOf(listGroup(R.string.backup_entry_location, diff.geohashes, { ReviewItem.Text(it) })) to diff.privateItems + is HashtagListDiff -> listOf(listGroup(Res.string.backup_entry_hashtag, diff.hashtags, { ReviewItem.Text("#$it") })) to diff.privateItems + is GeohashListDiff -> listOf(listGroup(Res.string.backup_entry_location, diff.geohashes, { ReviewItem.Text(it) })) to diff.privateItems is FavoriteAlgoFeedsListDiff -> listOf( listGroup( - R.string.backup_entry_algo_feed, + Res.string.backup_entry_algo_feed, diff.feeds, { ReviewItem.Addressable(it.address) }, { ReviewItem.Addressable(it.after.address, arrow(it.before.relayHint?.url, it.after.relayHint?.url)) }, ), ) to diff.privateItems - is EphemeralChatListDiff -> listOf(listGroup(R.string.backup_entry_chat_room, diff.rooms, { ReviewItem.ChatRoom(it) })) to diff.privateItems + is EphemeralChatListDiff -> listOf(listGroup(Res.string.backup_entry_chat_room, diff.rooms, { ReviewItem.ChatRoom(it) })) to diff.privateItems is SimpleGroupListDiff -> listOf( listGroup( - R.string.backup_entry_relay_group, + Res.string.backup_entry_relay_group, diff.groups, { ReviewItem.Text(it.name ?: it.groupId, it.relayUrl) }, { ReviewItem.Text(it.after.name ?: it.after.groupId, arrow(it.before.name, it.after.name)) }, @@ -372,7 +501,7 @@ fun presentationOf( is TrustProviderListDiff -> listOf( listGroup( - R.string.backup_entry_trust_provider, + Res.string.backup_entry_trust_provider, diff.providers, { ReviewItem.Person(it.pubkey, it.service.type) }, { ReviewItem.Person(it.after.pubkey, it.after.service.type + ": " + arrow(it.before.relayUrl.url, it.after.relayUrl.url)) }, @@ -381,19 +510,19 @@ fun presentationOf( is NutzapInfoDiff -> listOf( listGroup( - R.string.backup_entry_mint, + Res.string.backup_entry_mint, diff.mints, { ReviewItem.Text(it.mintUrl, it.units.joinToString().ifEmpty { null }) }, { ReviewItem.Text(it.after.mintUrl, arrow(it.before.units.joinToString(), it.after.units.joinToString())) }, ), - listGroup(R.string.backup_entry_relay, diff.relays, { ReviewItem.Relay(it) }), + listGroup(Res.string.backup_entry_relay, diff.relays, { ReviewItem.Relay(it) }), nutzapKeyGroup(diff.p2pkPubkey), ) to ContentChange.NONE is PaymentTargetsDiff -> listOf( - listGroup(R.string.backup_entry_payment_target, diff.targets, { ReviewItem.Text(it.type, clip(it.authority)) }), + listGroup(Res.string.backup_entry_payment_target, diff.targets, { ReviewItem.Text(it.type, clip(it.authority)) }), ) to ContentChange.NONE - is Bolt12OfferListDiff -> listOf(listGroup(R.string.backup_entry_offer, diff.offers, { ReviewItem.Text(clip(it)) })) to ContentChange.NONE + is Bolt12OfferListDiff -> listOf(listGroup(Res.string.backup_entry_offer, diff.offers, { ReviewItem.Text(clip(it)) })) to ContentChange.NONE is CashuWalletDiff -> emptyList() to diff.wallet is ConcordCommunityListDiff -> emptyList() to diff.communities is AppSpecificDataDiff -> emptyList() to diff.data @@ -404,13 +533,13 @@ fun presentationOf( private fun nutzapKeyGroup(change: ValueChange?): DiffGroup { val none = emptyList() - if (change == null) return DiffGroup(R.string.backup_entry_nutzap_key, none, none, none) + if (change == null) return DiffGroup(Res.string.backup_entry_nutzap_key, none, none, none) val before = change.before val after = change.after return when { - before != null && after == null -> DiffGroup(R.string.backup_entry_nutzap_key, listOf(ReviewItem.Text(before)), none, none) - before == null && after != null -> DiffGroup(R.string.backup_entry_nutzap_key, none, listOf(ReviewItem.Text(after)), none) - else -> DiffGroup(R.string.backup_entry_nutzap_key, none, none, listOf(ReviewItem.Text(arrow(before, after)))) + before != null && after == null -> DiffGroup(Res.string.backup_entry_nutzap_key, listOf(ReviewItem.Text(before)), none, none) + before == null && after != null -> DiffGroup(Res.string.backup_entry_nutzap_key, none, listOf(ReviewItem.Text(after)), none) + else -> DiffGroup(Res.string.backup_entry_nutzap_key, none, none, listOf(ReviewItem.Text(arrow(before, after)))) } } @@ -422,64 +551,64 @@ fun clip(text: String?): String { return if (oneLine.length > MAX_VALUE_LENGTH) oneLine.take(MAX_VALUE_LENGTH) + "…" else oneLine } -fun eventTypeName(type: BackupEventType): Int = +fun eventTypeName(type: BackupEventType): StringResource = when (type) { - BackupEventType.PROFILE -> R.string.backup_type_profile - BackupEventType.FOLLOW_LIST -> R.string.backup_type_follow_list - BackupEventType.MUTE_LIST -> R.string.backup_type_mute_list - BackupEventType.OUTBOX_INBOX_RELAYS -> R.string.backup_type_outbox_inbox_relays - BackupEventType.DM_RELAYS -> R.string.backup_type_dm_relays - BackupEventType.KEY_PACKAGE_RELAYS -> R.string.backup_type_key_package_relays - BackupEventType.SEARCH_RELAYS -> R.string.backup_type_search_relays - BackupEventType.INDEXER_RELAYS -> R.string.backup_type_indexer_relays - BackupEventType.RELAY_FEEDS -> R.string.backup_type_relay_feeds - BackupEventType.BLOCKED_RELAYS -> R.string.backup_type_blocked_relays - BackupEventType.TRUSTED_RELAYS -> R.string.backup_type_trusted_relays - BackupEventType.PRIVATE_OUTBOX_RELAYS -> R.string.backup_type_private_outbox_relays - BackupEventType.APP_SETTINGS -> R.string.backup_type_app_settings - BackupEventType.PUBLIC_CHATS -> R.string.backup_type_public_chats - BackupEventType.COMMUNITIES -> R.string.backup_type_communities - BackupEventType.HASHTAGS -> R.string.backup_type_hashtags - BackupEventType.GEOHASHES -> R.string.backup_type_geohashes - BackupEventType.FAVORITE_ALGO_FEEDS -> R.string.backup_type_favorite_algo_feeds - BackupEventType.EPHEMERAL_CHATS -> R.string.backup_type_ephemeral_chats - BackupEventType.RELAY_GROUPS -> R.string.backup_type_relay_groups - BackupEventType.CONCORD_COMMUNITIES -> R.string.backup_type_concord_communities - BackupEventType.TRUST_PROVIDERS -> R.string.backup_type_trust_providers - BackupEventType.CASHU_WALLET -> R.string.backup_type_cashu_wallet - BackupEventType.NUTZAP_INFO -> R.string.backup_type_nutzap_info - BackupEventType.PAYMENT_TARGETS -> R.string.backup_type_payment_targets - BackupEventType.BOLT12_OFFERS -> R.string.backup_type_bolt12_offers - BackupEventType.OTHER -> R.string.backup_type_other + BackupEventType.PROFILE -> Res.string.backup_type_profile + BackupEventType.FOLLOW_LIST -> Res.string.backup_type_follow_list + BackupEventType.MUTE_LIST -> Res.string.backup_type_mute_list + BackupEventType.OUTBOX_INBOX_RELAYS -> Res.string.backup_type_outbox_inbox_relays + BackupEventType.DM_RELAYS -> Res.string.backup_type_dm_relays + BackupEventType.KEY_PACKAGE_RELAYS -> Res.string.backup_type_key_package_relays + BackupEventType.SEARCH_RELAYS -> Res.string.backup_type_search_relays + BackupEventType.INDEXER_RELAYS -> Res.string.backup_type_indexer_relays + BackupEventType.RELAY_FEEDS -> Res.string.backup_type_relay_feeds + BackupEventType.BLOCKED_RELAYS -> Res.string.backup_type_blocked_relays + BackupEventType.TRUSTED_RELAYS -> Res.string.backup_type_trusted_relays + BackupEventType.PRIVATE_OUTBOX_RELAYS -> Res.string.backup_type_private_outbox_relays + BackupEventType.APP_SETTINGS -> Res.string.backup_type_app_settings + BackupEventType.PUBLIC_CHATS -> Res.string.backup_type_public_chats + BackupEventType.COMMUNITIES -> Res.string.backup_type_communities + BackupEventType.HASHTAGS -> Res.string.backup_type_hashtags + BackupEventType.GEOHASHES -> Res.string.backup_type_geohashes + BackupEventType.FAVORITE_ALGO_FEEDS -> Res.string.backup_type_favorite_algo_feeds + BackupEventType.EPHEMERAL_CHATS -> Res.string.backup_type_ephemeral_chats + BackupEventType.RELAY_GROUPS -> Res.string.backup_type_relay_groups + BackupEventType.CONCORD_COMMUNITIES -> Res.string.backup_type_concord_communities + BackupEventType.TRUST_PROVIDERS -> Res.string.backup_type_trust_providers + BackupEventType.CASHU_WALLET -> Res.string.backup_type_cashu_wallet + BackupEventType.NUTZAP_INFO -> Res.string.backup_type_nutzap_info + BackupEventType.PAYMENT_TARGETS -> Res.string.backup_type_payment_targets + BackupEventType.BOLT12_OFFERS -> Res.string.backup_type_bolt12_offers + BackupEventType.OTHER -> Res.string.backup_type_other } -fun eventTypeExplainer(type: BackupEventType): Int = +fun eventTypeExplainer(type: BackupEventType): StringResource = when (type) { - BackupEventType.PROFILE -> R.string.backup_type_profile_explainer - BackupEventType.FOLLOW_LIST -> R.string.backup_type_follow_list_explainer - BackupEventType.MUTE_LIST -> R.string.backup_type_mute_list_explainer - BackupEventType.OUTBOX_INBOX_RELAYS -> R.string.backup_type_outbox_inbox_relays_explainer - BackupEventType.DM_RELAYS -> R.string.backup_type_dm_relays_explainer - BackupEventType.KEY_PACKAGE_RELAYS -> R.string.backup_type_key_package_relays_explainer - BackupEventType.SEARCH_RELAYS -> R.string.backup_type_search_relays_explainer - BackupEventType.INDEXER_RELAYS -> R.string.backup_type_indexer_relays_explainer - BackupEventType.RELAY_FEEDS -> R.string.backup_type_relay_feeds_explainer - BackupEventType.BLOCKED_RELAYS -> R.string.backup_type_blocked_relays_explainer - BackupEventType.TRUSTED_RELAYS -> R.string.backup_type_trusted_relays_explainer - BackupEventType.PRIVATE_OUTBOX_RELAYS -> R.string.backup_type_private_outbox_relays_explainer - BackupEventType.APP_SETTINGS -> R.string.backup_type_app_settings_explainer - BackupEventType.PUBLIC_CHATS -> R.string.backup_type_public_chats_explainer - BackupEventType.COMMUNITIES -> R.string.backup_type_communities_explainer - BackupEventType.HASHTAGS -> R.string.backup_type_hashtags_explainer - BackupEventType.GEOHASHES -> R.string.backup_type_geohashes_explainer - BackupEventType.FAVORITE_ALGO_FEEDS -> R.string.backup_type_favorite_algo_feeds_explainer - BackupEventType.EPHEMERAL_CHATS -> R.string.backup_type_ephemeral_chats_explainer - BackupEventType.RELAY_GROUPS -> R.string.backup_type_relay_groups_explainer - BackupEventType.CONCORD_COMMUNITIES -> R.string.backup_type_concord_communities_explainer - BackupEventType.TRUST_PROVIDERS -> R.string.backup_type_trust_providers_explainer - BackupEventType.CASHU_WALLET -> R.string.backup_type_cashu_wallet_explainer - BackupEventType.NUTZAP_INFO -> R.string.backup_type_nutzap_info_explainer - BackupEventType.PAYMENT_TARGETS -> R.string.backup_type_payment_targets_explainer - BackupEventType.BOLT12_OFFERS -> R.string.backup_type_bolt12_offers_explainer - BackupEventType.OTHER -> R.string.backup_type_other_explainer + BackupEventType.PROFILE -> Res.string.backup_type_profile_explainer + BackupEventType.FOLLOW_LIST -> Res.string.backup_type_follow_list_explainer + BackupEventType.MUTE_LIST -> Res.string.backup_type_mute_list_explainer + BackupEventType.OUTBOX_INBOX_RELAYS -> Res.string.backup_type_outbox_inbox_relays_explainer + BackupEventType.DM_RELAYS -> Res.string.backup_type_dm_relays_explainer + BackupEventType.KEY_PACKAGE_RELAYS -> Res.string.backup_type_key_package_relays_explainer + BackupEventType.SEARCH_RELAYS -> Res.string.backup_type_search_relays_explainer + BackupEventType.INDEXER_RELAYS -> Res.string.backup_type_indexer_relays_explainer + BackupEventType.RELAY_FEEDS -> Res.string.backup_type_relay_feeds_explainer + BackupEventType.BLOCKED_RELAYS -> Res.string.backup_type_blocked_relays_explainer + BackupEventType.TRUSTED_RELAYS -> Res.string.backup_type_trusted_relays_explainer + BackupEventType.PRIVATE_OUTBOX_RELAYS -> Res.string.backup_type_private_outbox_relays_explainer + BackupEventType.APP_SETTINGS -> Res.string.backup_type_app_settings_explainer + BackupEventType.PUBLIC_CHATS -> Res.string.backup_type_public_chats_explainer + BackupEventType.COMMUNITIES -> Res.string.backup_type_communities_explainer + BackupEventType.HASHTAGS -> Res.string.backup_type_hashtags_explainer + BackupEventType.GEOHASHES -> Res.string.backup_type_geohashes_explainer + BackupEventType.FAVORITE_ALGO_FEEDS -> Res.string.backup_type_favorite_algo_feeds_explainer + BackupEventType.EPHEMERAL_CHATS -> Res.string.backup_type_ephemeral_chats_explainer + BackupEventType.RELAY_GROUPS -> Res.string.backup_type_relay_groups_explainer + BackupEventType.CONCORD_COMMUNITIES -> Res.string.backup_type_concord_communities_explainer + BackupEventType.TRUST_PROVIDERS -> Res.string.backup_type_trust_providers_explainer + BackupEventType.CASHU_WALLET -> Res.string.backup_type_cashu_wallet_explainer + BackupEventType.NUTZAP_INFO -> Res.string.backup_type_nutzap_info_explainer + BackupEventType.PAYMENT_TARGETS -> Res.string.backup_type_payment_targets_explainer + BackupEventType.BOLT12_OFFERS -> Res.string.backup_type_bolt12_offers_explainer + BackupEventType.OTHER -> Res.string.backup_type_other_explainer } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt index 8b5d7b0150..6497b54846 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupConflictReviewScreen.kt @@ -59,11 +59,34 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.model.backups.BackupEventType import com.vitorpamplona.amethyst.commons.model.backups.ReplaceableBackupConflict import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.backup_action_block_again +import com.vitorpamplona.amethyst.commons.resources.backup_action_keep_count +import com.vitorpamplona.amethyst.commons.resources.backup_action_rejoin +import com.vitorpamplona.amethyst.commons.resources.backup_action_remute +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_count +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_feeds +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_places +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_profile +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_providers +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_relays +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_topics +import com.vitorpamplona.amethyst.commons.resources.backup_action_restore_wallet +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_added +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_changed +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_keep_new +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_private_added +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_private_changed +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_private_cleared +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_removed +import com.vitorpamplona.amethyst.commons.resources.backup_conflict_restore_mine +import com.vitorpamplona.amethyst.commons.resources.backup_review_changed_by_other_app +import com.vitorpamplona.amethyst.commons.resources.backup_review_title_cleared +import com.vitorpamplona.amethyst.commons.resources.backup_review_title_updated import com.vitorpamplona.amethyst.commons.ui.insets.imePaddingSafe import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton @@ -97,22 +120,23 @@ import com.vitorpamplona.quartz.nip60Cashu.wallet.CashuWalletDiff import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListDiff import com.vitorpamplona.quartz.nip72ModCommunities.follow.CommunityListDiff import com.vitorpamplona.quartz.nip85TrustedAssertions.list.TrustProviderListDiff +import org.jetbrains.compose.resources.StringResource /** A row of the review list, flattened so hundreds of entries scroll lazily. */ @Immutable internal sealed interface ReviewRow { class Section( - val titleRes: Int, + val titleRes: StringResource, val count: Int, val tone: Tone, ) : ReviewRow class Note( - val textRes: Int, + val textRes: StringResource, ) : ReviewRow class Group( - val labelRes: Int, + val labelRes: StringResource, ) : ReviewRow class Entry( @@ -124,15 +148,15 @@ internal enum class Tone { REMOVED, ADDED, CHANGED } internal fun buildRows( presentation: DiffPresentation, - skipGroups: Set = emptySet(), + skipGroups: Set = emptySet(), ): List { val rows = mutableListOf() fun section( - titleRes: Int, + titleRes: StringResource, count: Int, tone: Tone, - contentNote: Int?, + contentNote: StringResource?, items: (DiffGroup) -> List, ) { if (count == 0 && contentNote == null) return @@ -149,9 +173,9 @@ internal fun buildRows( } val content = presentation.content - section(R.string.backup_conflict_removed, presentation.removedCount, Tone.REMOVED, R.string.backup_conflict_private_cleared.takeIf { content == ContentChange.CLEARED }) { it.removed } - section(R.string.backup_conflict_added, presentation.addedCount, Tone.ADDED, R.string.backup_conflict_private_added.takeIf { content == ContentChange.ADDED }) { it.added } - section(R.string.backup_conflict_changed, presentation.changedCount, Tone.CHANGED, R.string.backup_conflict_private_changed.takeIf { content == ContentChange.CHANGED }) { it.changed } + section(Res.string.backup_conflict_removed, presentation.removedCount, Tone.REMOVED, Res.string.backup_conflict_private_cleared.takeIf { content == ContentChange.CLEARED }) { it.removed } + section(Res.string.backup_conflict_added, presentation.addedCount, Tone.ADDED, Res.string.backup_conflict_private_added.takeIf { content == ContentChange.ADDED }) { it.added } + section(Res.string.backup_conflict_changed, presentation.changedCount, Tone.CHANGED, Res.string.backup_conflict_private_changed.takeIf { content == ContentChange.CHANGED }) { it.changed } return rows } @@ -268,7 +292,7 @@ internal fun LazyListScope.genericDiffItems( } @Composable -internal fun GroupLabel(labelRes: Int) { +internal fun GroupLabel(labelRes: StringResource) { Text( text = stringRes(labelRes), style = MaterialTheme.typography.labelLarge, @@ -339,7 +363,7 @@ internal fun eventTitle(conflict: ReplaceableBackupConflict): String { val name = stringRes(eventTypeName(conflict.eventType)).replaceFirstChar { it.uppercase() } // Says what happened to it, not just what it is: "Community list updated". val emptied = conflict.incoming.tags.isEmpty() && conflict.incoming.content.isEmpty() - return stringRes(if (emptied) R.string.backup_review_title_cleared else R.string.backup_review_title_updated, name) + return stringRes(if (emptied) Res.string.backup_review_title_cleared else Res.string.backup_review_title_updated, name) } /** The two choices, worded for what they do to this event: "Keep 120" / "Restore 523". */ @@ -348,48 +372,48 @@ private fun actionLabels(conflict: ReplaceableBackupConflict): Pair { val (saved, new) = conflict.followCounts - stringRes(R.string.backup_action_keep_count, new.toString()) to stringRes(R.string.backup_action_restore_count, saved.toString()) + stringRes(Res.string.backup_action_keep_count, new.toString()) to stringRes(Res.string.backup_action_restore_count, saved.toString()) } is MuteListDiff -> { val removed = diff.publicMutes.removed.size - stringRes(R.string.backup_conflict_keep_new) to - if (removed > 0) stringRes(R.string.backup_action_remute, removed.toString()) else stringRes(R.string.backup_conflict_restore_mine) + stringRes(Res.string.backup_conflict_keep_new) to + if (removed > 0) stringRes(Res.string.backup_action_remute, removed.toString()) else stringRes(Res.string.backup_conflict_restore_mine) } is SimpleGroupListDiff -> { val removed = diff.groups.removed.size - stringRes(R.string.backup_conflict_keep_new) to - if (removed > 0) stringRes(R.string.backup_action_rejoin, removed.toString()) else stringRes(R.string.backup_conflict_restore_mine) + stringRes(Res.string.backup_conflict_keep_new) to + if (removed > 0) stringRes(Res.string.backup_action_rejoin, removed.toString()) else stringRes(Res.string.backup_conflict_restore_mine) } - is MetadataDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_profile) + is MetadataDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_profile) is RelayListDiff -> if (conflict.eventType == BackupEventType.BLOCKED_RELAYS && diff.relays.removed.isNotEmpty()) { - stringRes(R.string.backup_conflict_keep_new) to + stringRes(Res.string.backup_conflict_keep_new) to stringRes( - R.string.backup_action_block_again, + Res.string.backup_action_block_again, diff.relays.removed.size .toString(), ) } else { - stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_relays) + stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_relays) } - is AdvertisedRelayListDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_relays) + is AdvertisedRelayListDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_relays) is ChannelListDiff -> rejoinLabels(diff.channels.removed.size) is CommunityListDiff -> rejoinLabels(diff.communities.removed.size) is EphemeralChatListDiff -> rejoinLabels(diff.rooms.removed.size) - is FavoriteAlgoFeedsListDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_feeds) - is HashtagListDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_topics) + is FavoriteAlgoFeedsListDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_feeds) + is HashtagListDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_topics) // Geohashes are places, not topics: the screen counts "places gone" under "Followed // locations", so the button has to agree with the page it sits on. - is GeohashListDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_places) - is TrustProviderListDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_providers) - is CashuWalletDiff -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_action_restore_wallet) - else -> stringRes(R.string.backup_conflict_keep_new) to stringRes(R.string.backup_conflict_restore_mine) + is GeohashListDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_places) + is TrustProviderListDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_providers) + is CashuWalletDiff -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_action_restore_wallet) + else -> stringRes(Res.string.backup_conflict_keep_new) to stringRes(Res.string.backup_conflict_restore_mine) } @Composable private fun rejoinLabels(removed: Int): Pair = - stringRes(R.string.backup_conflict_keep_new) to - if (removed > 0) stringRes(R.string.backup_action_rejoin, removed.toString()) else stringRes(R.string.backup_conflict_restore_mine) + stringRes(Res.string.backup_conflict_keep_new) to + if (removed > 0) stringRes(Res.string.backup_action_rejoin, removed.toString()) else stringRes(Res.string.backup_conflict_restore_mine) /** When the other app changed it, and what the event is for. */ @Composable @@ -399,7 +423,7 @@ private fun BackupConflictIntro( ) { Column(modifier, verticalArrangement = Arrangement.spacedBy(2.dp)) { Text( - text = stringRes(R.string.backup_review_changed_by_other_app, timeAgoNoDot(conflict.cause.createdAt)), + text = stringRes(Res.string.backup_review_changed_by_other_app, timeAgoNoDot(conflict.cause.createdAt)), style = MaterialTheme.typography.labelLarge, color = conflictTones().removed, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt index 644d10c45e..c84bbfbd80 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarCollectionsView.kt @@ -64,13 +64,13 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_export_event import com.vitorpamplona.amethyst.commons.resources.calendar_export_share_title import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyListState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.pluralStringRes import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.video.UserCardHeader import com.vitorpamplona.quartz.nip01Core.core.Address diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt index 443c0b0b0d..0d62fc715b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/calendars/CalendarFeedView.kt @@ -47,11 +47,11 @@ import com.vitorpamplona.amethyst.commons.resources.calendar_empty_feed_title import com.vitorpamplona.amethyst.commons.resources.calendar_section_past import com.vitorpamplona.amethyst.commons.resources.calendar_section_upcoming import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding -import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.quartz.utils.TimeUtils diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt index 0e19b487cb..c892f3d020 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnComposer.kt @@ -42,12 +42,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.chats.ui.ThinSendButton import com.vitorpamplona.amethyst.commons.model.cordnGroups.CordnGroupChatroom import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiPackState import com.vitorpamplona.amethyst.commons.model.nip30CustomEmojis.EmojiSuggestionState import com.vitorpamplona.amethyst.commons.nip30CustomEmojis.ui.ShowEmojiSuggestionList +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.cordn_composer_hint import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.commons.ui.theme.EditFieldBorder @@ -233,7 +234,7 @@ internal fun CordnComposer( shape = EditFieldBorder, placeholder = { Text( - text = stringRes(R.string.cordn_composer_hint), + text = stringRes(Res.string.cordn_composer_hint), color = MaterialTheme.colorScheme.placeholderText, ) }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt index 6deedde2d4..0b78b0ea5e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateGroupScreen.kt @@ -55,11 +55,9 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.cordn.DiscoveredCoordinator import com.vitorpamplona.amethyst.commons.cordn.GroupExposure @@ -69,6 +67,55 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_none +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_seen +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_seen_on +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_unheard +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_hide_older +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_relays_more +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_show_all +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_show_fewer +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_show_older +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_stale_note +import com.vitorpamplona.amethyst.commons.resources.cordn_create_action +import com.vitorpamplona.amethyst.commons.resources.cordn_create_action_invite +import com.vitorpamplona.amethyst.commons.resources.cordn_create_admin_count +import com.vitorpamplona.amethyst.commons.resources.cordn_create_admin_only_me_on +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_change +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_discover +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_hide +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_new +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_pubkey +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_relays +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coverage_all +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coverage_partial +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coverage_unknown +import com.vitorpamplona.amethyst.commons.resources.cordn_create_description +import com.vitorpamplona.amethyst.commons.resources.cordn_create_egalitarian +import com.vitorpamplona.amethyst.commons.resources.cordn_create_egalitarian_note +import com.vitorpamplona.amethyst.commons.resources.cordn_create_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_create_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_create_name +import com.vitorpamplona.amethyst.commons.resources.cordn_create_no_coordinator +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_link +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_no_welcome +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_open +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_skipped +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_title +import com.vitorpamplona.amethyst.commons.resources.cordn_create_outcome_waiting +import com.vitorpamplona.amethyst.commons.resources.cordn_create_people_none +import com.vitorpamplona.amethyst.commons.resources.cordn_create_step_admins +import com.vitorpamplona.amethyst.commons.resources.cordn_create_step_name +import com.vitorpamplona.amethyst.commons.resources.cordn_create_step_people +import com.vitorpamplona.amethyst.commons.resources.cordn_create_step_where +import com.vitorpamplona.amethyst.commons.resources.cordn_create_title +import com.vitorpamplona.amethyst.commons.resources.cordn_create_unreachable_count +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_member_count import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.model.cordn.CordnCoverage @@ -131,7 +178,7 @@ fun CordnCreateGroupScreen( Icon(MaterialSymbols.AutoMirrored.ArrowBack, contentDescription = stringRes(Res.string.back)) } }, - title = { Text(stringRes(R.string.cordn_create_title)) }, + title = { Text(stringRes(Res.string.cordn_create_title)) }, ) }, ) { padding -> @@ -139,8 +186,8 @@ fun CordnCreateGroupScreen( // The app's own empty state, centred and titled, rather than a // sentence stranded in the top-left corner. EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -164,14 +211,14 @@ fun CordnCreateGroupScreen( val draft = rememberCordnGroupDraft(accountViewModel) var creation by remember { mutableStateOf(null) } var error by remember { mutableStateOf(null) } - val failureFallback = stringRes(R.string.cordn_create_failed) + val failureFallback = stringRes(Res.string.cordn_create_failed) var busy by remember { mutableStateOf(false) } // Coordinators this account has never used, from their CEP-6 // announcements. Not added to the account by looking: picking one here // is what commits to it, and `createGroup` opens the session. var discovering by remember { mutableStateOf(false) } - val discoverFailed = stringRes(R.string.cordn_coordinators_discover_failed) + val discoverFailed = stringRes(Res.string.cordn_coordinators_discover_failed) // Offers this account already holds are not offers; they are the choices // above, and listing them twice would let the same coordinator be picked @@ -222,29 +269,29 @@ fun CordnCreateGroupScreen( verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( - text = stringRes(R.string.cordn_create_explainer), + text = stringRes(Res.string.cordn_create_explainer), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) - StepHeading(1, stringRes(R.string.cordn_create_step_name)) + StepHeading(1, stringRes(Res.string.cordn_create_step_name)) OutlinedTextField( value = draft.name, onValueChange = { draft.name = it }, - label = { Text(stringRes(R.string.cordn_create_name)) }, + label = { Text(stringRes(Res.string.cordn_create_name)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) OutlinedTextField( value = draft.description, onValueChange = { draft.description = it }, - label = { Text(stringRes(R.string.cordn_create_description)) }, + label = { Text(stringRes(Res.string.cordn_create_description)) }, singleLine = false, modifier = Modifier.fillMaxWidth(), ) - StepHeading(2, stringRes(R.string.cordn_create_step_people)) + StepHeading(2, stringRes(Res.string.cordn_create_step_people)) RosterSummary( roster = draft.roster, @@ -254,7 +301,7 @@ fun CordnCreateGroupScreen( nav = nav, ) - StepHeading(3, stringRes(R.string.cordn_create_step_where)) + StepHeading(3, stringRes(Res.string.cordn_create_step_where)) // Collapsed to the one coordinator that will be used, because with a // draft.roster in hand there is usually nothing left to decide. The whole @@ -326,9 +373,9 @@ fun CordnCreateGroupScreen( TextButton(onClick = { draft.showAllLive = !draft.showAllLive }) { Text( if (draft.showAllLive) { - stringRes(R.string.cordn_coordinators_show_fewer) + stringRes(Res.string.cordn_coordinators_show_fewer) } else { - stringRes(R.string.cordn_coordinators_show_all, live.size) + stringRes(Res.string.cordn_coordinators_show_all, live.size) }, ) } @@ -338,9 +385,9 @@ fun CordnCreateGroupScreen( TextButton(onClick = { draft.showStale = !draft.showStale }) { Text( if (draft.showStale) { - stringRes(R.string.cordn_coordinators_hide_older) + stringRes(Res.string.cordn_coordinators_hide_older) } else { - stringRes(R.string.cordn_coordinators_show_older, stale.size) + stringRes(Res.string.cordn_coordinators_show_older, stale.size) }, ) } @@ -348,7 +395,7 @@ fun CordnCreateGroupScreen( if (draft.showStale && stale.isNotEmpty()) { Text( - text = stringRes(R.string.cordn_coordinators_stale_note), + text = stringRes(Res.string.cordn_coordinators_stale_note), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -372,7 +419,7 @@ fun CordnCreateGroupScreen( } CoordinatorChoice( - label = stringRes(R.string.cordn_create_coordinator_new), + label = stringRes(Res.string.cordn_create_coordinator_new), pubKey = null, selected = draft.selected == null, onSelect = { @@ -402,20 +449,20 @@ fun CordnCreateGroupScreen( }, enabled = !discovering && !busy, ) { - Text(stringRes(R.string.cordn_create_coordinator_discover)) + Text(stringRes(Res.string.cordn_create_coordinator_discover)) } draft.discovered?.takeIf { offers.isEmpty() }?.let { result -> Text( text = if (result.unreachable.isEmpty()) { - stringRes(R.string.cordn_coordinators_discover_none) + stringRes(Res.string.cordn_coordinators_discover_none) } else { // "Nobody is announcing" and "we were not told" are // different answers and only one of them is final. // Reporting the first for the second sends someone // off to paste a pubkey by hand over a timeout. - stringRes(R.string.cordn_coordinators_discover_unheard, result.unreachable.size) + stringRes(Res.string.cordn_coordinators_discover_unheard, result.unreachable.size) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -433,7 +480,7 @@ fun CordnCreateGroupScreen( draft.userPicked = true error = null }, - label = { Text(stringRes(R.string.cordn_create_coordinator_pubkey)) }, + label = { Text(stringRes(Res.string.cordn_create_coordinator_pubkey)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) @@ -444,7 +491,7 @@ fun CordnCreateGroupScreen( draft.userPicked = true error = null }, - label = { Text(stringRes(R.string.cordn_create_coordinator_relays)) }, + label = { Text(stringRes(Res.string.cordn_create_coordinator_relays)) }, // A coordinator has no address beyond its pubkey (§8.5), so // the relays are how it is reached and more than one is // ordinary. One per line rather than comma-separated, @@ -456,7 +503,7 @@ fun CordnCreateGroupScreen( } } - StepHeading(4, stringRes(R.string.cordn_create_step_admins)) + StepHeading(4, stringRes(Res.string.cordn_create_step_admins)) // spec/01.md §5.3: leaving the admin list empty is not "set it up // later", it is choosing draft.egalitarian permanently -- so it is offered @@ -472,15 +519,15 @@ fun CordnCreateGroupScreen( horizontalArrangement = Arrangement.spacedBy(12.dp), ) { Column(Modifier.weight(1f)) { - Text(stringRes(R.string.cordn_create_egalitarian), style = MaterialTheme.typography.bodyMedium) + Text(stringRes(Res.string.cordn_create_egalitarian), style = MaterialTheme.typography.bodyMedium) Text( text = if (draft.egalitarian) { - stringRes(R.string.cordn_create_egalitarian_note) + stringRes(Res.string.cordn_create_egalitarian_note) } else if (draft.coAdmins.isEmpty()) { - stringRes(R.string.cordn_create_admin_only_me_on) + stringRes(Res.string.cordn_create_admin_only_me_on) } else { - pluralStringRes(LocalContext.current, R.plurals.cordn_create_admin_count, draft.coAdmins.size + 1, draft.coAdmins.size + 1) + pluralStringRes(Res.plurals.cordn_create_admin_count, draft.coAdmins.size + 1, draft.coAdmins.size + 1) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -561,9 +608,9 @@ fun CordnCreateGroupScreen( ) { Text( if (draft.roster.isEmpty()) { - stringRes(R.string.cordn_create_action) + stringRes(Res.string.cordn_create_action) } else { - pluralStringRes(LocalContext.current, R.plurals.cordn_create_action_invite, draft.roster.size, draft.roster.size) + pluralStringRes(Res.plurals.cordn_create_action_invite, draft.roster.size, draft.roster.size) }, ) } @@ -691,9 +738,9 @@ private fun resolvedName( @Composable private fun announcedLabel(announcedAt: Long): String = if (TimeUtils.now() - announcedAt > TimeUtils.ONE_MONTH) { - stringRes(R.string.cordn_coordinators_discover_seen_on, timeAgoNoDot(announcedAt).trim()) + stringRes(Res.string.cordn_coordinators_discover_seen_on, timeAgoNoDot(announcedAt).trim()) } else { - stringRes(R.string.cordn_coordinators_discover_seen, timeAgoNoDot(announcedAt).trim()) + stringRes(Res.string.cordn_coordinators_discover_seen, timeAgoNoDot(announcedAt).trim()) } /** The hosts it answers on, the first two and a count of the rest. */ @@ -705,7 +752,7 @@ private fun relayLabel(relays: List): String? { return if (hosts.size <= 2) { shown } else { - stringRes(R.string.cordn_coordinators_relays_more, shown, hosts.size - 2) + stringRes(Res.string.cordn_coordinators_relays_more, shown, hosts.size - 2) } } @@ -791,7 +838,7 @@ private fun RosterSummary( ) { if (roster.isEmpty()) { Text( - text = stringRes(R.string.cordn_create_people_none), + text = stringRes(Res.string.cordn_create_people_none), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.weight(1f), @@ -804,7 +851,7 @@ private fun RosterSummary( } Column(Modifier.weight(1f)) { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_member_count, roster.size + 1, roster.size + 1), + text = pluralStringRes(Res.plurals.cordn_member_count, roster.size + 1, roster.size + 1), style = MaterialTheme.typography.bodyMedium, ) // Counted over coordinators that answered, so an unreachable one @@ -812,7 +859,7 @@ private fun RosterSummary( val unreachable = roster.count { member -> coverage.values.none { it.answered && member in it.reachable } } if (unreachable > 0 && coverage.values.any { it.answered }) { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_create_unreachable_count, unreachable, unreachable), + text = pluralStringRes(Res.plurals.cordn_create_unreachable_count, unreachable, unreachable), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.error, ) @@ -855,7 +902,7 @@ private fun CoordinatorSummary( ) { if (config == null) { Text( - text = stringRes(R.string.cordn_create_no_coordinator), + text = stringRes(Res.string.cordn_create_no_coordinator), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.weight(1f), @@ -879,9 +926,9 @@ private fun CoordinatorSummary( Text( text = when { - coverage == null || !coverage.answered -> stringRes(R.string.cordn_create_coverage_unknown) - reached == rosterSize -> stringRes(R.string.cordn_create_coverage_all, rosterSize) - else -> stringRes(R.string.cordn_create_coverage_partial, reached ?: 0, rosterSize) + coverage == null || !coverage.answered -> stringRes(Res.string.cordn_create_coverage_unknown) + reached == rosterSize -> stringRes(Res.string.cordn_create_coverage_all, rosterSize) + else -> stringRes(Res.string.cordn_create_coverage_partial, reached ?: 0, rosterSize) }, style = MaterialTheme.typography.labelSmall, color = @@ -899,9 +946,9 @@ private fun CoordinatorSummary( TextButton(onClick = onToggle) { Text( if (expanded) { - stringRes(R.string.cordn_create_coordinator_hide) + stringRes(Res.string.cordn_create_coordinator_hide) } else { - stringRes(R.string.cordn_create_coordinator_change) + stringRes(Res.string.cordn_create_coordinator_change) }, ) } @@ -934,11 +981,11 @@ private fun CordnCreationOutcome( AlertDialog( onDismissRequest = onDismiss, - title = { Text(stringRes(R.string.cordn_create_outcome_title)) }, + title = { Text(stringRes(Res.string.cordn_create_outcome_title)) }, text = { Column(verticalArrangement = Arrangement.spacedBy(10.dp)) { Text( - text = stringRes(R.string.cordn_create_outcome_explainer), + text = stringRes(Res.string.cordn_create_outcome_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -960,10 +1007,10 @@ private fun CordnCreationOutcome( Text( text = when { - outcome == null -> stringRes(R.string.cordn_create_outcome_skipped) - outcome.sent -> stringRes(R.string.cordn_create_outcome_waiting) - outcome.joinedWithoutWelcome -> stringRes(R.string.cordn_create_outcome_no_welcome) - else -> outcome.failure?.message ?: stringRes(R.string.cordn_create_outcome_failed) + outcome == null -> stringRes(Res.string.cordn_create_outcome_skipped) + outcome.sent -> stringRes(Res.string.cordn_create_outcome_waiting) + outcome.joinedWithoutWelcome -> stringRes(Res.string.cordn_create_outcome_no_welcome) + else -> outcome.failure?.message ?: stringRes(Res.string.cordn_create_outcome_failed) }, style = MaterialTheme.typography.labelSmall, color = @@ -979,12 +1026,12 @@ private fun CordnCreationOutcome( // open themselves -- which needs the group to exist, // and now it does. if (outcome == null) { - TextButton(onClick = open) { Text(stringRes(R.string.cordn_create_outcome_link)) } + TextButton(onClick = open) { Text(stringRes(Res.string.cordn_create_outcome_link)) } } } } } }, - confirmButton = { TextButton(onClick = open) { Text(stringRes(R.string.cordn_create_outcome_open)) } }, + confirmButton = { TextButton(onClick = open) { Text(stringRes(Res.string.cordn_create_outcome_open)) } }, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt index e80829bf90..1a09a1c890 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnCreateMembersScreen.kt @@ -47,15 +47,31 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentActivity import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.User +import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.cordn_create_add_member +import com.vitorpamplona.amethyst.commons.resources.cordn_create_admin +import com.vitorpamplona.amethyst.commons.resources.cordn_create_people_done +import com.vitorpamplona.amethyst.commons.resources.cordn_create_people_empty +import com.vitorpamplona.amethyst.commons.resources.cordn_create_people_note +import com.vitorpamplona.amethyst.commons.resources.cordn_create_reach_count +import com.vitorpamplona.amethyst.commons.resources.cordn_create_reach_none +import com.vitorpamplona.amethyst.commons.resources.cordn_create_reach_unknown +import com.vitorpamplona.amethyst.commons.resources.cordn_create_step_people +import com.vitorpamplona.amethyst.commons.resources.cordn_create_you +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member_none +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member_placeholder +import com.vitorpamplona.amethyst.commons.resources.cordn_info_has_key_package +import com.vitorpamplona.amethyst.commons.resources.cordn_info_remove_member +import com.vitorpamplona.amethyst.commons.resources.cordn_member_count import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton @@ -101,12 +117,12 @@ fun CordnCreateMembersScreen( val draft = rememberCordnGroupDraft(accountViewModel) Scaffold( - topBar = { TopBarWithBackButton(stringRes(R.string.cordn_create_step_people), nav) }, + topBar = { TopBarWithBackButton(stringRes(Res.string.cordn_create_step_people), nav) }, ) { padding -> if (runtime == null) { EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -137,7 +153,7 @@ fun CordnCreateMembersScreen( verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( - text = stringRes(R.string.cordn_create_people_note), + text = stringRes(Res.string.cordn_create_people_note), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -148,8 +164,8 @@ fun CordnCreateMembersScreen( search = it if (it.length > 2) userSuggestions.processCurrentWord(it) else userSuggestions.reset() }, - label = { Text(stringRes(R.string.cordn_create_add_member)) }, - placeholder = { Text(stringRes(R.string.cordn_info_add_member_placeholder)) }, + label = { Text(stringRes(Res.string.cordn_create_add_member)) }, + placeholder = { Text(stringRes(Res.string.cordn_info_add_member_placeholder)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) @@ -168,7 +184,7 @@ fun CordnCreateMembersScreen( modifier = SuggestionListDefaultHeightChat, onEmpty = { Text( - text = stringRes(R.string.cordn_info_add_member_none), + text = stringRes(Res.string.cordn_info_add_member_none), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), @@ -182,7 +198,7 @@ fun CordnCreateMembersScreen( if (user.pubkeyHex in reachable) { Icon( symbol = MaterialSymbols.Key, - contentDescription = stringRes(R.string.cordn_info_has_key_package), + contentDescription = stringRes(Res.string.cordn_info_has_key_package), modifier = Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -194,7 +210,7 @@ fun CordnCreateMembersScreen( }) { Icon( symbol = MaterialSymbols.PersonAdd, - contentDescription = stringRes(R.string.cordn_create_add_member), + contentDescription = stringRes(Res.string.cordn_create_add_member), tint = MaterialTheme.colorScheme.primary, ) } @@ -206,7 +222,7 @@ fun CordnCreateMembersScreen( HorizontalDivider() Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_member_count, draft.roster.size + 1, draft.roster.size + 1), + text = pluralStringRes(Res.plurals.cordn_member_count, draft.roster.size + 1, draft.roster.size + 1), style = MaterialTheme.typography.titleSmall, ) @@ -230,7 +246,7 @@ fun CordnCreateMembersScreen( if (draft.roster.isEmpty()) { Text( - text = stringRes(R.string.cordn_create_people_empty), + text = stringRes(Res.string.cordn_create_people_empty), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -240,7 +256,7 @@ fun CordnCreateMembersScreen( onClick = { nav.popBack() }, modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), ) { - Text(stringRes(R.string.cordn_create_people_done)) + Text(stringRes(Res.string.cordn_create_people_done)) } } } @@ -263,14 +279,14 @@ private fun CreatorRow( Column(Modifier.weight(1f)) { Text(observeUserNameByHex(me, accountViewModel), style = MaterialTheme.typography.bodyMedium) Text( - text = stringRes(R.string.cordn_create_you), + text = stringRes(Res.string.cordn_create_you), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } if (!egalitarian) { Text( - text = stringRes(R.string.cordn_create_admin), + text = stringRes(Res.string.cordn_create_admin), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.primary, ) @@ -304,9 +320,9 @@ private fun MemberRow( Text( text = when { - answered == 0 -> stringRes(R.string.cordn_create_reach_unknown) - reaching > 0 -> pluralStringRes(LocalContext.current, R.plurals.cordn_create_reach_count, reaching, reaching) - else -> stringRes(R.string.cordn_create_reach_none) + answered == 0 -> stringRes(Res.string.cordn_create_reach_unknown) + reaching > 0 -> pluralStringRes(Res.plurals.cordn_create_reach_count, reaching, reaching) + else -> stringRes(Res.string.cordn_create_reach_none) }, style = MaterialTheme.typography.labelSmall, color = @@ -323,7 +339,7 @@ private fun MemberRow( if (!egalitarian) { TextButton(onClick = onToggleAdmin) { Text( - text = stringRes(R.string.cordn_create_admin), + text = stringRes(Res.string.cordn_create_admin), style = MaterialTheme.typography.labelMedium, color = if (isAdmin) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -333,7 +349,7 @@ private fun MemberRow( IconButton(onClick = onRemove) { Icon( symbol = MaterialSymbols.PersonRemove, - contentDescription = stringRes(R.string.cordn_info_remove_member), + contentDescription = stringRes(Res.string.cordn_info_remove_member), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt index 7e0e2d7a13..b884f56dbd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupChatScreen.kt @@ -69,7 +69,6 @@ import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.Amethyst -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CordnGroupManager import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols @@ -78,10 +77,33 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.cancel +import com.vitorpamplona.amethyst.commons.resources.cordn_action_editing +import com.vitorpamplona.amethyst.commons.resources.cordn_action_unpin +import com.vitorpamplona.amethyst.commons.resources.cordn_chat_empty_description +import com.vitorpamplona.amethyst.commons.resources.cordn_chat_empty_title +import com.vitorpamplona.amethyst.commons.resources.cordn_group_info +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable import com.vitorpamplona.amethyst.commons.resources.cordn_group_untitled +import com.vitorpamplona.amethyst.commons.resources.cordn_media_download_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_media_no_server +import com.vitorpamplona.amethyst.commons.resources.cordn_media_unreadable +import com.vitorpamplona.amethyst.commons.resources.cordn_media_upload_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_member_count +import com.vitorpamplona.amethyst.commons.resources.cordn_message_deleted +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_by +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_count +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_next +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_previous +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_show_all +import com.vitorpamplona.amethyst.commons.resources.cordn_pinned_title +import com.vitorpamplona.amethyst.commons.resources.cordn_send_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_send_no_session +import com.vitorpamplona.amethyst.commons.resources.cordn_voice_record +import com.vitorpamplona.amethyst.commons.resources.cordn_voice_stop import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlImage import com.vitorpamplona.amethyst.commons.richtext.EncryptedMediaUrlVideo import com.vitorpamplona.amethyst.commons.ui.components.EmptyState +import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText @@ -152,7 +174,7 @@ fun CordnGroupChatScreen( // (it was forgotten, or never opened) and not an error to throw at the // user as a blank screen. Column(Modifier.fillMaxSize().padding(24.dp), verticalArrangement = Arrangement.Center) { - Text(stringRes(R.string.cordn_group_unavailable), style = MaterialTheme.typography.bodyLarge) + Text(stringRes(Res.string.cordn_group_unavailable), style = MaterialTheme.typography.bodyLarge) } return } @@ -209,9 +231,9 @@ private fun CordnGroupChat( // and simply never arrived. var sendError by remember { mutableStateOf(null) } val context = LocalContext.current - val uploadFailed = stringRes(R.string.cordn_media_upload_failed) - val sendFailed = stringRes(R.string.cordn_send_failed) - val noSession = stringRes(R.string.cordn_send_no_session) + val uploadFailed = stringRes(Res.string.cordn_media_upload_failed) + val sendFailed = stringRes(Res.string.cordn_send_failed) + val noSession = stringRes(Res.string.cordn_send_no_session) fun manager() = accountViewModel.account.cordnRuntime @@ -359,8 +381,8 @@ private fun CordnGroupChat( // action that actually needed it. if (rows.isEmpty()) { EmptyState( - title = stringRes(R.string.cordn_chat_empty_title), - description = stringRes(R.string.cordn_chat_empty_description), + title = stringRes(Res.string.cordn_chat_empty_title), + description = stringRes(Res.string.cordn_chat_empty_description), modifier = Modifier.weight(1f), ) } @@ -548,7 +570,7 @@ private fun CordnGroupChat( } if (editing != null) { ComposerBanner( - label = stringRes(R.string.cordn_action_editing), + label = stringRes(Res.string.cordn_action_editing), onCancel = { editing = null room.draft.value = "" @@ -712,7 +734,7 @@ private fun PinnedRibbon( IconButton(onClick = { index = (at - 1 + pinned.size) % pinned.size }, modifier = Modifier.size(28.dp)) { Icon( symbol = MaterialSymbols.AutoMirrored.KeyboardArrowLeft, - contentDescription = stringRes(R.string.cordn_pinned_previous), + contentDescription = stringRes(Res.string.cordn_pinned_previous), modifier = Modifier.size(18.dp), ) } @@ -724,7 +746,7 @@ private fun PinnedRibbon( IconButton(onClick = { index = (at + 1) % pinned.size }, modifier = Modifier.size(28.dp)) { Icon( symbol = MaterialSymbols.AutoMirrored.KeyboardArrowRight, - contentDescription = stringRes(R.string.cordn_pinned_next), + contentDescription = stringRes(Res.string.cordn_pinned_next), modifier = Modifier.size(18.dp), ) } @@ -733,7 +755,7 @@ private fun PinnedRibbon( IconButton(onClick = { showingAll = true }, modifier = Modifier.size(28.dp)) { Icon( symbol = MaterialSymbols.AutoMirrored.List, - contentDescription = stringRes(R.string.cordn_pinned_show_all), + contentDescription = stringRes(Res.string.cordn_pinned_show_all), modifier = Modifier.size(18.dp), ) } @@ -786,7 +808,7 @@ private fun PinnedLine( // points at. text = if (annotations.isDeleted(message.envelope.id)) { - stringRes(R.string.cordn_message_deleted) + stringRes(Res.string.cordn_message_deleted) } else { annotations.contentOf(message.envelope.id).orEmpty() }, @@ -822,7 +844,7 @@ private fun AllPinnedDialog( Row(verticalAlignment = Alignment.CenterVertically) { Icon(MaterialSymbols.PushPin, contentDescription = null, modifier = Modifier.size(18.dp)) Text( - text = stringRes(R.string.cordn_pinned_title), + text = stringRes(Res.string.cordn_pinned_title), modifier = Modifier.padding(start = 8.dp), ) } @@ -830,7 +852,7 @@ private fun AllPinnedDialog( text = { Column { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_pinned_count, pinned.size, pinned.size), + text = pluralStringRes(Res.plurals.cordn_pinned_count, pinned.size, pinned.size), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -861,7 +883,7 @@ private fun AllPinnedDialog( modifier = Modifier.weight(1f).padding(start = 8.dp), ) TextButton(onClick = { onUnpin(message) }) { - Text(stringRes(R.string.cordn_action_unpin), style = MaterialTheme.typography.labelSmall) + Text(stringRes(Res.string.cordn_action_unpin), style = MaterialTheme.typography.labelSmall) } } @@ -869,7 +891,7 @@ private fun AllPinnedDialog( Text( text = stringRes( - R.string.cordn_pinned_by, + Res.string.cordn_pinned_by, observeUserNameByHex(pinnedBy, accountViewModel), ), style = MaterialTheme.typography.labelSmall, @@ -880,7 +902,7 @@ private fun AllPinnedDialog( Text( text = if (annotations.isDeleted(message.envelope.id)) { - stringRes(R.string.cordn_message_deleted) + stringRes(Res.string.cordn_message_deleted) } else { annotations.contentOf(message.envelope.id).orEmpty() }, @@ -944,7 +966,7 @@ private fun CordnChatTopBar( Text(title, maxLines = 1, overflow = TextOverflow.Ellipsis) if (members.isNotEmpty()) { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_member_count, members.size, members.size), + text = pluralStringRes(Res.plurals.cordn_member_count, members.size, members.size), style = MaterialTheme.typography.bodySmall, ) } @@ -963,7 +985,7 @@ private fun CordnChatTopBar( // GroupAdd rather than Info, as in Marmot: the same screen, and the thing // people come to it for is adding someone. IconButton(onClick = onInfo) { - Icon(MaterialSymbols.GroupAdd, contentDescription = stringRes(R.string.cordn_group_info)) + Icon(MaterialSymbols.GroupAdd, contentDescription = stringRes(Res.string.cordn_group_info)) } }, ) @@ -995,10 +1017,10 @@ private suspend fun sendAttachment( // a reason a person can act on. val session = accountViewModel.account.cordnRuntime?.sessionOrNull(room.coordinatorPubKey) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_send_no_session)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_send_no_session)) val group = session.manager.group(room.gid) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_send_no_session)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_send_no_session)) // The gallery inside the dialog can delete what was picked, which leaves an empty // orchestrator rather than a null one. canPost() now refuses that, but indexing it @@ -1052,14 +1074,14 @@ private suspend fun sendAttachment( val name = withContext(Dispatchers.IO) { resolveDisplayName(context, uri) } val bytes = withContext(Dispatchers.IO) { context.contentResolver.openInputStream(finalUri)?.use { it.readBytes() } } - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_media_unreadable)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_media_unreadable)) // Null means the chosen host has no base URL, which is a setting the person can // change — the one failure here that is entirely actionable. val tag = CordnMediaService(accountViewModel.account) .upload(group, bytes, mime, name, context, state.selectedServer.baseUrl) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_media_no_server)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_media_no_server)) // Into the room as well, for the same reason every other send is: an // attachment of your own echoes back as an Echo and would otherwise be @@ -1140,7 +1162,7 @@ internal fun CordnAttachment( if (mediaKey == null) { Text( - text = stringRes(R.string.cordn_media_download_failed), + text = stringRes(Res.string.cordn_media_download_failed), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.error, ) @@ -1254,7 +1276,7 @@ internal fun VoiceNoteButton( ) { Icon( symbol = if (recording) MaterialSymbols.Stop else MaterialSymbols.Mic, - contentDescription = stringRes(if (recording) R.string.cordn_voice_stop else R.string.cordn_voice_record), + contentDescription = stringRes(if (recording) Res.string.cordn_voice_stop else Res.string.cordn_voice_record), // Matches the attach icon beside it; red only while recording, // which is the one state worth pulling the eye. tint = if (recording) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.placeholderText, @@ -1284,10 +1306,10 @@ private suspend fun sendVoiceNote( // note that goes nowhere and says nothing is the same bug twice. val session = accountViewModel.account.cordnRuntime?.sessionOrNull(room.coordinatorPubKey) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_send_no_session)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_send_no_session)) val group = session.manager.group(room.gid) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_send_no_session)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_send_no_session)) try { val bytes = withContext(Dispatchers.IO) { recording.file.readBytes() } @@ -1304,7 +1326,7 @@ private suspend fun sendVoiceNote( // is what makes the bubble match the preview. waveform = recording.amplitudes, ) - ?: throw CordnAttachmentException(stringRes(context, R.string.cordn_media_no_server)) + ?: throw CordnAttachmentException(loadStringRes(Res.string.cordn_media_no_server)) // Into the room as well, for the same reason every other send is: an // attachment of your own echoes back as an Echo and would otherwise be // invisible to the person who sent it. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt index 25c90c354e..e134442396 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupInfoScreen.kt @@ -20,7 +20,6 @@ */ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup -import android.content.Context import android.util.Log import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable @@ -58,12 +57,10 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboardManager -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CordnGroupException import com.vitorpamplona.amethyst.commons.cordn.GroupExposure import com.vitorpamplona.amethyst.commons.cordn.ui.CordnExposureCard @@ -76,8 +73,58 @@ import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back import com.vitorpamplona.amethyst.commons.resources.cancel import com.vitorpamplona.amethyst.commons.resources.copy_npub_to_clipboard +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_action_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_coordinator_silent +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_no_key_package +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_no_self_remove +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_no_welcome +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_not_a_member +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_someone +import com.vitorpamplona.amethyst.commons.resources.cordn_admin_wrong_key_package +import com.vitorpamplona.amethyst.commons.resources.cordn_create_description +import com.vitorpamplona.amethyst.commons.resources.cordn_create_name +import com.vitorpamplona.amethyst.commons.resources.cordn_exposure_close +import com.vitorpamplona.amethyst.commons.resources.cordn_exposure_open +import com.vitorpamplona.amethyst.commons.resources.cordn_group_info +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail import com.vitorpamplona.amethyst.commons.resources.cordn_group_untitled +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member_none +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member_note +import com.vitorpamplona.amethyst.commons.resources.cordn_info_add_member_placeholder +import com.vitorpamplona.amethyst.commons.resources.cordn_info_admin_badge +import com.vitorpamplona.amethyst.commons.resources.cordn_info_admins_kept +import com.vitorpamplona.amethyst.commons.resources.cordn_info_coordinator +import com.vitorpamplona.amethyst.commons.resources.cordn_info_coordinator_key +import com.vitorpamplona.amethyst.commons.resources.cordn_info_coordinator_nprofile +import com.vitorpamplona.amethyst.commons.resources.cordn_info_copy_nprofile +import com.vitorpamplona.amethyst.commons.resources.cordn_info_edit_details +import com.vitorpamplona.amethyst.commons.resources.cordn_info_egalitarian +import com.vitorpamplona.amethyst.commons.resources.cordn_info_epoch +import com.vitorpamplona.amethyst.commons.resources.cordn_info_gid +import com.vitorpamplona.amethyst.commons.resources.cordn_info_has_key_package +import com.vitorpamplona.amethyst.commons.resources.cordn_info_members +import com.vitorpamplona.amethyst.commons.resources.cordn_info_remove_confirm_body +import com.vitorpamplona.amethyst.commons.resources.cordn_info_remove_confirm_title +import com.vitorpamplona.amethyst.commons.resources.cordn_info_remove_member +import com.vitorpamplona.amethyst.commons.resources.cordn_info_save +import com.vitorpamplona.amethyst.commons.resources.cordn_info_technical +import com.vitorpamplona.amethyst.commons.resources.cordn_member_count +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_accept +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_admin_only +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_check +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_decline +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_none +import com.vitorpamplona.amethyst.commons.resources.cordn_requests_title +import com.vitorpamplona.amethyst.commons.resources.cordn_send_no_session +import com.vitorpamplona.amethyst.commons.resources.cordn_share_copied +import com.vitorpamplona.amethyst.commons.resources.cordn_share_copy +import com.vitorpamplona.amethyst.commons.resources.cordn_share_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_share_title import com.vitorpamplona.amethyst.commons.ui.components.EmptyState +import com.vitorpamplona.amethyst.commons.ui.loadStringRes import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.SuggestionListDefaultHeightChat import com.vitorpamplona.amethyst.commons.util.toShortDisplay @@ -124,8 +171,8 @@ fun CordnGroupInfoScreen( // The app's own empty state, centred and titled, rather than a // sentence stranded in the top-left corner. EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) } @@ -151,7 +198,7 @@ private fun InfoTopBar( Icon(MaterialSymbols.AutoMirrored.ArrowBack, contentDescription = stringRes(Res.string.back)) } }, - title = { Text(stringRes(R.string.cordn_group_info)) }, + title = { Text(stringRes(Res.string.cordn_group_info)) }, actions = actions, ) } @@ -208,8 +255,8 @@ private fun CordnGroupInfo( DisposableEffect(Unit) { onDispose { userSuggestions.reset() } } - val failed = stringRes(R.string.cordn_admin_action_failed) - val noSession = stringRes(R.string.cordn_send_no_session) + val failed = stringRes(Res.string.cordn_admin_action_failed) + val noSession = stringRes(Res.string.cordn_send_no_session) // Computed, never asserted: hardcoding these made the card look like a // disclosure while reporting the same four values for every group. @@ -236,8 +283,6 @@ private fun CordnGroupInfo( * roster, and a rename stayed the old name. The runtime's own methods pair * each commit with that refresh. */ - val context = LocalContext.current - fun runAdmin( who: String? = null, block: suspend (CordnRuntime) -> Unit, @@ -257,7 +302,7 @@ private fun CordnGroupInfo( // and gids in full, so the screen that had just shown a face // answered with 64 hex characters. Log.w("CordnGroupInfo", "admin action failed in ${room.gid}: ${e.message}", e) - adminError = adminFailureText(context, e, who, failed) + adminError = adminFailureText(e, who, failed) } finally { busy = false } @@ -274,7 +319,7 @@ private fun CordnGroupInfo( IconButton(onClick = { renaming = true }, enabled = !busy) { Icon( symbol = MaterialSymbols.Edit, - contentDescription = stringRes(R.string.cordn_info_edit_details), + contentDescription = stringRes(Res.string.cordn_info_edit_details), ) } } @@ -303,7 +348,7 @@ private fun CordnGroupInfo( } // A subtitle, not a labelled row above a list that is itself the count. Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_member_count, members.size, members.size), + text = pluralStringRes(Res.plurals.cordn_member_count, members.size, members.size), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 4.dp), @@ -321,7 +366,7 @@ private fun CordnGroupInfo( // ContextVM addresses it with ordinary p-tags, so it has a kind 0 like // anyone else and the app can already resolve it to a name, an avatar // and a profile to tap through to. - Text(stringRes(R.string.cordn_info_coordinator), style = MaterialTheme.typography.titleMedium) + Text(stringRes(Res.string.cordn_info_coordinator), style = MaterialTheme.typography.titleMedium) Row( Modifier.fillMaxWidth().padding(top = 8.dp), @@ -347,7 +392,7 @@ private fun CordnGroupInfo( IconButton(onClick = { showExposure = true }, enabled = exposure != null) { Icon( symbol = MaterialSymbols.Info, - contentDescription = stringRes(R.string.cordn_exposure_open), + contentDescription = stringRes(Res.string.cordn_exposure_open), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } @@ -355,7 +400,7 @@ private fun CordnGroupInfo( HorizontalDivider(Modifier.padding(vertical = 16.dp)) - Text(stringRes(R.string.cordn_info_members), style = MaterialTheme.typography.titleMedium) + Text(stringRes(Res.string.cordn_info_members), style = MaterialTheme.typography.titleMedium) // Said once, and only when it is true. An empty admin set is not "none // configured" -- spec/01.md makes it permanently egalitarian, so the @@ -364,7 +409,7 @@ private fun CordnGroupInfo( // a count of them adds nothing. if (admins.isEmpty()) { Text( - text = stringRes(R.string.cordn_info_egalitarian), + text = stringRes(Res.string.cordn_info_egalitarian), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 2.dp, bottom = 4.dp), @@ -385,7 +430,7 @@ private fun CordnGroupInfo( ) if (member in admins) { Text( - text = stringRes(R.string.cordn_info_admin_badge), + text = stringRes(Res.string.cordn_info_admin_badge), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.primary, ) @@ -398,7 +443,7 @@ private fun CordnGroupInfo( IconButton(onClick = { removing = member }, enabled = !busy) { Icon( symbol = MaterialSymbols.PersonRemove, - contentDescription = stringRes(R.string.cordn_info_remove_member), + contentDescription = stringRes(Res.string.cordn_info_remove_member), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.error, ) @@ -476,9 +521,9 @@ private fun CordnGroupInfo( // would be a setting nobody should be nudged into. AlertDialog( onDismissRequest = { removing = null }, - title = { Text(stringRes(R.string.cordn_info_remove_confirm_title)) }, + title = { Text(stringRes(Res.string.cordn_info_remove_confirm_title)) }, text = { - Text(stringRes(R.string.cordn_info_remove_confirm_body, removingName)) + Text(stringRes(Res.string.cordn_info_remove_confirm_body, removingName)) }, confirmButton = { TextButton(onClick = { @@ -486,7 +531,7 @@ private fun CordnGroupInfo( runAdmin(removingName) { it.removeMember(coordinatorPubKey, room.gid, target) } }) { Text( - text = stringRes(R.string.cordn_info_remove_member), + text = stringRes(Res.string.cordn_info_remove_member), color = MaterialTheme.colorScheme.error, ) } @@ -518,7 +563,7 @@ private fun CordnGroupInfo( text = { CordnExposureCard(it) }, confirmButton = { TextButton(onClick = { showExposure = false }) { - Text(stringRes(R.string.cordn_exposure_close)) + Text(stringRes(Res.string.cordn_exposure_close)) } }, ) @@ -577,15 +622,15 @@ private fun CordnAddMember( OutlinedTextField( value = search, onValueChange = onSearchChange, - label = { Text(stringRes(R.string.cordn_info_add_member)) }, - placeholder = { Text(stringRes(R.string.cordn_info_add_member_placeholder)) }, + label = { Text(stringRes(Res.string.cordn_info_add_member)) }, + placeholder = { Text(stringRes(Res.string.cordn_info_add_member_placeholder)) }, singleLine = true, enabled = !busy, modifier = Modifier.fillMaxWidth(), ) Text( - text = stringRes(R.string.cordn_info_add_member_note), + text = stringRes(Res.string.cordn_info_add_member_note), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 4.dp), @@ -601,7 +646,7 @@ private fun CordnAddMember( modifier = SuggestionListDefaultHeightChat, onEmpty = { Text( - text = stringRes(R.string.cordn_info_add_member_none), + text = stringRes(Res.string.cordn_info_add_member_none), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), @@ -612,7 +657,7 @@ private fun CordnAddMember( if (reachable?.contains(user.pubkeyHex) == true) { Icon( symbol = MaterialSymbols.Key, - contentDescription = stringRes(R.string.cordn_info_has_key_package), + contentDescription = stringRes(Res.string.cordn_info_has_key_package), modifier = Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -620,7 +665,7 @@ private fun CordnAddMember( IconButton(onClick = { onInvite(user) }) { Icon( symbol = MaterialSymbols.PersonAdd, - contentDescription = stringRes(R.string.cordn_info_add_member), + contentDescription = stringRes(Res.string.cordn_info_add_member), tint = MaterialTheme.colorScheme.primary, ) } @@ -643,20 +688,19 @@ private fun CordnAddMember( * better than silence — and the caller has logged the throwable in full either * way. */ -private fun adminFailureText( - context: Context, +private suspend fun adminFailureText( e: Throwable, who: String?, fallback: String, ): String { - val name = who ?: stringRes(context, R.string.cordn_admin_someone) + val name = who ?: loadStringRes(Res.string.cordn_admin_someone) return when (e) { is CordnGroupException -> when (e.reason) { - CordnGroupException.Reason.NO_KEY_PACKAGE -> stringRes(context, R.string.cordn_admin_no_key_package, name) - CordnGroupException.Reason.WRONG_KEY_PACKAGE_OWNER -> stringRes(context, R.string.cordn_admin_wrong_key_package, name) - CordnGroupException.Reason.NO_WELCOME -> stringRes(context, R.string.cordn_admin_no_welcome, name) - CordnGroupException.Reason.NOT_A_MEMBER -> stringRes(context, R.string.cordn_admin_not_a_member, name) + CordnGroupException.Reason.NO_KEY_PACKAGE -> loadStringRes(Res.string.cordn_admin_no_key_package, name) + CordnGroupException.Reason.WRONG_KEY_PACKAGE_OWNER -> loadStringRes(Res.string.cordn_admin_wrong_key_package, name) + CordnGroupException.Reason.NO_WELCOME -> loadStringRes(Res.string.cordn_admin_no_welcome, name) + CordnGroupException.Reason.NOT_A_MEMBER -> loadStringRes(Res.string.cordn_admin_not_a_member, name) CordnGroupException.Reason.OTHER -> e.message ?: fallback } @@ -664,14 +708,14 @@ private fun adminFailureText( // roster and the button disagreed rather than that anyone tried. is IllegalArgumentException -> if (e.message?.contains("self-removal") == true) { - stringRes(context, R.string.cordn_admin_no_self_remove) + loadStringRes(Res.string.cordn_admin_no_self_remove) } else { e.message ?: fallback } // A coordinator that does not answer is the single commonest failure // here and says nothing useful in its own words. - is TimeoutCancellationException -> stringRes(context, R.string.cordn_admin_coordinator_silent) + is TimeoutCancellationException -> loadStringRes(Res.string.cordn_admin_coordinator_silent) else -> e.message ?: fallback } @@ -701,7 +745,7 @@ private fun TechnicalDetails( verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringRes(R.string.cordn_info_technical), + text = stringRes(Res.string.cordn_info_technical), style = MaterialTheme.typography.titleMedium, modifier = Modifier.weight(1f), ) @@ -725,22 +769,22 @@ private fun TechnicalDetails( val coordinator = remember(coordinatorPubKey) { LocalCache.getOrCreateUser(coordinatorPubKey) } CopyableKeyRow( - label = stringRes(R.string.cordn_info_coordinator_key), + label = stringRes(Res.string.cordn_info_coordinator_key), shown = coordinator.pubkeyDisplayHex(), copied = coordinator.pubkeyNpub(), copyDescription = stringRes(Res.string.copy_npub_to_clipboard), ) CopyableKeyRow( - label = stringRes(R.string.cordn_info_coordinator_nprofile), + label = stringRes(Res.string.cordn_info_coordinator_nprofile), shown = coordinator.toNProfile().toShortDisplay(6), copied = coordinator.toNProfile(), - copyDescription = stringRes(R.string.cordn_info_copy_nprofile), + copyDescription = stringRes(Res.string.cordn_info_copy_nprofile), ) SelectionContainer { Column { - InfoRow(stringRes(R.string.cordn_info_gid), gid) - InfoRow(stringRes(R.string.cordn_info_epoch), epoch.toString()) + InfoRow(stringRes(Res.string.cordn_info_gid), gid) + InfoRow(stringRes(Res.string.cordn_info_epoch), epoch.toString()) } } } @@ -835,7 +879,7 @@ private fun JoinRequests( ) { val runtime = accountViewModel.account.cordnRuntime ?: return val scope = rememberCoroutineScope() - val failed = stringRes(R.string.cordn_requests_failed) + val failed = stringRes(Res.string.cordn_requests_failed) var requests by remember { mutableStateOf?>(null) } var busy by remember { mutableStateOf(false) } @@ -853,15 +897,15 @@ private fun JoinRequests( } } - Text(stringRes(R.string.cordn_requests_title), style = MaterialTheme.typography.titleMedium) + Text(stringRes(Res.string.cordn_requests_title), style = MaterialTheme.typography.titleMedium) Text( - text = stringRes(R.string.cordn_requests_admin_only), + text = stringRes(Res.string.cordn_requests_admin_only), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) OutlinedButton(onClick = { scope.launch { reload() } }, enabled = !busy) { - Text(stringRes(R.string.cordn_requests_check)) + Text(stringRes(Res.string.cordn_requests_check)) } error?.let { Text(it, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error) } @@ -870,7 +914,7 @@ private fun JoinRequests( if (loaded != null && !busy) { if (loaded.isEmpty()) { Text( - text = stringRes(R.string.cordn_requests_none), + text = stringRes(Res.string.cordn_requests_none), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -899,7 +943,7 @@ private fun JoinRequests( reload() } }) { - Text(stringRes(R.string.cordn_requests_accept)) + Text(stringRes(Res.string.cordn_requests_accept)) } TextButton(onClick = { scope.launch { @@ -911,7 +955,7 @@ private fun JoinRequests( reload() } }) { - Text(stringRes(R.string.cordn_requests_decline)) + Text(stringRes(Res.string.cordn_requests_decline)) } } } @@ -949,9 +993,9 @@ private fun ShareGroup( val clipboard = LocalClipboardManager.current var copied by remember { mutableStateOf(false) } - Text(stringRes(R.string.cordn_share_title), style = MaterialTheme.typography.titleMedium) + Text(stringRes(Res.string.cordn_share_title), style = MaterialTheme.typography.titleMedium) Text( - text = stringRes(R.string.cordn_share_explainer), + text = stringRes(Res.string.cordn_share_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -968,7 +1012,7 @@ private fun ShareGroup( }, modifier = Modifier.padding(top = 8.dp), ) { - Text(stringRes(if (copied) R.string.cordn_share_copied else R.string.cordn_share_copy)) + Text(stringRes(if (copied) Res.string.cordn_share_copied else Res.string.cordn_share_copy)) } } @@ -993,26 +1037,26 @@ private fun EditGroupDetailsDialog( AlertDialog( onDismissRequest = onDismiss, - title = { Text(stringRes(R.string.cordn_info_edit_details)) }, + title = { Text(stringRes(Res.string.cordn_info_edit_details)) }, text = { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { OutlinedTextField( value = draftName, onValueChange = { draftName = it }, - label = { Text(stringRes(R.string.cordn_create_name)) }, + label = { Text(stringRes(Res.string.cordn_create_name)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) OutlinedTextField( value = draftDescription, onValueChange = { draftDescription = it }, - label = { Text(stringRes(R.string.cordn_create_description)) }, + label = { Text(stringRes(Res.string.cordn_create_description)) }, singleLine = false, modifier = Modifier.fillMaxWidth(), ) if (admins.isNotEmpty()) { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_info_admins_kept, admins.size, admins.size), + text = pluralStringRes(Res.plurals.cordn_info_admins_kept, admins.size, admins.size), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -1024,7 +1068,7 @@ private fun EditGroupDetailsDialog( onClick = { onSave(draftName.trim(), draftDescription.trim()) }, enabled = draftName.isNotBlank(), ) { - Text(stringRes(R.string.cordn_info_save)) + Text(stringRes(Res.string.cordn_info_save)) } }, dismissButton = { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt index e7a5defb33..13876ffbe1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnGroupListScreen.kt @@ -41,10 +41,8 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CoordinatorHealth import com.vitorpamplona.amethyst.commons.cordn.ui.CoordinatorHealthRow import com.vitorpamplona.amethyst.commons.icons.symbols.Icon @@ -52,6 +50,14 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cordnGroups.CordnGroupChatroom import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_count +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_down_note +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_manage +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_none +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_none_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_groups_start import com.vitorpamplona.amethyst.commons.resources.cordn_groups_title import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -106,14 +112,14 @@ fun CordnGroupListScreen( IconButton(onClick = { nav.nav(Route.CordnCoordinators) }) { Icon( symbol = MaterialSymbols.Dns, - contentDescription = stringRes(R.string.cordn_groups_manage), + contentDescription = stringRes(Res.string.cordn_groups_manage), modifier = Modifier.size(22.dp), ) } IconButton(onClick = { nav.nav(Route.CordnCreateGroup) }) { Icon( symbol = MaterialSymbols.Add, - contentDescription = stringRes(R.string.cordn_groups_start), + contentDescription = stringRes(Res.string.cordn_groups_start), modifier = Modifier.size(24.dp), ) } @@ -122,8 +128,8 @@ fun CordnGroupListScreen( ) { padding -> if (runtime == null) { EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -148,8 +154,8 @@ fun CordnGroupListScreen( if (sections.isEmpty()) { EmptyState( - title = stringRes(R.string.cordn_groups_none), - description = stringRes(R.string.cordn_groups_none_detail), + title = stringRes(Res.string.cordn_groups_none), + description = stringRes(Res.string.cordn_groups_none_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -230,7 +236,7 @@ private fun CoordinatorSection( }, ) Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_groups_count, groupCount, groupCount), + text = pluralStringRes(Res.plurals.cordn_groups_count, groupCount, groupCount), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -248,7 +254,7 @@ private fun CoordinatorSection( verticalAlignment = Alignment.Top, ) { Text( - text = stringRes(R.string.cordn_groups_down_note), + text = stringRes(Res.string.cordn_groups_down_note), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.error, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt index a1292ad0e6..b145042c85 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnInvitationsScreen.kt @@ -48,16 +48,30 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.icons.symbols.Icon import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.back +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail import com.vitorpamplona.amethyst.commons.resources.cordn_group_untitled +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_accept +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_decline +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_decline_warning +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_load_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_members +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_members_more +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_no_coordinators +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_none +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_refresh +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_skipped +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_title +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_unreachable +import com.vitorpamplona.amethyst.commons.resources.cordn_invitations_via import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.model.cordn.CordnInvitation @@ -69,6 +83,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.CoordinatorI import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.cordn.coordinatorDisplayName import com.vitorpamplona.amethyst.ui.stringRes import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.pluralStringResource /** * Invitations to cordn groups, waiting to be answered. @@ -106,7 +121,7 @@ fun CordnInvitationsScreen( var invitations by remember { mutableStateOf(null) } var busy by remember { mutableStateOf(false) } var error by remember { mutableStateOf(null) } - val loadFailed = stringRes(R.string.cordn_invitations_load_failed) + val loadFailed = stringRes(Res.string.cordn_invitations_load_failed) suspend fun reload() { busy = true @@ -130,10 +145,10 @@ fun CordnInvitationsScreen( Icon(MaterialSymbols.AutoMirrored.ArrowBack, contentDescription = stringRes(Res.string.back)) } }, - title = { Text(stringRes(R.string.cordn_invitations_title)) }, + title = { Text(stringRes(Res.string.cordn_invitations_title)) }, actions = { IconButton(onClick = { scope.launch { reload() } }, enabled = !busy) { - Icon(MaterialSymbols.Refresh, contentDescription = stringRes(R.string.cordn_invitations_refresh)) + Icon(MaterialSymbols.Refresh, contentDescription = stringRes(Res.string.cordn_invitations_refresh)) } }, ) @@ -150,8 +165,8 @@ fun CordnInvitationsScreen( ) { if (runtime == null) { EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), ) return@Column } @@ -163,7 +178,7 @@ fun CordnInvitationsScreen( val coordinators by runtime.coordinators.collectAsStateWithLifecycle() Text( - text = stringRes(R.string.cordn_invitations_explainer), + text = stringRes(Res.string.cordn_invitations_explainer), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -212,7 +227,7 @@ fun CordnInvitationsScreen( NoticeCard( title = stringRes( - R.string.cordn_invitations_unreachable, + Res.string.cordn_invitations_unreachable, coordinatorDisplayName(it.coordinator.pubKey, it.coordinator.label, accountViewModel), ), detail = it.reason, @@ -225,7 +240,7 @@ fun CordnInvitationsScreen( // friend swears they sent simply does not exist here. loaded.skipped.forEach { NoticeCard( - title = stringRes(R.string.cordn_invitations_skipped), + title = stringRes(Res.string.cordn_invitations_skipped), detail = it.reason, isError = false, ) @@ -235,9 +250,9 @@ fun CordnInvitationsScreen( Text( text = if (coordinators.isEmpty()) { - stringRes(R.string.cordn_invitations_no_coordinators) + stringRes(Res.string.cordn_invitations_no_coordinators) } else { - stringRes(R.string.cordn_invitations_none) + stringRes(Res.string.cordn_invitations_none) }, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -276,7 +291,7 @@ private fun InvitationCard( // "Already in it", never "invited you" — see the screen KDoc. Text( - text = pluralStringResource(R.plurals.cordn_invitations_members, welcome.members.size, welcome.members.size), + text = pluralStringResource(Res.plurals.cordn_invitations_members, welcome.members.size, welcome.members.size), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -300,7 +315,7 @@ private fun InvitationCard( } if (welcome.members.size > MEMBER_FACES) { Text( - text = stringRes(R.string.cordn_invitations_members_more, welcome.members.size - MEMBER_FACES), + text = stringRes(Res.string.cordn_invitations_members_more, welcome.members.size - MEMBER_FACES), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -329,7 +344,7 @@ private fun InvitationCard( size = 20.dp, ) { name -> Text( - text = stringRes(R.string.cordn_invitations_via, name), + text = stringRes(Res.string.cordn_invitations_via, name), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -340,11 +355,11 @@ private fun InvitationCard( horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically, ) { - Button(onClick = onAccept) { Text(stringRes(R.string.cordn_invitations_accept)) } - TextButton(onClick = onDecline) { Text(stringRes(R.string.cordn_invitations_decline)) } + Button(onClick = onAccept) { Text(stringRes(Res.string.cordn_invitations_accept)) } + TextButton(onClick = onDecline) { Text(stringRes(Res.string.cordn_invitations_decline)) } } Text( - text = stringRes(R.string.cordn_invitations_decline_warning), + text = stringRes(Res.string.cordn_invitations_decline_warning), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt index 189fca42a9..031512faea 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/cordnGroup/CordnMessageRow.kt @@ -55,7 +55,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.chats.ui.ChatDivisor import com.vitorpamplona.amethyst.commons.chats.ui.UserDisplayNameLayout import com.vitorpamplona.amethyst.commons.cordn.CordnMentions @@ -67,6 +66,24 @@ import com.vitorpamplona.amethyst.commons.model.navigation.Route import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.copied_to_clipboard import com.vitorpamplona.amethyst.commons.resources.copy_text +import com.vitorpamplona.amethyst.commons.resources.cordn_action_delete +import com.vitorpamplona.amethyst.commons.resources.cordn_action_edit +import com.vitorpamplona.amethyst.commons.resources.cordn_action_go_to_message +import com.vitorpamplona.amethyst.commons.resources.cordn_action_pin +import com.vitorpamplona.amethyst.commons.resources.cordn_action_reply +import com.vitorpamplona.amethyst.commons.resources.cordn_action_unpin +import com.vitorpamplona.amethyst.commons.resources.cordn_chat_unread_divider +import com.vitorpamplona.amethyst.commons.resources.cordn_chat_yesterday +import com.vitorpamplona.amethyst.commons.resources.cordn_delete_confirm_body +import com.vitorpamplona.amethyst.commons.resources.cordn_delete_confirm_title +import com.vitorpamplona.amethyst.commons.resources.cordn_delivery_accepted +import com.vitorpamplona.amethyst.commons.resources.cordn_message_deleted +import com.vitorpamplona.amethyst.commons.resources.cordn_message_details_coordinator +import com.vitorpamplona.amethyst.commons.resources.cordn_message_details_cursor +import com.vitorpamplona.amethyst.commons.resources.cordn_message_details_sent_at +import com.vitorpamplona.amethyst.commons.resources.cordn_message_details_title +import com.vitorpamplona.amethyst.commons.resources.cordn_message_edited +import com.vitorpamplona.amethyst.commons.resources.cordn_reactions_title import com.vitorpamplona.amethyst.commons.resources.quick_action_share import com.vitorpamplona.amethyst.commons.resources.today import com.vitorpamplona.amethyst.commons.ui.components.ClickableBox @@ -292,7 +309,7 @@ private fun CordnBubbleContents( when { text == null -> Text( - text = stringRes(R.string.cordn_message_deleted), + text = stringRes(Res.string.cordn_message_deleted), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -448,7 +465,7 @@ private fun CordnReactionDetailSheet( ) { Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState()).padding(bottom = 24.dp)) { Text( - text = stringRes(R.string.cordn_reactions_title), + text = stringRes(Res.string.cordn_reactions_title), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(horizontal = 20.dp, vertical = 12.dp), ) @@ -519,7 +536,7 @@ internal fun CordnQuotedMessage( val body = if (annotations.isDeleted(parent.envelope.id)) { - stringRes(R.string.cordn_message_deleted) + stringRes(Res.string.cordn_message_deleted) } else { annotations.contentOf(parent.envelope.id).orEmpty() } @@ -575,7 +592,7 @@ private fun CordnQuoteActionSheet( Column(Modifier.padding(bottom = 24.dp)) { TileRow { if (onGoToMessage != null) { - ActionTile(MaterialSymbols.ArrowUpward, stringRes(R.string.cordn_action_go_to_message)) { + ActionTile(MaterialSymbols.ArrowUpward, stringRes(Res.string.cordn_action_go_to_message)) { onGoToMessage() onDismiss() } @@ -594,7 +611,7 @@ private fun CordnQuoteActionSheet( */ @Composable internal fun UnreadDivider() { - ChatDivisor(stringRes(R.string.cordn_chat_unread_divider), MaterialTheme.colorScheme.primary) + ChatDivisor(stringRes(Res.string.cordn_chat_unread_divider), MaterialTheme.colorScheme.primary) } /** @@ -618,7 +635,7 @@ private fun CordnMessageFooter( if (isPinned) { Icon( symbol = MaterialSymbols.PushPin, - contentDescription = stringRes(R.string.cordn_action_pin), + contentDescription = stringRes(Res.string.cordn_action_pin), modifier = Modifier.size(12.dp), tint = MaterialTheme.colorScheme.primary, ) @@ -627,7 +644,7 @@ private fun CordnMessageFooter( if (isEdited) { Text( - text = stringRes(R.string.cordn_message_edited), + text = stringRes(Res.string.cordn_message_edited), fontSize = Font12SP, color = MaterialTheme.colorScheme.placeholderText, maxLines = 1, @@ -658,7 +675,7 @@ private fun CordnMessageFooter( Spacer(StdHorzSpacer) Icon( symbol = MaterialSymbols.Done, - contentDescription = stringRes(R.string.cordn_delivery_accepted), + contentDescription = stringRes(Res.string.cordn_delivery_accepted), modifier = Modifier.size(12.dp), tint = MaterialTheme.colorScheme.allGoodColor, ) @@ -711,18 +728,18 @@ private fun CordnMessageDetailsSheet( verticalArrangement = Arrangement.spacedBy(6.dp), ) { Text( - text = stringRes(R.string.cordn_message_details_title), + text = stringRes(Res.string.cordn_message_details_title), style = MaterialTheme.typography.titleSmall, ) - DetailLine(stringRes(R.string.cordn_message_details_sent_at), sentAt) - DetailLine(stringRes(R.string.cordn_message_details_cursor), message.cursor.toString()) + DetailLine(stringRes(Res.string.cordn_message_details_sent_at), sentAt) + DetailLine(stringRes(Res.string.cordn_message_details_cursor), message.cursor.toString()) DetailLine( - stringRes(R.string.cordn_message_details_coordinator), + stringRes(Res.string.cordn_message_details_coordinator), coordinatorDisplayName(coordinatorPubKey, label = null, accountViewModel = accountViewModel), ) if (isMine) { Text( - text = stringRes(R.string.cordn_delivery_accepted), + text = stringRes(Res.string.cordn_delivery_accepted), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.allGoodColor, ) @@ -797,10 +814,10 @@ private fun CordnMessageActionSheet( if (confirmingDelete) { QuickActionAlertDialog( - title = stringRes(R.string.cordn_delete_confirm_title), - textContent = stringRes(R.string.cordn_delete_confirm_body), + title = stringRes(Res.string.cordn_delete_confirm_title), + textContent = stringRes(Res.string.cordn_delete_confirm_body), buttonIcon = MaterialSymbols.Delete, - buttonText = stringRes(R.string.cordn_action_delete), + buttonText = stringRes(Res.string.cordn_action_delete), onClickDoOnce = performDelete, onClickDontShowAgain = { accountViewModel.account.settings.setHideDeleteRequestDialog() @@ -843,7 +860,7 @@ private fun CordnMessageActionSheet( TileRow { if (isLive) { - ActionTile(MaterialSymbols.AutoMirrored.Chat, stringRes(R.string.cordn_action_reply)) { + ActionTile(MaterialSymbols.AutoMirrored.Chat, stringRes(Res.string.cordn_action_reply)) { onReply() onDismiss() } @@ -853,7 +870,7 @@ private fun CordnMessageActionSheet( // message rather than only on your own. ActionTile( MaterialSymbols.PushPin, - stringRes(if (isPinned) R.string.cordn_action_unpin else R.string.cordn_action_pin), + stringRes(if (isPinned) Res.string.cordn_action_unpin else Res.string.cordn_action_pin), ) { onTogglePin() onDismiss() @@ -863,11 +880,11 @@ private fun CordnMessageActionSheet( // anyone else. Hiding them here is the same rule, stated where it stops // being a surprise. if (isMine && isLive) { - ActionTile(MaterialSymbols.Edit, stringRes(R.string.cordn_action_edit)) { + ActionTile(MaterialSymbols.Edit, stringRes(Res.string.cordn_action_edit)) { onEdit() onDismiss() } - ActionTile(MaterialSymbols.Delete, stringRes(R.string.cordn_action_delete), isDestructive = true) { + ActionTile(MaterialSymbols.Delete, stringRes(Res.string.cordn_action_delete), isDestructive = true) { // A withdrawal cannot be taken back and the coordinator keeps // the ciphertext either way, so it is worth one question — // unless the account has already opted out of being asked. @@ -989,7 +1006,7 @@ internal fun DaySeparator( val label = when (day) { today -> stringRes(Res.string.today) - today.minusDays(1) -> stringRes(R.string.cordn_chat_yesterday) + today.minusDays(1) -> stringRes(Res.string.cordn_chat_yesterday) // Year included only when it is not this one: printing 2026 on every // divider all year is noise. else -> diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt index 8b2ba48747..f758b7bdcc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/ChatroomHeaderCompose.kt @@ -106,7 +106,9 @@ import com.vitorpamplona.amethyst.commons.resources.relay_group_server_label import com.vitorpamplona.amethyst.commons.resources.remove_from_messages import com.vitorpamplona.amethyst.commons.resources.unmute_notifications import com.vitorpamplona.amethyst.commons.resources.unpin_conversation +import com.vitorpamplona.amethyst.commons.ui.components.NewItemsBubble import com.vitorpamplona.amethyst.commons.ui.components.RobohashFallbackAsyncImage +import com.vitorpamplona.amethyst.commons.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.HeaderPill import com.vitorpamplona.amethyst.commons.ui.screen.LocalDisplaySettings @@ -118,7 +120,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText -import com.vitorpamplona.amethyst.commons.ui.theme.newItemBubbleModifier import com.vitorpamplona.amethyst.commons.ui.theme.placeholderText import com.vitorpamplona.amethyst.model.buzz.toMembershipNotice import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo @@ -126,7 +127,6 @@ import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observe import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteHasEvent import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderByParentFilterAssemblerSubscription import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserName -import com.vitorpamplona.amethyst.ui.layouts.ChatHeaderLayout import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.note.BlankNote import com.vitorpamplona.amethyst.ui.note.LoadDecryptedContentOrNull @@ -1377,8 +1377,3 @@ private fun TimeAgo(channelLastTime: Long?) { color = MaterialTheme.colorScheme.grayText, ) } - -@Composable -fun NewItemsBubble() { - Box(MaterialTheme.colorScheme.newItemBubbleModifier) -} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt index 4623df34fe..fda82b5723 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip28Chats/RenderPublicChatChannelThumb.kt @@ -53,6 +53,7 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.Mute import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.chat_about_topic +import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding @@ -61,7 +62,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.service.relayClient.reqCommand.channel.observeChannel -import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner import com.vitorpamplona.amethyst.ui.note.Gallery import com.vitorpamplona.amethyst.ui.note.LikeReaction diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt index 0a4dc47515..43dfdebcbe 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip72Communities/CommunityCard.kt @@ -55,6 +55,7 @@ import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.Mute import com.vitorpamplona.amethyst.commons.model.topNavFeeds.noteBased.muted.MutedAuthorsByProxyTopNavFilter import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.community_about_topic +import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.stringRes import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding @@ -63,7 +64,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.service.relayClient.reqCommand.event.observeNoteEvent -import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.ui.note.DisplayAuthorBanner import com.vitorpamplona.amethyst.ui.note.Gallery import com.vitorpamplona.amethyst.ui.note.LikeReaction diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt index 64b35607fc..89efcd5e61 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip90DVMs/DVMCard.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.model.AddressableNote import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.HalfTopPadding import com.vitorpamplona.amethyst.commons.ui.theme.RowColSpacing5dp @@ -51,7 +52,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.grayText import com.vitorpamplona.amethyst.commons.ui.theme.nip05 import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.UserFinderFilterAssemblerSubscription import com.vitorpamplona.amethyst.ui.components.MyAsyncImage -import com.vitorpamplona.amethyst.ui.layouts.LeftPictureLayout import com.vitorpamplona.amethyst.ui.note.LikeReaction import com.vitorpamplona.amethyst.ui.note.ZapReaction import com.vitorpamplona.amethyst.ui.note.elements.BannerImage diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt index 4aa7c25131..ddcb0b073f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/browse/BrowseEmojiSetsScreen.kt @@ -46,12 +46,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox import com.vitorpamplona.amethyst.commons.ui.feeds.ScrollStateKeys +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.feeds.rememberForeverLazyGridState import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav -import com.vitorpamplona.amethyst.ui.feeds.StickToTopOnPrepend -import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt index 66ebccef97..14b4ff9783 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/HomeScreen.kt @@ -61,6 +61,8 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.Amethyst +import com.vitorpamplona.amethyst.commons.feeds.ChannelFeedContentState +import com.vitorpamplona.amethyst.commons.feeds.ChannelFeedState import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import com.vitorpamplona.amethyst.commons.model.emphChat.EphemeralChatChannel @@ -96,8 +98,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.TabRowHeight import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonRow import com.vitorpamplona.amethyst.service.location.LocationState -import com.vitorpamplona.amethyst.ui.feeds.ChannelFeedContentState -import com.vitorpamplona.amethyst.ui.feeds.ChannelFeedState import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt index e471e8f3c7..bec6b7c1fa 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedView.kt @@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachCursor import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachDetailDialog import com.vitorpamplona.amethyst.commons.ui.feeds.RelayReachMarkers +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.commons.ui.layouts.rememberFeedContentPadding import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.CloseIcon @@ -73,7 +74,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.Size10dp import com.vitorpamplona.amethyst.commons.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.commons.ui.theme.imageModifier import com.vitorpamplona.amethyst.logTime -import com.vitorpamplona.amethyst.ui.feeds.StickToTopOnPrepend import com.vitorpamplona.amethyst.ui.note.BadgeCompose import com.vitorpamplona.amethyst.ui.note.MessageSetCompose import com.vitorpamplona.amethyst.ui.note.MultiSetCompose diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt index abed0924d7..d600bd16fd 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/newthreads/TabNotesNewThreads.kt @@ -40,12 +40,12 @@ import com.vitorpamplona.amethyst.commons.ui.feeds.FeedEmpty import com.vitorpamplona.amethyst.commons.ui.feeds.FeedError import com.vitorpamplona.amethyst.commons.ui.feeds.LoadingFeed import com.vitorpamplona.amethyst.commons.ui.feeds.RefresheableBox +import com.vitorpamplona.amethyst.commons.ui.feeds.StickToTopOnPrepend +import com.vitorpamplona.amethyst.commons.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness import com.vitorpamplona.amethyst.commons.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.feeds.PrefetchLoadedFeedMedia -import com.vitorpamplona.amethyst.ui.feeds.StickToTopOnPrepend -import com.vitorpamplona.amethyst.ui.feeds.WatchScrollToTop import com.vitorpamplona.amethyst.ui.note.NoteCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.profile.newthreads.dal.UserProfileNewThreadsFeedViewModel diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt index ed93534498..f3d45d8565 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/profile/zaps/ZapNoteCompose.kt @@ -35,12 +35,12 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.model.User import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.model.navigation.routeFor +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.EmptyNav import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor import com.vitorpamplona.amethyst.ui.note.UserActionOptions import com.vitorpamplona.amethyst.ui.note.UserPicture diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt index fd0e1f5a7c..0498e1996f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/nip86/RelayManagementScreen.kt @@ -122,6 +122,7 @@ import com.vitorpamplona.amethyst.commons.resources.relay_management_tab_pubkeys import com.vitorpamplona.amethyst.commons.resources.relay_management_tab_settings import com.vitorpamplona.amethyst.commons.resources.relay_management_title import com.vitorpamplona.amethyst.commons.resources.search_and_add_a_user +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.note.ClearTextIcon import com.vitorpamplona.amethyst.commons.ui.stringRes @@ -133,7 +134,6 @@ import com.vitorpamplona.amethyst.commons.ui.theme.SmallBorder import com.vitorpamplona.amethyst.commons.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.commons.ui.theme.nip05 import com.vitorpamplona.amethyst.service.relayClient.searchCommand.UserSearchDataSourceSubscription -import com.vitorpamplona.amethyst.ui.layouts.listItem.SlimListItem import com.vitorpamplona.amethyst.ui.note.AboutDisplay import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.ObserveAndRenderNIP05VerifiedSymbol diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt index 3560b60be6..0876d4cf5d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnBackupScreen.kt @@ -52,13 +52,26 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_contents_body +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_contents_title +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_export +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_exported +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_passphrase +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_restore +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_restore_body +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_restore_confirm_body +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_restore_confirm_title +import com.vitorpamplona.amethyst.commons.resources.cordn_backup_restored import com.vitorpamplona.amethyst.commons.resources.cordn_backup_section_export import com.vitorpamplona.amethyst.commons.resources.cordn_backup_section_passphrase import com.vitorpamplona.amethyst.commons.resources.cordn_backup_section_restore import com.vitorpamplona.amethyst.commons.resources.cordn_backup_title +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton @@ -113,9 +126,9 @@ fun CordnBackupScreen( var error by remember { mutableStateOf(null) } var pendingRestore by remember { mutableStateOf(null) } - val exported = stringRes(R.string.cordn_backup_exported) - val restored = stringRes(R.string.cordn_backup_restored) - val failed = stringRes(R.string.cordn_backup_failed) + val exported = stringRes(Res.string.cordn_backup_exported) + val restored = stringRes(Res.string.cordn_backup_restored) + val failed = stringRes(Res.string.cordn_backup_failed) val saver = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("application/octet-stream")) { uri -> @@ -179,8 +192,8 @@ fun CordnBackupScreen( // The app's own empty state, centred and titled, rather than a // sentence stranded in the top-left corner. EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -196,7 +209,7 @@ fun CordnBackupScreen( verticalArrangement = Arrangement.spacedBy(20.dp), ) { Text( - text = stringRes(R.string.cordn_backup_explainer), + text = stringRes(Res.string.cordn_backup_explainer), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -212,7 +225,7 @@ fun CordnBackupScreen( passphrase = it error = null }, - label = { Text(stringRes(R.string.cordn_backup_passphrase)) }, + label = { Text(stringRes(Res.string.cordn_backup_passphrase)) }, visualTransformation = PasswordVisualTransformation(), // The dots are only half of it. Without the password // keyboard type the IME treats this as ordinary prose: @@ -230,9 +243,9 @@ fun CordnBackupScreen( SettingsSection(Res.string.cordn_backup_section_export) { SettingsFormBlock { - Text(stringRes(R.string.cordn_backup_contents_title), style = MaterialTheme.typography.titleSmall) + Text(stringRes(Res.string.cordn_backup_contents_title), style = MaterialTheme.typography.titleSmall) Text( - text = stringRes(R.string.cordn_backup_contents_body), + text = stringRes(Res.string.cordn_backup_contents_body), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -248,7 +261,7 @@ fun CordnBackupScreen( // Key derivation here is scrypt, which is slow on // purpose, so a greyed-out button was the only sign // anything was happening for several seconds. - BusyLabel(busy, stringRes(R.string.cordn_backup_export)) + BusyLabel(busy, stringRes(Res.string.cordn_backup_export)) } } } @@ -256,7 +269,7 @@ fun CordnBackupScreen( SettingsSection(Res.string.cordn_backup_section_restore) { SettingsFormBlock { Text( - text = stringRes(R.string.cordn_backup_restore_body), + text = stringRes(Res.string.cordn_backup_restore_body), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -266,7 +279,7 @@ fun CordnBackupScreen( enabled = !busy && passphrase.isNotBlank(), modifier = Modifier.fillMaxWidth(), ) { - BusyLabel(busy, stringRes(R.string.cordn_backup_restore)) + BusyLabel(busy, stringRes(Res.string.cordn_backup_restore)) } } } @@ -276,8 +289,8 @@ fun CordnBackupScreen( pendingRestore?.let { uri -> AlertDialog( onDismissRequest = { pendingRestore = null }, - title = { Text(stringRes(R.string.cordn_backup_restore_confirm_title)) }, - text = { Text(stringRes(R.string.cordn_backup_restore_confirm_body)) }, + title = { Text(stringRes(Res.string.cordn_backup_restore_confirm_title)) }, + text = { Text(stringRes(Res.string.cordn_backup_restore_confirm_body)) }, confirmButton = { TextButton(onClick = { pendingRestore = null @@ -302,7 +315,7 @@ fun CordnBackupScreen( } } }) { - Text(stringRes(R.string.cordn_backup_restore), color = MaterialTheme.colorScheme.error) + Text(stringRes(Res.string.cordn_backup_restore), color = MaterialTheme.colorScheme.error) } }, dismissButton = { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt index 01b0a3c93f..3459eec409 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnCoordinatorsScreen.kt @@ -58,7 +58,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.cordn.CoordinatorHealth import com.vitorpamplona.amethyst.commons.cordn.CordnCoordinatorDiscovery @@ -68,10 +67,45 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.resources.Res import com.vitorpamplona.amethyst.commons.resources.cancel +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_add_action +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_add_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_copy_key +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_action +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_add +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_none +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_seen +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_discover_unheard +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_health_down +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_health_ok +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_health_retrying +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_health_unknown +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_identify +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_key +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_label +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_label_note +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_more +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_none +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_purge +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_purge_body +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_purge_title +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_relays_label +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_remove +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_rename import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_section_discover import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_section_manual import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_section_yours +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_server +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_server_claim +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_server_silent import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_title +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_pubkey +import com.vitorpamplona.amethyst.commons.resources.cordn_create_coordinator_relays +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_info_save import com.vitorpamplona.amethyst.commons.ui.components.CrossfadeIfEnabled import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -127,8 +161,8 @@ fun CordnCoordinatorsScreen( // The app's own empty state, centred and titled, rather than a // sentence stranded in the top-left corner. EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -146,7 +180,7 @@ fun CordnCoordinatorsScreen( verticalArrangement = Arrangement.spacedBy(20.dp), ) { Text( - text = stringRes(R.string.cordn_coordinators_explainer), + text = stringRes(Res.string.cordn_coordinators_explainer), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -165,7 +199,7 @@ fun CordnCoordinatorsScreen( if (coordinators.isEmpty()) { Text( - text = stringRes(R.string.cordn_coordinators_none), + text = stringRes(Res.string.cordn_coordinators_none), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -225,7 +259,7 @@ private fun CoordinatorCard( IconButton(onClick = { renaming = true }) { Icon( symbol = MaterialSymbols.Edit, - contentDescription = stringRes(R.string.cordn_coordinators_rename), + contentDescription = stringRes(Res.string.cordn_coordinators_rename), modifier = Modifier.size(18.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -264,10 +298,10 @@ private fun CoordinatorCard( // away on the clipboard, which is how a comparison is actually done. val coordinator = remember(config.pubKey) { LocalCache.getOrCreateUser(config.pubKey) } CopyableKeyRow( - label = stringRes(R.string.cordn_coordinators_key), + label = stringRes(Res.string.cordn_coordinators_key), shown = coordinator.pubkeyDisplayHex(), copied = coordinator.pubkeyNpub(), - copyDescription = stringRes(R.string.cordn_coordinators_copy_key), + copyDescription = stringRes(Res.string.cordn_coordinators_copy_key), ) // Every relay, not the first two and a count: this is the management @@ -275,7 +309,7 @@ private fun CoordinatorCard( // came here to check or to rule out. Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { Text( - text = stringRes(R.string.cordn_coordinators_relays_label), + text = stringRes(Res.string.cordn_coordinators_relays_label), style = MaterialTheme.typography.labelMedium, fontWeight = FontWeight.SemiBold, ) @@ -304,10 +338,10 @@ private fun CoordinatorCard( text = info?.let { stringRes( - R.string.cordn_coordinators_server, + Res.string.cordn_coordinators_server, listOfNotNull(it.name, it.version, it.protocolVersion).joinToString(" \u00b7 "), ) - } ?: stringRes(R.string.cordn_coordinators_server_silent), + } ?: stringRes(Res.string.cordn_coordinators_server_silent), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -315,7 +349,7 @@ private fun CoordinatorCard( // Said next to it, every time, because a name on a settings // screen reads as verified and this one is not: §8.5 makes // the pubkey the identity and nothing else. - text = stringRes(R.string.cordn_coordinators_server_claim), + text = stringRes(Res.string.cordn_coordinators_server_claim), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -333,7 +367,7 @@ private fun CoordinatorCard( infoChecked = true } }) { - Text(stringRes(R.string.cordn_coordinators_identify)) + Text(stringRes(Res.string.cordn_coordinators_identify)) } Spacer(Modifier.weight(1f)) @@ -345,14 +379,14 @@ private fun CoordinatorCard( IconButton(onClick = { menuOpen = true }) { Icon( symbol = MaterialSymbols.MoreVert, - contentDescription = stringRes(R.string.cordn_coordinators_more), + contentDescription = stringRes(Res.string.cordn_coordinators_more), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant, ) } DropdownMenu(expanded = menuOpen, onDismissRequest = { menuOpen = false }) { DropdownMenuItem( - text = { Text(stringRes(R.string.cordn_coordinators_remove)) }, + text = { Text(stringRes(Res.string.cordn_coordinators_remove)) }, onClick = { menuOpen = false scope.launch { runtime.forget(config.pubKey) } @@ -361,7 +395,7 @@ private fun CoordinatorCard( DropdownMenuItem( text = { Text( - text = stringRes(R.string.cordn_coordinators_purge), + text = stringRes(Res.string.cordn_coordinators_purge), color = MaterialTheme.colorScheme.error, ) }, @@ -378,14 +412,14 @@ private fun CoordinatorCard( if (confirmingPurge) { AlertDialog( onDismissRequest = { confirmingPurge = false }, - title = { Text(stringRes(R.string.cordn_coordinators_purge_title)) }, - text = { Text(stringRes(R.string.cordn_coordinators_purge_body)) }, + title = { Text(stringRes(Res.string.cordn_coordinators_purge_title)) }, + text = { Text(stringRes(Res.string.cordn_coordinators_purge_body)) }, confirmButton = { TextButton(onClick = { confirmingPurge = false scope.launch { runtime.purge(config.pubKey) } }) { - Text(stringRes(R.string.cordn_coordinators_purge), color = MaterialTheme.colorScheme.error) + Text(stringRes(Res.string.cordn_coordinators_purge), color = MaterialTheme.colorScheme.error) } }, dismissButton = { @@ -409,10 +443,10 @@ private fun CoordinatorCard( private fun HealthLine(state: CoordinatorHealth.State) { val text = when { - state.isUnknown -> stringRes(R.string.cordn_coordinators_health_unknown) - state.isDown -> stringRes(R.string.cordn_coordinators_health_down, state.consecutiveFailures) - state.consecutiveFailures > 0 -> stringRes(R.string.cordn_coordinators_health_retrying) - else -> stringRes(R.string.cordn_coordinators_health_ok) + state.isUnknown -> stringRes(Res.string.cordn_coordinators_health_unknown) + state.isDown -> stringRes(Res.string.cordn_coordinators_health_down, state.consecutiveFailures) + state.consecutiveFailures > 0 -> stringRes(Res.string.cordn_coordinators_health_retrying) + else -> stringRes(Res.string.cordn_coordinators_health_ok) } Text( @@ -447,10 +481,10 @@ private fun DiscoverCoordinators( var result by remember { mutableStateOf(null) } var busy by remember { mutableStateOf(false) } var error by remember { mutableStateOf(null) } - val failed = stringRes(R.string.cordn_coordinators_discover_failed) + val failed = stringRes(Res.string.cordn_coordinators_discover_failed) Text( - text = stringRes(R.string.cordn_coordinators_discover_explainer), + text = stringRes(Res.string.cordn_coordinators_discover_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -475,7 +509,7 @@ private fun DiscoverCoordinators( CircularProgressIndicator(Modifier.size(16.dp), strokeWidth = 2.dp) Spacer(Modifier.width(8.dp)) } - Text(stringRes(R.string.cordn_coordinators_discover_action)) + Text(stringRes(Res.string.cordn_coordinators_discover_action)) } error?.let { Text(it, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error) } @@ -497,11 +531,11 @@ private fun DiscoverCoordinators( Text( text = if (found.unreachable.isEmpty()) { - stringRes(R.string.cordn_coordinators_discover_none) + stringRes(Res.string.cordn_coordinators_discover_none) } else { // "Nobody is announcing" and "we were not told" are // different answers and only one of them is final. - stringRes(R.string.cordn_coordinators_discover_unheard, found.unreachable.size) + stringRes(Res.string.cordn_coordinators_discover_unheard, found.unreachable.size) }, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -529,19 +563,19 @@ private fun RenameCoordinatorDialog( AlertDialog( onDismissRequest = onDismiss, - title = { Text(stringRes(R.string.cordn_coordinators_rename)) }, + title = { Text(stringRes(Res.string.cordn_coordinators_rename)) }, text = { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { OutlinedTextField( value = input, onValueChange = { input = it }, - label = { Text(stringRes(R.string.cordn_coordinators_label)) }, + label = { Text(stringRes(Res.string.cordn_coordinators_label)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) Text( // The same caution the add form gives, for the same reason. - text = stringRes(R.string.cordn_coordinators_label_note), + text = stringRes(Res.string.cordn_coordinators_label_note), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -549,7 +583,7 @@ private fun RenameCoordinatorDialog( }, confirmButton = { TextButton(onClick = { onSave(input.trim().ifEmpty { null }) }) { - Text(stringRes(R.string.cordn_info_save)) + Text(stringRes(Res.string.cordn_info_save)) } }, dismissButton = { @@ -601,7 +635,7 @@ private fun DiscoveredCard( Text( // Staleness matters more here than anywhere: the last live // survey found most announcements were months-dead demos. - text = stringRes(R.string.cordn_coordinators_discover_seen, timeAgoNoDot(offer.announcedAt).trim()), + text = stringRes(Res.string.cordn_coordinators_discover_seen, timeAgoNoDot(offer.announcedAt).trim()), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -619,7 +653,7 @@ private fun DiscoveredCard( enabled = !busy, modifier = Modifier.padding(top = 4.dp), ) { - Text(stringRes(R.string.cordn_coordinators_discover_add)) + Text(stringRes(Res.string.cordn_coordinators_discover_add)) } } } @@ -633,7 +667,7 @@ private fun AddCoordinator(runtime: CordnRuntime) { var labelInput by remember { mutableStateOf("") } var error by remember { mutableStateOf(null) } var busy by remember { mutableStateOf(false) } - val failed = stringRes(R.string.cordn_coordinators_add_failed) + val failed = stringRes(Res.string.cordn_coordinators_add_failed) val config = remember(pubKeyInput, relaysInput, labelInput) { @@ -652,7 +686,7 @@ private fun AddCoordinator(runtime: CordnRuntime) { pubKeyInput = it error = null }, - label = { Text(stringRes(R.string.cordn_create_coordinator_pubkey)) }, + label = { Text(stringRes(Res.string.cordn_create_coordinator_pubkey)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) @@ -662,14 +696,14 @@ private fun AddCoordinator(runtime: CordnRuntime) { relaysInput = it error = null }, - label = { Text(stringRes(R.string.cordn_create_coordinator_relays)) }, + label = { Text(stringRes(Res.string.cordn_create_coordinator_relays)) }, singleLine = false, modifier = Modifier.fillMaxWidth(), ) OutlinedTextField( value = labelInput, onValueChange = { labelInput = it }, - label = { Text(stringRes(R.string.cordn_coordinators_label)) }, + label = { Text(stringRes(Res.string.cordn_coordinators_label)) }, singleLine = true, modifier = Modifier.fillMaxWidth(), ) @@ -677,7 +711,7 @@ private fun AddCoordinator(runtime: CordnRuntime) { Text( // A label is ours, never theirs. A coordinator cannot prove a name and // this one is not asked for one. - text = stringRes(R.string.cordn_coordinators_label_note), + text = stringRes(Res.string.cordn_coordinators_label_note), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -705,6 +739,6 @@ private fun AddCoordinator(runtime: CordnRuntime) { enabled = !busy && config != null, modifier = Modifier.fillMaxWidth(), ) { - Text(stringRes(R.string.cordn_coordinators_add_action)) + Text(stringRes(Res.string.cordn_coordinators_add_action)) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt index 5f33e13b24..b3ebf82863 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnKeyPackagesScreen.kt @@ -47,14 +47,28 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CoordinatorConfig import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.cordn_coordinators_none +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_disclosure +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_explainer +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_last_resort_no +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_last_resort_yes +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_orphans +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_orphans_body +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_publish +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_publish_last_resort import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_section +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_summary import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_title +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_topup_note +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_withdraw_all +import com.vitorpamplona.amethyst.commons.resources.cordn_keypackages_withdraw_orphans import com.vitorpamplona.amethyst.commons.ui.components.EmptyState import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton @@ -106,8 +120,8 @@ fun CordnKeyPackagesScreen( ) { padding -> if (runtime == null) { EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold @@ -125,7 +139,7 @@ fun CordnKeyPackagesScreen( verticalArrangement = Arrangement.spacedBy(20.dp), ) { Text( - text = stringRes(R.string.cordn_keypackages_explainer), + text = stringRes(Res.string.cordn_keypackages_explainer), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -140,7 +154,7 @@ fun CordnKeyPackagesScreen( SettingsFormBlock { if (coordinators.isEmpty()) { Text( - text = stringRes(R.string.cordn_coordinators_none), + text = stringRes(Res.string.cordn_coordinators_none), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -169,7 +183,7 @@ private fun CoordinatorKeyPackages( var rows by remember(config.pubKey) { mutableStateOf?>(null) } var busy by remember(config.pubKey) { mutableStateOf(false) } var error by remember(config.pubKey) { mutableStateOf(null) } - val failed = stringRes(R.string.cordn_keypackages_failed) + val failed = stringRes(Res.string.cordn_keypackages_failed) suspend fun reload() { busy = true @@ -204,15 +218,15 @@ private fun CoordinatorKeyPackages( val hasLastResort = loaded.any { it.lastResort } Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_keypackages_summary, single, single), + text = pluralStringRes(Res.plurals.cordn_keypackages_summary, single, single), style = MaterialTheme.typography.bodyMedium, ) Text( text = if (hasLastResort) { - stringRes(R.string.cordn_keypackages_last_resort_yes) + stringRes(Res.string.cordn_keypackages_last_resort_yes) } else { - stringRes(R.string.cordn_keypackages_last_resort_no) + stringRes(Res.string.cordn_keypackages_last_resort_no) }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, @@ -225,11 +239,11 @@ private fun CoordinatorKeyPackages( ) { Column(Modifier.padding(12.dp)) { Text( - text = pluralStringRes(LocalContext.current, R.plurals.cordn_keypackages_orphans, orphans.size, orphans.size), + text = pluralStringRes(Res.plurals.cordn_keypackages_orphans, orphans.size, orphans.size), style = MaterialTheme.typography.titleSmall, ) Text( - text = stringRes(R.string.cordn_keypackages_orphans_body), + text = stringRes(Res.string.cordn_keypackages_orphans_body), style = MaterialTheme.typography.bodySmall, ) TextButton(onClick = { @@ -242,7 +256,7 @@ private fun CoordinatorKeyPackages( reload() } }) { - Text(stringRes(R.string.cordn_keypackages_withdraw_orphans)) + Text(stringRes(Res.string.cordn_keypackages_withdraw_orphans)) } } } @@ -251,7 +265,7 @@ private fun CoordinatorKeyPackages( Text( // Above the buttons, because it is the part that cannot be taken // back: §8.4 makes publishing an attributable, permanent record. - text = stringRes(R.string.cordn_keypackages_disclosure), + text = stringRes(Res.string.cordn_keypackages_disclosure), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) @@ -274,7 +288,7 @@ private fun CoordinatorKeyPackages( }, enabled = !busy, ) { - Text(stringRes(R.string.cordn_keypackages_publish)) + Text(stringRes(Res.string.cordn_keypackages_publish)) } OutlinedButton( onClick = { @@ -289,7 +303,7 @@ private fun CoordinatorKeyPackages( }, enabled = !busy && !hasLastResort, ) { - Text(stringRes(R.string.cordn_keypackages_publish_last_resort)) + Text(stringRes(Res.string.cordn_keypackages_publish_last_resort)) } if (loaded.isNotEmpty()) { TextButton( @@ -305,7 +319,7 @@ private fun CoordinatorKeyPackages( }, enabled = !busy, ) { - Text(stringRes(R.string.cordn_keypackages_withdraw_all), color = MaterialTheme.colorScheme.error) + Text(stringRes(Res.string.cordn_keypackages_withdraw_all), color = MaterialTheme.colorScheme.error) } } } @@ -313,7 +327,7 @@ private fun CoordinatorKeyPackages( Text( // The rule CordnRuntime.maintainKeyPackages implements, said where // someone can see that it applies to them. - text = stringRes(R.string.cordn_keypackages_topup_note), + text = stringRes(Res.string.cordn_keypackages_topup_note), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt index 86aab6c17c..f4ac911967 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnLinkScreen.kt @@ -45,7 +45,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CordnLinkInspection import com.vitorpamplona.amethyst.commons.cordn.ui.CordnExposureCard import com.vitorpamplona.amethyst.commons.resources.Res @@ -60,6 +59,11 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_link_no_coordinator import com.vitorpamplona.amethyst.commons.resources.cordn_link_not_joinable import com.vitorpamplona.amethyst.commons.resources.cordn_link_paste import com.vitorpamplona.amethyst.commons.resources.cordn_link_relays +import com.vitorpamplona.amethyst.commons.resources.cordn_link_request +import com.vitorpamplona.amethyst.commons.resources.cordn_link_request_disclosure +import com.vitorpamplona.amethyst.commons.resources.cordn_link_request_failed +import com.vitorpamplona.amethyst.commons.resources.cordn_link_request_sent +import com.vitorpamplona.amethyst.commons.resources.cordn_link_scan import com.vitorpamplona.amethyst.commons.resources.cordn_link_section_input import com.vitorpamplona.amethyst.commons.resources.cordn_link_title import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav @@ -102,8 +106,8 @@ fun CordnLinkScreen( var requesting by remember { mutableStateOf(false) } val runtime = accountViewModel.account.cordnRuntime val scope = rememberCoroutineScope() - val requestFailed = stringRes(R.string.cordn_link_request_failed) - val asked = stringRes(R.string.cordn_link_request_sent) + val requestFailed = stringRes(Res.string.cordn_link_request_failed) + val asked = stringRes(Res.string.cordn_link_request_sent) var scanning by remember { mutableStateOf(false) } val clipboard = LocalClipboardManager.current @@ -163,7 +167,7 @@ fun CordnLinkScreen( Text(stringResource(Res.string.cordn_link_paste)) } OutlinedButton(onClick = { scanning = true }) { - Text(stringRes(R.string.cordn_link_scan)) + Text(stringRes(Res.string.cordn_link_scan)) } if (input.isNotEmpty()) { OutlinedButton( @@ -265,7 +269,7 @@ fun CordnLinkScreen( enabled = !requesting, modifier = Modifier.fillMaxWidth(), ) { - Text(stringRes(R.string.cordn_link_request)) + Text(stringRes(Res.string.cordn_link_request)) } Text( @@ -274,7 +278,7 @@ fun CordnLinkScreen( // KeyPackage under this account's own key and tells // the coordinator this account wants into this // group, whether or not anyone ever answers (§8.4). - text = stringRes(R.string.cordn_link_request_disclosure), + text = stringRes(Res.string.cordn_link_request_disclosure), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt index db9b3d4d4e..6c55c2bbb0 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/cordn/CordnMigrateScreen.kt @@ -47,9 +47,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.cordn.CordnMigration import com.vitorpamplona.amethyst.commons.resources.Res +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable +import com.vitorpamplona.amethyst.commons.resources.cordn_group_unavailable_detail import com.vitorpamplona.amethyst.commons.resources.cordn_migrate_cancel import com.vitorpamplona.amethyst.commons.resources.cordn_migrate_cancel_desc import com.vitorpamplona.amethyst.commons.resources.cordn_migrate_code_note @@ -119,8 +120,8 @@ fun CordnMigrateScreen( ) { padding -> if (runtime == null) { EmptyState( - title = stringRes(R.string.cordn_group_unavailable), - description = stringRes(R.string.cordn_group_unavailable_detail), + title = stringRes(Res.string.cordn_group_unavailable), + description = stringRes(Res.string.cordn_group_unavailable_detail), modifier = Modifier.padding(padding), ) return@Scaffold diff --git a/amethyst/src/main/res/values-hi-rIN/strings.xml b/amethyst/src/main/res/values-hi-rIN/strings.xml index 60879f7b96..8343082ebf 100644 --- a/amethyst/src/main/res/values-hi-rIN/strings.xml +++ b/amethyst/src/main/res/values-hi-rIN/strings.xml @@ -353,322 +353,4 @@ ध्वनि सक्रिय। मौन करने के लिए टाँकें चलाएँ विराम - आपने अपना %1$s अन्य क्रमक में परिवर्तित किया - हटाए गए (%1$s) - जोडे गए (%1$s) - परिवर्तित (%1$s) - आपने सभी निजी (रहस्यीकृत) वस्तुओं को हटा दिया। - आपने निजी (रहस्यीकृत) वस्तुओं का परिवर्तन भी किया। उनकी तुलना यहाँ नहीं की जा सकती। - आपने निजी (रहस्यीकृत) वस्तुओं को जोडा। - सुरक्षित संस्करण पुनःस्थापन - इस यन्त्र पर - नया संस्करण - स्थापित नहीं - %1$s हटाए गए - %1$s जोडे गए - %1$s परिवर्तित - - आपने %1$d व्यक्ति का अनुगमन हटाया - आपने %1$d व्यक्तियों का अनुगमन हटाए - - स्वीकार - %1$s अद्यतनकृत - %1$s पारित - अन्य क्रमक में परिवर्तित। %1$s - रखें %1$s - पुनःस्थापन %1$s - पुनःमौन %1$s - पुनःजुडें %1$s - परिचय पुनःस्थापध - पुनःप्रसारक पुनःस्थापन - %1$s रखे गए - %1$s परित्यक्त - %1$s नए - परित्यक्त। %1$s - नए। %1$s - सम्पादित। %1$s - %1$s लोग खोजें - यहाँ कुछ नहीं - %1$s मौनावस्था हटाए गए - ये पुनः आपके सूचनावलियों तक अभिगम्य - %1$s नए मौनकृत - शब्द तथा विषयसूचक - %1$s तथा %2$s अधिक - आपने सभी निजी वस्तुओं को हटा दिया - वे रहस्यीकृत हैं। इसलिए केवल आप देख सकते हैं कि वे क्या थे। पुनःस्थापन से सब लौटके आ जाएँगे। - आपने वस्तुओं को निजी किया - वे अब रहस्यीकृत हैं। जो कि सम्भाव्यतः ऊपर के सार्वजनिक वस्तुओं का गन्तव्य था। - आपने निजी वस्तुओं का परिवर्तन किया - वे रहस्यीकृत हैं। इसलिए उनकी तुलना यहाँ नहीं की जा सकती। - चला गया - नव्य - परित्यक्त - स्थानान्तरित - इकाई - शेष - पुनःनामकृत - निर्गतपेटिका - आप जहाँ प्रकाशित करते हैं - आगतपेटिका - जहाँ अन्य आप तक अभिगमन करते हैं - ग्राहक कुंचिका प्रतिस्थापित - ग्राहक कुंचिका हटाया गया - नटज्साप आगे से इस कुंचिका से बद्ध होंगे। यदि इस यन्त्र में वह नहीं है तो आप सम्भाव्यतः उनको यहाँ नहीं चुका सकते। - शेष - जुड गए - पुनःनामकृत - पूर्वतः %1$s था - पुनःबाधित करें %1$s को - सूचनावलियाँ पुनःस्थापन - विषय पुनःस्थापन - स्थल पुनःस्थापन - प्रदाता पुनःस्थापन - धनकोष पुनःस्थापन - रखे गए - ग्रहण मध्य - सूचीबद्ध - खोज मध्य - अभिलेखन मध्य - विश्वसनीय - अविश्वसनीय - %1$s अबाधित - अमेथिस्ट पुनः उनसे जुडेगा - अब से बाधित नहीं - नव्यतः बाधित - अभी भी बाधित - अनुमत - स्थानान्तरित - सूचनावली - विषय हटाए गए - स्थल हटाए गए - नव्य - विषयसूचक जिनका आप अनुगमन करते हैं - स्थल जिनका आप अनुगमन करते हैं - %2$s में से %1$s सेवाएँ परिवर्तित - वे अब अन्य व्यक्ति से आते है। अथवा किसी से नहीं - सेवा - श्रेणी - अनुचर - विषयसूची - श्रेणीयाँ तथा अनुचर गिनती तथा कचरालेख छालन जो आप देखते हैं इन प्रदाताओं से आते हैं। - - आपको भुगतान करने की %1$d विधि हटाया गया - आपको भुगतान करने की %1$d विधियाँ हटाए गए - - - %1$d प्रस्ताव हटाया गया - %1$d प्रस्ताव हटाए गए - - लोग जो आपको भुगतान करते हैं उसी को देखते हैं जो इस सूची में है। - बोल्ट॰बारह प्रस्ताव - आपने उसे रिक्त किया - आपने उसे बनाया - आपने उसे परिवर्तित किया - आपके धनकोष के टकसाल तथा कुंचिकाएँ आपके लिए रहस्यीकृत हैं। इसलिए उनकी तुलना वस्तु प्रति वस्तु यहाँ नहीं की जा सकती। पुनःस्थापन उन्हीं को लौट डालेगा जिनका अभिलेखन इस यन्त्र ने किया। - आपके कोंकोर्ड समुदाय आपके लिए रहस्यीकृत हैं। इसलिए उनकी तुलना यहाँ नहीं की जा सकती। पुनःस्थापन उन्हीं को लौट डालेगा जिनका अभिलेखन इस यन्त्र ने किया। - - आपने %1$d की मौनावस्था हटाया - आपने %1$d की मौनावस्था हटाए - - - आपने %1$d परिचय प्रपत्रस्थान हटाया - आपने %1$d परिचय प्रपत्रस्थान हटाए - - - आपने %1$d सार्वजनिक पुनःप्रसारक हटाया - आपने %1$d सार्वजनिक पुनःप्रसारकों को हटाए - - - आपने %1$d सीधासन्देश पुनःप्रसारक हटाया - आपने %1$d सीधासन्देश पुनःप्रसारकों को हटाए - - - आपने %1$d समूहचर्चा कुंचिका पुनःप्रसारक हटाया - आपने %1$d समूहचर्चा कुंचिका पुनःप्रसारकों को हटाए - - - आपने %1$d खोज पुनःप्रसारक हटाया - आपने %1$d खोज पुनःप्रसारकों को हटाए - - - आपने %1$d अनुक्रमणीकार पुनःप्रसारक हटाया - आपने %1$d अनुक्रमणीकार पुनःप्रसारकों को हटाए - - - आपने %1$d पुनःप्रसारक सूचनावली हटाया - आपने %1$d पुनःप्रसारक सूचनावलियाँ हटाए - - - आपने %1$d निजी पुनःप्रसारक हटाया - आपने %1$d निजी पुनःप्रसारकों को हटाए - - - आपने %1$d पुनःप्रसारक पर विश्वास करना रोक दिया - आपने %1$d पुनःप्रसारकों पर विश्वास करना रोक दिए - - - आपने %1$d पुनःप्रसारक अबाधित किया - आपने %1$d पुनःप्रसारकों को अबाधित किए - - - आपने %1$d सार्वजनिक चर्चा छोड दिया - आपने %1$d सार्वजनिक चर्चाओं को छोड दिए - - - आपने %1$d समुदाय छोड दिया - आपने %1$d समुदायों को छोड दिए - - - आपने %1$d चर्चाशाला छोड दिया - आपने %1$d चर्चाशालाओं को छोड दिए - - - आपने %1$d समूह छोड दिया - आपने %1$d समूहों को छोड दिए - - - आपने %1$d इष्ट सूचनावली हटाया - आपने %1$d इष्ट सूचनावलियों को हटाए - - - आपने %1$d विषयसूचक का अनुगमन हटाया - आपने %1$d विषयसूचकों का अनुगमन हटाए - - - आपने %1$d स्थल का अनुगमन हटाया - आपने %1$d स्थलों का अनुगमन हटाए - - - आपने %1$d विश्वाससेवा प्रदाता परिवर्तित किया - आपने %1$d विश्वाससेवाओं के प्रदाता को परिवर्तित किया - - - आपने %1$d नटज्साप टकसाल हटाया - आपने %1$d नटज्साप टकसालों को हटाए - - - आपने %1$d भुगतान प्राप्त करने की विधि हटाया - आपने %1$d भुगतान प्राप्त करने के विधियों को हटाए - - - आपने %1$d बोल्ट॰बारह प्रस्ताव हटाया - आपने %1$d बोल्ट॰बारह प्रस्तावों को हटाए - - - %1$s तथा %2$d जोडा - %1$s तथा %2$d जोडे - - - %1$s तथा %2$d का अनुगमन किया - %1$s तथा %2$d का अनुगमन किए - - - %1$s तथा %2$d को मौनकृत किया - %1$s तथा %2$d को मौनकृत किए - - - %1$s तथा %2$d से जुडे - %1$s तथा %2$d से जुडे - - - %1$s तथा %2$d बाधित किया - %1$s तथा %2$d को बाधित किए - - आपके अमेथिस्ट समचरणीकृत क्रमक स्थापना विकल्पों को परिवर्तित किया गया एक अन्य क्रमक में और वह अमेथिस्ट नहीं था। इससे समस्याएँ उत्पन्न हो सकते हैं। - आपने अपनी नटज्साप कुंचिका का प्रतिस्थापन किया - आपने अपनी नटज्साप कुंचिका को हटाया - आपने अपना काशयू धनकोष रिक्त किया - आपने अपने काशयू धनकोष को परिवर्तित किया - आपने अपनी कोंकोर्ड सूची रिक्त की - आपने अपनी कोंकोर्ड सूची का परिवर्तन किया - नया संस्करण का उपयोग करें - पठनेवशक्य - लेखनेवशक्य - पठन तथा लेखन - परिचय - आपका नाम चित्र चरित तथा भुगतान पते। जैसे सब को दिखते हैं वैसे। - अनुचरण सूची - निर्णय करता है किसके पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। - मौन सूची - छिपाता है लोग शब्द विषयसूचक तथा सूत्र उन सब में से जो आप देखते हैं। - सार्वजनिक पुनःप्रसारक सूची - सबको बताता है आपके पत्र कहाँ प्राप्त करें तथा आपको उत्तर तथा उल्लेखों को कहाँ भेजें। - सीधासन्देश पुनःप्रसारक सूची - जहाँ अन्य आपके निजी सन्देश भेजते हैं। - समूहचर्चा कुंचिका पुनःप्रसारक - जहाँ अन्य उन कुंचिकाओं को प्राप्त करते हैं आपको रहस्यीकृत समूहचर्चाओं में जोडने के लिए। - खोज पुनःप्रसारक सूची - उपयुक्त पुनःप्रसारक जब आप खोजते हैं। - अनुक्रमणीकार पुनःप्रसारक सूची - पुनःप्रसारक उपयुक्त अन्य लोगों के परिचय तथा पुनःप्रसारक सूचियों को प्राप्त करने के लिए। - इष्ट पुनःप्रसारक सूचनावलियाँ - पुनःप्रसारक जिनका आप वीक्षण करते हैं सूचनावलियों के रूप में। - बाधित पुनःप्रसारक सूची - पुनःप्रसारक जिनसे यह क्रमक कभी भी संयोजन नहीं करता। - विश्वसनीय पुनःप्रसारक सूची - पुनःप्रसारक जिनपर आप पर्याप्त विश्वास करते हैं बिना पूछे उनसे संयोजन करने के लिए। - निजी पुनःप्रसारक सूची - जहाँ आपके पाण्डुलिपियाँ तथा निजी जानकारी रखे जाते हैं। - समचरणीकृत क्रमक स्थापना विकल्प - अमेथिस्ट स्थापना विकल्प समचरणीकृत आपके यन्त्रों में। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। - सार्वजनिक चर्चा सूची - सार्वजनिक चर्चाएँ जिनसे आप जुडे। - समुदाय सूची - समुदाय जिनसे आप जुडे। - अनुचरित विषयसूचक - विषयसूचक जिससे युक्त पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। - अनुचरित स्थान - स्थान जहाँ से पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। - इष्ट सूचनावली सूची - कलनविध्यात्मक सूचनावलियाँ जिनको आपने अभिलेखित किया। - अस्थायी चर्चा सूची - अस्थायी चर्चा शालाएँ जिनसे आप जुडे। - समूह सूची - पुनःप्रसारक आधारित समूह जिनसे आप जुडे। - कोंकोर्ड समुदाय सूची - कोंकोर्ड समुदाय जिनसे आप जुडे। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। - विश्वाससेवा प्रदाता सूची - सेवाएँ जिनपर आप विश्वास करते है आपके लिए लोगों का सत्यापन तथा श्रेणीकरण करने के लिए। - काशयू धनकोष - आपके ईकाश धनकोष स्थापना विकल्प तथा टकसाल। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। - नटज्साप प्राप्ती स्थापना विकल्प - टकसाल तथा कुंचिका जिनका उपयोग अन्य करते हैं आपको नटज्साप भेजने के लिए। - भुगतान पते - विधियाँ जिनसे अन्य लोग आपको भुगतान कर सके। - बोल्ट॰बारह प्रस्ताव - लैटनिंग प्रस्ताव जिनका उपयोग करके अन्य लोग आपको भुगतान करते हैं। - सूची - इस यन्त्र पर अभिलेखित सूची। - परिचय प्रपत्रस्थान - लोग - विषयसूचक - शब्द - सूत्र - सार्वजनिक चर्चाएँ - समुदाय - सूचनावलियाँ - स्थान - पुनःप्रसारक - समूह - चर्चा शालाएँ - विश्वाससेवा प्रदाता - टकसाल - नटज्साप कुंचिकाएँ - भुगतान पते - प्रस्ताव - सम्बन्धित व्यक्तिगण - अन्य प्रविष्टियाँ - प्रयोक्तानाम - प्रदर्शन नाम - जानकारी - चित्र - ध्वज - जालस्थान - नोस्टर पता - लैटनिंग पता - लैटनिंग जालपता - सर्वनाम - जन्मदिन - क्लिंक॰ प्रस्ताव - क्रमचर चिह्न diff --git a/amethyst/src/main/res/values-hu-rHU/strings.xml b/amethyst/src/main/res/values-hu-rHU/strings.xml index e7a9da119d..37bd743202 100644 --- a/amethyst/src/main/res/values-hu-rHU/strings.xml +++ b/amethyst/src/main/res/values-hu-rHU/strings.xml @@ -353,322 +353,4 @@ Hang bekapcsolva. Koppintson a némításhoz Lejátszás Szüneteltetés - Ön módosította a következőt: %1$s, egy másik alkalmazásban - Eltávolítva (%1$s) - Hozzáadva (%1$s) - Módosítva (%1$s) - Ön eltávolította az összes privát (titkosított) elemet. - Ön privát (titkosított) elemeket is módosított. Ezek itt nem hasonlíthatók össze. - Ön privát (titkosított) elemeket adott hozzá. - Mentett verzió visszaállítása - Ezen az eszközön - Új verzió - Nincs beállítva - %1$s eltávolítva - %1$s hozzáadva - %1$s módosítva - - %1$d személyt nem követ többé - %1$d személyt nem követ többé - - Elfogadás - %1$s frissítve - %1$s törölve - Módosítva egy másik alkalmazásban · %1$s - %1$s megtartása - %1$s visszaállítása - %1$s újbóli némítása - Újbóli csatlakozás ehhez: %1$s - Profil visszaállítása - Átjátszók visszaállítása - %1$s megtartva - %1$s elvetve - %1$s új - Elvetve · %1$s - Új · %1$s - Szerkesztve · %1$s - %1$s személy keresése - Itt nincs semmi - %1$s némítása feloldva - Ezek újra megjelenhetnek a hírfolyamaiban - %1$s újonnan némítva - Szavak és kulcsszavak - %1$s és %2$s további - Ön eltávolította az összes privát elemet - Titkosítva vannak, így csak Ön láthatja, mik voltak. A visszaállítás mindet visszahozza. - Ön priváttá tette az elemeket - Most már titkosítva vannak, valószínűleg ide kerültek a fenti nyilvános elemek. - Ön módosította a privát elemeket - Titkosítva vannak, így itt nem hasonlíthatók össze. - Eltűnt - Új - Elvetve - Áthelyezve - Egységek - Elhagyva - Átnevezve - Kimenő - ahol közzétesz - Bejövő - ahol mások elérik Önt - Fogadási kulcs lecserélve - Fogadási kulcs eltávolítva - A nutzapok ehhez az új kulcshoz lesznek kötve. Ha ez az eszköz nem rendelkezik vele, lehet, hogy itt nem tudja beváltani őket. - elhagyta a csoportot - csatlakozott - átnevezte - „%1$s” volt - %1$s újbóli letiltása - Hírfolyamok visszaállítása - Témák visszaállítása - Helyek visszaállítása - Szolgáltatók visszaállítása - Pénztárca visszaállítása - megtartva - Fogadás - Listázva - Keresés - Tárolás - Megbízható - Nem megbízható - %1$s letiltása feloldva - Az Amethyst újra kapcsolódni fog hozzájuk - Már nincs letiltva - Újonnan letiltva - Továbbra is le van tiltva - Engedélyezve - Áthelyezve - Hírfolyam - eltűnt témák - eltűnt helyek - új - Ön által követett kulcsszavak - Ön által követett helyek - %2$s szolgáltatásból %1$s módosult - Most már valaki mástól vagy senkitől sem származnak - Szolgáltatás - Rang - Követők - Témák - A látott rangok, követőszámok és a kéretlen tartalomszűrés ezektől a szolgáltatóktól származnak. - - %1$d fizetési mód eltávolítva - %1$d fizetési mód eltávolítva - - - %1$d ajánlat eltávolítva - %1$d ajánlat eltávolítva - - A fizető emberek csak azt látják, ami ebben a listában van. - BOLT12 ajánlat - Ön kiürítette - Ön hozta létre - Ön módosította - A saját pénztárca pénzverdéi és kulcsai Önhöz vannak titkosítva, így itt nem hasonlíthatók össze tételesen. A visszaállítás pontosan azt hozza vissza, amit ez az eszköz mentett. - A Concord közösségei Önhöz vannak titkosítva, így itt nem hasonlíthatók össze. A visszaállítás pontosan azt hozza vissza, amit ez az eszköz mentett. - - Ön %1$d dolog némítását oldotta fel - %1$d dolog némítását oldotta fel - - - Ön %1$d profilmezőt távolított el - %1$d profilmezőt távolított el - - - Ön %1$d nyilvános átjátszót távolított el - %1$d nyilvános átjátszót távolított el - - - Ön %1$d privát üzenetátjátszót távolított el - %1$d privát üzenet átjátszót távolított el - - - Ön %1$d csoportos csevegési kulcsátjátszót távolított el - %1$d csoportcsevegés kulcs átjátszót távolított el - - - Ön %1$d kereső átjátszót távolított el - %1$d kereső átjátszót távolított el - - - Ön %1$d indexelő átjátszót távolított el - %1$d indexelő átjátszót távolított el - - - Ön %1$d átjátszó-hírfolyamot távolított el - %1$d átjátszó hírfolyamot távolított el - - - Ön %1$d privát átjátszót távolított el - %1$d privát átjátszót távolított el - - - Ön %1$d átjátszóban nem bízik többé - %1$d átjátszóban nem bízik többé - - - Ön %1$d átjátszó letiltását oldotta fel - %1$d átjátszó blokkolását oldotta fel - - - Ön %1$d nyilvános csevegést hagyott el - %1$d nyilvános csevegést hagyott el - - - Ön %1$d közösséget hagyott el - %1$d közösséget hagyott el - - - Ön %1$d csevegőszobát hagyott el - %1$d csevegőszobát hagyott el - - - Ön %1$d csoportot hagyott el - %1$d csoportot hagyott el - - - Ön %1$d kedvenc hírfolyamot távolított el - %1$d kedvenc hírfolyamot távolított el - - - Ön %1$d kulcsszót nem követ többé - %1$d hashtaget nem követ többé - - - Ön %1$d helyet nem követ többé - %1$d helyet nem követ többé - - - Ön %1$d bizalmi szolgáltatás szolgáltatóját módosította - %1$d bizalmi szolgáltatás szolgáltatóját változtatta meg - - - Ön %1$d nutzap pénzverdét távolított el - %1$d nutzap pénzverdét távolított el - - - Ön %1$d fizetési módot távolított el - %1$d fizetési módot távolított el - - - Ön %1$d BOLT12 ajánlatot távolított el - %1$d BOLT12 ajánlatot távolított el - - - %1$s és %2$d hozzáadva - %1$s és %2$d hozzáadva - - - %1$s és %2$d követve - %1$s és %2$d követve - - - %1$s és %2$d némítva - %1$s és %2$d némítva - - - %1$s és %2$d csatlakozva - %1$s és %2$d csatlakozva - - - %1$s és %2$d letiltva - %1$s és %2$d letiltva - - A szinkronizált Amethyst alkalmazásbeállításai egy másik, nem Amethyst alkalmazásban módosultak. Ez problémákat okozhat. - Ön lecserélte a nutzap kulcsát - Ön eltávolította a nutzap kulcsát - Ön kiürítette a Cashu pénztárcáját - Ön módosította a Cashu pénztárcáját - Ön kiürítette a Concord listáját - Ön módosította a Concord listáját - Új verzió használata - csak olvasható - csak írható - olvasás és írás - profil - Az Ön neve, képe, bemutatkozása és fizetési címei, ahogy mindenki látja őket. - követési lista - Meghatározza, kinek a bejegyzései jelenjenek meg a kezdőlapon. - némítási lista - Elrejti a személyeket, szavakat, kulcsszavakat és beszélgetéseket mindenből, amit lát. - nyilvános átjátszólista - Megmondja mindenkinek, hol találhatók a bejegyzései, és hová küldjék a válaszokat és említéseket. - privát üzenet átjátszólista - Ahová mások kézbesítik a privát üzeneteit. - csoportos csevegési kulcsátjátszók - Ahol mások megtalálják a kulcsokat, hogy titkosított csoportos csevegésekhez adhassák Önt. - kereső átjátszólista - Kereséskor használt átjátszók. - indexelő átjátszólista - Azok az átjátszók, amelyeket mások profiljainak és átjátszólistáinak megtalálásához használnak. - kedvenc átjátszóhírfolyamok - Olyan átjátszók, amelyeket hírfolyamként böngész. - letiltott átjátszólista - Átjátszók, amelyekhez ez az alkalmazás soha nem kapcsolódik. - megbízható átjátszólista - Átjátszók, amelyekhez kérdezés nélkül kapcsolódhat. - privát átjátszólista - Ahol a piszkozatai és privát adatai tárolódnak. - szinkronizált alkalmazásbeállítások - Az eszközök között szinkronizált Amethyst-beállítások. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. - nyilvános csevegési lista - Nyilvános csevegések, amelyekhez csatlakozott. - közösséglista - Közösségek, amelyekhez csatlakozott. - követett kulcsszavak - Kulcsszavak, amelyek bejegyzései megjelennek a hírfolyamban. - követett helyek - Helyek, amelyek bejegyzései megjelennek a hírfolyamaiban. - kedvenc hírfolyamlista - Mentett algoritmus-hírfolyamok. - rövid életű csevegési lista - Rövid életű csevegőszobák, amelyekhez csatlakozott. - csoportlista - Átjátszó-alapú csoportok, amelyekhez csatlakozott. - Concord közösséglista - A Concord közösségek, amelyekhez csatlakozott. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. - bizalmi szolgáltatólista - A szolgáltatások, amelyekben megbízik, hogy rangsorolják és ellenőrizzék Önnek az embereket. - Cashu pénztárca - Az ecash pénztárca beállításai és pénzverdéi. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. - nutzap fogadási beállítások - A pénzverdék és a kulcs, amelyeket mások a nutzapok küldéséhez használnak az Ön számára. - fizetési címek - A módok, ahogy mások fizethetnek Önnek. - BOLT12 ajánlatok - A lightning ajánlatok, amelyeket mások a fizetéshez használnak az Ön számára. - lista - Egy listaelem ezen az eszközön mentve. - Profilmezők - Személyek - Kulcsszavak - Szavak - Beszélgetések - Nyilvános csevegések - Közösségek - Hírfolyamok - Helyek - Átjátszók - Csoportok - Csevegőszobák - Bizalmi szolgáltatók - Pénzverdék - Nutzap kulcsok - Fizetési címek - Ajánlatok - Kapcsolt identitások - Egyéb bejegyzések - Felhasználónév - Megjelenített név - Névjegy - Kép - Borító - Weboldal - Nostr-cím - Lightning-cím - LNURL - Névmások - Születésnap - CLINK-ajánlat - Bot jelölő diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index 601165a320..eda8c8fe1a 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -381,382 +381,4 @@ Dźwięk włączony. Kliknij, aby wyciszyć Odtwórz Pauza - Zmieniłeś %1$s w innej aplikacji - Usunięto (%1$s) - Dodano (%1$s) - Zmieniono (%1$s) - Usunąłeś wszystkie prywatne (zaszyfrowane) elementy. - Zmieniłeś również elementy prywatne (zaszyfrowane). Nie można ich tutaj porównać. - Dodano prywatne (zaszyfrowane) pozycje. - Przywróć zapisaną wersję - Na tym urządzeniu - Nowa wersja - Nie ustawiono - Usunięto %1$s - Dodano %1$s - %1$s zmieniono - - Przestałeś obserwować %1$d osobę - Przestałeś obserwować %1$d osób - Przestałeś obserwować %1$d osób - Przestałeś obserwować %1$d osoby - - Zaakceptuj - %1$s zaktualizowano - %1$s wyczyszczono - Zmieniono w innej aplikacji · %1$s - Zachowaj %1$s - Przywróć %1$s - Ponownie wycisz %1$s - Ponów %1$s - Przywróć profil - Przywróć transmitery - Zachowano %1$s - %1$s odrzuconych - %1$s nowych - Usunięte · %1$s - Nowe · %1$s - Edytowane · %1$s - Szukaj %1$s osób - Nic tu nie ma! - %1$s odblokowanych - Mogą one ponownie pojawić się w Twoich informacjach - %1$s nowo wyciszonych - Wyrazy & hasztagi - %1$s i %2$s więcej - Usunąłeś wszystkie prywatne elementy - Są zaszyfrowane, więc tylko Ty możesz zobaczyć, co to było. Odtworzenie przywróci je wszystkie. - Ustawiłeś te pozycje jako prywatne - Są teraz zaszyfrowane, co prawdopodobnie wyjaśnia, gdzie podziały się powyższe elementy publiczne. - Zmieniłeś prywatne elementy - Są zaszyfrowane, więc nie można ich tu porównać. - Zniknęła - Nowa - Usunięta - Przeniesiona - Jednostek - Zostało - Zmieniono nazwę - Skrzynka nadawcza - gdzie publikujesz - Skrzynka odbiorcza - gdzie inni docierają do Ciebie - Wymieniono klucz odbierający - Usunięto klucz odbierający - Nutzapy zostaną przypisane do tego nowego klucza. Jeśli urządzenie nie posiada tego klucza, może się okazać, że nie będzie można ich tutaj zrealizować. - zostało - dołączył(a) - zmieniono nazwę - było „%1$s” - Zablokuj %1$s ponownie - Przywróć kanały - Przywróć tematy - Przywróć miejsca - Przywróć dostawców - Przywróć portfel - zachowane - Pobieranie - Na Liście - Szukam - Przechowywanie - Zaufane - Niezaufane - %1$s odblokowane - Ametyst ponownie połączy się z nimi - Nie jest już zablokowana - Nowo zablokowana - Nadal zablokowana - Dozwolona - Przeniesiona - Kanał - tematy zniknęły - miejsca zniknęły - nowe - Hashtagi, które obserwujesz - Miejsca które obserwujesz - Zmieniono %1$s z %2$s serwisów - Teraz pochodzą od kogoś innego albo od nikogo - Serwis - Ranking - Obserwujący - Tematy - Rankingi, liczba obserwujących i filtrowanie spamu, które widzisz, pochodzą od tych dostawców. - - %1$d sposób płatności został usunięty - %1$d sposobów płatności zostało usuniętych - %1$d sposobów płatności zostało usuniętych - %1$d sposoby płatności zostały usunięte - - - %1$d oferta usunięta - %1$d ofert usunięto - %1$d ofert usunięto - %1$d oferty usunięte - - Osoby, które Ci płacą, widzą tylko to, co znajduje się na tej liście. - Oferta BOLT12 - Opróżniłeś to - Utworzyłeś to - Zmieniłeś to - Minty i klucze w Twoim portfelu są zaszyfrowane dla Ciebie, więc nie można ich tutaj porównać pozycja po pozycji. Przywrócenie danych powoduje przywrócenie dokładnie tego, co zostało zapisane na tym urządzeniu. - Twoje społeczności w Concord są dla Ciebie zaszyfrowane, więc nie można ich tutaj porównać. Przywrócenie danych powoduje przywrócenie dokładnie tego, co zostało zapisane na tym urządzeniu. - - Włączyłeś dźwięk dla %1$d elementu - Włączyłeś dźwięk dla %1$d elementów - Włączyłeś dźwięk dla %1$d elementów - %1$d elementy mają włączony dźwięk - - - Usunąłeś %1$d pole profilu - Usunąłeś %1$d pól profilowych - Usunąłeś %1$d pól profilowych - Usunąłeś %1$d pola profilowe - - - Usunąłeś %1$d publiczny transmiter - Usunąłeś %1$d publicznych transmiterów - Usunąłeś %1$d publicznych transmiterów - Usunąłeś %1$d publiczne transmitery - - - Usunąłeś %1$d transmiter DM - Usunąłeś %1$d transmiterów DM - Usunąłeś %1$d transmiterów DM - Usunąłeś %1$d transmitery DM - - - Usunięto %1$d transmiter klucza grupowego czatu - Usunięto %1$d transmiterów klucza grupowego czatu - Usunięto %1$d transmiterów klucza grupowego czatu - Usunięto %1$d transmitery klucza grupowego czatu - - - Usunięto %1$d transmiter wyszukiwania - Usunięto %1$d transmiterów wyszukiwania - Usunięto %1$d transmiterów wyszukiwania - Usunięto %1$d transmitery wyszukiwania - - - Usunięto %1$d transmiter indeksujący - Usunięto %1$d transmiterów indeksujących - Usunięto %1$d transmiterów indeksujących - Usunięto %1$d transmitery indeksujące - - - Usunięto %1$d kanał transmitera - Usunięto %1$d kanałów transmitera - Usunięto %1$d kanałów transmitera - Usunięto %1$d kanały transmitera - - - Usunięto %1$d prywatny transmiter - Usunięto %1$d prywatnych transmiterów - Usunięto %1$d prywatnych transmiterów - Usunięto %1$d prywatne transmitery - - - Przestałeś ufać %1$d transmiterowi - Przestałeś ufać %1$d transmiterom - Przestałeś ufać %1$d transmiterom - Przestałeś ufać %1$d transmiterom - - - Odblokowałeś %1$d transmiter - Odblokowałeś %1$d transmiterów - Odblokowałeś %1$d transmiterów - Odblokowałeś %1$d transmitery - - - Opuściłeś %1$d czat publiczny - Opuściłeś %1$d czatów publicznych - Opuściłeś %1$d czatów publicznych - Opuściłeś %1$d czaty publiczne - - - Opuściłeś %1$d społeczność - Opuściłeś %1$d społeczności - Opuściłeś %1$d społeczności - Opuściłeś %1$d społeczności - - - Opuściłeś %1$d pokój czatu - Opuściłeś %1$d pokoi czatu - Opuściłeś %1$d pokoi czatu - Opuściłeś %1$d pokoje czatu - - - Opuściłeś %1$d grupę - Opuściłeś %1$d grup - Opuściłeś %1$d grup - Opuszczono %1$d grupy - - - Usunąłeś %1$d ulubiony kanał - Usunąłeś %1$d ulubionych kanałów - Usunąłeś %1$d ulubionych kanałów - Usunięto %1$d ulubione kanały - - - Przestałeś obserwować %1$d hashtag - Przestałeś obserwować %1$d hashtagów - Przestałeś obserwować %1$d hashtagów - Przestałeś obserwować %1$d hashtagi - - - Przestałeś obserwować %1$d miejsce - Przestałeś obserwować %1$d miejsc - Przestałeś obserwować %1$d miejsc - Przestałeś obserwować %1$d miejsca - - - Zmieniłeś dostawcę %1$d zaufanego serwisu - Zmieniłeś dostawcę %1$d zaufanych serwisów - Zmieniłeś dostawcę %1$d zaufanych serwisów - Zmieniłeś dostawcę %1$d zaufanych serwisów - - - Usunięto %1$d nutzap mint - Usunięto %1$d nutzap mintów - Usunięto %1$d nutzap mintów - Usunięto %1$d nutzap minty - - - Usunięto %1$d sposób na otrzymanie zapłaty - Usunięto %1$d sposobów otrzymywania zapłaty - Usunięto %1$d sposobów otrzymywania zapłaty - Usunięto %1$d sposoby otrzymywania zapłaty - - - Usunięto %1$d ofertę BOLT12 - Usunięto %1$d ofert BOLT12 - Usunięto %1$d ofert BOLT12 - Usunięto %1$d oferty BOLT12 - - - %1$s i dodano %2$d - %1$s i dodano %2$d - %1$s i dodano %2$d - %1$s i dodano %2$d - - - %1$s i obserwowany %2$d - %1$s i obserwowanych %2$d - %1$s i obserwowanych %2$d - %1$s i obserwowane %2$d - - - %1$s i wyciszony %2$d - %1$s i wyciszono %2$d - %1$s i wyciszono %2$d - %1$s i wyciszone %2$d - - - %1$s i dołączono do %2$d - %1$s i dołączono do %2$d - %1$s i dołączono do %2$d - %1$s i dołączono do %2$d - - - %1$s i zablokowano %2$d - %1$s i zablokowano %2$d - %1$s i zablokowano %2$d - %1$s i zablokowano %2$d - - Twoje zsynchronizowane ustawienia aplikacji Amethyst zostały zmienione w innej aplikacji, która nie jest Amethystem. To może powodować problemy. - Wymieniłeś swój klucz Nutzap - Usunąłeś swój klucz nutzap - Opróżniłeś swój portfel Cashu - Zmieniłeś swój portfel Cashu - Opróżniłeś swoją listę Concorda - Zmieniłeś swoją listę Concorda - Użyj nowej wersji - tylko do odczytu - tylko do zapisu - odczyt i zapis - profil - Twoje imię i nazwisko, zdjęcie, biografia oraz adresy do płatności – tak, jak widzą je wszyscy. - lista obserwowanych - Określa, czyje posty pojawiają się w Twoim kanale głównym. - lista zablokowanych - Ukrywa osoby, słowa, hashtagi i wątki we wszystkich wyświetlanych treściach. - lista publicznych transmiterów - Informuje wszystkich, gdzie mogą znaleźć Twoje posty oraz gdzie mają wysyłać Ci odpowiedzi i wzmianki. - Lista transmiterów DM - Gdzie inni dostarczają Twoje prywatne wiadomości. - transmitery kluczy czatu grupowego - Gdzie inni znajdą klucze do dodawania cię do zaszyfrowanych czatów grupowych. - lista transmiterów wyszukiwania - Transmitery używane podczas wyszukiwania. - lista transmiterów indeksujących - Transmitery służące do wyszukiwania profili innych osób oraz list transmiterów. - ulubione kanały transmitera - Transmitery, które przeglądasz jako kanały informacyjne. - lista zablokowanych przekaźników - Transmitery, z którymi ta aplikacja nigdy się nie łączy. - lista zaufanych transmiterów - Zaufane transmitery, z którymi bez wahania nawiązujesz połączenie. - lista prywatnych transmiterów - Gdzie przechowywane są Twoje projekty i prywatne dane. - zsynchronizowane ustawienia aplikacji - Ustawienia Amethyst są synchronizowane na wszystkich Twoich urządzeniach. Są one zaszyfrowane, więc można porównać jedynie sam fakt ich obecności. - lista czatów publicznych - Publiczne czaty, do których dołączyłeś. - lista społeczności - Społeczności, do których dołączyłeś. - obserwowane hashtagi - Hashtagi, z których pochodzą posty wyświetlane w Twoich kanałach. - obserwowane lokalizacje - Miejsca, z których posty pojawiają się na Twoich kanałach. - lista ulubionych kanałów - Zapisane przez Ciebie kanały algorytmiczne. - lista czatów efemerycznych - Tymczasowe czaty, do których dołączyłeś. - lista grup - Grupy oparte na transmiterach, do których dołączyłeś. - Lista społeczności Concord - Społeczności Concord, do których dołączyłeś. Są one zaszyfrowane, więc można porównać jedynie fakt ich istnienia. - lista zaufanych dostawców - Serwisy, którym ufasz, a które zajmują się klasyfikowaniem i weryfikacją osób w Twoim imieniu. - Portfel Cashu - Ustawienia portfela ecash oraz minty. Są one zaszyfrowane, więc można porównać jedynie sam fakt ich istnienia. - ustawienia odbioru nutzap - Minty i klucz, które inni używają do wysyłania ci „nutzapów”. - adresy płatności - Sposoby, w jakie inni mogą Ci zapłacić. - Oferta BOLT12 - Ta możliwość pozwala innym płacić Ci za pomocą Lightning. - lista - Lista zapisana na tym urządzeniu. - Pola profilu - Osoby - Hashtagi - Słowa - Wątki - Czaty publiczne - Społeczności - Kanały - Lokalizacje - Transmitery - Grupy - Czat pokoje - Zaufani dostawcy - Minty - Klucze Nutzap - Adresy płatności - Oferty - Powiązane tożsamości - Inne wpisy - Nazwa użytkownika - Nazwa wyświetlana - O profilu - Zdjęcie - Baner - Strona www - Adres Nostr - Lightning Adres - LNURL - Zaimki - Data urodzin - Oferta CLINK - Flaga bota diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 2da4657d8d..3803e00f8a 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -305,250 +305,6 @@ - Coordinators - Nothing is arriving from these groups. Amethyst keeps retrying. - No cordn groups yet - A cordn group lives on one coordinator that holds its membership and passes messages along, without ever seeing what anyone writes. - Start one - This group is not available. Its coordinator may have been removed. - Group info - Message deleted - edited - Go to message - Withdraw message - Everyone in the group will see this message as withdrawn, and Amethyst will stop showing its text. The coordinator still holds the encrypted copy it was sent as, and anyone who already read it has already read it. - Accepted by the coordinator - Message details - Sent - Cursor - Coordinator - Message - Reply - Edit - Delete - Pin - Previous pinned message - Next pinned message - Show all pinned messages - Pinned messages - Pinned by %1$s - - %1$d pinned message in this group - %1$d pinned messages in this group - - Unpin - Editing your message - Could not send that file. - That did not send. - This group\'s coordinator is not open, so nothing can be sent yet. - Could not open that file. - No media server is set for this account, so there is nowhere to put the file. Pick one in Settings. - That file could not be read. - Record a voice note - Stop and send - Play voice note - Your nsec cannot bring cordn groups back. A cordn group lives as encryption state on this device and an ordered stream on a coordinator that cannot read it — lose the device without a backup and the group is gone, including everything already said in it. - Passphrase - What is in the file - Your group encryption keys, your key packages, and every message in those groups. Anyone who opens it can read the conversations. The passphrase is the only thing protecting it once it leaves Amethyst. - Export - Backup saved. - Restore - Restoring replaces the cordn groups on this device with the ones in the file. It is for a phone that has taken over from another — not a way to use the same groups on two devices at once. - Restore - Replace this device\'s cordn groups? - Every cordn group now on this device will be removed and replaced by the ones in the file.\n\nDo not restore onto a second phone while the first is still in use. Both would hold the same group keys, and once both have sent a message the group breaks for everyone — silently, and with no way back. - Restored. - That did not work. Check the passphrase and the file. - Send - Coordinator - Coordinator key - Coordinator link - Copy the coordinator\'s nprofile - Group id - Epoch - Members - This group has no admins: everyone can add, remove and rename, permanently. - Technical details - New Cordn group - A cordn group is ordered by one coordinator you choose. Creating the group happens on this device — the coordinator only learns the group exists once you invite someone or send a message. - Nobody yet — tap to add people - Nobody added yet. A group can be created empty and invitations sent later, but naming people now is what shows which coordinator can reach them. - Done - You, always an admin - Name it - Who is in it - Where it lives - Who can add and remove - Add someone - Naming people now is what tells us which coordinator can reach them. Each one gets a Welcome left on that coordinator, which they pick up next time they open their app. - Not checked yet - No key on any coordinator you use - Everyone can add and remove - Admin - No coordinator chosen - Change - Done - Not checked — picking it will ask - Reaches all %1$d of your people - Reaches %1$d of %2$d — the rest would be left out - The group exists - Each invitation is a Welcome left on the coordinator, so they can fail one at a time. Nobody has been notified: they see it next time they open their app. - Added to the group, but the invitation did not reach them — try again from the group screen - Waiting for them - The coordinator refused the invitation - No key here, so no Welcome could be left - Send a link - Open the chat - Coordinator - Find coordinators - Another coordinator - Coordinator public key (hex or npub) - Relays it answers on, one per line - Group name - Description (optional) - Everyone in the group can invite, remove members and change its details. Any member can name admins later, which ends that. - Only I manage this group - That change could not be made. - Remove - Remove from group? - %1$s stops receiving messages from here. They keep what they have already read, and this cannot be undone — they would have to be invited again. - Edit details - Save - Only you can invite, remove members or change the group\'s details. You can hand that to someone else later. - Create group - The group could not be created. - Cordn invitations - Checked when you open this screen, and at no other time — asking a coordinator whether anyone invited you tells it you are here, so Amethyst does not do it in the background. - Check again - Join - Decline - Declining is permanent. Getting back in means being invited again. - Yesterday - New messages - No messages yet - Anything sent here is encrypted for this group. The coordinator relays it without being able to read it. - Reactions - Add a coordinator in Settings to start using cordn groups. - Reads announcements your relays already carry. No coordinator is contacted, so none of them learns you looked. - Look for coordinators - Add - Could not read announcements - Nobody is announcing on your relays. - Nothing found, and %1$d of your relays did not answer. - Announced %1$s ago - Last announced %1$s - %1$s - %1$s +%2$d more - Show all %1$d - Show fewer - Show %1$d that stopped announcing - Hide the ones that stopped announcing - These have not announced in over a month. Creating a group on one that has gone away will fail. - Add someone - Name, npub or name@domain - Can be added on this coordinator - They can only be added if they published a key package to this coordinator. - What this coordinator can see - Got it - That person - %1$s has not published a key package to this coordinator, so they cannot be added yet. Ask them to open cordn on this coordinator first. - This coordinator served a key package that belongs to someone else, so %1$s was not added. Nothing was changed. - %1$s could not be given a way into the group, so the add was abandoned. - %1$s is not in this group. - You cannot remove yourself from a cordn group. - The coordinator did not answer, so nothing was changed. Try again in a moment. - Nobody found by that name. - Admin - +%1$d more - Through %1$s - No invitations waiting. - You have no coordinator open. cordn invitations arrive through a coordinator, so there is nowhere to look yet. - %1$s did not answer - An invitation was left for another device - Could not read invitations. - Ask to join this group - This publishes a key package under your own account key and tells the coordinator you want into this group — whether or not anyone answers. - Asked. A member of the group has to add you; the invitation will show up under cordn invitations. - Could not ask to join. - Requests to join - Check for requests - Nobody is waiting to join. - Add - Dismiss - Only an admin can accept. In a group with no admins, that is everyone. - Could not read the requests. - Scan - Share this group - Anyone with this link can ask to join. An admin still has to let them in. - Copy link - Copied - A coordinator orders one group\'s messages and is the only thing that can. Losing it loses the ordering, and a second one does not mirror the first — so these are named things you choose, not interchangeable relays. - No coordinators yet. - Add - Could not open that coordinator. - A name for it (yours, optional) - Answers on - Coordinator key - Copy the coordinator\'s npub - More actions - Rename - This name is yours and stays on this device. A coordinator cannot prove a name, so it is never asked for one. - Ask who it is - Says it is: %1$s - Answered, but named nothing. - A coordinator\'s name and version are strings it chose. Its public key is the only thing that identifies it. - Answering. - A call failed; retrying. - Not answering — %1$d calls in a row have failed. Groups on it are not syncing. - Nothing asked of it yet. - Remove - Purge - Purge this coordinator? - Removing keeps the groups on this device, so adding the coordinator back brings them with it. Purging deletes them: the group keys, the read positions and your key packages all go, and those groups can only be re-entered by a fresh invitation.\n\nThe coordinator is not told and keeps whatever it already had. - Others can only add you to a cordn group by taking a key package you published to that coordinator. cordn has no other place to keep one, so with none published nobody can invite you — and nothing tells them why. - - %1$d person cannot be reached by any coordinator you use - %1$d people cannot be reached by any coordinator you use - - - %1$d group - %1$d groups - - - Reachable on %1$d coordinator - Reachable on %1$d coordinators - - - %1$d person can add and remove - %1$d people can add and remove - - - Create and invite %1$d person - Create and invite %1$d people - - - %1$d member - %1$d members - - - %1$d single-use package available. - %1$d single-use packages available. - - A last-resort package is published, so an invitation can still be made once the single-use ones run out. - No last-resort package. Once the single-use ones run out, invitations fail. - - %1$d package this device cannot open - %1$d packages this device cannot open - - The coordinator will hand these to anyone inviting you, but the private half is not on this device — it belongs to another install. If that install is gone, an invitation using one of these produces a welcome nobody can ever open. - Withdraw those - Publishing signs a record under your own account key. That coordinator then knows this account exists and is invitable — permanently, and whether or not anyone invites you. - Publish one - Publish last-resort - Withdraw all - Once you have published here, Amethyst quietly replaces packages as they are used up. It never publishes the first one for you. - Could not read the key packages. Forum channel Threaded posts instead of a chat timeline. This cannot be changed later. @@ -899,10 +655,6 @@ - - %1$d person is already in this group - %1$d people are already in this group - Private Message Chat message Nest — Live @@ -931,326 +683,4 @@ Sound on. Click to mute Play Pause - You changed your %1$s in another app - Removed (%1$s) - Added (%1$s) - Changed (%1$s) - You removed all private (encrypted) items. - You also changed private (encrypted) items. They can\'t be compared here. - You added private (encrypted) items. - Restore saved version - On this device - New version - Not set - %1$s removed - %1$s added - %1$s changed - - You unfollowed %1$d person - You unfollowed %1$d people - - Accept - %1$s updated - %1$s cleared - Changed in another app · %1$s - Keep %1$s - Restore %1$s - Re-mute %1$s - Rejoin %1$s - Restore profile - Restore relays - %1$s kept - %1$s dropped - %1$s new - Dropped · %1$s - New · %1$s - Edited · %1$s - Search %1$s people - Nothing here - %1$s unmuted - These can reach your feeds again - %1$s newly muted - Words & hashtags - %1$s and %2$s more - You removed all private items - They\'re encrypted, so only you can see what they were. Restoring brings them all back. - You made items private - They\'re encrypted now, which is likely where the public items above went. - You changed private items - They\'re encrypted, so they can\'t be compared here. - Gone - New - Dropped - Moved - Units - Left - Renamed - Outbox - where you publish - Inbox - where others reach you - Receiving key replaced - Receiving key removed - Nutzaps will be locked to this new key. If this device doesn\'t have it, you may not be able to redeem them here. - left - joined - renamed - was “%1$s” - Block %1$s again - Restore feeds - Restore topics - Restore places - Restore providers - Restore wallet - kept - Receiving - Listed - Searching - Storing - Trusted - Untrusted - %1$s unblocked - Amethyst will connect to them again - No longer blocked - Newly blocked - Still blocked - Allowed - Moved - Feed - topics gone - places gone - new - Hashtags you follow - Places you follow - %1$s of %2$s services changed - They now come from someone else, or no one - Service - Rank - Followers - Topics - Ranks, follower counts and spam filtering you see come from these providers. - - %1$d way to pay you removed - %1$d ways to pay you removed - - - %1$d offer removed - %1$d offers removed - - People paying you only see what\'s in this list. - BOLT12 offer - You emptied it - You created it - You changed it - Your wallet\'s mints and keys are encrypted to you, so they can\'t be compared item by item here. Restoring puts back exactly what this device saved. - Your Concord communities are encrypted to you, so they can\'t be compared here. Restoring puts back exactly what this device saved. - - You unmuted %1$d thing - You unmuted %1$d things - - - You removed %1$d profile field - You removed %1$d profile fields - - - You removed %1$d public relay - You removed %1$d public relays - - - You removed %1$d DM relay - You removed %1$d DM relays - - - You removed %1$d group-chat key relay - You removed %1$d group-chat key relays - - - You removed %1$d search relay - You removed %1$d search relays - - - You removed %1$d indexer relay - You removed %1$d indexer relays - - - You removed %1$d relay feed - You removed %1$d relay feeds - - - You removed %1$d private relay - You removed %1$d private relays - - - You stopped trusting %1$d relay - You stopped trusting %1$d relays - - - You unblocked %1$d relay - You unblocked %1$d relays - - - You left %1$d public chat - You left %1$d public chats - - - You left %1$d community - You left %1$d communities - - - You left %1$d chat room - You left %1$d chat rooms - - - You left %1$d group - You left %1$d groups - - - You removed %1$d favorite feed - You removed %1$d favorite feeds - - - You unfollowed %1$d hashtag - You unfollowed %1$d hashtags - - - You unfollowed %1$d place - You unfollowed %1$d places - - - You changed the provider of %1$d trust service - You changed the provider of %1$d trust services - - - You removed %1$d nutzap mint - You removed %1$d nutzap mints - - - You removed %1$d way to get paid - You removed %1$d ways to get paid - - - You removed %1$d BOLT12 offer - You removed %1$d BOLT12 offers - - - %1$s and added %2$d - %1$s and added %2$d - - - %1$s and followed %2$d - %1$s and followed %2$d - - - %1$s and muted %2$d - %1$s and muted %2$d - - - %1$s and joined %2$d - %1$s and joined %2$d - - - %1$s and blocked %2$d - %1$s and blocked %2$d - - Your Amethyst synced app settings changed in another app that is not Amethyst. This can create problems. - You replaced your nutzap key - You removed your nutzap key - You emptied your Cashu wallet - You changed your Cashu wallet - You emptied your Concord list - You changed your Concord list - Use new version - read only - write only - read and write - profile - Your name, picture, bio and payment addresses, as everyone sees them. - follow list - Decides whose posts appear in your home feed. - mute list - Hides people, words, hashtags and threads from everything you see. - public relay list - Tells everyone where to find your posts and where to send you replies and mentions. - DM relay list - Where others deliver your private messages. - group-chat key relays - Where others find the keys to add you to encrypted group chats. - search relay list - The relays used when you search. - indexer relay list - The relays used to find other people\'s profiles and relay lists. - favorite relay feeds - The relays you browse as feeds. - blocked relay list - Relays this app never connects to. - trusted relay list - Relays you trust to connect to without asking. - private relay list - Where your drafts and private data are stored. - synced app settings - Amethyst settings synced across your devices. They are encrypted, so only their presence can be compared. - public chat list - The public chats you joined. - community list - The communities you joined. - followed hashtags - Hashtags whose posts appear in your feeds. - followed locations - Locations whose posts appear in your feeds. - favorite feeds list - The algorithmic feeds you saved. - ephemeral chat list - The ephemeral chat rooms you joined. - group list - The relay-based groups you joined. - Concord community list - The Concord communities you joined. They are encrypted, so only their presence can be compared. - trust provider list - The services you trust to rank and verify people for you. - Cashu wallet - Your ecash wallet settings and mints. They are encrypted, so only their presence can be compared. - nutzap receiving settings - The mints and key others use to send you nutzaps. - payment addresses - The ways other people can pay you. - BOLT12 offers - The lightning offers others use to pay you. - list - A list saved on this device. - Profile fields - People - Hashtags - Words - Threads - Public chats - Communities - Feeds - Locations - Relays - Groups - Chat rooms - Trust providers - Mints - Nutzap keys - Payment addresses - Offers - Linked identities - Other entries - Username - Display name - About - Picture - Banner - Website - Nostr address - Lightning address - LNURL - Pronouns - Birthday - CLINK offer - Bot flag - - The group\'s %1$d admin stays as it is. - The group\'s %1$d admins stay as they are. - diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/napplet/NappletProtocolJsonTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/napplet/NappletProtocolJsonTest.kt index 1f2422de4b..93399e85a2 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/napplet/NappletProtocolJsonTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/napplet/NappletProtocolJsonTest.kt @@ -184,6 +184,13 @@ class NappletProtocolJsonTest { assertEquals("Hi", up.bytes.decodeToString()) } + @Test + fun uploadAcceptsUnpaddedBase64() { + // java.util.Base64 decoded "SGk" (no '=') as "Hi"; the commonMain decoder must too. + val up = NappletProtocolJson.decodeRequest("""{"type":"upload.upload","request":{"dataBase64":"SGk"}}""") as NappletRequest.UploadBlob + assertEquals("Hi", up.bytes.decodeToString()) + } + @Test fun unknownTypeDecodesToNull() { assertNull(NappletProtocolJson.decodeRequest("""{"type":"inc.emit","id":"1"}""")) diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorkGateTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorkGateTest.kt index e346274630..d3028575ea 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorkGateTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/service/scheduledposts/ScheduledPostWorkGateTest.kt @@ -57,7 +57,7 @@ class ScheduledPostWorkGateTest { decisions.clear() } - private fun newStore() = ScheduledPostStore(file) + private fun newStore() = ScheduledPostStore(file.path) private fun TestScope.startGate(store: ScheduledPostStore) = ScheduledPostWorkGate( diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupPresentationLabelsTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupPresentationLabelsTest.kt new file mode 100644 index 0000000000..bd28de71ee --- /dev/null +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/backups/BackupPresentationLabelsTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.ui.screen.loggedIn.backups + +import com.vitorpamplona.quartz.nip01Core.diff.EventDiff +import com.vitorpamplona.quartz.nip01Core.diff.ListDiff +import com.vitorpamplona.quartz.nip01Core.metadata.MetadataDiff +import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListDiff +import org.jetbrains.compose.resources.StringResource +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * rememberPresentation resolves labels in composition and hands presentationOf a lookup + * over exactly [labelsWrittenBy]; a label presentationOf asks for that is not in that list + * crashes the review screen. presentationOf asks for every label of a diff type + * regardless of which fields changed, so an empty diff of each type exercises them all. + */ +class BackupPresentationLabelsTest { + private fun empty() = ListDiff(emptyList(), emptyList(), emptyList()) + + private fun asked(diff: EventDiff): Set { + val asked = mutableSetOf() + presentationOf(diff) { + asked.add(it) + "" + } + return asked + } + + @Test + fun metadataLabelsAreAllProvided() { + val diff = MetadataDiff(null, null, null, null, null, null, null, null, null, null, null, null, null, empty(), empty()) + assertEquals(labelsWrittenBy(diff).toSet(), asked(diff)) + } + + @Test + fun relayListLabelsAreAllProvided() { + val diff = AdvertisedRelayListDiff(empty()) + assertEquals(labelsWrittenBy(diff).toSet(), asked(diff)) + } +} diff --git a/commons/plans/2026-08-30-commons-migration-sweep.md b/commons/plans/2026-08-30-commons-migration-sweep.md index 20982ddae2..46de62e8af 100644 --- a/commons/plans/2026-08-30-commons-migration-sweep.md +++ b/commons/plans/2026-08-30-commons-migration-sweep.md @@ -771,11 +771,11 @@ Options, for the maintainer to pick: ### Next work, in recommended order (needs maintainer go-ahead per item) -- **Tier 4 unlocks** (small, mechanical): `NappletProtocolJson` +- **Tier 4 unlocks** — **done 2026-09-26**, see the last section. (Was: small, mechanical: `NappletProtocolJson` `java.util.Base64` → `kotlin.io.encoding.Base64` (frees `NappletIdentityWatch`); `ScheduledPostStore` Jackson+`java.io.File` → kotlinx-serialization+okio (frees `ScheduledPostWorkGate`). - `LargeSoftCache` stays parked (needs a WeakReference expect/actual). + `LargeSoftCache` stays parked (needs a WeakReference expect/actual).) - **Wave 2: LocalCache move-group** — **part A landed (2026-09-19)**, see the section below. Part B (repoint `desktopApp`, delete `DesktopLocalCache.kt`) is the remaining half. @@ -1302,3 +1302,133 @@ through an `ingest` helper that pins what the cache built for the lifetime of the test instance, the way a screen holds the notes it is showing in the app, and keeps the forced GC in the test that failed so the contract is asserted rather than left to the heap. + +## 2026-09-26 — Tier 4 unlocks, the strings drift, and the UI stragglers + +### Tier 4: two jvmAndroid groups promoted to `commonMain` + +- **Napplet wire protocol.** `NappletProtocolJson`, `NappletIdentityWatch` and + `NappletRequestRouter` moved to `commons/commonMain/…/napplet`. The only + pins were `java.util.Base64` and one `System.currentTimeMillis()`. Base64 is + now `kotlin.io.encoding.Base64`, decoding with `PaddingOption.PRESENT_OPTIONAL` + because `java.util.Base64.getDecoder()` accepted unpadded input and applets + may send it. The clock is `TimeUtils.now()`. +- **Scheduled posts.** `ScheduledPostStore` had already dropped Jackson for + kotlinx-serialization; what pinned it was `java.io.File` and a POSIX + `chmod`. It now takes an okio `Path` plus a `FileSystem` (default + `platformFileSystem`), and a `String` constructor so callers need no okio, + the same shape as `FileSystemNip95BlobStore`. The owner-only permission is a + new `expect fun restrictFileToOwner(path, tag)`: + `Files.setPosixFilePermissions` on jvmAndroid, POSIX `chmod(0600)` on iOS. + The temp-file swap is `FileSystem.atomicMove`, which replaces an existing + target on every platform, so the old "rename, else delete and rename again" + fallback went with it. `ScheduledPostWorkGate`, `ScheduledPostPublisher` and + `ScheduledPostNotifier` came along; none had a JVM pin of its own. + +### The strings drift, fixed + +Between the 2026-09-22 move and today, the cordn UI and the backup-conflict +review added **447 keys** to `amethyst/src/main/res` (`cordn_*`, `backup_*`), +taking it from 190 keys back to 597. All 447 moved with +`tools/strings-migrate/migrate.py` (1,131 elements over 57 locales) and the 18 +files that read them were repointed. The non-mechanical sites: + +- `stringRes(context, …)` inside `suspend` senders (`sendAttachment`, + `sendVoiceNote`) → `loadStringRes(…)`. `adminFailureText` became `suspend`; + its only caller is already in `scope.launch`. +- The backup review kept its labels as `@StringRes Int` (`DiffGroup.label`, + `ReviewRow.*Res`, `eventTypeName()`, the `countTiles`/`moneyHero`/`laneItems` + params) → `StringResource` / `PluralStringResource`. +- `rememberPresentation` resolved labels inside `remember { }` through + `LocalResources`. Compose resources have no non-suspend accessor, so the 16 + labels `presentationOf` writes into item text are resolved in composition into + a map, and the map is the `remember` key. +- `androidx.compose.ui.res.pluralStringResource` → the compose-resources one. + +Six moved keys have no reader today (`cordn_backup_restore_title`, +`cordn_coordinators_relays`, `cordn_create_admin_only_me`, +`cordn_create_coordinator`, `cordn_send`, `cordn_voice_play`). They moved +rather than being deleted; dropping them is the feature owner's call. +`pow_notification_sending` stays in Android `res/`: the PoW foreground service +reads it synchronously. + +The rule is now written down in `.claude/CLAUDE.md` ("Strings"), in +`commonsUI/ARCHITECTURE.md`, and in the `android-expert` and +`find-missing-translations` skills: new strings go in `commonsUI` +composeResources, even for Android-only screens. + +### UI stragglers moved to `commonsUI` + +A survey against `main` found that most of "Batch 4" had already landed in +other PRs (`dde228d2`, `1a563cf2`, `8dd409cb`, `1f1b6dab`): the theme +constants (in `commonsUI/…/theme/Shape.kt`, not the `Sizes.kt` this plan +named), the feed shell, the top bars, `M3ActionDialog`, `NoteComposeLayout`, +`RepostLayout` and the toast queue. This round moved what was left that had no +real blocker: + +| Moved | To | Note | +|---|---|---| +| `NewItemsBubble` (from `ChatroomHeaderCompose.kt`) | `commonsUI/…/ui/components` | | +| `ChatHeaderLayout`, `LeftPictureLayout` | `commonsUI/…/ui/layouts` | Their `@Preview`s use app drawables, `TimeAgo` and `TextCount`, so the previews stay app-side in `*Preview.kt` files | +| `listItem/SlimListItemLayout` | `commonsUI/…/ui/layouts/listItem` | Same preview split; `@VisibleForTesting` dropped (no androidx.annotation in commonMain) | +| `WatchScrollToTop` (list/grid/pager overloads) | `commonsUI/…/ui/feeds` | The `CardFeedContentState` overload stays in the app | +| app `StickToTopOnPrepend` | deleted | It was a copy of the commons one. The commons copy now collects with `collectAsStateWithLifecycle`, as the app copy did | +| `ChannelFeedState`, `ChannelFeedContentState` | `commons/commonMain/…/feeds` | `checkNotInMainThread()` → `LocalCache.appHost.assertNotMainThread()`, which Android wires to the same check | +| `ClickableBuzzInviteLink`, `ClickableConcordInviteLink`, `ClickableRelayGroupLink`, `ClickableRelayUrl`, `OutlinedThinPaddingTextField` | `commonsUI/…/ui/components` | | +| app `ClickableEmail`, `ClickablePhone` | deleted | Android now uses the commons ones (`mailto:` / `tel:` through `LocalUriHandler`) instead of `ACTION_SEND` / `ACTION_DIAL` intents. The commons `ClickablePhone` is new. Desktop still renders phone numbers as plain text, on purpose | + +**Still app-side, with the reason:** + +- `AmethystClickableIcon`: 9 lines around an Android debug action; moving it + only pushes `LocalContext` into its two callers. +- `ScreenLayout`: needs `LocalConfiguration` → `LocalWindowInfo`, and the + window-size-class breakpoints inlined. +- `SlidingCarousel`: needs `animatedViewerChromeInset` hoisted out of the + viewer-chrome file. +- `AudioWaveformReadOnly`: needs two enums from the Android-only waveform + library replaced. +- `FileAttachmentCard`: needs `extractFilename` hoisted. +- `PdfFetcher`: needs the disk cache injected. +- `ClickablePhone` / `ClickableEmail` on Desktop: deliberately unchanged. +- **`AmethystTheme` split** (the pure scheme/typography half to commonsUI; the + `Amethyst.instance` overload and the system-bar `SideEffect` stay). +- **`TimeAgo` split**: the labels, `NowProvider` and the style enum are pure; + the absolute and short formatters need expect/actual over + `android.text.format`. +- **Palette unification**: Desktop's `PlatformColorScheme` and the app palette + differ in primary, secondary, surfaces and outlines, and every shared token + (`placeholderText`, `chatBubbleThem`, …) is frozen from the app palette. This + is a design decision, not a move. + +### Audit of the 2026-09-26 round + +The four commits were reviewed file by file against the originals. They had no +functional bugs. The follow-ups: + +- **Compose resources keep XML whitespace; Android didn't.** This is older than this + round (it dates back to the first string moves), and it is the one real + regression. aapt collapses every whitespace run in an unquoted value and trims + the ends; Compose draws the XML text verbatim. So the values wrapped over + indented lines (`account_backup_tips2_md`, `push_server_install_app_description`, + `couldnt_find_nwc_wallets_description`, the chat explainers, and 349 translated + values) rendered with a leading line break and eight spaces. In the `_md` strings + CommonMark turns that into a code block. Crowdin also exports a translator's stray + edge space, which aapt used to drop, for example ` miejsca zniknęły` and Hindi's + ` दि॰` time suffix. `fix_escapes.py` now applies aapt's rule to runs holding a line + break or tab. In a translation it also trims an edge space its source string lacks, + which keeps deliberate ones like `" and "`. The Crowdin workflow already runs it + after every sync, and `compose_escaping_check.py` now fails on raw line breaks, so + a sync can't bring it back. 598 values across 54 files were repaired. +- `rememberPresentation` read all 16 backup labels on every recomposition, even for + diff types that write none. It now reads only the ones its diff type uses, and + `BackupPresentationLabelsTest` fails if `presentationOf` asks for a label that list + lacks. +- `ScheduledPostStore`: a failed stat now counts as "no file" rather than throwing + (okio's posix metadata throws on EACCES where `File.exists()` returned false). + Symlinked store files still count as present. The chmod is skipped for an injected + non-system `FileSystem`, and the cleanup log keeps its throwable. +- `ClickableEmail` percent-encodes `%` in the `mailto:` URI (RFC 6068). +- Left as-is, by design: Kotlin's Base64 rejects non-zero pad bits (`"SGl="`) that + Java ignored, which no browser encoder produces. `%1$d` arguments now render ASCII + digits in every locale, the same as every other migrated string. + `ChannelFeedContentState` reaches `LocalCache.appHost` for its main-thread check. diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedContentState.kt similarity index 92% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedContentState.kt index 611d27ff59..296893376c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedContentState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedContentState.kt @@ -18,26 +18,24 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.feeds +package com.vitorpamplona.amethyst.commons.feeds import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf -import com.vitorpamplona.amethyst.commons.feeds.AdditiveComplexFeedFilter -import com.vitorpamplona.amethyst.commons.feeds.InvalidatableContent -import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState import com.vitorpamplona.amethyst.commons.model.Channel import com.vitorpamplona.amethyst.commons.model.Note +import com.vitorpamplona.amethyst.commons.model.cache.LocalCache import com.vitorpamplona.amethyst.commons.service.BundledInsert import com.vitorpamplona.amethyst.commons.service.BundledUpdate -import com.vitorpamplona.amethyst.service.checkNotInMainThread -import com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.equalImmutableLists +import com.vitorpamplona.amethyst.commons.util.equalImmutableLists import com.vitorpamplona.quartz.utils.Log import com.vitorpamplona.quartz.utils.flattenToSet import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch @@ -75,7 +73,7 @@ class ChannelFeedContentState( } fun refreshSuspended() { - checkNotInMainThread() + LocalCache.appHost.assertNotMainThread() isRefreshing.value = true try { @@ -178,7 +176,7 @@ class ChannelFeedContentState( } fun destroy() { - Log.d("Init") { "OnCleared: ${this.javaClass.simpleName}" } + Log.d("Init") { "OnCleared: ${this::class.simpleName}" } bundlerInsert.cancel() bundler.cancel() } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedState.kt similarity index 93% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedState.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedState.kt index be96af6803..b3cb58b1e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/feeds/ChannelFeedState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/feeds/ChannelFeedState.kt @@ -18,10 +18,9 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.feeds +package com.vitorpamplona.amethyst.commons.feeds import androidx.compose.runtime.Stable -import com.vitorpamplona.amethyst.commons.feeds.LoadedFeedState import com.vitorpamplona.amethyst.commons.model.Channel import kotlinx.coroutines.flow.MutableStateFlow diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletIdentityWatch.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletIdentityWatch.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletIdentityWatch.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletIdentityWatch.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletRequestRouter.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletRequestRouter.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletRequestRouter.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/NappletRequestRouter.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt similarity index 96% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt index 027cae99df..c72f1bf825 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/napplet/protocol/NappletProtocolJson.kt @@ -22,6 +22,7 @@ package com.vitorpamplona.amethyst.commons.napplet.protocol import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter +import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject @@ -37,7 +38,7 @@ import kotlinx.serialization.json.long import kotlinx.serialization.json.put import kotlinx.serialization.json.putJsonArray import kotlinx.serialization.json.putJsonObject -import java.util.Base64 +import kotlin.io.encoding.Base64 /** * Marshals the KMP-pure [NappletRequest] / [NappletResponse] types to and from the wire the @@ -45,10 +46,10 @@ import java.util.Base64 * (`@napplet/shim` / `@napplet/nap`): requests are `{ "type": ".", "id", ...fields }` * and replies are `{ "type": "..result", "id", ...fields }`. * - * Lives in `commons/jvmAndroid` (not in any single front end) because the wire contract is identical + * Lives in `commons/commonMain` (not in any single front end) because the wire contract is identical * across hosts: the Android `:napplet` WebView host and a future desktop host both marshal through - * here. It depends only on `quartz` (Event/Filter), kotlinx.serialization, and `java.util.Base64` - * (available on Android API 26+ and the JVM) — no platform-UI or process APIs. + * here. It depends only on `quartz` (Event/Filter), kotlinx.serialization and `kotlin.io.encoding` + * — no platform-UI or process APIs. * * This is the only place the boundary parses untrusted applet input, so it is deliberately * strict: an unrecognized `type` decodes to `null` (the broker denies it) and a malformed/short @@ -58,6 +59,11 @@ import java.util.Base64 object NappletProtocolJson { private val json = Json { ignoreUnknownKeys = true } + // Accepts unpadded input, as java.util.Base64's decoder did before this moved to commonMain. + // One difference remains: non-zero pad bits ("SGl=") are rejected where Java ignored them. + // Browsers' btoa/readAsDataURL never produce those, so only a hand-crafted payload hits it. + private val lenientBase64 = Base64.withPadding(Base64.PaddingOption.PRESENT_OPTIONAL) + /** The `type` discriminant of a request envelope, used to build the matching `.result` type. */ fun readType(envelopeJson: String): String? = json.parseToJsonElement(envelopeJson).jsonObject.str("type") @@ -166,7 +172,7 @@ object NappletProtocolJson { kind = t.kindOf(), tags = decodeTags(t), content = t.str("content") ?: "", - createdAt = t["created_at"]?.jsonPrimitive?.long ?: (System.currentTimeMillis() / 1000), + createdAt = t["created_at"]?.jsonPrimitive?.long ?: TimeUtils.now(), ) } // NIP-07 nip44.encrypt/decrypt: crypto only, no publish. `peer` is the counterparty @@ -194,7 +200,7 @@ object NappletProtocolJson { // The Blob in `request.data` is inlined as base64 `request.dataBase64` by shell.html. val request = o.getValue("request").jsonObject NappletRequest.UploadBlob( - bytes = Base64.getDecoder().decode(request.req("dataBase64")), + bytes = lenientBase64.decode(request.req("dataBase64")), contentType = request.str("mimeType") ?: "application/octet-stream", filename = request.str("filename"), ) @@ -275,7 +281,7 @@ object NappletProtocolJson { } is NappletResponse.Bytes -> { put("ok", true) - put("bytes", Base64.getEncoder().encodeToString(response.bytes)) + put("bytes", Base64.encode(response.bytes)) put("mime", response.contentType) } is NappletResponse.ResourceInfo -> { @@ -301,7 +307,7 @@ object NappletProtocolJson { put("url", item.url) put("ok", item.resource != null) item.resource?.let { - put("bytes", Base64.getEncoder().encodeToString(it.bytes)) + put("bytes", Base64.encode(it.bytes)) put("mime", it.contentType) } item.error?.let { put("error", it) } diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostNotifier.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostNotifier.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostNotifier.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostNotifier.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostPublisher.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostPublisher.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostPublisher.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostPublisher.kt diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt similarity index 84% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt index d19e8e7a6c..c3eb84304f 100644 --- a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStore.kt @@ -20,21 +20,31 @@ */ package com.vitorpamplona.amethyst.commons.scheduledposts +import com.vitorpamplona.amethyst.commons.util.platformFileSystem +import com.vitorpamplona.amethyst.commons.util.restrictFileToOwner import com.vitorpamplona.quartz.utils.Log +import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.serialization.json.Json -import java.io.File -import java.nio.file.Files -import java.nio.file.attribute.PosixFilePermission +import okio.FileSystem +import okio.Path +import okio.Path.Companion.toPath class ScheduledPostStore( - private val storageFile: File, - private val nowSec: () -> Long = { System.currentTimeMillis() / 1000 }, + private val storageFile: Path, + private val nowSec: () -> Long = { TimeUtils.now() }, + private val fileSystem: FileSystem = platformFileSystem, ) { + /** Takes the platform's own path string, so callers need no okio of their own. */ + constructor( + storagePath: String, + nowSec: () -> Long = { TimeUtils.now() }, + ) : this(storagePath.toPath(), nowSec) + /** * `encodeDefaults = true` so this writes the same bytes Jackson did — kotlinx * omits a value equal to its default, which would silently drop `"version":1` @@ -214,7 +224,7 @@ class ScheduledPostStore( */ suspend fun publishNow( id: String, - nowSec: Long = System.currentTimeMillis() / 1000, + nowSec: Long = TimeUtils.now(), ): Boolean = mutex.withLock { ensureLoaded() @@ -336,8 +346,8 @@ class ScheduledPostStore( private fun reloadFromDiskLocked() { val fromDisk = try { - if (storageFile.exists() && storageFile.length() > 0) { - json.decodeFromString(storageFile.readText()).posts.toMutableList() + if (hasContent()) { + json.decodeFromString(readText()).posts.toMutableList() } else { // File vanished — treat as no external state; keep current in-memory. return @@ -354,8 +364,8 @@ class ScheduledPostStore( if (loaded) return posts = try { - if (storageFile.exists() && storageFile.length() > 0) { - json.decodeFromString(storageFile.readText()).posts.toMutableList() + if (hasContent()) { + json.decodeFromString(readText()).posts.toMutableList() } else { mutableListOf() } @@ -367,7 +377,7 @@ class ScheduledPostStore( // Secure a pre-existing file up front (an older build may have left it at the // 0644 umask default) so it's owner-only even if nothing mutates the store // this session. - if (storageFile.exists()) restrictToOwner(storageFile) + if (storeFileExists()) restrictToOwner(storageFile) var dirty = purgeStale(nowSec()) // Recover claims stranded by a crash-mid-publish so they aren't lost forever. if (recoverStuckClaimsLocked(nowSec())) dirty = true @@ -412,49 +422,58 @@ class ScheduledPostStore( private fun persist() { val snapshot = posts.toList() _flow.value = snapshot - storageFile.parentFile?.mkdirs() - val tmp = File(storageFile.parentFile, storageFile.name + ".tmp") + val tmp = "$storageFile.tmp".toPath() try { - tmp.writeText(json.encodeToString(ScheduledPostFile(version = 1, posts = snapshot))) - // Restrict to owner-only BEFORE the rename so the store is never briefly + storageFile.parent?.let { fileSystem.createDirectories(it) } + fileSystem.write(tmp) { writeUtf8(json.encodeToString(ScheduledPostFile(version = 1, posts = snapshot))) } + // Restrict to owner-only BEFORE the rename, so the store file itself is never // world-readable. It holds pre-signed events + the account's pubkey, which - // must not leak to other local users on a shared machine. + // must not leak to other local users on a shared machine. (The tmp file is + // created at the umask default and narrowed right after its write; the + // directory around it is owner-only on every host that uses this store.) restrictToOwner(tmp) - if (!tmp.renameTo(storageFile)) { - if (!storageFile.delete()) { - Log.w(TAG) { "Failed to delete existing $storageFile before rename retry" } - } - if (!tmp.renameTo(storageFile)) { - Log.e(TAG) { "Failed to rename $tmp to $storageFile" } - if (!tmp.delete()) { - Log.w(TAG) { "Failed to clean up temp file $tmp after rename failure" } - } - } - } + // Replaces an existing target, including on Windows, where a plain rename + // onto an existing file fails. + fileSystem.atomicMove(tmp, storageFile) } catch (e: Exception) { Log.e(TAG, "Failed to persist scheduled posts to $storageFile", e) - if (!tmp.delete()) { - Log.w(TAG) { "Failed to clean up temp file $tmp after persist exception" } + try { + fileSystem.delete(tmp) + } catch (cleanupError: Exception) { + Log.w(TAG, "Failed to clean up temp file $tmp after persist exception", cleanupError) } } } /** - * Best-effort chmod to `0600` (owner read/write only). No-op on filesystems - * without POSIX permissions (e.g. Windows), where confidentiality relies on the - * per-user home directory instead. Never throws. + * Permissions are a property of the real disk, so a caller that injects another + * [FileSystem] (an in-memory fake) gets no chmod aimed at a same-named real path. */ - private fun restrictToOwner(file: File) { - try { - Files.setPosixFilePermissions( - file.toPath(), - setOf(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE), - ) - } catch (e: Exception) { - Log.w(TAG) { "Could not restrict permissions on $file: ${e.message}" } - } + private fun restrictToOwner(path: Path) { + if (fileSystem === platformFileSystem) restrictFileToOwner(path, TAG) } + /** + * The store file's metadata, or null when there is none. A directory is not a store + * file. A symlink counts: okio's metadata does not follow links, so its size is the + * link's, and reading it (which does follow) decides whether there is anything in it. + * A stat that fails (EACCES on iOS, where File.exists() used to answer false) is "no + * file" rather than an exception out of the store. + */ + private fun storeFileMetadata() = + try { + fileSystem.metadataOrNull(storageFile)?.takeIf { it.isRegularFile || it.symlinkTarget != null } + } catch (e: Exception) { + Log.w(TAG, "Could not stat $storageFile", e) + null + } + + private fun storeFileExists(): Boolean = storeFileMetadata() != null + + private fun hasContent(): Boolean = (storeFileMetadata()?.size ?: 0L) > 0L + + private fun readText(): String = fileSystem.read(storageFile) { readUtf8() } + companion object { private const val TAG = "ScheduledPostStore" const val FILE_NAME = "scheduled_posts.json" diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostWorkGate.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostWorkGate.kt similarity index 100% rename from commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostWorkGate.kt rename to commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostWorkGate.kt diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.kt new file mode 100644 index 0000000000..05934c55ca --- /dev/null +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import okio.Path + +/** + * Restricts the file at [path] to owner read/write (`0600`), best-effort. Never throws. + * + * Silent where the filesystem has no POSIX permissions (Windows), where the user profile's + * ACLs apply instead; logs under [tag] when a POSIX filesystem refuses. + */ +expect fun restrictFileToOwner( + path: Path, + tag: String, +) diff --git a/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.ios.kt b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.ios.kt new file mode 100644 index 0000000000..ebd18c664a --- /dev/null +++ b/commons/src/iosMain/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.ios.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.utils.Log +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.convert +import okio.Path +import platform.posix.S_IRUSR +import platform.posix.S_IWUSR +import platform.posix.chmod +import platform.posix.errno + +@OptIn(ExperimentalForeignApi::class) +actual fun restrictFileToOwner( + path: Path, + tag: String, +) { + if (chmod(path.toString(), (S_IRUSR or S_IWUSR).convert()) != 0) { + val error = errno + Log.w(tag) { "Could not restrict permissions on $path: errno $error" } + } +} diff --git a/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.jvmAndroid.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.jvmAndroid.kt new file mode 100644 index 0000000000..cbcfe50038 --- /dev/null +++ b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/util/OwnerOnlyFile.jvmAndroid.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.util + +import com.vitorpamplona.quartz.utils.Log +import okio.Path +import java.nio.file.Files +import java.nio.file.attribute.PosixFilePermission + +actual fun restrictFileToOwner( + path: Path, + tag: String, +) { + try { + Files.setPosixFilePermissions( + path.toNioPath(), + setOf(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE), + ) + } catch (_: UnsupportedOperationException) { + // Windows: no POSIX permissions; the user profile's NTFS ACLs apply instead. + } catch (e: Exception) { + Log.w(tag, "Could not restrict permissions on $path", e) + } +} diff --git a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStoreTest.kt b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStoreTest.kt index 6033715624..bf0fdb92e2 100644 --- a/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStoreTest.kt +++ b/commons/src/jvmTest/kotlin/com/vitorpamplona/amethyst/commons/scheduledposts/ScheduledPostStoreTest.kt @@ -47,7 +47,7 @@ class ScheduledPostStoreTest { file = File(temp.root, "scheduled_posts.json") } - private fun newStore(now: () -> Long = { System.currentTimeMillis() / 1000 }) = ScheduledPostStore(file, now) + private fun newStore(now: () -> Long = { System.currentTimeMillis() / 1000 }) = ScheduledPostStore(file.path, now) private fun samplePost( id: String = "id-1", diff --git a/commonsUI/ARCHITECTURE.md b/commonsUI/ARCHITECTURE.md index b693e06a2b..8a091c05f7 100644 --- a/commonsUI/ARCHITECTURE.md +++ b/commonsUI/ARCHITECTURE.md @@ -58,7 +58,10 @@ is specific to the UI module. `tools/icon-font/build_icon_font.py` read `icons/` and write `composeResources/font/` in this module (see root `.claude/CLAUDE.md`, "Icons"). - Translations: `crowdin.yml` and `tools/strings-migrate/` target - `commonsUI/src/commonMain/composeResources/`. + `commonsUI/src/commonMain/composeResources/`. This is where **every new + user-visible string** goes, Android-only screens included; the app's own + `res/values/strings.xml` holds only the synchronous-platform tier (see root + `.claude/CLAUDE.md`, "Strings"). - CI: `.github/workflows/build.yml` runs `:commonsUI:jvmTest`, `:commonsUI:verifyKmpPurity` and the iOS compile/test tasks next to the `:commons` ones. diff --git a/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml b/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml index c93820fa84..c9b3131eff 100644 --- a/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ar-rSA/strings.xml @@ -234,7 +234,7 @@ نسخ معرف المستخدم إلغاء حظر عن مستخدم هذا المستخدم محظور/مكتوم. منشوراته مخفية. - npub, hex, username + npub, hex, username نظف شعار التطبيق nsec / npub / hex private key @@ -282,15 +282,8 @@ ضع علامة على جميع الرسائل/الاشعارات المعروفة كمقروء تعيين الجديد كمقروء تعيين الكل كمقروء - ## النصائح الرئيسية للنسخ الاحتياطي والسلامة - \n\n- يتم تأمين حسابك بمفتاح سري. المفتاح السري هو سلسلة عشوائية طويلة تبدأ بـ **nsec1**. أي شخص لديه مفتاحك السري يمكنه نشر المحتوى باستخدام هويتك. - \n\n- لا تقم بوضع مفتاحك السري في أي موقع أو برنامج لا تثق به. - \n- مطوري Amethyst لن يطلبوا منك **أبدا** المفتاح السري الخاص بك. - \n- حافظ على نسخة احتياطية آمنة لمفتاحك السري لاسترداد الحساب. نوصي باستخدام برنامج لادارة كلمات المرور. - - للحصول على أمان إضافي، يمكنك تشفير مفتاحك الخاص بكلمة مرور. يبدأ هذا المفتاح المشفر بـ **ncryptsec1** ولا يمكن استخدامه دون كلمة المرور الخاصة بك. - \n\nإذا فقدت كلمة المرور، لن تتمكن من استرداد مفتاحك الخاص. - + ## النصائح الرئيسية للنسخ الاحتياطي والسلامة \n\n- يتم تأمين حسابك بمفتاح سري. المفتاح السري هو سلسلة عشوائية طويلة تبدأ بـ **nsec1**. أي شخص لديه مفتاحك السري يمكنه نشر المحتوى باستخدام هويتك. \n\n- لا تقم بوضع مفتاحك السري في أي موقع أو برنامج لا تثق به. \n- مطوري Amethyst لن يطلبوا منك **أبدا** المفتاح السري الخاص بك. \n- حافظ على نسخة احتياطية آمنة لمفتاحك السري لاسترداد الحساب. نوصي باستخدام برنامج لادارة كلمات المرور. + للحصول على أمان إضافي، يمكنك تشفير مفتاحك الخاص بكلمة مرور. يبدأ هذا المفتاح المشفر بـ **ncryptsec1** ولا يمكن استخدامه دون كلمة المرور الخاصة بك. \n\nإذا فقدت كلمة المرور، لن تتمكن من استرداد مفتاحك الخاص. تشفير و نسخ المفتاح الخاص صورة شارة مكافئة ل %1$s "صورة منح الشارة @@ -311,7 +304,7 @@ إزالة هذه الوسائط من معرضك. طلب حذفها سيطلب Amethyst حذف ملاحظتك من المرحلات المتصل بها حاليا، لا يوجد ضمان لحذفها من هذه المرحلات أو من المرحلات الأخرى التي ربما حفظت فيها. - حظر + حظر حذف حظر التبليغ @@ -693,8 +686,7 @@ إضافة شرح توضيحي صديقي المميز وصف المحتوى/المحتويات - A blue boat in a white sandy beach at sunset -(قارب أزرق في شاطئ رملي أبيض عند غروب الشمس) + A blue boat in a white sandy beach at sunset (قارب أزرق في شاطئ رملي أبيض عند غروب الشمس) اقتراح من الذكاء الاصطناعي، يمكنك تعديله رفض اقتراح الذكاء الاصطناعي نوع الزاب @@ -847,7 +839,7 @@ منذ %1$s حتى %1$s الحد %1$d - الحد الأدنى لل prefix + الحد الأدنى لل prefix الحد الأقصى لوسوم الحدث الحد الأقصى لطول المحتوى تُهمَل أقدم من @@ -886,10 +878,8 @@ العلامات المُتابعة هذه قوائم بالمستخدمين التي توصي بها للآخرين. يُسمح فقط بالمستخدمين العامين. المنشورات الموافق عليها - هذه المجموعة ليس لديها وصف أو قواعد. - تحدث إلى المالك لإضافة مستخدم جديد - هذا المجتمع ليس لديه وصف أو قواعد. - تحدث إلى المالك لإضافة مستخدم جديد + هذه المجموعة ليس لديها وصف أو قواعد. تحدث إلى المالك لإضافة مستخدم جديد + هذا المجتمع ليس لديه وصف أو قواعد. تحدث إلى المالك لإضافة مستخدم جديد تفضيلات المستخدم البحث في الإعدادات لا توجد إعدادات لـ "%1$s" @@ -982,9 +972,7 @@ تعطيل الإشعارات يتم استخدام هذا التطبيق: %1$s إعدادات الإشعارات - لاستخدام الإشعارات حمل أي تطبيق يدعم ال [Unified Push](https://unifiedpush.org/) -مثل [Ntfy](https://ntfy.sh/). -بعد تثبيتك التطبيق قم باختياره من الإعدادات + لاستخدام الإشعارات حمل أي تطبيق يدعم ال [Unified Push](https://unifiedpush.org/) مثل [Ntfy](https://ntfy.sh/). بعد تثبيتك التطبيق قم باختياره من الإعدادات الخيط أرسل رسالة إلى البائع مرحبًا، هل هذا لا يزال متاحًا؟ @@ -1876,7 +1864,7 @@ فشلت المصادقة فشل التحقق البيومتري في مصادقة مالك هذا الهاتف فشل التحقق البيومتري في مصادقة مالك هذا الهاتف. الخطأ: %1$s - حظر + حظر لن يتصل Amethyst أبدًا بهذه الـ relays المستخدمين المحظورين قائمة إشارات مرجعية جديدة @@ -1986,8 +1974,7 @@ نشر طلب حذف لتوصية kind:38000 الخاصة بك لـ %1$s. ستحذفها الـ relays التي تحترم NIP-09. تم استرداد %1$s sats عبر %2$s أدلة. تم استلام Cashu - %1$s sats أرسلت الى محفظتك -(الرسوم: sats %2$s ) + %1$s sats أرسلت الى محفظتك (الرسوم: sats %2$s ) لا أموال محتجزة في mint غير مستخدم أموال محتجزة في %1$d mint لا تستخدمه @@ -2060,15 +2047,7 @@ تعذّر جلب الفاتورة من %1$s: %2$s تعذّر فتح الملف المضغوط لم يتم العثور على المحفظة - لم يتمكن Amethyst من العثور على أي تطبيقات محافظ تدعم Nostr Wallet Connect (NWC). -\n\nما يمكنك فعله: -\n\t1. التحقق من دعم NWC: تأكد من أن تطبيق محفظتك المفضل متوافق مع Nostr Wallet Connect. -\n\t2. إنشاء اتصال: انتقل إلى تطبيق محفظتك وأنشئ اتصال NWC جديدًا. -\n\t3. الربط بـ Amethyst: عادةً ما تتيح محفظتك ثلاثة خيارات: -\n\t\t3.1 ربط تلقائي: زر لفتح Amethyst والاتصال به تلقائيًا. إذا كان الأمر كذلك، اضغط على الزر، وافتح Amethyst واضغط على حفظ في الشاشة الجديدة. -\n\t\t3.2 ربط يدوي: عنوان URI للاتصال يمكنك نسخه والضغط على أيقونة اللصق في هذه الشاشة لإدخاله مباشرةً. -\n\t\t3.3 رمز QR: تنشئ المحفظة رمز QR يمكنك قراءته من زر رمز QR في هذه الشاشة. - + لم يتمكن Amethyst من العثور على أي تطبيقات محافظ تدعم Nostr Wallet Connect (NWC). \n\nما يمكنك فعله: \n\t1. التحقق من دعم NWC: تأكد من أن تطبيق محفظتك المفضل متوافق مع Nostr Wallet Connect. \n\t2. إنشاء اتصال: انتقل إلى تطبيق محفظتك وأنشئ اتصال NWC جديدًا. \n\t3. الربط بـ Amethyst: عادةً ما تتيح محفظتك ثلاثة خيارات: \n\t\t3.1 ربط تلقائي: زر لفتح Amethyst والاتصال به تلقائيًا. إذا كان الأمر كذلك، اضغط على الزر، وافتح Amethyst واضغط على حفظ في الشاشة الجديدة. \n\t\t3.2 ربط يدوي: عنوان URI للاتصال يمكنك نسخه والضغط على أيقونة اللصق في هذه الشاشة لإدخاله مباشرةً. \n\t\t3.3 رمز QR: تنشئ المحفظة رمز QR يمكنك قراءته من زر رمز QR في هذه الشاشة. إنشاء يوم منطقة الخطر @@ -2451,7 +2430,7 @@ قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من إرسال Zaps قم بتسجيل الدخول باستخدام مفتاحك السري لتتمكن من إظهار الكلمة أو الجملة أنت تستخدم مفتاحًا عامًا وهو للقراءة فقط. سجّل الدخول بمفتاح خاص لتتمكن من توقيع الأحداث - قم بتسجيل الدخول بمفتاحك الخاص للتتمكن من إلغاء متابعة المستخدمين + قم بتسجيل الدخول بمفتاحك الخاص للتتمكن من إلغاء متابعة المستخدمين أنت تستخدم مفتاحًا عامًا وهو للقراءة فقط. سجّل الدخول بمفتاح خاص لتتمكن من الرفع تسجيل الدخول باستخدام مفتاح خاص لإبداء الإعجاب بالمنشورات مقاطع فيديو @@ -2786,8 +2765,7 @@ معاينة صورة البطاقة لـ %1$s خيارات الخصوصية سياسة الخصوصية - <استحالة فك تشفير الرسالة الخاصة> -\n\n أنت الآن في محادثة خاصة/مشفرة بين %1$s و %2$s . + <استحالة فك تشفير الرسالة الخاصة> \n\n أنت الآن في محادثة خاصة/مشفرة بين %1$s و %2$s . أدخل ما بين 1 و3 relays لتكون صندوقًا واردًا خاصًا. سيستخدم الآخرون هذه الـ relays لإرسال رسائل مباشرة إليك. يجب أن تقبل DM Inbox relays أي رسالة من أي شخص، لكن تسمح لك وحدك بتنزيلها. خيارات جيدة:\n - inbox.nostr.wine (مدفوع)\n - auth.nostr1.com (مجاني)\n - you.nostr1.com (relays شخصية - مدفوعة) المستخدم يستقبل الرسائل المباشرة على هذه الـ relays رسالة خاصة @@ -2807,11 +2785,8 @@ اقتراح تعديل الـ relays التجميعية التي يجب أن يستخدمها التطبيق لتنزيل تغذياتك منها، مثل filter.nostr.wine. هذا يستبدل نموذج outbox وسيجعل التطبيق يتصل فقط بالـ relays الموجودة في قوائمك. الدردشة العامة - المحادثات العامة مرئية للجميع على Nostr ويمكن لأي شخص - المشاركة فيها. إنها مناسبة للمجتمعات المفتوحة حول مواضيع محددة. - يمكن التحكم في الإشراف عبر حذف المنشورات على relay المجموعة - أدخل من 1 إلى 3 relay تستضيف هذه المجموعة. - تستخدم تطبيقات Nostr هذا الإعداد لمعرفة مكان تنزيل الرسائل وإرسالها. + المحادثات العامة مرئية للجميع على Nostr ويمكن لأي شخص المشاركة فيها. إنها مناسبة للمجتمعات المفتوحة حول مواضيع محددة. يمكن التحكم في الإشراف عبر حذف المنشورات على relay المجموعة + أدخل من 1 إلى 3 relay تستضيف هذه المجموعة. تستخدم تطبيقات Nostr هذا الإعداد لمعرفة مكان تنزيل الرسائل وإرسالها. بيانات المحادثة العامة المحادثات العامة يخزّن هذا النوع من الـ relay جميع محتواك. سيرسل Amethyst منشوراتك إليها وسيستخدم الآخرون هذه الـ relays للعثور على محتواك. أدخل ما بين 1 و3 relays. يمكن أن تكون relays شخصية أو مدفوعة أو عامة. @@ -2833,10 +2808,7 @@ مستخدم في وضع القراءة فقط اضغط مطوّلًا لتسجيل رسالة محادثة relay - محادثات relay هي مجموعات دردشة يتحكم فيها الـ relay المضيف. - إنها مرئية للجميع على Nostr ويمكن لأي شخص المشاركة فيها. - إنها مناسبة للمجتمعات المفتوحة حول مواضيع محددة. بعض هذه المجموعات مؤقتة - وبالتالي تختفي رسائل الدردشة بمرور الوقت + محادثات relay هي مجموعات دردشة يتحكم فيها الـ relay المضيف. إنها مرئية للجميع على Nostr ويمكن لأي شخص المشاركة فيها. إنها مناسبة للمجتمعات المفتوحة حول مواضيع محددة. بعض هذه المجموعات مؤقتة وبالتالي تختفي رسائل الدردشة بمرور الوقت محادثات relay الأحداث عناوين IP diff --git a/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml b/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml index e575eee7eb..75664b26ee 100644 --- a/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-bn-rBD/strings.xml @@ -271,15 +271,8 @@ পরিচিত সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন নতুন সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন - ## মূল ব্যাকআপ এবং নিরাপত্তা টিপস - \n\n আপনার অ্যাকাউন্ট একটি গোপন কী দ্বারা সুরক্ষিত। মূলটি হল অক্ষরগুলির একটি দীর্ঘ ক্রম যা শুরু হয় **nsec1**. যে কেউ এই গোপন কী অ্যাক্সেস করতে পারে পোস্ট এবং আপনার পরিচয় পরিবর্তন করতে পারেন. - \n\n- আপনি বিশ্বাস করেন না এমন কোনো ওয়েবসাইট বা সফ্টওয়্যারে আপনার গোপন কী **করবেন না**. - \n- অ্যামেথিস্ট ডেভেলপাররা **কখনই** আপনার গোপন কী চাইবে না. - \n- **করুন** অ্যাকাউন্ট পুনরুদ্ধারের জন্য আপনার গোপন কীটির একটি নিরাপদ ব্যাকআপ রাখুন৷. আমরা একটি পাসওয়ার্ড ম্যানেজার ব্যবহার করার পরামর্শ দিই।. - - অতিরিক্ত নিরাপত্তার জন্য, আপনি একটি পাসওয়ার্ড দিয়ে আপনার কী এনক্রিপ্ট করতে পারেন. এই কী দিয়ে শুরু হয় **ncryptsec1** এবং আপনার পাসওয়ার্ড ছাড়া ব্যবহার করা যাবে না।. - \n\n আপনি যদি আপনার পাসওয়ার্ড হারিয়ে ফেলেন, আপনি আপনার কী পুনরুদ্ধার করতে পারবেন না।. - + ## মূল ব্যাকআপ এবং নিরাপত্তা টিপস \n\n আপনার অ্যাকাউন্ট একটি গোপন কী দ্বারা সুরক্ষিত। মূলটি হল অক্ষরগুলির একটি দীর্ঘ ক্রম যা শুরু হয় **nsec1**. যে কেউ এই গোপন কী অ্যাক্সেস করতে পারে পোস্ট এবং আপনার পরিচয় পরিবর্তন করতে পারেন. \n\n- আপনি বিশ্বাস করেন না এমন কোনো ওয়েবসাইট বা সফ্টওয়্যারে আপনার গোপন কী **করবেন না**. \n- অ্যামেথিস্ট ডেভেলপাররা **কখনই** আপনার গোপন কী চাইবে না. \n- **করুন** অ্যাকাউন্ট পুনরুদ্ধারের জন্য আপনার গোপন কীটির একটি নিরাপদ ব্যাকআপ রাখুন৷. আমরা একটি পাসওয়ার্ড ম্যানেজার ব্যবহার করার পরামর্শ দিই।. + অতিরিক্ত নিরাপত্তার জন্য, আপনি একটি পাসওয়ার্ড দিয়ে আপনার কী এনক্রিপ্ট করতে পারেন. এই কী দিয়ে শুরু হয় **ncryptsec1** এবং আপনার পাসওয়ার্ড ছাড়া ব্যবহার করা যাবে না।. \n\n আপনি যদি আপনার পাসওয়ার্ড হারিয়ে ফেলেন, আপনি আপনার কী পুনরুদ্ধার করতে পারবেন না।. এনক্রিপ্ট এবং আমার গোপন কী অনুলিপি %1$s -এর জন্য ব্যাজ পুরষ্কারের ছবি "ব্যাজ পুরস্কার চিত্র @@ -963,9 +956,7 @@ Push বিজ্ঞপ্তি নিষ্ক্রিয় করে অ্যাপ %1$s ব্যবহার করে Push বিজ্ঞপ্তি সেটআপ - পুশ নোটিফিকেশন পেতে, [Unified Push](https://unifiedpush.org/) সমর্থন করে এমন যেকোনো অ্যাপ ইনস্টল করুন, যেমন [Ntfy](https://ntfy.sh/)। - ইনস্টল করার পরে, সেটিংসে আপনি যে অ্যাপটি ব্যবহার করতে চান তা নির্বাচন করুন। - + পুশ নোটিফিকেশন পেতে, [Unified Push](https://unifiedpush.org/) সমর্থন করে এমন যেকোনো অ্যাপ ইনস্টল করুন, যেমন [Ntfy](https://ntfy.sh/)। ইনস্টল করার পরে, সেটিংসে আপনি যে অ্যাপটি ব্যবহার করতে চান তা নির্বাচন করুন। থ্রেড বিক্রেতাকে একটি বার্তা পাঠান হাই, এটা কি এখনও পাওয়া যায়? @@ -2022,15 +2013,7 @@ %1$s থেকে ইনভয়েস আনতে পারেনি: %2$s সংকুচিত ফাইলটি খোলা যায়নি ওয়ালেট পাওয়া যায়নি - Amethyst কোনো ওয়ালেট অ্যাপ খুঁজে পায়নি যা Nostr Wallet Connect (NWC) সমর্থন করে। -\n\nআপনি যা করতে পারেন: -\n\t১. NWC সমর্থন যাচাই করুন: নিশ্চিত করুন যে আপনার পছন্দের ওয়ালেট অ্যাপ Nostr Wallet Connect-এর সাথে সামঞ্জস্যপূর্ণ। -\n\t২. সংযোগ তৈরি করুন: আপনার ওয়ালেট অ্যাপে যান এবং একটি নতুন NWC সংযোগ তৈরি করুন। -\n\t৩. Amethyst-এ লিঙ্ক করুন: আপনার ওয়ালেট সাধারণত তিনটি বিকল্প দেবে: -\n\t\t৩.১ স্বয়ংক্রিয় লিঙ্ক: একটি বোতাম যা স্বয়ংক্রিয়ভাবে Amethyst খুলে সংযুক্ত করবে। যদি তাই হয়, সেই বোতামে ক্লিক করুন, Amethyst খুলুন এবং নতুন স্ক্রিনে সেভ চাপুন। -\n\t\t৩.২ ম্যানুয়াল লিঙ্ক: একটি Connection URI যা কপি করে এই স্ক্রিনের পেস্ট আইকনে ক্লিক করে সরাসরি ইনপুট করতে পারবেন। -\n\t\t৩.৩ QR কোড: ওয়ালেট একটি QR কোড তৈরি করে যা আপনি এই স্ক্রিনের QR কোড বোতাম থেকে পড়তে পারবেন। - + Amethyst কোনো ওয়ালেট অ্যাপ খুঁজে পায়নি যা Nostr Wallet Connect (NWC) সমর্থন করে। \n\nআপনি যা করতে পারেন: \n\t১. NWC সমর্থন যাচাই করুন: নিশ্চিত করুন যে আপনার পছন্দের ওয়ালেট অ্যাপ Nostr Wallet Connect-এর সাথে সামঞ্জস্যপূর্ণ। \n\t২. সংযোগ তৈরি করুন: আপনার ওয়ালেট অ্যাপে যান এবং একটি নতুন NWC সংযোগ তৈরি করুন। \n\t৩. Amethyst-এ লিঙ্ক করুন: আপনার ওয়ালেট সাধারণত তিনটি বিকল্প দেবে: \n\t\t৩.১ স্বয়ংক্রিয় লিঙ্ক: একটি বোতাম যা স্বয়ংক্রিয়ভাবে Amethyst খুলে সংযুক্ত করবে। যদি তাই হয়, সেই বোতামে ক্লিক করুন, Amethyst খুলুন এবং নতুন স্ক্রিনে সেভ চাপুন। \n\t\t৩.২ ম্যানুয়াল লিঙ্ক: একটি Connection URI যা কপি করে এই স্ক্রিনের পেস্ট আইকনে ক্লিক করে সরাসরি ইনপুট করতে পারবেন। \n\t\t৩.৩ QR কোড: ওয়ালেট একটি QR কোড তৈরি করে যা আপনি এই স্ক্রিনের QR কোড বোতাম থেকে পড়তে পারবেন। তৈরি করুন d বিপদজনক এলাকা @@ -2699,11 +2682,8 @@ প্রক্সি Relay অ্যাগ্রিগেটর relay যা অ্যাপটিকে আপনার ফিড ডাউনলোড করতে অবশ্যই ব্যবহার করতে হবে, যেমন filter.nostr.wine। এটি আউটবক্স মডেলকে প্রতিস্থাপন করে এবং অ্যাপটিকে শুধুমাত্র আপনার তালিকার relay গুলোতে সংযুক্ত করবে। সার্বজনীন আলাপ - পাবলিক চ্যাটগুলো Nostr-এর সবার কাছে দৃশ্যমান এবং যে কেউ - এতে অংশগ্রহণ করতে পারে। নির্দিষ্ট বিষয়ের চারপাশে উন্মুক্ত সম্প্রদায়ের জন্য এগুলো দুর্দান্ত। - এর relay-তে পোস্ট মুছে পরিচালনা নিয়ন্ত্রণ করা যায় - এই গ্রুপটি হোস্ট করে এমন ১-৩ টি relay যোগ করুন। - Nostr ক্লায়েন্টগুলো এই সেটিং ব্যবহার করে জানে যে কোথা থেকে বার্তা ডাউনলোড করতে হবে এবং আপনার বার্তা কোথায় পাঠাতে হবে। + পাবলিক চ্যাটগুলো Nostr-এর সবার কাছে দৃশ্যমান এবং যে কেউ এতে অংশগ্রহণ করতে পারে। নির্দিষ্ট বিষয়ের চারপাশে উন্মুক্ত সম্প্রদায়ের জন্য এগুলো দুর্দান্ত। এর relay-তে পোস্ট মুছে পরিচালনা নিয়ন্ত্রণ করা যায় + এই গ্রুপটি হোস্ট করে এমন ১-৩ টি relay যোগ করুন। Nostr ক্লায়েন্টগুলো এই সেটিং ব্যবহার করে জানে যে কোথা থেকে বার্তা ডাউনলোড করতে হবে এবং আপনার বার্তা কোথায় পাঠাতে হবে। Relay-গুলি পাবলিক চ্যাট মেটাডেটা পাবলিক চ্যাট @@ -2728,10 +2708,7 @@ শুধু-পড়ার ব্যবহারকারী একটি বার্তা রেকর্ড করতে ক্লিক করুন এবং ধরে রাখুন Relay চ্যাট - Relay চ্যাটগুলো হলো চ্যাট গ্রুপ যা তাদের হোম relay দ্বারা নিয়ন্ত্রিত হয়। - এগুলো Nostr-এর সবার কাছে দৃশ্যমান এবং যে কেউ এতে অংশগ্রহণ করতে পারে। - নির্দিষ্ট বিষয়ের চারপাশে উন্মুক্ত সম্প্রদায়ের জন্য এগুলো দুর্দান্ত। এই গ্রুপগুলোর কিছু ক্ষণস্থায়ী - এবং সেজন্য চ্যাট বার্তাগুলো সময়ের সাথে মুছে যায় + Relay চ্যাটগুলো হলো চ্যাট গ্রুপ যা তাদের হোম relay দ্বারা নিয়ন্ত্রিত হয়। এগুলো Nostr-এর সবার কাছে দৃশ্যমান এবং যে কেউ এতে অংশগ্রহণ করতে পারে। নির্দিষ্ট বিষয়ের চারপাশে উন্মুক্ত সম্প্রদায়ের জন্য এগুলো দুর্দান্ত। এই গ্রুপগুলোর কিছু ক্ষণস্থায়ী এবং সেজন্য চ্যাট বার্তাগুলো সময়ের সাথে মুছে যায় Relay চ্যাট ইভেন্ট আইপি diff --git a/commonsUI/src/commonMain/composeResources/values-cs/strings.xml b/commonsUI/src/commonMain/composeResources/values-cs/strings.xml index 4611482789..b21d6ee05a 100644 --- a/commonsUI/src/commonMain/composeResources/values-cs/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-cs/strings.xml @@ -473,13 +473,8 @@ Označit všechny známé jako přečtené Označit všechny nové jako přečtené Označit všechny jako přečtené - ## Tipy pro zálohování klíčů a bezpečnost - \n\nVaše konto je zabezpečeno tajným klíčem. Klíč je dlouhá posloupnost znaků začínající s **nsec1**. Kdo má přístup k tomuto tajnému klíči, může přispívat a měnit vaši identitu. - \n\n- **Nedávejte** svůj tajný klíč na žádnou webovou stránku nebo do žádného softwaru, kterému nedůvěřujete. - \n- Vývojáři Amethystu nikdy **nebudou** žádat o váš tajný klíč. - \n- **Udržujte** bezpečnou zálohu vašeho tajného klíče pro obnovení účtu. Doporučujeme použití správce hesel. - Pro další zabezpečení můžete svůj klíč zašifrovat heslem. Tento klíč začíná s **ncryptsec1** a nelze ho použít bez vašeho hesla. - \n\nPokud zapomenete heslo, nebudete moci obnovit svůj klíč. + ## Tipy pro zálohování klíčů a bezpečnost \n\nVaše konto je zabezpečeno tajným klíčem. Klíč je dlouhá posloupnost znaků začínající s **nsec1**. Kdo má přístup k tomuto tajnému klíči, může přispívat a měnit vaši identitu. \n\n- **Nedávejte** svůj tajný klíč na žádnou webovou stránku nebo do žádného softwaru, kterému nedůvěřujete. \n- Vývojáři Amethystu nikdy **nebudou** žádat o váš tajný klíč. \n- **Udržujte** bezpečnou zálohu vašeho tajného klíče pro obnovení účtu. Doporučujeme použití správce hesel. + Pro další zabezpečení můžete svůj klíč zašifrovat heslem. Tento klíč začíná s **ncryptsec1** a nelze ho použít bez vašeho hesla. \n\nPokud zapomenete heslo, nebudete moci obnovit svůj klíč. Zálohujte si klíče Váš tajný klíč je jediný způsob, jak se k tomuto účtu dostat. Pokud ho ztratíte, nelze ho už nikdy obnovit. Uložte si ho někam do bezpečí. Zálohovat nyní @@ -1598,9 +1593,7 @@ Zakázat Push oznámení Použít aplikaci %1$s Nastavení Push-oznámení - Pro příjem Push-oznámení nainstalujte libovolnou aplikaci, která podporuje [Unified Push](https://unifiedpush.org/), jako je [Ntfy](https://ntfy.sh/). - Po instalaci vyberte aplikaci kterou chcete používat v Nastavení. - + Pro příjem Push-oznámení nainstalujte libovolnou aplikaci, která podporuje [Unified Push](https://unifiedpush.org/), jako je [Ntfy](https://ntfy.sh/). Po instalaci vyberte aplikaci kterou chcete používat v Nastavení. Vlákno Poslat prodejci zprávu Ahoj, je to stále k dispozici? @@ -3393,14 +3386,7 @@ Nelze získat fakturu z %1$s: %2$s Nepodařilo se otevřít komprimovaný soubor Peněženka nebyla nalezená - Amethyst nenašel žádné aplikace peněženek, které podporují Nostr Wallet Connect (NWC). -\n\nCo můžete udělat: -\n\t1. Ověřte podporu NWC: Zkontrolujte, že vaše oblíbená peněženka podporuje Nostr Wallet Connect. -\n\t2. Vytvořte připojení: Otevřete svou peněženku a vytvořte nové NWC připojení. -\n\t3. Propojte s Amethyst: Vaše peněženka obvykle nabídne tři možnosti: -\n\t\t3.1 Automatické propojení: Tlačítko pro automatické otevření a připojení k Amethyst. Klikněte na něj, otevřete Amethyst a uložte na nové obrazovce. -\n\t\t3.2 Ruční propojení: URI připojení, které můžete zkopírovat a vložit přes ikonu vložení na této obrazovce. -\n\t\t3.3 QR kód: Peněženka vytvoří QR kód, který můžete naskenovat pomocí tlačítka QR kódu na této obrazovce. + Amethyst nenašel žádné aplikace peněženek, které podporují Nostr Wallet Connect (NWC). \n\nCo můžete udělat: \n\t1. Ověřte podporu NWC: Zkontrolujte, že vaše oblíbená peněženka podporuje Nostr Wallet Connect. \n\t2. Vytvořte připojení: Otevřete svou peněženku a vytvořte nové NWC připojení. \n\t3. Propojte s Amethyst: Vaše peněženka obvykle nabídne tři možnosti: \n\t\t3.1 Automatické propojení: Tlačítko pro automatické otevření a připojení k Amethyst. Klikněte na něj, otevřete Amethyst a uložte na nové obrazovce. \n\t\t3.2 Ruční propojení: URI připojení, které můžete zkopírovat a vložit přes ikonu vložení na této obrazovce. \n\t\t3.3 QR kód: Peněženka vytvoří QR kód, který můžete naskenovat pomocí tlačítka QR kódu na této obrazovce. Vytvořit d Nebezpečná zóna @@ -4611,11 +4597,8 @@ Proxy přenašeče Agregační přenašeče, které aplikace používá ke stahování vašich zdrojů, jako např. filter.nostr.wine Veřejný chat - Veřejné konverzace jsou viditelné pro všechny na Nostru a kdokoli - se na nich může podílet. Jsou skvělé pro otevřené komunity kolem konkrétních témat. - Moderaci lze ovládat smazáním příspěvků na relé - Vložte mezi 1–3 relé, které hostí tuto skupinu. - Klienti Nostr používají toto nastavení, aby věděli, kam stahovat zprávy a odesílat zprávy. + Veřejné konverzace jsou viditelné pro všechny na Nostru a kdokoli se na nich může podílet. Jsou skvělé pro otevřené komunity kolem konkrétních témat. Moderaci lze ovládat smazáním příspěvků na relé + Vložte mezi 1–3 relé, které hostí tuto skupinu. Klienti Nostr používají toto nastavení, aby věděli, kam stahovat zprávy a odesílat zprávy. Rele Metadata veřejného chatu Veřejné chaty @@ -4684,10 +4667,7 @@ auth autentizace relay podepsat ověřit nip-42 identita Autentizace relay Relé chat - Relay chaty jsou chatové skupiny ovládané jejich domácí relé. - Jsou viditelné pro všechny na Nostru a každý se jich může zúčastnit. - Jsou skvělé pro otevřené komunity kolem konkrétních témat. Některé z těchto skupin jsou efemérní - a proto zprávy časem mizí + Relay chaty jsou chatové skupiny ovládané jejich domácí relé. Jsou viditelné pro všechny na Nostru a každý se jich může zúčastnit. Jsou skvělé pro otevřené komunity kolem konkrétních témat. Některé z těchto skupin jsou efemérní a proto zprávy časem mizí Relé chaty Váš vlastní profil, nastavení a koncepty na vašich domovských relayích. Relaye, na které každá komunita publikuje své roviny. diff --git a/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml b/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml index 076f687129..17617a8ae7 100644 --- a/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-de-rDE/strings.xml @@ -361,7 +361,7 @@ Benutzer-ID kopieren Benutzer freigeben Dieser Nutzer ist blockiert/stummgeschaltet. Seine Beiträge sind ausgeblendet. - npub, Benutzername, Text + npub, Benutzername, Text Löschen App-Logo nsec.. oder npub.. @@ -463,13 +463,8 @@ Alle Kontakte als gelesen markieren Alle Unbekannten als gelesen markieren Alle als gelesen markieren - ## Tipps zur Schlüsselsicherheit - \n\nDein Konto ist durch einen privaten Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen privaten Schlüssel hat, kann in deinem Namen posten und dein Profil ändern. - \n\n- Lege deinen privaten Schlüssel **nicht** auf einer Website oder in einer Software ab, der du nicht vertraust. - \n- Die Entwickler von Amethyst werden dich **niemals** nach deinem privaten Schlüssel fragen. - \n- **Bewahre** eine sichere Kopie deines privaten Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. - Für zusätzliche Sicherheit kannst du deinen Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne dein Passwort nicht verwendet werden. - \n\nWenn du dein Passwort verlierst, kannst du deinen Schlüssel nicht wiederherstellen. + ## Tipps zur Schlüsselsicherheit \n\nDein Konto ist durch einen privaten Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen privaten Schlüssel hat, kann in deinem Namen posten und dein Profil ändern. \n\n- Lege deinen privaten Schlüssel **nicht** auf einer Website oder in einer Software ab, der du nicht vertraust. \n- Die Entwickler von Amethyst werden dich **niemals** nach deinem privaten Schlüssel fragen. \n- **Bewahre** eine sichere Kopie deines privaten Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. + Für zusätzliche Sicherheit kannst du deinen Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne dein Passwort nicht verwendet werden. \n\nWenn du dein Passwort verlierst, kannst du deinen Schlüssel nicht wiederherstellen. Sichere deine Schlüssel Dein geheimer Schlüssel ist der einzige Weg zu diesem Konto. Wenn du ihn verlierst, kann er nie wiederhergestellt werden. Speichere ihn jetzt an einem sicheren Ort. Jetzt sichern @@ -1584,9 +1579,7 @@ Push-Benachrichtigungen deaktivieren Verwendet die App %1$s Push-Benachrichtigungen einrichten - Um Push-Benachrichtigungen zu erhalten, installiere eine App, die [Unified Push](https://unifiedpush.org/) unterstützt, wie zum Beispiel [Ntfy](https://ntfy.sh/). - Nach der Installation wähle in den Einstellungen die App aus, die du verwenden möchtest. - + Um Push-Benachrichtigungen zu erhalten, installiere eine App, die [Unified Push](https://unifiedpush.org/) unterstützt, wie zum Beispiel [Ntfy](https://ntfy.sh/). Nach der Installation wähle in den Einstellungen die App aus, die du verwenden möchtest. Faden Dem Verkäufer eine Nachricht senden Hallo, ist das noch verfügbar? @@ -3323,14 +3316,7 @@ Rechnung konnte nicht von %1$s abgerufen werden: %2$s Konnte die komprimierte Datei nicht öffnen Wallet nicht gefunden - Amethyst konnte keine Wallet-Apps finden, die Nostr Wallet Connect (NWC) unterstützen. -\n\nWas du tun kannst: -\n\t1. NWC-Unterstützung überprüfen: Stelle sicher, dass deine bevorzugte Wallet-App mit Nostr Wallet Connect kompatibel ist. -\n\t2. Verbindung erstellen: Öffne deine Wallet-App und erstelle eine neue NWC-Verbindung. -\n\t3. Mit Amethyst verknüpfen: Deine Wallet bietet normalerweise drei Optionen: -\n\t\t3.1 Automatische Verknüpfung: Eine Schaltfläche zum automatischen Öffnen und Verbinden mit Amethyst. Klicke darauf, öffne Amethyst und speichere auf dem neuen Bildschirm. -\n\t\t3.2 Manuelle Verknüpfung: Eine Verbindungs-URI, die du kopieren und über das Einfügesymbol auf diesem Bildschirm einfügen kannst. -\n\t\t3.3 QR-Code: Die Wallet erstellt einen QR-Code, den du über die QR-Schaltfläche auf diesem Bildschirm scannen kannst. + Amethyst konnte keine Wallet-Apps finden, die Nostr Wallet Connect (NWC) unterstützen. \n\nWas du tun kannst: \n\t1. NWC-Unterstützung überprüfen: Stelle sicher, dass deine bevorzugte Wallet-App mit Nostr Wallet Connect kompatibel ist. \n\t2. Verbindung erstellen: Öffne deine Wallet-App und erstelle eine neue NWC-Verbindung. \n\t3. Mit Amethyst verknüpfen: Deine Wallet bietet normalerweise drei Optionen: \n\t\t3.1 Automatische Verknüpfung: Eine Schaltfläche zum automatischen Öffnen und Verbinden mit Amethyst. Klicke darauf, öffne Amethyst und speichere auf dem neuen Bildschirm. \n\t\t3.2 Manuelle Verknüpfung: Eine Verbindungs-URI, die du kopieren und über das Einfügesymbol auf diesem Bildschirm einfügen kannst. \n\t\t3.3 QR-Code: Die Wallet erstellt einen QR-Code, den du über die QR-Schaltfläche auf diesem Bildschirm scannen kannst. Erstellen t Gefahrenzone @@ -4427,11 +4413,8 @@ Proxy-Relays Aggregator-Relays wie filter.nostr.wine, von denen die App deine Feeds herunterlädt Öffentlicher Chat - Öffentliche Chats sind für jeden auf Nostr sichtbar und jeder - kann daran teilnehmen. Sie eignen sich hervorragend für offene Gemeinschaften rund um bestimmte Themen. - Moderation kann durch Löschen von Beiträgen auf den Relays gesteuert werden - Füge zwischen 1–3 Relays ein, die diese Gruppe beherbergen. - Nostr Clients verwenden diese Einstellung, um zu wissen, woher sie Nachrichten herunterladen und an welche gesendet werden sollen. + Öffentliche Chats sind für jeden auf Nostr sichtbar und jeder kann daran teilnehmen. Sie eignen sich hervorragend für offene Gemeinschaften rund um bestimmte Themen. Moderation kann durch Löschen von Beiträgen auf den Relays gesteuert werden + Füge zwischen 1–3 Relays ein, die diese Gruppe beherbergen. Nostr Clients verwenden diese Einstellung, um zu wissen, woher sie Nachrichten herunterladen und an welche gesendet werden sollen. Relays Öffentliche Chat Metadaten Öffentliche Chats @@ -4496,10 +4479,7 @@ auth authentifizierung relay signieren verifizieren nip-42 identität Relay-Authentifizierung Relay-Chat - Relay-Chats sind Chatgruppen, die von ihrem Home-Relay gesteuert werden. - Sie sind für jeden auf Nostr sichtbar und jeder kann an ihnen teilnehmen. - Sie eignen sich hervorragend für offene Communities rund um bestimmte Themen. Einige dieser Gruppen sind kurzsichtig - und daher verschwinden Chat-Nachrichten im Laufe der Zeit + Relay-Chats sind Chatgruppen, die von ihrem Home-Relay gesteuert werden. Sie sind für jeden auf Nostr sichtbar und jeder kann an ihnen teilnehmen. Sie eignen sich hervorragend für offene Communities rund um bestimmte Themen. Einige dieser Gruppen sind kurzsichtig und daher verschwinden Chat-Nachrichten im Laufe der Zeit Relay-Chats Dein eigenes Profil, deine Einstellungen und Entwürfe auf deinen Heim-Relays. Die Relays, auf denen jede Community ihre Planes veröffentlicht. diff --git a/commonsUI/src/commonMain/composeResources/values-de/strings.xml b/commonsUI/src/commonMain/composeResources/values-de/strings.xml index fe28311d40..a1bc04624c 100644 --- a/commonsUI/src/commonMain/composeResources/values-de/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-de/strings.xml @@ -211,7 +211,7 @@ Benutzer-ID kopieren Benutzer freigeben Dieser Nutzer ist blockiert/stummgeschaltet. Seine Beiträge sind ausgeblendet. - Npub, Hex, Benutzername + Npub, Hex, Benutzername Löschen App-Logo Nsec / Npub / Hex-Privatschlüssel @@ -219,9 +219,7 @@ Passwort anzeigen Ich akzeptiere die Nutzungsbedingungen - Die Akzept - -anz der Bedingungen ist erforderlich + Die Akzept anz der Bedingungen ist erforderlich Anmeldung Anmelden Konto erstellen @@ -261,13 +259,8 @@ anz der Bedingungen ist erforderlich Alle als bekannt markieren Alle als neu markieren Alle als gelesen markieren - ## Schlüsselsicherheits-Tipps - \n\nIhr Konto ist durch einen geheimen Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen geheimen Schlüssel hat, kann Ihre Identität posten und ändern. - \n\n- Legen Sie Ihren geheimen Schlüssel **nicht** auf eine Website oder in eine Software, der Sie nicht vertrauen. - \n- Die Entwickler von Amethyst werden Sie **niemals** nach Ihrem geheimen Schlüssel fragen. - \n- **Bewahren Sie** eine sichere Sicherung Ihres geheimen Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. - Für zusätzliche Sicherheit können Sie Ihren Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne Ihr Passwort nicht verwendet werden. - \n\nWenn Sie Ihr Passwort verlieren, können Sie Ihren Schlüssel nicht wiederherstellen. + ## Schlüsselsicherheits-Tipps \n\nIhr Konto ist durch einen geheimen Schlüssel gesichert. Der Schlüssel ist eine lange Zeichenfolge, die mit **nsec1** beginnt. Jeder, der Zugriff auf diesen geheimen Schlüssel hat, kann Ihre Identität posten und ändern. \n\n- Legen Sie Ihren geheimen Schlüssel **nicht** auf eine Website oder in eine Software, der Sie nicht vertrauen. \n- Die Entwickler von Amethyst werden Sie **niemals** nach Ihrem geheimen Schlüssel fragen. \n- **Bewahren Sie** eine sichere Sicherung Ihres geheimen Schlüssels zur Kontowiederherstellung auf. Wir empfehlen die Verwendung eines Passwort-Managers. + Für zusätzliche Sicherheit können Sie Ihren Schlüssel mit einem Passwort verschlüsseln. Dieser Schlüssel beginnt mit **ncryptsec1** und kann ohne Ihr Passwort nicht verwendet werden. \n\nWenn Sie Ihr Passwort verlieren, können Sie Ihren Schlüssel nicht wiederherstellen. Verschlüsseln und kopieren Sie meinen geheimen Schlüssel Auszeichnungsbild für %1$s Auszeichnungsbild @@ -960,9 +953,7 @@ anz der Bedingungen ist erforderlich Push-Benachrichtigungen deaktivieren Verwendet die App %1$s Push-Benachrichtigungen einrichten - Um Push-Benachrichtigungen zu erhalten, installieren Sie eine App, die [Unified Push](https://unifiedpush.org/) unterstützt, wie zum Beispiel [Ntfy](https://ntfy.sh/). - Nach der Installation wählen Sie die App aus, die Sie in den Einstellungen verwenden möchten. - + Um Push-Benachrichtigungen zu erhalten, installieren Sie eine App, die [Unified Push](https://unifiedpush.org/) unterstützt, wie zum Beispiel [Ntfy](https://ntfy.sh/). Nach der Installation wählen Sie die App aus, die Sie in den Einstellungen verwenden möchten. Faden Dem Verkäufer eine Nachricht senden Hallo, ist das noch verfügbar? @@ -2064,14 +2055,7 @@ anz der Bedingungen ist erforderlich Rechnung konnte nicht von %1$s abgerufen werden: %2$s Konnte die komprimierte Datei nicht öffnen Wallet nicht gefunden - Amethyst konnte keine Wallet-Apps finden, die Nostr Wallet Connect (NWC) unterstützen. -\n\nWas du tun kannst: -\n\t1. NWC-Unterstützung überprüfen: Stelle sicher, dass deine bevorzugte Wallet-App mit Nostr Wallet Connect kompatibel ist. -\n\t2. Verbindung erstellen: Öffne deine Wallet-App und erstelle eine neue NWC-Verbindung. -\n\t3. Mit Amethyst verknüpfen: Deine Wallet bietet normalerweise drei Optionen: -\n\t\t3.1 Automatische Verknüpfung: Eine Schaltfläche zum automatischen Öffnen und Verbinden mit Amethyst. Klicke darauf, öffne Amethyst und speichere auf dem neuen Bildschirm. -\n\t\t3.2 Manuelle Verknüpfung: Eine Verbindungs-URI, die du kopieren und über das Einfügesymbol auf diesem Bildschirm einfügen kannst. -\n\t\t3.3 QR-Code: Die Wallet erstellt einen QR-Code, den du über die QR-Schaltfläche auf diesem Bildschirm scannen kannst. + Amethyst konnte keine Wallet-Apps finden, die Nostr Wallet Connect (NWC) unterstützen. \n\nWas du tun kannst: \n\t1. NWC-Unterstützung überprüfen: Stelle sicher, dass deine bevorzugte Wallet-App mit Nostr Wallet Connect kompatibel ist. \n\t2. Verbindung erstellen: Öffne deine Wallet-App und erstelle eine neue NWC-Verbindung. \n\t3. Mit Amethyst verknüpfen: Deine Wallet bietet normalerweise drei Optionen: \n\t\t3.1 Automatische Verknüpfung: Eine Schaltfläche zum automatischen Öffnen und Verbinden mit Amethyst. Klicke darauf, öffne Amethyst und speichere auf dem neuen Bildschirm. \n\t\t3.2 Manuelle Verknüpfung: Eine Verbindungs-URI, die du kopieren und über das Einfügesymbol auf diesem Bildschirm einfügen kannst. \n\t\t3.3 QR-Code: Die Wallet erstellt einen QR-Code, den du über die QR-Schaltfläche auf diesem Bildschirm scannen kannst. Erstellen t Gefahrenzone @@ -2274,9 +2258,7 @@ anz der Bedingungen ist erforderlich Schleife erkannt - Der Server erkennt eine Endlosschleife, während er die Anfrage bearbeitet Netzwerk-Authentifizierung erforderlich - Der Client muss authentifiziert werden, um auf das Netzwerk zuzugreifen Illegales Verhalten - Bild in der Gal - -erie gespeichert + Bild in der Gal erie gespeichert Vortäuschung Kontakte, folgen, Folgeliste, importieren Eingehende Relays @@ -2777,11 +2759,8 @@ erie gespeichert Proxy-Relays Aggregator-Relays wie filter.nostr.wine, von denen die App deine Feeds herunterlädt Öffentlicher Chat - Öffentliche Chats sind für jeden auf Nostr sichtbar und jeder - kann daran teilnehmen. Sie eignen sich hervorragend für offene Gemeinschaften rund um bestimmte Themen. - Moderation kann durch Löschen von Beiträgen auf den Relais gesteuert werden - Fügen Sie zwischen 1–3 Relais ein, die diese Gruppe beherbergen. - Nostr Clients verwenden diese Einstellung, um zu wissen, woher sie Nachrichten herunterladen und an welche gesendet werden sollen. + Öffentliche Chats sind für jeden auf Nostr sichtbar und jeder kann daran teilnehmen. Sie eignen sich hervorragend für offene Gemeinschaften rund um bestimmte Themen. Moderation kann durch Löschen von Beiträgen auf den Relais gesteuert werden + Fügen Sie zwischen 1–3 Relais ein, die diese Gruppe beherbergen. Nostr Clients verwenden diese Einstellung, um zu wissen, woher sie Nachrichten herunterladen und an welche gesendet werden sollen. Relais Öffentliche Chat Metadaten Öffentliche Chats @@ -2808,10 +2787,7 @@ erie gespeichert Nur-Lese-Benutzer Zum Aufnehmen einer Nachricht gedrückt halten Relay-Chat - Relaischats sind Chatgruppen, die von ihrem Home-Relais gesteuert werden. - Sie sind für jeden auf Nostr sichtbar und jeder kann an ihnen teilnehmen. - Sie eignen sich hervorragend für offene Communities rund um bestimmte Themen. Einige dieser Gruppen sind kurzsichtig - und daher verschwinden Chat-Nachrichten im Laufe der Zeit + Relaischats sind Chatgruppen, die von ihrem Home-Relais gesteuert werden. Sie sind für jeden auf Nostr sichtbar und jeder kann an ihnen teilnehmen. Sie eignen sich hervorragend für offene Communities rund um bestimmte Themen. Einige dieser Gruppen sind kurzsichtig und daher verschwinden Chat-Nachrichten im Laufe der Zeit Relay-Chats Ereignisse IPs diff --git a/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml b/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml index 6569dd09c3..ffe6a08835 100644 --- a/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-el-rGR/strings.xml @@ -271,15 +271,8 @@ Σήμανση όλων των γνωστοποιήσεων ως αναγνωσμένων Σήμανση όλων ως αναγνωσμένων Σήμανση όλων ως αναγνωσμένα - ## Συμβουλές ασφαλείας και δημιουργίας αντιγράφων ασφαλείας κλειδιού - \n\nΟ λογαριασμός σου ασφαλίζεται με ένα μυστικό κλειδί. Το κλειδί είναι μια μακρά ακολουθία χαρακτήρων που ξεκινά με **nsec1**. Όποιος έχει πρόσβαση σε αυτό το μυστικό κλειδί μπορεί να δημοσιεύει και να αλλάζει την ταυτότητά σου. - \n\n- **Μην** βάζεις το μυστικό σου κλειδί σε κανέναν ιστότοπο ή λογισμικό που δεν εμπιστεύεσαι. - \n- Οι προγραμματιστές του Amethyst **δεν** θα ζητήσουν ποτέ το μυστικό σου κλειδί. - \n- **Διατήρησε** ένα ασφαλές αντίγραφο ασφαλείας του μυστικού σου κλειδιού για ανάκτηση λογαριασμού. Συνιστούμε τη χρήση διαχειριστή κωδικών πρόσβασης. - - Για πρόσθετη ασφάλεια, μπορείς να κρυπτογραφήσεις το κλειδί σου με κωδικό πρόσβασης. Αυτό το κλειδί ξεκινά με **ncryptsec1** και δεν μπορεί να χρησιμοποιηθεί χωρίς τον κωδικό σου. - \n\nΑν χάσεις τον κωδικό σου, δεν θα μπορείς να ανακτήσεις το κλειδί σου. - + ## Συμβουλές ασφαλείας και δημιουργίας αντιγράφων ασφαλείας κλειδιού \n\nΟ λογαριασμός σου ασφαλίζεται με ένα μυστικό κλειδί. Το κλειδί είναι μια μακρά ακολουθία χαρακτήρων που ξεκινά με **nsec1**. Όποιος έχει πρόσβαση σε αυτό το μυστικό κλειδί μπορεί να δημοσιεύει και να αλλάζει την ταυτότητά σου. \n\n- **Μην** βάζεις το μυστικό σου κλειδί σε κανέναν ιστότοπο ή λογισμικό που δεν εμπιστεύεσαι. \n- Οι προγραμματιστές του Amethyst **δεν** θα ζητήσουν ποτέ το μυστικό σου κλειδί. \n- **Διατήρησε** ένα ασφαλές αντίγραφο ασφαλείας του μυστικού σου κλειδιού για ανάκτηση λογαριασμού. Συνιστούμε τη χρήση διαχειριστή κωδικών πρόσβασης. + Για πρόσθετη ασφάλεια, μπορείς να κρυπτογραφήσεις το κλειδί σου με κωδικό πρόσβασης. Αυτό το κλειδί ξεκινά με **ncryptsec1** και δεν μπορεί να χρησιμοποιηθεί χωρίς τον κωδικό σου. \n\nΑν χάσεις τον κωδικό σου, δεν θα μπορείς να ανακτήσεις το κλειδί σου. Κρυπτογράφηση και αντιγραφή του μυστικού μου κλειδιού Σήμα βράβευσης για %1$s "Εικόνα βραβείου παρασήμου @@ -934,8 +927,7 @@ Συντονιστές Σύνδεση με Amber Ενημέρωση κατάστασης - Η ψηφοφορία σε μια δημοσίευση Δημοσκόπησης γίνεται με zaps. Τα zaps είναι μικροπληρωμές σε satoshi (sats). Τα sats είναι υποδιαίρεση του Bitcoin. Κάθε Bitcoin έχει 100.000.000 sats. -Η επιλογή με τα περισσότερα zaps (δηλαδή τα περισσότερα sats) είναι η επικρατέστερη. Μπορείτε να ορίσετε ένα ελάχιστο ποσό zap για να αποφύγετε την ψήφο spammers αλλά και ένα μέγιστο ποσό ώστε να αποφύγετε μεγάλους zappers (χρήστες που στέλνουν zaps) που επιθυμούν να χειραγωγήσουν την ψηφοφορία. Χρησιμοποιήστε το ίδιο ποσό και στα δύο πεδία για να βεβαιωθείτε ότι κάθε ψήφος αποτιμάται το ίδιο. Ή αφήστε τα πεδία κενά για να αποδεχτείτε οποιοδήποτε ποσό. + Η ψηφοφορία σε μια δημοσίευση Δημοσκόπησης γίνεται με zaps. Τα zaps είναι μικροπληρωμές σε satoshi (sats). Τα sats είναι υποδιαίρεση του Bitcoin. Κάθε Bitcoin έχει 100.000.000 sats. Η επιλογή με τα περισσότερα zaps (δηλαδή τα περισσότερα sats) είναι η επικρατέστερη. Μπορείτε να ορίσετε ένα ελάχιστο ποσό zap για να αποφύγετε την ψήφο spammers αλλά και ένα μέγιστο ποσό ώστε να αποφύγετε μεγάλους zappers (χρήστες που στέλνουν zaps) που επιθυμούν να χειραγωγήσουν την ψηφοφορία. Χρησιμοποιήστε το ίδιο ποσό και στα δύο πεδία για να βεβαιωθείτε ότι κάθε ψήφος αποτιμάται το ίδιο. Ή αφήστε τα πεδία κενά για να αποδεχτείτε οποιοδήποτε ποσό. Μήνυμα στον Χρήστη Μήνυμα σε %1$s ΟΚ @@ -963,9 +955,7 @@ Απενεργοποίηση Ειδοποιήσεων Push Χρήση εφαρμογής %1$s Ρυθμίσεις Ειδοποιήσεων Push - Για να λαμβάνετε ειδοποιήσεις Push, εγκαταστήστε οποιαδήποτε εφαρμογή τις υποστηρίζει [Unified Push](https://unifiedpush.org/), όπως πχ το [Ntfy](https://ntfy.sh/). - Μετά την εγκατάσταση, επιλέξτε την εφαρμογή που θέλετε να χρησιμοποιήσετε από τις Ρυθμίσεις. - + Για να λαμβάνετε ειδοποιήσεις Push, εγκαταστήστε οποιαδήποτε εφαρμογή τις υποστηρίζει [Unified Push](https://unifiedpush.org/), όπως πχ το [Ntfy](https://ntfy.sh/). Μετά την εγκατάσταση, επιλέξτε την εφαρμογή που θέλετε να χρησιμοποιήσετε από τις Ρυθμίσεις. Νήμα Στείλτε μήνυμα στον πωλητή Γεια σου, είναι ακόμα διαθέσιμο; @@ -2008,15 +1998,7 @@ Δεν ήταν δυνατή η λήψη τιμολογίου από %1$s: %2$s Δεν ήταν δυνατό το άνοιγμα του συμπιεσμένου αρχείου Το πορτοφόλι δεν βρέθηκε - Το Amethyst δεν βρήκε εφαρμογές πορτοφολιού που υποστηρίζουν Nostr Wallet Connect (NWC). -\n\nΤι μπορείτε να κάνετε: -\n\t1. Επαλήθευση υποστήριξης NWC: Βεβαιωθείτε ότι η προτιμώμενη εφαρμογή πορτοφολιού σας είναι συμβατή με Nostr Wallet Connect. -\n\t2. Δημιουργία σύνδεσης: Μεταβείτε στην εφαρμογή πορτοφολιού σας και δημιουργήστε μια νέα σύνδεση NWC. -\n\t3. Σύνδεση με το Amethyst: Το πορτοφόλι σας συνήθως θα σας δώσει τρεις επιλογές: -\n\t\t3.1 Αυτόματη σύνδεση: Ένα κουμπί για αυτόματο άνοιγμα και σύνδεση με το Amethyst. Αν ναι, κάντε κλικ σε αυτό το κουμπί, ανοίξτε το Amethyst και πατήστε αποθήκευση στη νέα οθόνη. -\n\t\t3.2 Χειροκίνητη σύνδεση: Ένα URI σύνδεσης που μπορείτε να αντιγράψετε και να κάνετε κλικ στο εικονίδιο επικόλλησης σε αυτή την οθόνη για απευθείας εισαγωγή. -\n\t\t3.3 Κωδικός QR: Το πορτοφόλι δημιουργεί κωδικό QR τον οποίο μπορείτε να σαρώσετε από το κουμπί κωδικού QR σε αυτή την οθόνη. - + Το Amethyst δεν βρήκε εφαρμογές πορτοφολιού που υποστηρίζουν Nostr Wallet Connect (NWC). \n\nΤι μπορείτε να κάνετε: \n\t1. Επαλήθευση υποστήριξης NWC: Βεβαιωθείτε ότι η προτιμώμενη εφαρμογή πορτοφολιού σας είναι συμβατή με Nostr Wallet Connect. \n\t2. Δημιουργία σύνδεσης: Μεταβείτε στην εφαρμογή πορτοφολιού σας και δημιουργήστε μια νέα σύνδεση NWC. \n\t3. Σύνδεση με το Amethyst: Το πορτοφόλι σας συνήθως θα σας δώσει τρεις επιλογές: \n\t\t3.1 Αυτόματη σύνδεση: Ένα κουμπί για αυτόματο άνοιγμα και σύνδεση με το Amethyst. Αν ναι, κάντε κλικ σε αυτό το κουμπί, ανοίξτε το Amethyst και πατήστε αποθήκευση στη νέα οθόνη. \n\t\t3.2 Χειροκίνητη σύνδεση: Ένα URI σύνδεσης που μπορείτε να αντιγράψετε και να κάνετε κλικ στο εικονίδιο επικόλλησης σε αυτή την οθόνη για απευθείας εισαγωγή. \n\t\t3.3 Κωδικός QR: Το πορτοφόλι δημιουργεί κωδικό QR τον οποίο μπορείτε να σαρώσετε από το κουμπί κωδικού QR σε αυτή την οθόνη. Δημιουργία η Επικίνδυνη ζώνη @@ -2653,11 +2635,8 @@ Relay Διαμεσολαβητή Relay συγκεντρωτές που η εφαρμογή πρέπει να χρησιμοποιεί για να κατεβάσει τις τροφοδοσίες σας, όπως filter.nostr.wine. Αυτό αντικαθιστά το μοντέλο outbox και θα κάνει την εφαρμογή να συνδέεται μόνο στα relay στις λίστες σας. Δημόσια Συζήτηση - Οι δημόσιες συνομιλίες είναι ορατές σε όλους στο Nostr και οποιοσδήποτε - μπορεί να συμμετάσχει σε αυτές. Είναι ιδανικές για ανοιχτές κοινότητες γύρω από συγκεκριμένα θέματα. - Η εποπτεία μπορεί να ελεγχθεί με διαγραφή αναρτήσεων στα relay της - Εισάγετε 1–3 relay που φιλοξενούν αυτή την ομάδα. - Οι πελάτες Nostr χρησιμοποιούν αυτή τη ρύθμιση για να γνωρίζουν πού να κατεβάσουν μηνύματα και πού να στέλνουν τα μηνύματά σου. + Οι δημόσιες συνομιλίες είναι ορατές σε όλους στο Nostr και οποιοσδήποτε μπορεί να συμμετάσχει σε αυτές. Είναι ιδανικές για ανοιχτές κοινότητες γύρω από συγκεκριμένα θέματα. Η εποπτεία μπορεί να ελεγχθεί με διαγραφή αναρτήσεων στα relay της + Εισάγετε 1–3 relay που φιλοξενούν αυτή την ομάδα. Οι πελάτες Nostr χρησιμοποιούν αυτή τη ρύθμιση για να γνωρίζουν πού να κατεβάσουν μηνύματα και πού να στέλνουν τα μηνύματά σου. Μεταδεδομένα δημόσιας συνομιλίας Δημόσιες Συνομιλίες Δημόσια Relay Εξερχόμενων/Αρχικής @@ -2681,10 +2660,7 @@ Χρήστης μόνο για ανάγνωση Πάτα παρατεταμένα για να καταγράψεις ένα μήνυμα Συνομιλία relay - Οι συνομιλίες relay είναι ομάδες συνομιλίας που ελέγχονται από το αρχικό τους relay. - Είναι ορατές σε όλους στο Nostr και οποιοσδήποτε μπορεί να συμμετάσχει σε αυτές. - Είναι ιδανικές για ανοιχτές κοινότητες γύρω από συγκεκριμένα θέματα. Ορισμένες από αυτές τις ομάδες είναι εφήμερες - και έτσι τα μηνύματα συνομιλίας εξαφανίζονται με την πάροδο του χρόνου + Οι συνομιλίες relay είναι ομάδες συνομιλίας που ελέγχονται από το αρχικό τους relay. Είναι ορατές σε όλους στο Nostr και οποιοσδήποτε μπορεί να συμμετάσχει σε αυτές. Είναι ιδανικές για ανοιχτές κοινότητες γύρω από συγκεκριμένα θέματα. Ορισμένες από αυτές τις ομάδες είναι εφήμερες και έτσι τα μηνύματα συνομιλίας εξαφανίζονται με την πάροδο του χρόνου Συνομιλίες relay Συμβάντα Χρήστες diff --git a/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml b/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml index e55ddcf03c..35481e4172 100644 --- a/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-eo-rUY/strings.xml @@ -225,7 +225,7 @@ Kopii ID de uzanto Malbloki Uzanton Tiu ĉi uzanto estas blokita/silentita. Iliaj afiŝoj estas kaŝitaj. - npub, hekso, uzantnomo + npub, hekso, uzantnomo Klarigi Logo de Apo nsec / npub / heksa privata ŝlosilo @@ -273,15 +273,8 @@ Marki ĉiujn Konatajn legitaj Marki ĉiujn Novajn legitaj Marki ĉiujn legitajn - ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco - \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. - \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. - \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. - \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. - - Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. - \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. - + ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. + Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. Ĉifri kaj kopii mian seketan ŝlosilon Ŝildeto-premia bildo por %1$s "Insigna premibildeto @@ -971,9 +964,7 @@ Malaktivigi Puŝajn Sciigojn Uzas aplikaĵon %1$s Puŝa Sciig-Agordo - Por ricevi puŝajn sciigojn, instalu ajnan aplikaĵon kiu subtenas [Unified Push](https://unifiedpush.org/), kiel ekzemple [Ntfy](https://ntfy.sh/). - Post instalado, elektu la aplikaĵon, kiun vi volas uzi en la Agordoj. - + Por ricevi puŝajn sciigojn, instalu ajnan aplikaĵon kiu subtenas [Unified Push](https://unifiedpush.org/), kiel ekzemple [Ntfy](https://ntfy.sh/). Post instalado, elektu la aplikaĵon, kiun vi volas uzi en la Agordoj. Fadeno Sendi mesaĝon al la vendisto Saluton, ĉu ĉi tio ankoraŭ disponeblas? @@ -2031,15 +2022,7 @@ Ne eblis preni fakturon de %1$s: %2$s Ne eblis malfermi la kunpremitan dosieron Monujo ne trovita - Amethyst ne povis trovi ajnajn monujo-aplikojn, kiuj subtenas Nostr Wallet Connect (NWC). -\n\nKion vi povas fari: -\n\t1. Kontrolu NWC-subtenon: Duoble kontrolu, ĉu via preferata monujo-aplikaĵo estas kongrua kun Nostr Wallet Connect. -\n\t2. Krei Konekton: Iru al via monujo-aplikaĵo kaj kreu novan NWC-konekton. -\n\t3. Ligi al Amethyst: Via monujo kutime donos al vi tri opciojn: -\n\t\t3.1 Aŭtomata Ligo: Butono por aŭtomate malfermi kaj konekti al Amethyst. Se jes, alklaku tiun butonon, malfermu Amethyst kaj alklaku konservi sur la nova ekrano. -\n\t\t3.2 Mana Ligo: Konekta URI, kiun vi povas kopii kaj alklaki la algluu-ikonon sur ĉi tiu ekrano por rekte enigi ĝin. -\n\t\t3.3 QR-Kodo: La monujo kreas QR-kodon, kiun vi povas legi per la QR-koda butono sur ĉi tiu ekrano. - + Amethyst ne povis trovi ajnajn monujo-aplikojn, kiuj subtenas Nostr Wallet Connect (NWC). \n\nKion vi povas fari: \n\t1. Kontrolu NWC-subtenon: Duoble kontrolu, ĉu via preferata monujo-aplikaĵo estas kongrua kun Nostr Wallet Connect. \n\t2. Krei Konekton: Iru al via monujo-aplikaĵo kaj kreu novan NWC-konekton. \n\t3. Ligi al Amethyst: Via monujo kutime donos al vi tri opciojn: \n\t\t3.1 Aŭtomata Ligo: Butono por aŭtomate malfermi kaj konekti al Amethyst. Se jes, alklaku tiun butonon, malfermu Amethyst kaj alklaku konservi sur la nova ekrano. \n\t\t3.2 Mana Ligo: Konekta URI, kiun vi povas kopii kaj alklaki la algluu-ikonon sur ĉi tiu ekrano por rekte enigi ĝin. \n\t\t3.3 QR-Kodo: La monujo kreas QR-kodon, kiun vi povas legi per la QR-koda butono sur ĉi tiu ekrano. Krei t Danĝera Zono @@ -2701,11 +2684,8 @@ Prokuro-Relay-oj Agregataj relay-oj, kiujn la aplikaĵo devas uzi por elŝuti viajn fluojn, ekzemple filter.nostr.wine. Ĉi tio anstataŭas la sendkesta modelon kaj igos la aplikaĵon konektiĝi nur al la relay-oj en viaj listoj. Publika Babilado - Publikaj babilejoj estas videblaj al ĉiuj en Nostr kaj ĉiu ajn - povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. - Moderado povas esti kontrolata per forigo de afiŝoj sur siaj relays - Enigu inter 1–3 relays, kiuj gastigas ĉi tiun grupon. - Nostr-klientoj uzas ĉi tiun agordon por scii, kie elŝuti mesaĝojn kaj kien sendi viajn mesaĝojn. + Publikaj babilejoj estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Moderado povas esti kontrolata per forigo de afiŝoj sur siaj relays + Enigu inter 1–3 relays, kiuj gastigas ĉi tiun grupon. Nostr-klientoj uzas ĉi tiun agordon por scii, kie elŝuti mesaĝojn kaj kien sendi viajn mesaĝojn. Relay-oj Publikaj Babilejaj Metadatenoj Publikaj Babilejoj @@ -2730,10 +2710,7 @@ Nur-lega uzanto Alklaku kaj tenu por registri mesaĝon Relay-Babilejo - Relay-babilejoj estas babilaj grupoj kontrolataj de sia hejma relay. - Ili estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. - Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Kelkaj el ĉi tiuj grupoj estas efemeraj - kaj tial babilmesaĝoj malaperas kun la tempo + Relay-babilejoj estas babilaj grupoj kontrolataj de sia hejma relay. Ili estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Kelkaj el ĉi tiuj grupoj estas efemeraj kaj tial babilmesaĝoj malaperas kun la tempo Relay-Babilejaroj Eventoj IP-oj diff --git a/commonsUI/src/commonMain/composeResources/values-eo/strings.xml b/commonsUI/src/commonMain/composeResources/values-eo/strings.xml index f9cf0c8844..ef18a4b455 100644 --- a/commonsUI/src/commonMain/composeResources/values-eo/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-eo/strings.xml @@ -211,7 +211,7 @@ Kopii ID de uzanto Malbloki Uzanton Tiu ĉi uzanto estas blokita/silentita. Iliaj afiŝoj estas kaŝitaj. - npub, hekso, uzantnomo + npub, hekso, uzantnomo Klarigi Logo de Apo nsec / npub / heksa privata ŝlosilo @@ -259,17 +259,8 @@ Marki ĉiujn Konatajn legitaj Marki ĉiujn Novajn legitaj Marki ĉiujn legitajn - - ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco - \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. - \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. - \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. - \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. - - - Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. - \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. - + ## Konsiletoj pri Ŝlosila Sekurkopiao kaj Sekureco \n\nVia konto estas sekurigita per sekreta ŝlosilo. La ŝlosilo estas longa sinsekvo de signoj komencanta per **nsec1**. Ĉiu kiu havas aliron al ĉi tiu sekreta ŝlosilo povas afiŝi kaj ŝanĝi vian identecon. \n\n- **Ne** metu vian sekretan ŝlosilon en ajnan retejon aŭ programaron, kiun vi ne fidas. \n- Amethyst-programistoj **neniam** petos vian sekretan ŝlosilon. \n- **Faru** sekuran sekurkopion de via sekreta ŝlosilo por reakiro de konto. Ni rekomendas uzi pasvortan administrilon. + Por plia sekureco, vi povas ĉifri vian ŝlosilon per pasvorto. Ĉi tiu ŝlosilo komenciĝas per **ncryptsec1** kaj ne povas esti uzata sen via pasvorto. \n\nSe vi perdas vian pasvorton, vi ne povos reakiri vian ŝlosilon. Ĉifri kaj kopii mian seketan ŝlosilon Ŝildeto-premia bildo por %1$s "Insigna premibildeto @@ -962,10 +953,7 @@ Malaktivigi Puŝajn Sciigojn Uzas aplikaĵon %1$s Puŝa Sciig-Agordo - - Por ricevi puŝajn sciigojn, instalu ajnan aplikaĵon kiu subtenas [Unified Push](https://unifiedpush.org/), kiel ekzemple [Ntfy](https://ntfy.sh/). - Post instalado, elektu la aplikaĵon, kiun vi volas uzi en la Agordoj. - + Por ricevi puŝajn sciigojn, instalu ajnan aplikaĵon kiu subtenas [Unified Push](https://unifiedpush.org/), kiel ekzemple [Ntfy](https://ntfy.sh/). Post instalado, elektu la aplikaĵon, kiun vi volas uzi en la Agordoj. Fadeno Sendi mesaĝon al la vendisto Saluton, ĉu ĉi tio ankoraŭ disponeblas? @@ -2058,15 +2046,7 @@ Ne eblis preni fakturon de %1$s: %2$s Ne eblis malfermi la kunpremitan dosieron Monujo ne trovita - Amethyst ne povis trovi ajnajn monujo-aplikojn, kiuj subtenas Nostr Wallet Connect (NWC). -\n\nKion vi povas fari: -\n\t1. Kontrolu NWC-subtenon: Duoble kontrolu, ĉu via preferata monujo-aplikaĵo estas kongrua kun Nostr Wallet Connect. -\n\t2. Krei Konekton: Iru al via monujo-aplikaĵo kaj kreu novan NWC-konekton. -\n\t3. Ligi al Amethyst: Via monujo kutime donos al vi tri opciojn: -\n\t\t3.1 Aŭtomata Ligo: Butono por aŭtomate malfermi kaj konekti al Amethyst. Se jes, alklaku tiun butonon, malfermu Amethyst kaj alklaku konservi sur la nova ekrano. -\n\t\t3.2 Mana Ligo: Konekta URI, kiun vi povas kopii kaj alklaki la algluu-ikonon sur ĉi tiu ekrano por rekte enigi ĝin. -\n\t\t3.3 QR-Kodo: La monujo kreas QR-kodon, kiun vi povas legi per la QR-koda butono sur ĉi tiu ekrano. - + Amethyst ne povis trovi ajnajn monujo-aplikojn, kiuj subtenas Nostr Wallet Connect (NWC). \n\nKion vi povas fari: \n\t1. Kontrolu NWC-subtenon: Duoble kontrolu, ĉu via preferata monujo-aplikaĵo estas kongrua kun Nostr Wallet Connect. \n\t2. Krei Konekton: Iru al via monujo-aplikaĵo kaj kreu novan NWC-konekton. \n\t3. Ligi al Amethyst: Via monujo kutime donos al vi tri opciojn: \n\t\t3.1 Aŭtomata Ligo: Butono por aŭtomate malfermi kaj konekti al Amethyst. Se jes, alklaku tiun butonon, malfermu Amethyst kaj alklaku konservi sur la nova ekrano. \n\t\t3.2 Mana Ligo: Konekta URI, kiun vi povas kopii kaj alklaki la algluu-ikonon sur ĉi tiu ekrano por rekte enigi ĝin. \n\t\t3.3 QR-Kodo: La monujo kreas QR-kodon, kiun vi povas legi per la QR-koda butono sur ĉi tiu ekrano. Krei t Danĝera Zono @@ -2754,11 +2734,8 @@ Prokuro-Relay-oj Agregataj relay-oj, kiujn la aplikaĵo devas uzi por elŝuti viajn fluojn, ekzemple filter.nostr.wine. Ĉi tio anstataŭas la sendkesta modelon kaj igos la aplikaĵon konektiĝi nur al la relay-oj en viaj listoj. Publika Babilado - Publikaj babilejoj estas videblaj al ĉiuj en Nostr kaj ĉiu ajn - povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. - Moderado povas esti kontrolata per forigo de afiŝoj sur siaj relays - Enigu inter 1–3 relays, kiuj gastigas ĉi tiun grupon. - Nostr-klientoj uzas ĉi tiun agordon por scii, kie elŝuti mesaĝojn kaj kien sendi viajn mesaĝojn. + Publikaj babilejoj estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Moderado povas esti kontrolata per forigo de afiŝoj sur siaj relays + Enigu inter 1–3 relays, kiuj gastigas ĉi tiun grupon. Nostr-klientoj uzas ĉi tiun agordon por scii, kie elŝuti mesaĝojn kaj kien sendi viajn mesaĝojn. Relay-oj Publikaj Babilejaj Metadatenoj Publikaj Babilejoj @@ -2783,10 +2760,7 @@ Nur-lega uzanto Alklaku kaj tenu por registri mesaĝon Relay-Babilejo - Relay-babilejoj estas babilaj grupoj kontrolataj de sia hejma relay. - Ili estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. - Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Kelkaj el ĉi tiuj grupoj estas efemeraj - kaj tial babilmesaĝoj malaperas kun la tempo + Relay-babilejoj estas babilaj grupoj kontrolataj de sia hejma relay. Ili estas videblaj al ĉiuj en Nostr kaj ĉiu ajn povas partopreni en ili. Ili estas bonegaj por malfermitaj komunumoj pri specifaj temoj. Kelkaj el ĉi tiuj grupoj estas efemeraj kaj tial babilmesaĝoj malaperas kun la tempo Relay-Babilejaroj Eventoj IP-oj diff --git a/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml index ee9c2f0a5b..45b069c10c 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rES/strings.xml @@ -224,7 +224,7 @@ Copiar ID de usuario Desbloquear usuario Este usuario está bloqueado/silenciado. Sus publicaciones están ocultas. - npub, hex, username + npub, hex, username Limpiar Logo de la app nsec o npub @@ -272,15 +272,8 @@ Marcar los conocidos como leídos Marcar los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves - \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. - \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. - \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. - \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. - \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - + ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. + Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. Cifrar y copiar mi clave secreta Imagen del Badge para %1$s "Imagen de premio de insignia @@ -962,9 +955,7 @@ Desactiva las notificaciones push Usa la app %1$s Configuración de notificaciones push - Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Tras la instalación, selecciona la aplicación que deseas usar en la configuración. - + Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Tras la instalación, selecciona la aplicación que deseas usar en la configuración. Conversación Envía un mensaje al vendedor Hola, ¿esto todavía está disponible? @@ -2028,15 +2019,7 @@ No se ha podido obtener la factura de %1$s: %2$s No se pudo abrir el archivo comprimido Cartera no encontrada - Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). -\n\nQué puedes hacer: -\n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. -\n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. -\n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: -\n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. -\n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. -\n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. - + Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). \n\nQué puedes hacer: \n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. \n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. \n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: \n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. \n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. \n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. Crear d Zona peligrosa @@ -2715,11 +2698,8 @@ Relés de proxy Relés recopiladores que la app debe usar para descargar tus fuentes, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. Chat público - Los chats públicos son visibles para todos en Nostr y cualquiera - puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. - La moderación puede controlarse eliminando publicaciones en sus relés. - Inserta entre 1 y 3 relés que alojan este grupo. - Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. + Los chats públicos son visibles para todos en Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. La moderación puede controlarse eliminando publicaciones en sus relés. + Inserta entre 1 y 3 relés que alojan este grupo. Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. Relés Metadatos públicos del chat Chats públicos @@ -2744,10 +2724,7 @@ Usuario de solo lectura Haz clic y mantén pulsado para grabar un mensaje Chat en relé - Los chats en relé son grupos de chat controlados por su relé de origen. - Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. - Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros - y, por lo tanto, los mensajes del chat desaparecen con el tiempo + Los chats en relé son grupos de chat controlados por su relé de origen. Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros y, por lo tanto, los mensajes del chat desaparecen con el tiempo Chats en relé Eventos Tipos diff --git a/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml index f3e6fa1ca8..d941f9ea99 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rMX/strings.xml @@ -272,15 +272,8 @@ Marcar todos los conocidos como leídos Marcar todos los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves - \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. - \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. - \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. - \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. - \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - + ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. + Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. Cifrar y copiar mi clave secreta Imagen de premio de insignia por %1$s "Imagen de premio de insignia @@ -961,9 +954,7 @@ Desactiva las notificaciones push Usa la app %1$s Configuración de notificaciones push - Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Tras la instalación, selecciona la aplicación que deseas usar en la configuración. - + Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Tras la instalación, selecciona la aplicación que deseas usar en la configuración. Hilo Envía un mensaje al vendedor Hola, ¿esto todavía está disponible? @@ -2027,15 +2018,7 @@ No se pudo obtener la factura de %1$s: %2$s No se pudo abrir el archivo comprimido Billetera no encontrada - Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). -\n\nQué puedes hacer: -\n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. -\n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. -\n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: -\n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. -\n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. -\n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. - + Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). \n\nQué puedes hacer: \n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. \n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. \n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: \n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. \n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. \n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. Crear d Zona peligrosa @@ -2708,11 +2691,8 @@ Relés de proxy Relés recopiladores que la app debe usar para descargar tus feeds, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. Chat público - Los chats públicos son visibles para todos en Nostr y cualquiera - puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. - La moderación puede controlarse eliminando publicaciones en sus relés. - Inserta entre 1 y 3 relés que alojan este grupo. - Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. + Los chats públicos son visibles para todos en Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. La moderación puede controlarse eliminando publicaciones en sus relés. + Inserta entre 1 y 3 relés que alojan este grupo. Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. Relés Metadatos públicos del chat Chats públicos @@ -2737,10 +2717,7 @@ Usuario de solo lectura Haz clic y mantén presionado para grabar un mensaje Chat en relé - Los chats en relé son grupos de chat controlados por su relé de origen. - Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. - Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros - y, por lo tanto, los mensajes del chat desaparecen con el tiempo + Los chats en relé son grupos de chat controlados por su relé de origen. Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros y, por lo tanto, los mensajes del chat desaparecen con el tiempo Chats en relé Eventos Tipos diff --git a/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml b/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml index a86f5c2aaf..3e6060ab9c 100644 --- a/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es-rUS/strings.xml @@ -272,15 +272,8 @@ Marcar todos los conocidos como leídos Marcar todos los nuevos como leídos Marcar todos como leídos - ## Consejos sobre la protección y la copia de seguridad de las claves - \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. - \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. - \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. - \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. - \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - + ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. + Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. Cifrar y copiar mi clave secreta Imagen de premio de insignia por %1$s "Imagen de premio de insignia @@ -961,9 +954,7 @@ Desactiva las notificaciones push Usa la app %1$s Configuración de notificaciones push - Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Tras la instalación, selecciona la aplicación que deseas usar en la configuración. - + Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Tras la instalación, selecciona la aplicación que deseas usar en la configuración. Hilo Envía un mensaje al vendedor Hola, ¿esto todavía está disponible? @@ -2027,15 +2018,7 @@ No se pudo obtener la factura de %1$s: %2$s No se pudo abrir el archivo comprimido Billetera no encontrada - Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). -\n\nQué puedes hacer: -\n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. -\n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. -\n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: -\n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. -\n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. -\n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. - + Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). \n\nQué puedes hacer: \n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. \n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. \n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: \n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. \n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. \n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. Crear d Zona peligrosa @@ -2708,11 +2691,8 @@ Relés de proxy Relés recopiladores que la app debe usar para descargar tus feeds, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. Chat público - Los chats públicos son visibles para todos en Nostr y cualquiera - puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. - La moderación puede controlarse eliminando mensajes en sus relés. - Inserta entre 1 y 3 relés que alojan este grupo. - Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. + Los chats públicos son visibles para todos en Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. La moderación puede controlarse eliminando mensajes en sus relés. + Inserta entre 1 y 3 relés que alojan este grupo. Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. Relés Metadatos públicos del chat Chats públicos @@ -2737,10 +2717,7 @@ Usuario de solo lectura Haz clic y mantén presionado para grabar un mensaje Chat en relé - Los chats en relé son grupos de chat controlados por su relé de origen. - Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. - Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros - y, por lo tanto, los mensajes del chat desaparecen con el tiempo + Los chats en relé son grupos de chat controlados por su relé de origen. Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros y, por lo tanto, los mensajes del chat desaparecen con el tiempo Chats en relé Eventos Tipos diff --git a/commonsUI/src/commonMain/composeResources/values-es/strings.xml b/commonsUI/src/commonMain/composeResources/values-es/strings.xml index d9570812e6..0f52873364 100644 --- a/commonsUI/src/commonMain/composeResources/values-es/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-es/strings.xml @@ -211,7 +211,7 @@ Copiar ID de usuario Desbloquear usuario Este usuario está bloqueado/silenciado. Sus publicaciones están ocultas. - npub, hex, username + npub, hex, username Limpiar Logo de la app nsec / npub / hex private key @@ -951,9 +951,7 @@ Desactiva las notificaciones push Usa la app %1$s Configuración de notificaciones push - Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Tras la instalación, selecciona la aplicación que deseas usar en la configuración. - + Para recibir notificaciones push, instala cualquier aplicación compatible con [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Tras la instalación, selecciona la aplicación que deseas usar en la configuración. Conversación Envía un mensaje al vendedor Hola, ¿esto todavía está disponible? @@ -1802,15 +1800,8 @@ URL base de la API del explorador Pagar factura del DVM Pagar %1$s sats al DVM - ## Consejos sobre la protección y la copia de seguridad de las claves - \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. - \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. - \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. - \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. - - Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. - \n\nSi pierdes la contraseña, no podrás recuperar tu clave. - + ## Consejos sobre la protección y la copia de seguridad de las claves \n\nTu cuenta está protegida por una clave secreta. La clave es una larga secuencia de caracteres que empieza por **nsec1**. Cualquiera que tenga acceso a esta clave secreta puede publicar y cambiar tu identidad. \n\n- **No** guardes la clave secreta en ningún sitio web o software en los que no confíes. \n- Los desarrolladores de Amethyst **nunca** te pedirán la clave secreta. \n- **Sí** puedes realizar una copia de seguridad de la clave secreta para recuperar la cuenta. Para ello, te recomendamos usar un gestor de contraseñas. + Para mayor seguridad, puedes cifrar la clave con una contraseña. Esta clave empieza por **ncryptsec1** y no puede utilizarse sin tu contraseña. \n\nSi pierdes la contraseña, no podrás recuperar tu clave. Usar URL directa nSite: %1$s nApplet: %1$s @@ -2055,15 +2046,7 @@ No se ha podido obtener la factura de %1$s: %2$s No se pudo abrir el archivo comprimido Cartera no encontrada - Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). -\n\nQué puedes hacer: -\n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. -\n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. -\n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: -\n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. -\n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. -\n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. - + Amethyst no encontró ninguna aplicación de cartera compatible con Nostr Wallet Connect (NWC). \n\nQué puedes hacer: \n\t1. Verificar la compatibilidad con NWC: Comprueba que tu aplicación de cartera preferida es compatible con Nostr Wallet Connect. \n\t2. Crear conexión: Ve a tu aplicación de cartera y crea una nueva conexión NWC. \n\t3. Vincular con Amethyst: Tu cartera normalmente te ofrecerá tres opciones: \n\t\t3.1 Enlace automático: Un botón para abrir y conectar automáticamente a Amethyst. Si es así, pulsa ese botón, abre Amethyst y guarda en la nueva pantalla. \n\t\t3.2 Enlace manual: Un URI de conexión que puedes copiar y pegar usando el icono de pegado en esta pantalla para introducirlo directamente. \n\t\t3.3 Código QR: La cartera genera un código QR que puedes leer con el botón de código QR en esta pantalla. Crear d Zona peligrosa @@ -2751,11 +2734,8 @@ Relés de proxy Relés recopiladores que la app debe usar para descargar tus fuentes, como filter.nostr.wine. Esto reemplaza el modelo de bandeja de salida y hará que la app se conecte solo a los relés de tus listas. Chat público - Los chats públicos son visibles para todos en Nostr y cualquiera - puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. - La moderación puede controlarse eliminando publicaciones en sus relés. - Inserta entre 1 y 3 relés que alojan este grupo. - Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. + Los chats públicos son visibles para todos en Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas alrededor de temas específicos. La moderación puede controlarse eliminando publicaciones en sus relés. + Inserta entre 1 y 3 relés que alojan este grupo. Los clientes de Nostr utilizan esta configuración para saber de dónde descargar y adónde enviar los mensajes. Relés Metadatos públicos del chat Chats públicos @@ -2780,10 +2760,7 @@ Usuario de solo lectura Haz clic y mantén pulsado para grabar un mensaje Chat en relé - Los chats en relé son grupos de chat controlados por su relé de origen. - Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. - Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros - y, por lo tanto, los mensajes del chat desaparecen con el tiempo + Los chats en relé son grupos de chat controlados por su relé de origen. Son visibles para todos los usuarios de Nostr y cualquiera puede participar en ellos. Son ideales para comunidades abiertas en torno a temas específicos. Algunos de estos grupos son efímeros y, por lo tanto, los mensajes del chat desaparecen con el tiempo Chats en relé Eventos IPs diff --git a/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml b/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml index a92f92d82a..df5f3b4363 100644 --- a/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fa-rIR/strings.xml @@ -10,7 +10,7 @@ - پاسخ به + پاسخ به مجوزها: سایت اصلی @@ -226,7 +226,7 @@ کپی شناسه کاربر از بلاک درآوردن کاربر این کاربر مسدود/بی‌صدا شده است. پست‌های آن‌ها مخفی است. - npub, hex, نام کاربری + npub, hex, نام کاربری پاک کردن لوگوی اپ nsec / npub / hex کلید خصوصی @@ -248,7 +248,7 @@ در حال جستجوی پیام اصلی… این پیام پیدا نشد همه relay ها جستجو شد · برای مشاهده ضربه بزنید - :خطا در بارگیری پاسخ ها + :خطا در بارگیری پاسخ ها دوباره تلاش کنید هنوز هیچ اعلانی نیست. نظرسنجی باز @@ -274,14 +274,8 @@ همه شناس ها خوانده شده کن همه جدیدها را خوانده شده کن همه را خوانده شده کن - نکات ایمنی و ذخیره کلید - -حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. -هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. -سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. -یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. - برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. -اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. + نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. + برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. رمزنگاری و کپی کلید من تصویر مدال پاداش برای %1$s تصویر جایزه نشان @@ -301,7 +295,7 @@ حذف از گالری این رسانه را از گالری خود حذف کنید. درخواست حذف - آماتیست درخواست می کند که یادداشت شما از رله هایی که درحال حاضر به آن متصل هستید حذف شود. هیچ تضمینی نیست که یادداشت شما برای همیشه از آن رله ها یا از رله های دیگری که ممکن است در آنها ذخیره شده باشد حذف خواهد شد.. + آماتیست درخواست می کند که یادداشت شما از رله هایی که درحال حاضر به آن متصل هستید حذف شود. هیچ تضمینی نیست که یادداشت شما برای همیشه از آن رله ها یا از رله های دیگری که ممکن است در آنها ذخیره شده باشد حذف خواهد شد.. بلاک حذف بلاک @@ -970,9 +964,7 @@ غیرفعال سازی اعلان ها از اپلیکیشن %1$s استفاده می کند تنظیمات اعلان ها - برای دریافت اعلان ها، می توانید هر اپلیکیشنی که از [Unified Push](https://unifiedpush.org/) پشتیبانی می کند نصب کنید، مانند[Ntfy](https://ntfy.sh/). - پس از نصب، اپلیکیشنی را که می خواهید استفاده کنید در تنظیمات انتخاب کنید. - + برای دریافت اعلان ها، می توانید هر اپلیکیشنی که از [Unified Push](https://unifiedpush.org/) پشتیبانی می کند نصب کنید، مانند[Ntfy](https://ntfy.sh/). پس از نصب، اپلیکیشنی را که می خواهید استفاده کنید در تنظیمات انتخاب کنید. رسته به فروشنده پیغام دهید سلام، هنوز موجوده؟ @@ -1315,10 +1307,7 @@ نمایش nprofile به عنوان کد QR تنظیم رله های صندوق دریافت خصوصی با این تنظیمات همه می توانند بدانند که هنگام ارسال پیام به شما از کدام رله ها استفاده کنند. بدون این تنظیمات ممکن است برخی پیام ها را از دست بدهید. - گزینه های خوب: -- inbox.nostr.wine (پولی) -- auth.nostr1.com (رایگان) -- you.nostr1.com (رله شخصی - پولی) + گزینه های خوب: - inbox.nostr.wine (پولی) - auth.nostr1.com (رایگان) - you.nostr1.com (رله شخصی - پولی) از ۱ تا ۳ رله به عنوان رله خصوصی وارد کنید. رله های صندوق دربافت پیام های خصوصی می بایست هر پیامی از هرکس را بپذیرند، ولی تنها به شما اجازه بارگیری پیام ها را می دهند. هم اکنون تنظیم شود relay های صندوق ورودی DM یافت نشد. پیام‌ها تحویل داده نمی‌شوند تا زمانی که لیست relay خود را پیکربندی کنند. @@ -1345,7 +1334,7 @@ به توسعه دهندگان رپ دهید! هدیه شما به ما برای تاثیرگذاری کمک می کند. هر ساتوشی به حساب می آید! اکنون کمک کنید - تقدیم از طرف: + تقدیم از طرف: این نسخه نرم‌افزار پیشکش از: نسخه %1$s متشکریم! @@ -2025,7 +2014,7 @@ (@note1)شناسه یادداشت در کلیپبورد کپی شد یادداشت در کلیپبورد کپی شد در کلیپ‌بورد کپی شد - @npubنویسنده در کلیپبورد کپی شد + @npubنویسنده در کلیپبورد کپی شد کلید خصوصیم را کپی کن کپی به کلیپ‌بورد LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید. @@ -2034,15 +2023,7 @@ صورتحساب از %1$s گرفته نشد: %2$s فایل فشرده باز نشد کیف پول یافت نشد - Amethyst هیچ برنامه کیف پولی که از Nostr Wallet Connect (NWC) پشتیبانی کند پیدا نکرد. -\n\nکارهایی که می‌توانید انجام دهید: -\n\t1. بررسی پشتیبانی NWC: مطمئن شوید که برنامه کیف پول مورد نظر شما با Nostr Wallet Connect سازگار است. -\n\t2. ایجاد اتصال: به برنامه کیف پول خود بروید و یک اتصال NWC جدید ایجاد کنید. -\n\t3. اتصال به Amethyst: کیف پول شما معمولاً سه گزینه ارائه می‌دهد: -\n\t\t3.1 اتصال خودکار: دکمه‌ای برای باز کردن و اتصال خودکار به Amethyst. اگر این گزینه وجود دارد، آن دکمه را بزنید، Amethyst را باز کنید و روی صفحه جدید ذخیره کنید. -\n\t\t3.2 اتصال دستی: یک URI اتصال که می‌توانید کپی کنید و با کلیک روی آیکون paste در این صفحه مستقیماً وارد کنید. -\n\t\t3.3 کد QR: کیف پول یک کد QR ایجاد می‌کند که می‌توانید با دکمه کد QR در این صفحه آن را بخوانید. - + Amethyst هیچ برنامه کیف پولی که از Nostr Wallet Connect (NWC) پشتیبانی کند پیدا نکرد. \n\nکارهایی که می‌توانید انجام دهید: \n\t1. بررسی پشتیبانی NWC: مطمئن شوید که برنامه کیف پول مورد نظر شما با Nostr Wallet Connect سازگار است. \n\t2. ایجاد اتصال: به برنامه کیف پول خود بروید و یک اتصال NWC جدید ایجاد کنید. \n\t3. اتصال به Amethyst: کیف پول شما معمولاً سه گزینه ارائه می‌دهد: \n\t\t3.1 اتصال خودکار: دکمه‌ای برای باز کردن و اتصال خودکار به Amethyst. اگر این گزینه وجود دارد، آن دکمه را بزنید، Amethyst را باز کنید و روی صفحه جدید ذخیره کنید. \n\t\t3.2 اتصال دستی: یک URI اتصال که می‌توانید کپی کنید و با کلیک روی آیکون paste در این صفحه مستقیماً وارد کنید. \n\t\t3.3 کد QR: کیف پول یک کد QR ایجاد می‌کند که می‌توانید با دکمه کد QR در این صفحه آن را بخوانید. ساختن روز منطقه خطر @@ -2689,10 +2670,7 @@ سیاست حریم خصوصی <پیام خصوصی رمزگشایی نشد>\\n\nدر یک پیام خصوصی/رمزنگاری شده بین %1$s و %2$s نام شما آمده بود. رله های صندوق دریافت پیام خصوصی - بین ۱-۳ رله به عنوان رله صندوق ورودی خصوصی وارد کنید. دیگران از این رله ها برای ارسال پیام خصوصی به شما استفاده خواهند کرد. رله های صندوق دریافت پیام خصوصی می بایست هر پیامی از هر کسی را بپذیرند، اما فقط بگذارند شما آن ها را بارگیری کنید. انتخاب های خوب شامل: - - inbox.nostr.wine (پولی) -- auth.nostr1.com (رایگان) -- you.nostr1.com (رله پولی یا شخصی) + بین ۱-۳ رله به عنوان رله صندوق ورودی خصوصی وارد کنید. دیگران از این رله ها برای ارسال پیام خصوصی به شما استفاده خواهند کرد. رله های صندوق دریافت پیام خصوصی می بایست هر پیامی از هر کسی را بپذیرند، اما فقط بگذارند شما آن ها را بارگیری کنید. انتخاب های خوب شامل: - inbox.nostr.wine (پولی) - auth.nostr1.com (رایگان) - you.nostr1.com (رله پولی یا شخصی) کاربر DM ها را روی این relay ها دریافت می‌کند پیام خصوصی خصوصی کردن: یادداشت را به صورت gift-wrap فقط برای کاربران مطلع‌شده ارسال کن @@ -2713,11 +2691,8 @@ relay های پراکسی relay های تجمیع‌کننده که برنامه باید برای دانلود فیدهای شما از آن‌ها استفاده کند، مانند filter.nostr.wine. این جایگزین مدل outbox می‌شود و باعث می‌شود برنامه فقط به relay های موجود در لیست‌هایتان متصل شود. گفتگوی عمومی - گفتگوهای عمومی در ناستر برای همه نمایان هستند - می توانند در آن شرکت کنند. آنها برای انجمن های باز درباره موضوعات به‌خصوص عالی هستند. - نظارت می تواند توسط حذف پست ها از رله ها انجام گیرد - برای میزبانی این گروه ۱تا ۳ رله وارد کنید. - کلاینت های ناستر از این تنظیمات استفاده می کنند تا بدانند پیام ها را از کجا بارگیری کنند و به کجا بفرستند. + گفتگوهای عمومی در ناستر برای همه نمایان هستند می توانند در آن شرکت کنند. آنها برای انجمن های باز درباره موضوعات به‌خصوص عالی هستند. نظارت می تواند توسط حذف پست ها از رله ها انجام گیرد + برای میزبانی این گروه ۱تا ۳ رله وارد کنید. کلاینت های ناستر از این تنظیمات استفاده می کنند تا بدانند پیام ها را از کجا بارگیری کنند و به کجا بفرستند. رله ها فراداده گفتگوی عمومی گفتگوهای عمومی @@ -2742,10 +2717,7 @@ کاربر با امکان خواندن فقط برای ضبط پیام کلیک کنید و نگه دارید گفتگوی relay - گفتگوهای relay گروه‌های چت هستند که توسط relay خانگی خود کنترل می‌شوند. - آن‌ها برای همه در Nostr قابل مشاهده هستند و هر کسی می‌تواند در آن‌ها شرکت کند. - آن‌ها برای جوامع باز حول موضوعات خاص عالی هستند. برخی از این گروه‌ها ناپایدار - هستند و بنابراین پیام‌های چت با گذشت زمان ناپدید می‌شوند + گفتگوهای relay گروه‌های چت هستند که توسط relay خانگی خود کنترل می‌شوند. آن‌ها برای همه در Nostr قابل مشاهده هستند و هر کسی می‌تواند در آن‌ها شرکت کند. آن‌ها برای جوامع باز حول موضوعات خاص عالی هستند. برخی از این گروه‌ها ناپایدار هستند و بنابراین پیام‌های چت با گذشت زمان ناپدید می‌شوند گفتگوهای relay رویدادها آدرس‌های IP @@ -2903,7 +2875,7 @@ تور را برای رله های ارسال/دریافت الزامی کن تایید آدرس ناستر تور را برای تایید آدرس های NIP-05 الزامی کن - رله ها / آدرس های Onion + رله ها / آدرس های Onion از تور برای هر آدرس اونیون استفاده کن تصاویر نمایه تور را برای بارگیری تصاویر نمایه اجباری کن diff --git a/commonsUI/src/commonMain/composeResources/values-fa/strings.xml b/commonsUI/src/commonMain/composeResources/values-fa/strings.xml index a20d36b070..cf8347e236 100644 --- a/commonsUI/src/commonMain/composeResources/values-fa/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fa/strings.xml @@ -88,7 +88,7 @@ نقل قول فورک مبلغ جدید به ساتوشی - پاسخ به + پاسخ به و دنبال شونده دنبال کننده @@ -211,7 +211,7 @@ کپی شناسه کاربر از بلاک درآوردن کاربر این کاربر مسدود/بی‌صدا شده است. پست‌های آن‌ها مخفی است. - npub, hex, نام کاربری + npub, hex, نام کاربری پاک کردن لوگوی اپ nsec / npub / hex کلید خصوصی @@ -233,7 +233,7 @@ در حال جستجوی پیام اصلی… این پیام پیدا نشد همه relay ها جستجو شد · برای مشاهده ضربه بزنید - :خطا در بارگیری پاسخ ها + :خطا در بارگیری پاسخ ها دوباره تلاش کنید هنوز هیچ اعلانی نیست. نظرسنجی باز @@ -259,14 +259,8 @@ همه شناس ها خوانده شده کن همه جدیدها را خوانده شده کن همه را خوانده شده کن - نکات ایمنی و ذخیره کلید - -حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. -هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. -سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. -یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. - برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. -اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. + نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم. + برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید. رمزنگاری و کپی کلید من تصویر مدال پاداش برای %1$s تصویر جایزه نشان @@ -286,7 +280,7 @@ حذف از گالری این رسانه را از گالری خود حذف کنید. درخواست حذف - آماتیست درخواست می کند که یادداشت شما از رله هایی که درحال حاضر به آن متصل هستید حذف شود. هیچ تضمینی نیست که یادداشت شما برای همیشه از آن رله ها یا از رله های دیگری که ممکن است در آنها ذخیره شده باشد حذف خواهد شد.. + آماتیست درخواست می کند که یادداشت شما از رله هایی که درحال حاضر به آن متصل هستید حذف شود. هیچ تضمینی نیست که یادداشت شما برای همیشه از آن رله ها یا از رله های دیگری که ممکن است در آنها ذخیره شده باشد حذف خواهد شد.. بلاک حذف بلاک @@ -959,9 +953,7 @@ غیرفعال سازی اعلان ها از اپلیکیشن %1$s استفاده می کند تنظیمات اعلان ها - برای دریافت اعلان ها، می توانید هر اپلیکیشنی که از [Unified Push](https://unifiedpush.org/) پشتیبانی می کند نصب کنید، مانند[Ntfy](https://ntfy.sh/). - پس از نصب، اپلیکیشنی را که می خواهید استفاده کنید در تنظیمات انتخاب کنید. - + برای دریافت اعلان ها، می توانید هر اپلیکیشنی که از [Unified Push](https://unifiedpush.org/) پشتیبانی می کند نصب کنید، مانند[Ntfy](https://ntfy.sh/). پس از نصب، اپلیکیشنی را که می خواهید استفاده کنید در تنظیمات انتخاب کنید. رسته به فروشنده پیغام دهید سلام، هنوز موجوده؟ @@ -1313,10 +1305,7 @@ نمایش nprofile به عنوان کد QR تنظیم رله های صندوق دریافت خصوصی با این تنظیمات همه می توانند بدانند که هنگام ارسال پیام به شما از کدام رله ها استفاده کنند. بدون این تنظیمات ممکن است برخی پیام ها را از دست بدهید. - گزینه های خوب: -- inbox.nostr.wine (پولی) -- auth.nostr1.com (رایگان) -- you.nostr1.com (رله شخصی - پولی) + گزینه های خوب: - inbox.nostr.wine (پولی) - auth.nostr1.com (رایگان) - you.nostr1.com (رله شخصی - پولی) از ۱ تا ۳ رله به عنوان رله خصوصی وارد کنید. رله های صندوق دربافت پیام های خصوصی می بایست هر پیامی از هرکس را بپذیرند، ولی تنها به شما اجازه بارگیری پیام ها را می دهند. هم اکنون تنظیم شود relay های صندوق ورودی DM یافت نشد. پیام‌ها تحویل داده نمی‌شوند تا زمانی که لیست relay خود را پیکربندی کنند. @@ -1343,7 +1332,7 @@ به توسعه دهندگان رپ دهید! هدیه شما به ما برای تاثیرگذاری کمک می کند. هر ساتوشی به حساب می آید! اکنون کمک کنید - تقدیم از طرف: + تقدیم از طرف: این نسخه نرم‌افزار پیشکش از: نسخه %1$s متشکریم! @@ -2048,7 +2037,7 @@ (@note1)شناسه یادداشت در کلیپبورد کپی شد یادداشت در کلیپبورد کپی شد در کلیپ‌بورد کپی شد - @npubنویسنده در کلیپبورد کپی شد + @npubنویسنده در کلیپبورد کپی شد کلید خصوصیم را کپی کن کپی به کلیپ‌بورد LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید. @@ -2057,15 +2046,7 @@ صورتحساب از %1$s گرفته نشد: %2$s فایل فشرده باز نشد کیف پول یافت نشد - Amethyst هیچ برنامه کیف پولی که از Nostr Wallet Connect (NWC) پشتیبانی کند پیدا نکرد. -\n\nکارهایی که می‌توانید انجام دهید: -\n\t1. بررسی پشتیبانی NWC: مطمئن شوید که برنامه کیف پول مورد نظر شما با Nostr Wallet Connect سازگار است. -\n\t2. ایجاد اتصال: به برنامه کیف پول خود بروید و یک اتصال NWC جدید ایجاد کنید. -\n\t3. اتصال به Amethyst: کیف پول شما معمولاً سه گزینه ارائه می‌دهد: -\n\t\t3.1 اتصال خودکار: دکمه‌ای برای باز کردن و اتصال خودکار به Amethyst. اگر این گزینه وجود دارد، آن دکمه را بزنید، Amethyst را باز کنید و روی صفحه جدید ذخیره کنید. -\n\t\t3.2 اتصال دستی: یک URI اتصال که می‌توانید کپی کنید و با کلیک روی آیکون paste در این صفحه مستقیماً وارد کنید. -\n\t\t3.3 کد QR: کیف پول یک کد QR ایجاد می‌کند که می‌توانید با دکمه کد QR در این صفحه آن را بخوانید. - + Amethyst هیچ برنامه کیف پولی که از Nostr Wallet Connect (NWC) پشتیبانی کند پیدا نکرد. \n\nکارهایی که می‌توانید انجام دهید: \n\t1. بررسی پشتیبانی NWC: مطمئن شوید که برنامه کیف پول مورد نظر شما با Nostr Wallet Connect سازگار است. \n\t2. ایجاد اتصال: به برنامه کیف پول خود بروید و یک اتصال NWC جدید ایجاد کنید. \n\t3. اتصال به Amethyst: کیف پول شما معمولاً سه گزینه ارائه می‌دهد: \n\t\t3.1 اتصال خودکار: دکمه‌ای برای باز کردن و اتصال خودکار به Amethyst. اگر این گزینه وجود دارد، آن دکمه را بزنید، Amethyst را باز کنید و روی صفحه جدید ذخیره کنید. \n\t\t3.2 اتصال دستی: یک URI اتصال که می‌توانید کپی کنید و با کلیک روی آیکون paste در این صفحه مستقیماً وارد کنید. \n\t\t3.3 کد QR: کیف پول یک کد QR ایجاد می‌کند که می‌توانید با دکمه کد QR در این صفحه آن را بخوانید. ساختن روز منطقه خطر @@ -2732,10 +2713,7 @@ سیاست حریم خصوصی <پیام خصوصی رمزگشایی نشد>\\n\nدر یک پیام خصوصی/رمزنگاری شده بین %1$s و %2$s نام شما آمده بود. رله های صندوق دریافت پیام خصوصی - بین ۱-۳ رله به عنوان رله صندوق ورودی خصوصی وارد کنید. دیگران از این رله ها برای ارسال پیام خصوصی به شما استفاده خواهند کرد. رله های صندوق دریافت پیام خصوصی می بایست هر پیامی از هر کسی را بپذیرند، اما فقط بگذارند شما آن ها را بارگیری کنید. انتخاب های خوب شامل: - - inbox.nostr.wine (پولی) -- auth.nostr1.com (رایگان) -- you.nostr1.com (رله پولی یا شخصی) + بین ۱-۳ رله به عنوان رله صندوق ورودی خصوصی وارد کنید. دیگران از این رله ها برای ارسال پیام خصوصی به شما استفاده خواهند کرد. رله های صندوق دریافت پیام خصوصی می بایست هر پیامی از هر کسی را بپذیرند، اما فقط بگذارند شما آن ها را بارگیری کنید. انتخاب های خوب شامل: - inbox.nostr.wine (پولی) - auth.nostr1.com (رایگان) - you.nostr1.com (رله پولی یا شخصی) کاربر DM ها را روی این relay ها دریافت می‌کند پیام خصوصی خصوصی کردن: یادداشت را به صورت gift-wrap فقط برای کاربران مطلع‌شده ارسال کن @@ -2782,10 +2760,7 @@ کاربر با امکان خواندن فقط برای ضبط پیام کلیک کنید و نگه دارید گفتگوی relay - گفتگوهای relay گروه‌های چت هستند که توسط relay خانگی خود کنترل می‌شوند. - آن‌ها برای همه در Nostr قابل مشاهده هستند و هر کسی می‌تواند در آن‌ها شرکت کند. - آن‌ها برای جوامع باز حول موضوعات خاص عالی هستند. برخی از این گروه‌ها ناپایدار - هستند و بنابراین پیام‌های چت با گذشت زمان ناپدید می‌شوند + گفتگوهای relay گروه‌های چت هستند که توسط relay خانگی خود کنترل می‌شوند. آن‌ها برای همه در Nostr قابل مشاهده هستند و هر کسی می‌تواند در آن‌ها شرکت کند. آن‌ها برای جوامع باز حول موضوعات خاص عالی هستند. برخی از این گروه‌ها ناپایدار هستند و بنابراین پیام‌های چت با گذشت زمان ناپدید می‌شوند گفتگوهای relay رویدادها آدرس‌های IP @@ -2943,7 +2918,7 @@ تور را برای رله های ارسال/دریافت الزامی کن تایید آدرس ناستر تور را برای تایید آدرس های NIP-05 الزامی کن - رله ها / آدرس های Onion + رله ها / آدرس های Onion از تور برای هر آدرس اونیون استفاده کن تصاویر نمایه تور را برای بارگیری تصاویر نمایه اجباری کن diff --git a/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml b/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml index ede84f29eb..f2784cced4 100644 --- a/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fi-rFI/strings.xml @@ -268,15 +268,8 @@ Merkitse kaikki Tunnetut luetuiksi Merkitse kaikki Uudet luetuiksi Merkitse kaikki luetuiksi - ## Avainten varmuuskopiointi ja turvallisuusvinkit - \n\nTilisi on suojattu salaisella avaimella. Avain on pitkä merkkijono, joka alkaa **nsec1**:llä. Kuka tahansa, jolla on pääsy tähän salaiseen avaimeen, voi julkaista ja muuttaa henkilöllisyyttäsi. - \n\n- **Älä** anna salaista avaintasi mihinkään verkkosivustoon tai ohjelmistoon, johon et luota. - \n- Amethystin kehittäjät eivät **koskaan** pyydä salaista avaintasi. - \n- **Tee** turvallinen varmuuskopio salaisesta avaimestasi tilin palauttamista varten. Suosittelemme salasananhallintaohjelman käyttöä. - - Lisäturvallisuuden vuoksi voit salata avaimesi salasanalla. Tämä avain alkaa **ncryptsec1**:llä eikä sitä voi käyttää ilman salasanaasi. - \n\nJos kadotat salasanasi, et pysty palauttamaan avaintasi. - + ## Avainten varmuuskopiointi ja turvallisuusvinkit \n\nTilisi on suojattu salaisella avaimella. Avain on pitkä merkkijono, joka alkaa **nsec1**:llä. Kuka tahansa, jolla on pääsy tähän salaiseen avaimeen, voi julkaista ja muuttaa henkilöllisyyttäsi. \n\n- **Älä** anna salaista avaintasi mihinkään verkkosivustoon tai ohjelmistoon, johon et luota. \n- Amethystin kehittäjät eivät **koskaan** pyydä salaista avaintasi. \n- **Tee** turvallinen varmuuskopio salaisesta avaimestasi tilin palauttamista varten. Suosittelemme salasananhallintaohjelman käyttöä. + Lisäturvallisuuden vuoksi voit salata avaimesi salasanalla. Tämä avain alkaa **ncryptsec1**:llä eikä sitä voi käyttää ilman salasanaasi. \n\nJos kadotat salasanasi, et pysty palauttamaan avaintasi. Salaa ja kopioi salainen avaimeni Merkki kohteelle %1$s "Merkkipalkinnon kuva @@ -959,8 +952,7 @@ Poistaa Push-ilmoitukset käytöstä Käyttää sovellusta %1$s Push-ilmoituksen asennus - Saadaksesi push-ilmoituksia, asenna mikä tahansa sovellus, joka tukee Unified Push:ia, kuten Ntfy. - Asennuksen jälkeen valitse Asetuksista sovellus, jota haluat käyttää. + Saadaksesi push-ilmoituksia, asenna mikä tahansa sovellus, joka tukee Unified Push:ia, kuten Ntfy. Asennuksen jälkeen valitse Asetuksista sovellus, jota haluat käyttää. Keskusteluketju Lähetä myyjälle viesti Hei, onko tämä vielä saatavilla? @@ -2011,15 +2003,7 @@ Laskun hakeminen epäonnistui kohteesta %1$s: %2$s Pakattua tiedostoa ei voitu avata Lompakkoa ei löydy - Amethyst ei löytänyt yhtään lompakkosovellusta, joka tukee Nostr Wallet Connect (NWC) -toimintoa. -\n\nMitä voit tehdä: -\n\t1. Tarkista NWC-tuki: Varmista, että haluamasi lompakkosovellus on yhteensopiva Nostr Wallet Connectin kanssa. -\n\t2. Luo yhteys: Siirry lompakkosovellukseesi ja luo uusi NWC-yhteys. -\n\t3. Linkitä Amethystiin: Lompakkosi tarjoaa yleensä kolme vaihtoehtoa: -\n\t\t3.1 Automaattinen linkitys: Painike, joka avaa Amethystin ja yhdistää automaattisesti. Jos näet sen, paina painiketta, avaa Amethyst ja tallenna uudella näytöllä. -\n\t\t3.2 Manuaalinen linkitys: YhteysURI, jonka voit kopioida ja liittää tämän näytön liitä-kuvakkeella. -\n\t\t3.3 QR-koodi: Lompakko luo QR-koodin, jonka voit lukea tämän näytön QR-koodipainikkeella. - + Amethyst ei löytänyt yhtään lompakkosovellusta, joka tukee Nostr Wallet Connect (NWC) -toimintoa. \n\nMitä voit tehdä: \n\t1. Tarkista NWC-tuki: Varmista, että haluamasi lompakkosovellus on yhteensopiva Nostr Wallet Connectin kanssa. \n\t2. Luo yhteys: Siirry lompakkosovellukseesi ja luo uusi NWC-yhteys. \n\t3. Linkitä Amethystiin: Lompakkosi tarjoaa yleensä kolme vaihtoehtoa: \n\t\t3.1 Automaattinen linkitys: Painike, joka avaa Amethystin ja yhdistää automaattisesti. Jos näet sen, paina painiketta, avaa Amethyst ja tallenna uudella näytöllä. \n\t\t3.2 Manuaalinen linkitys: YhteysURI, jonka voit kopioida ja liittää tämän näytön liitä-kuvakkeella. \n\t\t3.3 QR-koodi: Lompakko luo QR-koodin, jonka voit lukea tämän näytön QR-koodipainikkeella. Luo pv Vaara-alue @@ -2677,11 +2661,8 @@ Proxy-relait Aggregaattorirelait, joita sovelluksen täytyy käyttää feedien lataamiseen, kuten filter.nostr.wine. Tämä korvaa outbox-mallin ja saa sovelluksen yhdistämään vain listoissasi oleviin relaihin. Julkinen keskustelu - Julkiset chatit ovat näkyvissä kaikille Nostrissa ja kuka tahansa - voi osallistua niihin. Ne sopivat hyvin avoimiin yhteisöihin tiettyjen aiheiden ympärille. - Moderointia voidaan hallita poistamalla julkaisuja sen relay-palvelimilta - Syötä 1–3 relay-palvelinta, jotka isännöivät tätä ryhmää. - Nostr-asiakkaat käyttävät tätä asetusta tietääkseen, mistä ladata viestejä ja mihin lähettää viestisi. + Julkiset chatit ovat näkyvissä kaikille Nostrissa ja kuka tahansa voi osallistua niihin. Ne sopivat hyvin avoimiin yhteisöihin tiettyjen aiheiden ympärille. Moderointia voidaan hallita poistamalla julkaisuja sen relay-palvelimilta + Syötä 1–3 relay-palvelinta, jotka isännöivät tätä ryhmää. Nostr-asiakkaat käyttävät tätä asetusta tietääkseen, mistä ladata viestejä ja mihin lähettää viestisi. relay-palvelimet Julkisen chatin metatiedot Julkiset keskustelut @@ -2706,10 +2687,7 @@ Vain luku -käyttäjä Paina ja pidä pohjassa tallentaaksesi ääniviesti relay-chat - relay-chatit ovat chat-ryhmiä, joita hallinnoi niiden kotipalvelin. - Ne ovat näkyvissä kaikille Nostrissa ja kuka tahansa voi osallistua niihin. - Ne sopivat hyvin avoimiin yhteisöihin tiettyjen aiheiden ympärille. Osa näistä ryhmistä on katoavia, - joten chat-viestit häviävät ajan myötä + relay-chatit ovat chat-ryhmiä, joita hallinnoi niiden kotipalvelin. Ne ovat näkyvissä kaikille Nostrissa ja kuka tahansa voi osallistua niihin. Ne sopivat hyvin avoimiin yhteisöihin tiettyjen aiheiden ympärille. Osa näistä ryhmistä on katoavia, joten chat-viestit häviävät ajan myötä relay-chatit Tapahtumat IP-osoitteet diff --git a/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml index 6dbdac7e80..677d4afb32 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr-rCA/strings.xml @@ -218,7 +218,7 @@ Copier l'ID utilisateur Débloquer l'utilisateur Cet utilisateur est bloqué/muet. Ses publications sont masquées. - npub, hex, nom d'utilisateur + npub, hex, nom d'utilisateur Nettoyer Logo de l'App nsec / npub / hex private key @@ -266,15 +266,8 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité - \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. - \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. - \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. - \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. - \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - + ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. + Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense @@ -823,7 +816,7 @@ Souscription maximale Nombre maximum de filtres par sub Limite Max (Renvoi des Évènements) - Longueur maximale du SubID + Longueur maximale du SubID Mint : %1$s Échanger Copier le Jeton @@ -938,9 +931,7 @@ Désactive les Notifications Push Utilise l'application %1$s Configuration des Notifications Push - Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). - Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. - + Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. Fil de discussion Envoyer un message au vendeur Bonjour, est-ce toujours disponible ? @@ -2603,11 +2594,8 @@ Relais Proxy Relais agrégateurs que l'application doit utiliser pour télécharger vos flux, tels que filter.nostr.wine. Cela remplace le modèle de boîte d'envoi et permettra à l'application de se connecter uniquement aux relais de vos listes. Chat public - Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui - peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. - La modération peut être contrôlée en supprimant les messages sur ses relais - Insérez entre 1 et 3 relais qui hébergent ce groupe. - Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. + Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. La modération peut être contrôlée en supprimant les messages sur ses relais + Insérez entre 1 et 3 relais qui hébergent ce groupe. Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. Relais Métadonnées de tchat public Chats publics @@ -2632,10 +2620,7 @@ Utilisateur en lecture seule Cliquez et maintenez pour enregistrer un message Relais de discussion - Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. - Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. - Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères - et, par conséquent, les messages de discussion disparaissent avec le temps + Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères et, par conséquent, les messages de discussion disparaissent avec le temps Relais de discussions Événements Utilisateurs diff --git a/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml index 41d6f05237..76a4f93daf 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr-rFR/strings.xml @@ -220,7 +220,7 @@ Copier l'ID utilisateur Débloquer l'utilisateur Cet utilisateur est bloqué/muet. Ses publications sont masquées. - npub, hex, nom d'utilisateur + npub, hex, nom d'utilisateur Nettoyer Logo de l'App nsec / npub / hex private key @@ -268,15 +268,8 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité - \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. - \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. - \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. - \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. - \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - + ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. + Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense @@ -905,7 +898,7 @@ Souscription maximale Nombre maximum de filtres par sub Limite Max (Renvoi des Évènements) - Longueur maximale du SubID + Longueur maximale du SubID Mint : %1$s Échanger Copier le Jeton @@ -1039,9 +1032,7 @@ Désactive les Notifications Push Utilise l'application %1$s Configuration des Notifications Push - Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). - Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. - + Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. Fil de discussion Envoyer un message au vendeur Bonjour, est-ce toujours disponible ? @@ -2883,11 +2874,8 @@ Relais Proxy Relais agrégateurs que l'application doit utiliser pour télécharger vos flux, tels que filter.nostr.wine. Cela remplace le modèle de boîte d'envoi et permettra à l'application de se connecter uniquement aux relais de vos listes. Chat public - Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui - peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. - La modération peut être contrôlée en supprimant les messages sur ses relais - Insérez entre 1 et 3 relais qui hébergent ce groupe. - Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. + Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. La modération peut être contrôlée en supprimant les messages sur ses relais + Insérez entre 1 et 3 relais qui hébergent ce groupe. Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. Relais Métadonnées de tchat public Chats publics @@ -2912,10 +2900,7 @@ Utilisateur en lecture seule Cliquez et maintenez pour enregistrer un message Relais de discussion - Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. - Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. - Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères - et, par conséquent, les messages de discussion disparaissent avec le temps + Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères et, par conséquent, les messages de discussion disparaissent avec le temps Relais de discussions Privé Événements diff --git a/commonsUI/src/commonMain/composeResources/values-fr/strings.xml b/commonsUI/src/commonMain/composeResources/values-fr/strings.xml index 2f9de43271..41b7112fcb 100644 --- a/commonsUI/src/commonMain/composeResources/values-fr/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-fr/strings.xml @@ -211,7 +211,7 @@ Copier l'ID utilisateur Débloquer l'utilisateur Cet utilisateur est bloqué/muet. Ses publications sont masquées. - npub, hex, nom d'utilisateur + npub, hex, nom d'utilisateur Nettoyer Logo de l'App nsec / npub / hex private key @@ -259,15 +259,8 @@ Marquer tous les Connus comme lu Marquer tous les Nouveaux comme lu Tout marquer comme lu - ## Sauvegarde des Clés et Conseils de Sécurité - \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. - \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. - \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. - \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. - - Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. - \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. - + ## Sauvegarde des Clés et Conseils de Sécurité \n\nVotre compte est sécurisé par une clé secrète. La clé est une longue séquence de caractères commençant par **nsec1**. Toute personne ayant accès à cette clé secrète peut publier et modifier votre identité. \n\n- Ne mettez **pas** votre clé secrète sur un site web ou un logiciel auquel vous ne faites pas confiance. \n- Les développeurs d'Amethyst ne vous demanderont **jamais** votre clé secrète. \n- **Faites** une sauvegarde sécurisée de votre clé secrète pour la récupération de votre compte. Nous vous recommandons d'utiliser un gestionnaire de mots de passe. + Pour plus de sécurité, vous pouvez chiffrer votre clé avec un mot de passe. Cette clé commence par **ncryptsec1** et ne peut être utilisée sans votre mot de passe. \n\nSi vous perdez votre mot de passe, vous ne pourrez pas récupérer votre clé. Chiffrer et copier ma clé secrète Image de badge pour %1$s Image du badge de récompense @@ -844,7 +837,7 @@ Souscription maximale Nombre maximum de filtres par sub Limite Max (Renvoi des Évènements) - Longueur maximale du SubID + Longueur maximale du SubID Mint : %1$s Échanger Copier le Jeton @@ -960,9 +953,7 @@ Désactive les Notifications Push Utilise l'application %1$s Configuration des Notifications Push - Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). - Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. - + Pour recevoir des notifications push, installez n'importe quelle application qui supporte les [Unified Push](https://unifiedpush.org/), tel que [Ntfy](https://ntfy.sh/). Après installation, sélectionnez l'application que vous voulez utiliser dans les Paramètres. Fil de discussion Envoyer un message au vendeur Bonjour, est-ce toujours disponible ? @@ -2743,11 +2734,8 @@ Relais Proxy Relais agrégateurs que l'application doit utiliser pour télécharger vos flux, tels que filter.nostr.wine. Cela remplace le modèle de boîte d'envoi et permettra à l'application de se connecter uniquement aux relais de vos listes. Chat public - Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui - peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. - La modération peut être contrôlée en supprimant les messages sur ses relais - Insérez entre 1 et 3 relais qui hébergent ce groupe. - Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. + Les conversations publiques sont visibles pour tout le monde sur Nostr et n'importe qui peut y participer. Elles sont idéales pour les communautés ouvertes autour de sujets spécifiques. La modération peut être contrôlée en supprimant les messages sur ses relais + Insérez entre 1 et 3 relais qui hébergent ce groupe. Les clients Nostr utilisent ce paramètre pour savoir où télécharger les messages et où les envoyer. Relais Métadonnées de tchat public Chats publics @@ -2772,10 +2760,7 @@ Utilisateur en lecture seule Cliquez et maintenez pour enregistrer un message Relais de discussion - Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. - Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. - Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères - et, par conséquent, les messages de discussion disparaissent avec le temps + Les relais de discussions sont des groupes de discussion contrôlés par leur relais d'origine. Ils sont visibles par tous les utilisateurs de Nostr et tout le monde peut y participer. Ils sont idéaux pour les communautés ouvertes autour de sujets spécifiques. Certains de ces groupes sont éphémères et, par conséquent, les messages de discussion disparaissent avec le temps Relais de discussions Événements IPs diff --git a/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml b/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml index 3a1f286d3d..cde8a721e1 100644 --- a/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-hi-rIN/strings.xml @@ -646,15 +646,8 @@ सब ज्ञात को पढ लिया चिह्नित करें सब नये को पढ लिया चिह्नित करें सब को पढ लिया चिह्नित करें - ## कुंचिका सुरक्षार्थ अनुकृति तथा सुरक्षा सुझाव - \n\nआपकी लेखा एक गुप्त कुंचिका से सुरक्षित किया गया है। कुंचिका अक्षरों की एक लम्बी श्रृंखला है जो **nsec1** से आरम्भ होता है। जिस किसी के पास यह कुंचिका है वह पत्र प्रकाशित कर सकेगा तथा आपका परिचय परिवर्तित कर सकेगा। - \n\n- आपकी गुप्त कुंचिका किसी भी जालस्थान अथवा क्रमक में **ना** डालें जिसपर आपका विश्वास ना हो। - \n- अमेथिस्ट क्रमलेख विकासकर्ता आपकी गुप्त कुंचिका **कभी नहीं** पूछेंगे। - \n- आपकी गुप्त कुंचिका की एक सुरक्षित अनुकृति **अवश्य** रखें अपनी लेखा पुनः प्राप्त करने के लिए। पारणशब्ध प्रबंधन क्रमक की पुनः प्रशंसा करते हैं। - - अधिक सुरक्षा के लिए आप अपनी कुंचिका का रहस्यीकरण कर सकते हैं एक पारणशब्द के साथ। यह कुंचिका आरम्भ होगी **ncryptsec1** से तथा पारणशब्द के बिना प्रयोग साध्य नहीं। - \n\n यदि आप अपना पारणशब्द खो देते हैं, तो आप अपनी कुंचिका को पुनः प्राप्त नहीं कर सकते। - + ## कुंचिका सुरक्षार्थ अनुकृति तथा सुरक्षा सुझाव \n\nआपकी लेखा एक गुप्त कुंचिका से सुरक्षित किया गया है। कुंचिका अक्षरों की एक लम्बी श्रृंखला है जो **nsec1** से आरम्भ होता है। जिस किसी के पास यह कुंचिका है वह पत्र प्रकाशित कर सकेगा तथा आपका परिचय परिवर्तित कर सकेगा। \n\n- आपकी गुप्त कुंचिका किसी भी जालस्थान अथवा क्रमक में **ना** डालें जिसपर आपका विश्वास ना हो। \n- अमेथिस्ट क्रमलेख विकासकर्ता आपकी गुप्त कुंचिका **कभी नहीं** पूछेंगे। \n- आपकी गुप्त कुंचिका की एक सुरक्षित अनुकृति **अवश्य** रखें अपनी लेखा पुनः प्राप्त करने के लिए। पारणशब्ध प्रबंधन क्रमक की पुनः प्रशंसा करते हैं। + अधिक सुरक्षा के लिए आप अपनी कुंचिका का रहस्यीकरण कर सकते हैं एक पारणशब्द के साथ। यह कुंचिका आरम्भ होगी **ncryptsec1** से तथा पारणशब्द के बिना प्रयोग साध्य नहीं। \n\n यदि आप अपना पारणशब्द खो देते हैं, तो आप अपनी कुंचिका को पुनः प्राप्त नहीं कर सकते। अपने कुंचिकाओं को सुरक्षित रखें आपकी गुप्त कुंचिका एकमात्र विधि है इस लेखा का अभिगमन करने के लिए। यदि आप इसे खो देते हैं तो इसे कभी भी पुनःप्राप्त नहीं कर सकते। इसे कहीं सुरक्षित रखें अभी इस समय। अभी इसी समय सुरक्षित अनुकृति बनाएँ @@ -1834,9 +1827,7 @@ प्रेषित सूचनाएँ अक्षम करता है %1$s क्रमक का प्रयोग करता है प्रेषित सूचना स्थापन - प्रेषित सूचनाएँ प्राप्त करने के लिए, किसी भी क्रमक की स्थापना करें जो [संयुक्त प्रेषण](https://unifiedpush.org/) का अवलम्बन करता है, जैसे [एनटीफै](https://ntfy.sh/)। - स्थापना पश्चात, जिस क्रमक का उपयोग करना चाहते हैं उसका चयन करें स्थापना विकल्पों में। - + प्रेषित सूचनाएँ प्राप्त करने के लिए, किसी भी क्रमक की स्थापना करें जो [संयुक्त प्रेषण](https://unifiedpush.org/) का अवलम्बन करता है, जैसे [एनटीफै](https://ntfy.sh/)। स्थापना पश्चात, जिस क्रमक का उपयोग करना चाहते हैं उसका चयन करें स्थापना विकल्पों में। सूत्र विक्रेता को संदेश भेजें नमस्ते, क्या यह अब भी उपलब्ध है? @@ -3585,17 +3576,9 @@ चालान नहीं लाया जा सका %1$s से : %2$s संकुचित अभिलेख को खोल नहीं पाए धनकोष अप्राप्त - अमेथिस्ट को कोई धनकोष क्रमक प्राप्य नहीं जो नोस्टर धनकोष संयोजन का अवलम्बन करता हो। -\n\nआप यह कर सकते हैं : -\n\t१॰ नोस्टर धनकोष संयोजन अवलम्बन का सत्यापन करें। दुबारा जाँचें की आपका मनचाहा धनकोष क्रमक नोस्टर धनकोष संयोजन के साथ संगत है। -\n\t२॰ संयोजन बनाएँ। आपके धनकोष क्रमक में जाकर एक नया नोस्टर धनकोष संयोजन बनाएँ। -\n\t३॰ अमेथिस्ट के साथ जोडें। आपका धनकोष क्रमक सामान्यतः तीन विकल्प देगा। -\n\t\t३॰१ स्वचालित जोड। एक घुण्डी जिससे स्वचालित रूप से खोलें तथा अमेथिस्ट से जोडें। यदि हो तो उस घुण्डी को टाँकें तथा अमेथिस्ट खोलें तथा नव्य पटल पर अभिलेखन करें। -\n\t\t३॰२ मनुष्यकृत जोड। एक संयोजन वैश्विकसंसाधनपरिचायक जिसकी अनुकृति करके सीधे इस पटल पर प्रविष्ट कर सकते हैं। -\n\t\t३॰३ क्यूआर॰ चित्र अक्षरराशि। धनकोष क्रमक एक क्यूआर॰ चित्र अक्षरराशि बनएगा जिसे आप परख सकते हैं इस पटल पर क्यूआर॰ क्रमचित्र घुण्डी द्वारा। - + अमेथिस्ट को कोई धनकोष क्रमक प्राप्य नहीं जो नोस्टर धनकोष संयोजन का अवलम्बन करता हो। \n\nआप यह कर सकते हैं : \n\t१॰ नोस्टर धनकोष संयोजन अवलम्बन का सत्यापन करें। दुबारा जाँचें की आपका मनचाहा धनकोष क्रमक नोस्टर धनकोष संयोजन के साथ संगत है। \n\t२॰ संयोजन बनाएँ। आपके धनकोष क्रमक में जाकर एक नया नोस्टर धनकोष संयोजन बनाएँ। \n\t३॰ अमेथिस्ट के साथ जोडें। आपका धनकोष क्रमक सामान्यतः तीन विकल्प देगा। \n\t\t३॰१ स्वचालित जोड। एक घुण्डी जिससे स्वचालित रूप से खोलें तथा अमेथिस्ट से जोडें। यदि हो तो उस घुण्डी को टाँकें तथा अमेथिस्ट खोलें तथा नव्य पटल पर अभिलेखन करें। \n\t\t३॰२ मनुष्यकृत जोड। एक संयोजन वैश्विकसंसाधनपरिचायक जिसकी अनुकृति करके सीधे इस पटल पर प्रविष्ट कर सकते हैं। \n\t\t३॰३ क्यूआर॰ चित्र अक्षरराशि। धनकोष क्रमक एक क्यूआर॰ चित्र अक्षरराशि बनएगा जिसे आप परख सकते हैं इस पटल पर क्यूआर॰ क्रमचित्र घुण्डी द्वारा। बनाएँ - दि॰ + दि॰ संकट क्षेत्र अन्धकारमय विवरण @@ -3791,7 +3774,7 @@ छलनी आवृत क्रमलेखकोश छलनी %1$s वित्तपोषित %2$s साट्स उद्देश्य में से - घं॰ + घं॰ यह विषयवस्तु परिवर्तित हुआ है। हो सकता है लेखक ने परिवर्तन देखा नहीं अथवा अनुमति दिया नहीं। इसका अर्थ क्या है? यह विषयवस्तु वैसे ही है जैसे पत्र प्रकाशन पर @@ -4080,7 +4063,7 @@ आप ख्याप्य कुंचिका का प्रयोग कर रहे हैं जिससे केवल पढ सकते हैं। आरोहण करने के लिए गुप्त कुंचिका के साथ प्रवेशांकन करें आप ख्याप्य कुंचिका का प्रयोग कर रहे हैं जिससे केवल पढ सकते हैं। प्रकाशित पत्रों को चाहने के लिए गुप्त कुंचिका के साथ प्रवेशांकन करें चलचित्र - मि॰ + मि॰ मेरे भावचिह्न पोटलियाँ चित्र जोडें जोडा जा रहा है %1$s… @@ -4711,11 +4694,8 @@ प्रतिनिधि पुनःप्रसारक संग्रहकर्ता पुनःप्रसारक जो क्रमक द्वारा उपयुक्त होना चाहिए आपके सूचनावलियों का अवरोहण करने के लिए। जैसे कि filter.nostr.wine । यह निर्गतपेटिका प्रतिरूप को प्रतिस्थापित करेगा तथा क्रमक आपके सूचियों में पुनःप्रसारकों के साथ ही जुडेगा। सार्वजनिक चर्चा - सार्वजनिक चर्चाएँ सबके लिए दृश्यमान हैं नोस्टर पर तथा सभी - इनमें भाग ले सकते हैं। ये उत्कृष्ट हैं खुले समुदायों के लिए विशिष्ट विषयों के प्रसंग में। - नियमन का नियन्त्रण किया जा सकता है पत्रों को मिटाने से पुनःप्रसारकों में - इस समुदाय के निवास के लिए १ - ३ पुनःप्रसारकों को जोडें। - नोस्टर ग्राहक इस स्थापना विकल्प का प्रयोग करेंगे यह जानने के लिए कि कहाँ से सन्देशों का अवरोहण करना है तथा कहाँ आपके सन्देश भेजने हैं। + सार्वजनिक चर्चाएँ सबके लिए दृश्यमान हैं नोस्टर पर तथा सभी इनमें भाग ले सकते हैं। ये उत्कृष्ट हैं खुले समुदायों के लिए विशिष्ट विषयों के प्रसंग में। नियमन का नियन्त्रण किया जा सकता है पत्रों को मिटाने से पुनःप्रसारकों में + इस समुदाय के निवास के लिए १ - ३ पुनःप्रसारकों को जोडें। नोस्टर ग्राहक इस स्थापना विकल्प का प्रयोग करेंगे यह जानने के लिए कि कहाँ से सन्देशों का अवरोहण करना है तथा कहाँ आपके सन्देश भेजने हैं। पुनःप्रसारक सार्वजनिक चर्चा उपतथ्य सार्वजनिक चर्चा @@ -4780,10 +4760,7 @@ प्रमाण प्रमाणीकरण प्रवेशांकन पुनःप्रसारक हस्ताक्षरण सत्यापन निप॰४२ परिचय पुनःप्रसारक प्रमाणीकरण पुनःप्रसारक चर्चा - पुनःप्रसारक चर्चाएँ आवासी पुनःप्रसारक द्वारा नियन्त्रित चर्चा समुदाएँ हैं। - वे नोस्टर पर सभी के लिए दृश्य हैं तथा उनमें सभी भाग ले सकते हैं। - वे उत्कृष्ट हैं खुले समुदायों के लिए विशिष्ट विषयों पर। इनमें से कुछ समुदाएँ अस्थायी हैं। - तथा इसीलिए समय के साथ चर्चा सन्देश अदृश्य हो जाते हैं + पुनःप्रसारक चर्चाएँ आवासी पुनःप्रसारक द्वारा नियन्त्रित चर्चा समुदाएँ हैं। वे नोस्टर पर सभी के लिए दृश्य हैं तथा उनमें सभी भाग ले सकते हैं। वे उत्कृष्ट हैं खुले समुदायों के लिए विशिष्ट विषयों पर। इनमें से कुछ समुदाएँ अस्थायी हैं। तथा इसीलिए समय के साथ चर्चा सन्देश अदृश्य हो जाते हैं पुनःप्रसारक चर्चाएँ आपके अपने परिचय तथा स्थापना विकल्प तथा पाण्डुलिपियाँ। आपके मुख्य पुनःप्रसारकों पर। पुनःप्रसारक जिनपर प्रत्येक समुदाय अपने समतलों को प्रकाशित करते हैं। @@ -5286,4 +5263,322 @@ हस्ताक्षररहित। इसलिए यह कर्ता केवल एक कथन है प्रकार %1$d का वस्तु। जिसे यह ग्राहक चित्रित नहीं करता %1$d अष्टकों का अमुक जिसे यह ग्राहक पढता नहीं + पुनःबाधित करें %1$s को + रखें %1$s + पुनःजुडें %1$s + पुनःमौन %1$s + पुनःस्थापन %1$s + सूचनावलियाँ पुनःस्थापन + स्थल पुनःस्थापन + परिचय पुनःस्थापध + प्रदाता पुनःस्थापन + पुनःप्रसारक पुनःस्थापन + विषय पुनःस्थापन + धनकोष पुनःस्थापन + स्वीकार + + %1$s तथा %2$d जोडा + %1$s तथा %2$d जोडे + + + %1$s तथा %2$d बाधित किया + %1$s तथा %2$d को बाधित किए + + + %1$s तथा %2$d का अनुगमन किया + %1$s तथा %2$d का अनुगमन किए + + + %1$s तथा %2$d से जुडे + %1$s तथा %2$d से जुडे + + + %1$s तथा %2$d को मौनकृत किया + %1$s तथा %2$d को मौनकृत किए + + आपके अमेथिस्ट समचरणीकृत क्रमक स्थापना विकल्पों को परिवर्तित किया गया एक अन्य क्रमक में और वह अमेथिस्ट नहीं था। इससे समस्याएँ उत्पन्न हो सकते हैं। + आपने अपनी कोंकोर्ड सूची रिक्त की + आपने अपनी कोंकोर्ड सूची का परिवर्तन किया + + आपने %1$d सीधासन्देश पुनःप्रसारक हटाया + आपने %1$d सीधासन्देश पुनःप्रसारकों को हटाए + + + आपने %1$d इष्ट सूचनावली हटाया + आपने %1$d इष्ट सूचनावलियों को हटाए + + + आपने %1$d व्यक्ति का अनुगमन हटाया + आपने %1$d व्यक्तियों का अनुगमन हटाए + + + आपने %1$d विषयसूचक का अनुगमन हटाया + आपने %1$d विषयसूचकों का अनुगमन हटाए + + + आपने %1$d अनुक्रमणीकार पुनःप्रसारक हटाया + आपने %1$d अनुक्रमणीकार पुनःप्रसारकों को हटाए + + + आपने %1$d समूहचर्चा कुंचिका पुनःप्रसारक हटाया + आपने %1$d समूहचर्चा कुंचिका पुनःप्रसारकों को हटाए + + + आपने %1$d सार्वजनिक चर्चा छोड दिया + आपने %1$d सार्वजनिक चर्चाओं को छोड दिए + + + आपने %1$d समुदाय छोड दिया + आपने %1$d समुदायों को छोड दिए + + + आपने %1$d समूह छोड दिया + आपने %1$d समूहों को छोड दिए + + + आपने %1$d चर्चाशाला छोड दिया + आपने %1$d चर्चाशालाओं को छोड दिए + + + आपने %1$d की मौनावस्था हटाया + आपने %1$d की मौनावस्था हटाए + + + आपने %1$d सार्वजनिक पुनःप्रसारक हटाया + आपने %1$d सार्वजनिक पुनःप्रसारकों को हटाए + + आपने अपनी नटज्साप कुंचिका को हटाया + आपने अपनी नटज्साप कुंचिका का प्रतिस्थापन किया + + आपने %1$d नटज्साप टकसाल हटाया + आपने %1$d नटज्साप टकसालों को हटाए + + + आपने %1$d बोल्ट॰बारह प्रस्ताव हटाया + आपने %1$d बोल्ट॰बारह प्रस्तावों को हटाए + + + आपने %1$d भुगतान प्राप्त करने की विधि हटाया + आपने %1$d भुगतान प्राप्त करने के विधियों को हटाए + + + आपने %1$d स्थल का अनुगमन हटाया + आपने %1$d स्थलों का अनुगमन हटाए + + + आपने %1$d निजी पुनःप्रसारक हटाया + आपने %1$d निजी पुनःप्रसारकों को हटाए + + + आपने %1$d परिचय प्रपत्रस्थान हटाया + आपने %1$d परिचय प्रपत्रस्थान हटाए + + + आपने %1$d पुनःप्रसारक सूचनावली हटाया + आपने %1$d पुनःप्रसारक सूचनावलियाँ हटाए + + + आपने %1$d खोज पुनःप्रसारक हटाया + आपने %1$d खोज पुनःप्रसारकों को हटाए + + + आपने %1$d विश्वाससेवा प्रदाता परिवर्तित किया + आपने %1$d विश्वाससेवाओं के प्रदाता को परिवर्तित किया + + + आपने %1$d पुनःप्रसारक पर विश्वास करना रोक दिया + आपने %1$d पुनःप्रसारकों पर विश्वास करना रोक दिए + + + आपने %1$d पुनःप्रसारक अबाधित किया + आपने %1$d पुनःप्रसारकों को अबाधित किए + + आपने अपना काशयू धनकोष रिक्त किया + आपने अपने काशयू धनकोष को परिवर्तित किया + जोडे गए (%1$s) + परिवर्तित (%1$s) + %1$s जोडे गए + %1$s परिवर्तित + %1$s हटाए गए + नया संस्करण का उपयोग करें + आपने निजी (रहस्यीकृत) वस्तुओं को जोडा। + आपने निजी (रहस्यीकृत) वस्तुओं का परिवर्तन भी किया। उनकी तुलना यहाँ नहीं की जा सकती। + आपने सभी निजी (रहस्यीकृत) वस्तुओं को हटा दिया। + पठनेवशक्य + पठन तथा लेखन + लेखनेवशक्य + हटाए गए (%1$s) + सुरक्षित संस्करण पुनःस्थापन + आपने अपना %1$s अन्य क्रमक में परिवर्तित किया + सूचनावलियाँ + चर्चा शालाएँ + समुदाय + विषयसूचक + सम्बन्धित व्यक्तिगण + स्थान + टकसाल + नटज्साप कुंचिकाएँ + प्रस्ताव + अन्य प्रविष्टियाँ + भुगतान पते + लोग + परिचय प्रपत्रस्थान + सार्वजनिक चर्चाएँ + पुनःप्रसारक + समूह + सूत्र + विश्वाससेवा प्रदाता + शब्द + जानकारी + ध्वज + जन्मदिन + क्रमचर चिह्न + क्लिंक॰ प्रस्ताव + प्रदर्शन नाम + लैटनिंग जालपता + लैटनिंग पता + प्रयोक्तानाम + नोस्टर पता + चित्र + सर्वनाम + जालस्थान + अनुमत + अन्य क्रमक में परिवर्तित। %1$s + आपके कोंकोर्ड समुदाय आपके लिए रहस्यीकृत हैं। इसलिए उनकी तुलना यहाँ नहीं की जा सकती। पुनःस्थापन उन्हीं को लौट डालेगा जिनका अभिलेखन इस यन्त्र ने किया। + स्थानान्तरित + %1$s परित्यक्त + परित्यक्त + आपने उसे बनाया + आपने उसे परिवर्तित किया + आपने उसे रिक्त किया + सूचनावली + चला गया + विषयसूचक जिनका आप अनुगमन करते हैं + आगतपेटिका + जहाँ अन्य आप तक अभिगमन करते हैं + जुड गए + रखे गए + %1$s रखे गए + ग्राहक कुंचिका हटाया गया + ग्राहक कुंचिका प्रतिस्थापित + नटज्साप आगे से इस कुंचिका से बद्ध होंगे। यदि इस यन्त्र में वह नहीं है तो आप सम्भाव्यतः उनको यहाँ नहीं चुका सकते। + शेष + शेष + सूचीबद्ध + स्थानान्तरित + %1$s तथा %2$s अधिक + नया संस्करण + %1$s नए + नव्य + नव्य + नव्यतः बाधित + %1$s नए मौनकृत + अब से बाधित नहीं + स्थापित नहीं + यहाँ कुछ नहीं + बोल्ट॰बारह प्रस्ताव + + %1$d प्रस्ताव हटाया गया + %1$d प्रस्ताव हटाए गए + + निर्गतपेटिका + आप जहाँ प्रकाशित करते हैं + + आपको भुगतान करने की %1$d विधि हटाया गया + आपको भुगतान करने की %1$d विधियाँ हटाए गए + + लोग जो आपको भुगतान करते हैं उसी को देखते हैं जो इस सूची में है। + स्थल हटाए गए + स्थल जिनका आप अनुगमन करते हैं + वे अब रहस्यीकृत हैं। जो कि सम्भाव्यतः ऊपर के सार्वजनिक वस्तुओं का गन्तव्य था। + आपने वस्तुओं को निजी किया + वे रहस्यीकृत हैं। इसलिए उनकी तुलना यहाँ नहीं की जा सकती। + आपने निजी वस्तुओं का परिवर्तन किया + वे रहस्यीकृत हैं। इसलिए केवल आप देख सकते हैं कि वे क्या थे। पुनःस्थापन से सब लौटके आ जाएँगे। + आपने सभी निजी वस्तुओं को हटा दिया + ग्रहण मध्य + पुनःनामकृत + पुनःनामकृत + इस यन्त्र पर + %1$s लोग खोजें + खोज मध्य + सेवा + अनुचर + श्रेणी + विषयसूची + %2$s में से %1$s सेवाएँ परिवर्तित + वे अब अन्य व्यक्ति से आते है। अथवा किसी से नहीं + अभी भी बाधित + अभिलेखन मध्य + परित्यक्त। %1$s + सम्पादित। %1$s + नए। %1$s + %1$s पारित + %1$s अद्यतनकृत + विषय हटाए गए + श्रेणीयाँ तथा अनुचर गिनती तथा कचरालेख छालन जो आप देखते हैं इन प्रदाताओं से आते हैं। + विश्वसनीय + %1$s अबाधित + अमेथिस्ट पुनः उनसे जुडेगा + इकाई + %1$s मौनावस्था हटाए गए + ये पुनः आपके सूचनावलियों तक अभिगम्य + अविश्वसनीय + आपके धनकोष के टकसाल तथा कुंचिकाएँ आपके लिए रहस्यीकृत हैं। इसलिए उनकी तुलना वस्तु प्रति वस्तु यहाँ नहीं की जा सकती। पुनःस्थापन उन्हीं को लौट डालेगा जिनका अभिलेखन इस यन्त्र ने किया। + पूर्वतः %1$s था + शब्द तथा विषयसूचक + समचरणीकृत क्रमक स्थापना विकल्प + अमेथिस्ट स्थापना विकल्प समचरणीकृत आपके यन्त्रों में। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। + बाधित पुनःप्रसारक सूची + पुनःप्रसारक जिनसे यह क्रमक कभी भी संयोजन नहीं करता। + बोल्ट॰बारह प्रस्ताव + लैटनिंग प्रस्ताव जिनका उपयोग करके अन्य लोग आपको भुगतान करते हैं। + काशयू धनकोष + आपके ईकाश धनकोष स्थापना विकल्प तथा टकसाल। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। + समुदाय सूची + समुदाय जिनसे आप जुडे। + कोंकोर्ड समुदाय सूची + कोंकोर्ड समुदाय जिनसे आप जुडे। वे रहस्यीकृत हैं। इसलिए केवल उनकी उपस्थिति की तुलना की जा सकती है। + सीधासन्देश पुनःप्रसारक सूची + जहाँ अन्य आपके निजी सन्देश भेजते हैं। + अस्थायी चर्चा सूची + अस्थायी चर्चा शालाएँ जिनसे आप जुडे। + इष्ट सूचनावली सूची + कलनविध्यात्मक सूचनावलियाँ जिनको आपने अभिलेखित किया। + अनुचरण सूची + निर्णय करता है किसके पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। + अनुचरित स्थान + स्थान जहाँ से पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। + अनुचरित विषयसूचक + विषयसूचक जिससे युक्त पत्र आपकी मुख्य सूचनावली में प्रकट होंगे। + अनुक्रमणीकार पुनःप्रसारक सूची + पुनःप्रसारक उपयुक्त अन्य लोगों के परिचय तथा पुनःप्रसारक सूचियों को प्राप्त करने के लिए। + समूहचर्चा कुंचिका पुनःप्रसारक + जहाँ अन्य उन कुंचिकाओं को प्राप्त करते हैं आपको रहस्यीकृत समूहचर्चाओं में जोडने के लिए। + मौन सूची + छिपाता है लोग शब्द विषयसूचक तथा सूत्र उन सब में से जो आप देखते हैं। + नटज्साप प्राप्ती स्थापना विकल्प + टकसाल तथा कुंचिका जिनका उपयोग अन्य करते हैं आपको नटज्साप भेजने के लिए। + सूची + इस यन्त्र पर अभिलेखित सूची। + सार्वजनिक पुनःप्रसारक सूची + सबको बताता है आपके पत्र कहाँ प्राप्त करें तथा आपको उत्तर तथा उल्लेखों को कहाँ भेजें। + भुगतान पते + विधियाँ जिनसे अन्य लोग आपको भुगतान कर सके। + निजी पुनःप्रसारक सूची + जहाँ आपके पाण्डुलिपियाँ तथा निजी जानकारी रखे जाते हैं। + परिचय + आपका नाम चित्र चरित तथा भुगतान पते। जैसे सब को दिखते हैं वैसे। + सार्वजनिक चर्चा सूची + सार्वजनिक चर्चाएँ जिनसे आप जुडे। + इष्ट पुनःप्रसारक सूचनावलियाँ + पुनःप्रसारक जिनका आप वीक्षण करते हैं सूचनावलियों के रूप में। + समूह सूची + पुनःप्रसारक आधारित समूह जिनसे आप जुडे। + खोज पुनःप्रसारक सूची + उपयुक्त पुनःप्रसारक जब आप खोजते हैं। + विश्वाससेवा प्रदाता सूची + सेवाएँ जिनपर आप विश्वास करते है आपके लिए लोगों का सत्यापन तथा श्रेणीकरण करने के लिए। + विश्वसनीय पुनःप्रसारक सूची + पुनःप्रसारक जिनपर आप पर्याप्त विश्वास करते हैं बिना पूछे उनसे संयोजन करने के लिए। diff --git a/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml b/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml index 950cdfa8b9..f7872f3f26 100644 --- a/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml @@ -311,7 +311,7 @@ %1$d%% Értéket az értékért Megnyitás - Olvasás + Olvasás Írás Hálózat Típus @@ -461,8 +461,7 @@ Zap-igazolás Közvetlen lightning-fizetés - nem lesz zapigazolás közzétéve a Nostr-on. Egy láncon belüli zapigazolás közzé lesz téve a Nostr-on, így a címzett megtalálhatja a kifizetést. - Fizetés közvetlenül a láncon belüli pénztárcából a profil megadott bitcoin-címére (%1$s) - nem lesz zapigazolás közzétéve. - + Fizetés közvetlenül a láncon belüli pénztárcából a profil megadott bitcoin-címére (%1$s) - nem lesz zapigazolás közzétéve. A nutzap-esemény magát az ecasht kézbesíti, így az mindig közzé lesz téve. Számla kérése… Számla kérése a Nostr hálózaton keresztül… @@ -647,15 +646,8 @@ Az összes ismert megjelölése olvasottként Az összes új üzenet megjelölése olvasottként Összes megjelölése olvasottként - ## Kulcs- és biztonsági mentési tippek - \n\nFiókját egy titkos kulcs védi. A kulcs egy hosszú véletlenszerű karakterlánc, amely **nsec1**-vel kezdődik. Bárki, aki az Ön titkos kulcsához hozzáfér, az Ön személyazonosságának használatával bármilyen tartalmat közzétehet. - \n\n- **Ne** helyezze el a titkos kulcsát olyan webhelyen vagy szoftverben, amelyben nem bízik. - \n- Az Amethyst fejlesztői az Ön titkos kulcsát **soha** nem fogják Öntől elkérni. - \n- A fiók-helyreállításának érdekében, a titkos kulcsáról **mindig** készítsen biztonsági másolatot. Javasoljuk egy jelszókezelő használatát. - - A nagyobb biztonság érdekében titkosítsa egy jelszóval. A jelszóval védett kulcs **ncryptsec1**-vel kezdődik, és a jelszava nélkül nem használható. - \n\nHa elveszíti a jelszavát, nem tudja visszaállítani a kulcsát. - + ## Kulcs- és biztonsági mentési tippek \n\nFiókját egy titkos kulcs védi. A kulcs egy hosszú véletlenszerű karakterlánc, amely **nsec1**-vel kezdődik. Bárki, aki az Ön titkos kulcsához hozzáfér, az Ön személyazonosságának használatával bármilyen tartalmat közzétehet. \n\n- **Ne** helyezze el a titkos kulcsát olyan webhelyen vagy szoftverben, amelyben nem bízik. \n- Az Amethyst fejlesztői az Ön titkos kulcsát **soha** nem fogják Öntől elkérni. \n- A fiók-helyreállításának érdekében, a titkos kulcsáról **mindig** készítsen biztonsági másolatot. Javasoljuk egy jelszókezelő használatát. + A nagyobb biztonság érdekében titkosítsa egy jelszóval. A jelszóval védett kulcs **ncryptsec1**-vel kezdődik, és a jelszava nélkül nem használható. \n\nHa elveszíti a jelszavát, nem tudja visszaállítani a kulcsát. Biztonsági mentés készítése a kulcsokról A titkos kulcs megadása az egyetlen módja a fiók elérésének. Ha elveszíti, akkor soha nem tudja visszaszerezni. Mentse el biztonságos helyre most. Biztonsági mentés most @@ -779,7 +771,7 @@ Eltávolítás Cím nélküli kitűző A kitűzőt %1$d érdemelte ki - Kitűzők · %1$d + Kitűzők · %1$d Válassza ki, hogy a megszerzett kitűzők közül melyek jelenjenek meg a profilban. Ön még nem kapott kitűzőt. Alkalmazások · %1$d @@ -1835,9 +1827,7 @@ Push-értesítések letiltása %1$s alkalmazást használ Push-értesítések beállítása - A push-értesítések fogadásához olyan alkalmazást telepítsen, amely támogatja a [Unified Push](https://unifiedpush.org/), például az [Ntfy](https://ntfy.sh/) alkalmazást. - A telepítés után a beállításokban válassza ki a használni kívánt alkalmazást. - + A push-értesítések fogadásához olyan alkalmazást telepítsen, amely támogatja a [Unified Push](https://unifiedpush.org/), például az [Ntfy](https://ntfy.sh/) alkalmazást. A telepítés után a beállításokban válassza ki a használni kívánt alkalmazást. Bejegyzés Üzenet küldése az eladónak Tisztelt hölgyem / uram! Ez még aktuális? @@ -3124,7 +3114,7 @@ Értesítések a bejövő hang- és videóhívásokhoz Bejövő hívások %1$s elfogadta az Ön sakk-kihívását - Értesítés a sakkjátékkal kapcsolatos eseményekre + Értesítés a sakkjátékkal kapcsolatos eseményekre Sakk Sakkfrissítések %1$s lépett - Ön következik @@ -3586,15 +3576,7 @@ Nem sikerült lekérni a számlát a következőtől: %1$s: %2$s Nem sikerült megnyitni a tömörített fájlt Nem található pénztárca - Az Amethyst nem talált olyan pénztárca-alkalmazást, amely támogatja a Nostr Wallet Connect (NWC) szolgáltatást. -\n\nAmit tehet: -\n\t1. NWC-támogatás ellenőrzése: Ellenőrizze, hogy a kívánt pénztárca-alkalmazás kompatibilis-e a Nostr Wallet Connect szolgáltatással. -\n\t2. Kapcsolat létrehozása: Nyissa meg a pénztárcaalkalmazást, és hozzon létre egy új NWC-kapcsolatot. -\n\t3. Kapcsolódás az Amethysthez: A pénztárcája általában három lehetőséget kínál: -\n\t\t3.1 Automatikus kapcsolódás: Egy gomb az Amethyst automatikus megnyitásához és kapcsolódáshoz. Koppintson erre a gombra, nyissa meg az Amethyst alkalmazást, és mentse el az új képernyőn. -\n\t\t3.2 Kézi kapcsolódás: Egy kapcsolódási cím, amelyet kimásolhat, és a képernyőn található beillesztés gombra koppintva közvetlenül beírhatja. -\n\t\t3.3 QR-kód: A pénztárca létrehoz egy QR-kódot, amelyet a képernyőn található QR-kód gombról olvashat be. - + Az Amethyst nem talált olyan pénztárca-alkalmazást, amely támogatja a Nostr Wallet Connect (NWC) szolgáltatást. \n\nAmit tehet: \n\t1. NWC-támogatás ellenőrzése: Ellenőrizze, hogy a kívánt pénztárca-alkalmazás kompatibilis-e a Nostr Wallet Connect szolgáltatással. \n\t2. Kapcsolat létrehozása: Nyissa meg a pénztárcaalkalmazást, és hozzon létre egy új NWC-kapcsolatot. \n\t3. Kapcsolódás az Amethysthez: A pénztárcája általában három lehetőséget kínál: \n\t\t3.1 Automatikus kapcsolódás: Egy gomb az Amethyst automatikus megnyitásához és kapcsolódáshoz. Koppintson erre a gombra, nyissa meg az Amethyst alkalmazást, és mentse el az új képernyőn. \n\t\t3.2 Kézi kapcsolódás: Egy kapcsolódási cím, amelyet kimásolhat, és a képernyőn található beillesztés gombra koppintva közvetlenül beírhatja. \n\t\t3.3 QR-kód: A pénztárca létrehoz egy QR-kódot, amelyet a képernyőn található QR-kód gombról olvashat be. Létrehozás n Kritikus beállítások @@ -3884,7 +3866,7 @@ Kalandos olvasmány Kalandjelenet Alkalmazáslista - Ajánlott alkalmazások + Ajánlott alkalmazások Találkozó Alkalmazások Időpont-visszaigazolás @@ -4712,11 +4694,8 @@ Proxyzott átjátszók Összesítő átjátszók, amelyeket az alkalmazásnak használnia kell a hírfolyamok letöltéséhez, például filter.nostr.wine. Ez helyettesíti a kimeneti modellt, és az alkalmazás csak a listákban szereplő átjátszókhoz fog csatlakozni. Nyilvános csevegés - A nyilvános csevegések mindenki számára láthatóak a Nostr-on, és bárki - részt vehet bennük. Ezek kiválóan alkalmasak bizonyos témák köré szerveződő nyílt közösségek számára. - A moderálás az átjátszókon lévő hozzászólások törlésével szabályozható - Adjon hozzá 1–3 olyan átjátszót, amelyek kiszolgálják ezt a csoportot. - A Nostr-kliensek ezt a beállítást használják arra, hogy tudják, honnan töltsék le az üzeneteket, és hová küldjék az üzeneteket. + A nyilvános csevegések mindenki számára láthatóak a Nostr-on, és bárki részt vehet bennük. Ezek kiválóan alkalmasak bizonyos témák köré szerveződő nyílt közösségek számára. A moderálás az átjátszókon lévő hozzászólások törlésével szabályozható + Adjon hozzá 1–3 olyan átjátszót, amelyek kiszolgálják ezt a csoportot. A Nostr-kliensek ezt a beállítást használják arra, hogy tudják, honnan töltsék le az üzeneteket, és hová küldjék az üzeneteket. Átjátszók Nyilvános csevegés metaadatai Nyilvános csevegések @@ -4781,10 +4760,7 @@ hitelesítés, átjátszó, aláírás, ellenőrzés, nip-42, azonosság Átjátszó-hitelesítés Átjátszócsevegés - Az átjátszócsevegések olyan csevegőcsoportok, amelyeket az otthoni átjátszó irányít. - Ezek mindenki számára láthatóak a Nostr-on, és bárki részt vehet rajtuk. - Remekül alkalmasak nyitott közösségek kialakítására bizonyos témák körül. Néhány ilyen csoport - rövid élettartamú, ezért a csevegési üzenetek idővel eltűnnek + Az átjátszócsevegések olyan csevegőcsoportok, amelyeket az otthoni átjátszó irányít. Ezek mindenki számára láthatóak a Nostr-on, és bárki részt vehet rajtuk. Remekül alkalmasak nyitott közösségek kialakítására bizonyos témák körül. Néhány ilyen csoport rövid élettartamú, ezért a csevegési üzenetek idővel eltűnnek Átjátszócsevegések Saját profil, -beállítások és -piszkozatok a gazda-átjátszókon. Azok az átjátszók, amelyekre az egyes közösségek közzéteszik a terveiket. @@ -5287,4 +5263,322 @@ Aláírás nélküli, így ez a szerző csak állítás Egy %1$d típusú elem, amelyet ez a kliens nem jelenít meg %1$d bájt valamiből, amit ez a kliens nem olvas + %1$s újbóli letiltása + %1$s megtartása + Újbóli csatlakozás ehhez: %1$s + %1$s újbóli némítása + %1$s visszaállítása + Hírfolyamok visszaállítása + Helyek visszaállítása + Profil visszaállítása + Szolgáltatók visszaállítása + Átjátszók visszaállítása + Témák visszaállítása + Pénztárca visszaállítása + Elfogadás + + %1$s és %2$d hozzáadva + %1$s és %2$d hozzáadva + + + %1$s és %2$d letiltva + %1$s és %2$d letiltva + + + %1$s és %2$d követve + %1$s és %2$d követve + + + %1$s és %2$d csatlakozva + %1$s és %2$d csatlakozva + + + %1$s és %2$d némítva + %1$s és %2$d némítva + + A szinkronizált Amethyst alkalmazásbeállításai egy másik, nem Amethyst alkalmazásban módosultak. Ez problémákat okozhat. + Ön kiürítette a Concord listáját + Ön módosította a Concord listáját + + Ön %1$d privát üzenetátjátszót távolított el + %1$d privát üzenet átjátszót távolított el + + + Ön %1$d kedvenc hírfolyamot távolított el + %1$d kedvenc hírfolyamot távolított el + + + %1$d személyt nem követ többé + %1$d személyt nem követ többé + + + Ön %1$d kulcsszót nem követ többé + %1$d hashtaget nem követ többé + + + Ön %1$d indexelő átjátszót távolított el + %1$d indexelő átjátszót távolított el + + + Ön %1$d csoportos csevegési kulcsátjátszót távolított el + %1$d csoportcsevegés kulcs átjátszót távolított el + + + Ön %1$d nyilvános csevegést hagyott el + %1$d nyilvános csevegést hagyott el + + + Ön %1$d közösséget hagyott el + %1$d közösséget hagyott el + + + Ön %1$d csoportot hagyott el + %1$d csoportot hagyott el + + + Ön %1$d csevegőszobát hagyott el + %1$d csevegőszobát hagyott el + + + Ön %1$d dolog némítását oldotta fel + %1$d dolog némítását oldotta fel + + + Ön %1$d nyilvános átjátszót távolított el + %1$d nyilvános átjátszót távolított el + + Ön eltávolította a nutzap kulcsát + Ön lecserélte a nutzap kulcsát + + Ön %1$d nutzap pénzverdét távolított el + %1$d nutzap pénzverdét távolított el + + + Ön %1$d BOLT12 ajánlatot távolított el + %1$d BOLT12 ajánlatot távolított el + + + Ön %1$d fizetési módot távolított el + %1$d fizetési módot távolított el + + + Ön %1$d helyet nem követ többé + %1$d helyet nem követ többé + + + Ön %1$d privát átjátszót távolított el + %1$d privát átjátszót távolított el + + + Ön %1$d profilmezőt távolított el + %1$d profilmezőt távolított el + + + Ön %1$d átjátszó-hírfolyamot távolított el + %1$d átjátszó hírfolyamot távolított el + + + Ön %1$d kereső átjátszót távolított el + %1$d kereső átjátszót távolított el + + + Ön %1$d bizalmi szolgáltatás szolgáltatóját módosította + %1$d bizalmi szolgáltatás szolgáltatóját változtatta meg + + + Ön %1$d átjátszóban nem bízik többé + %1$d átjátszóban nem bízik többé + + + Ön %1$d átjátszó letiltását oldotta fel + %1$d átjátszó blokkolását oldotta fel + + Ön kiürítette a Cashu pénztárcáját + Ön módosította a Cashu pénztárcáját + Hozzáadva (%1$s) + Módosítva (%1$s) + %1$s hozzáadva + %1$s módosítva + %1$s eltávolítva + Új verzió használata + Ön privát (titkosított) elemeket adott hozzá. + Ön privát (titkosított) elemeket is módosított. Ezek itt nem hasonlíthatók össze. + Ön eltávolította az összes privát (titkosított) elemet. + csak olvasható + olvasás és írás + csak írható + Eltávolítva (%1$s) + Mentett verzió visszaállítása + Ön módosította a következőt: %1$s, egy másik alkalmazásban + Hírfolyamok + Csevegőszobák + Közösségek + Kulcsszavak + Kapcsolt identitások + Helyek + Pénzverdék + Nutzap kulcsok + Ajánlatok + Egyéb bejegyzések + Fizetési címek + Személyek + Profilmezők + Nyilvános csevegések + Átjátszók + Csoportok + Beszélgetések + Bizalmi szolgáltatók + Szavak + Névjegy + Borító + Születésnap + Bot jelölő + CLINK-ajánlat + Megjelenített név + LNURL + Lightning-cím + Felhasználónév + Nostr-cím + Kép + Névmások + Weboldal + Engedélyezve + Módosítva egy másik alkalmazásban · %1$s + A Concord közösségei Önhöz vannak titkosítva, így itt nem hasonlíthatók össze. A visszaállítás pontosan azt hozza vissza, amit ez az eszköz mentett. + Áthelyezve + %1$s elvetve + Elvetve + Ön hozta létre + Ön módosította + Ön kiürítette + Hírfolyam + Eltűnt + Ön által követett kulcsszavak + Bejövő + ahol mások elérik Önt + csatlakozott + megtartva + %1$s megtartva + Fogadási kulcs eltávolítva + Fogadási kulcs lecserélve + A nutzapok ehhez az új kulcshoz lesznek kötve. Ha ez az eszköz nem rendelkezik vele, lehet, hogy itt nem tudja beváltani őket. + elhagyta a csoportot + Elhagyva + Listázva + Áthelyezve + %1$s és %2$s további + Új verzió + %1$s új + új + Új + Újonnan letiltva + %1$s újonnan némítva + Már nincs letiltva + Nincs beállítva + Itt nincs semmi + BOLT12 ajánlat + + %1$d ajánlat eltávolítva + %1$d ajánlat eltávolítva + + Kimenő + ahol közzétesz + + %1$d fizetési mód eltávolítva + %1$d fizetési mód eltávolítva + + A fizető emberek csak azt látják, ami ebben a listában van. + eltűnt helyek + Ön által követett helyek + Most már titkosítva vannak, valószínűleg ide kerültek a fenti nyilvános elemek. + Ön priváttá tette az elemeket + Titkosítva vannak, így itt nem hasonlíthatók össze. + Ön módosította a privát elemeket + Titkosítva vannak, így csak Ön láthatja, mik voltak. A visszaállítás mindet visszahozza. + Ön eltávolította az összes privát elemet + Fogadás + átnevezte + Átnevezve + Ezen az eszközön + %1$s személy keresése + Keresés + Szolgáltatás + Követők + Rang + Témák + %2$s szolgáltatásból %1$s módosult + Most már valaki mástól vagy senkitől sem származnak + Továbbra is le van tiltva + Tárolás + Elvetve · %1$s + Szerkesztve · %1$s + Új · %1$s + %1$s törölve + %1$s frissítve + eltűnt témák + A látott rangok, követőszámok és a kéretlen tartalomszűrés ezektől a szolgáltatóktól származnak. + Megbízható + %1$s letiltása feloldva + Az Amethyst újra kapcsolódni fog hozzájuk + Egységek + %1$s némítása feloldva + Ezek újra megjelenhetnek a hírfolyamaiban + Nem megbízható + A saját pénztárca pénzverdéi és kulcsai Önhöz vannak titkosítva, így itt nem hasonlíthatók össze tételesen. A visszaállítás pontosan azt hozza vissza, amit ez az eszköz mentett. + „%1$s” volt + Szavak és kulcsszavak + szinkronizált alkalmazásbeállítások + Az eszközök között szinkronizált Amethyst-beállítások. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. + letiltott átjátszólista + Átjátszók, amelyekhez ez az alkalmazás soha nem kapcsolódik. + BOLT12 ajánlatok + A lightning ajánlatok, amelyeket mások a fizetéshez használnak az Ön számára. + Cashu pénztárca + Az ecash pénztárca beállításai és pénzverdéi. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. + közösséglista + Közösségek, amelyekhez csatlakozott. + Concord közösséglista + A Concord közösségek, amelyekhez csatlakozott. Titkosítva vannak, így csak a jelenlétük hasonlítható össze. + privát üzenet átjátszólista + Ahová mások kézbesítik a privát üzeneteit. + rövid életű csevegési lista + Rövid életű csevegőszobák, amelyekhez csatlakozott. + kedvenc hírfolyamlista + Mentett algoritmus-hírfolyamok. + követési lista + Meghatározza, kinek a bejegyzései jelenjenek meg a kezdőlapon. + követett helyek + Helyek, amelyek bejegyzései megjelennek a hírfolyamaiban. + követett kulcsszavak + Kulcsszavak, amelyek bejegyzései megjelennek a hírfolyamban. + indexelő átjátszólista + Azok az átjátszók, amelyeket mások profiljainak és átjátszólistáinak megtalálásához használnak. + csoportos csevegési kulcsátjátszók + Ahol mások megtalálják a kulcsokat, hogy titkosított csoportos csevegésekhez adhassák Önt. + némítási lista + Elrejti a személyeket, szavakat, kulcsszavakat és beszélgetéseket mindenből, amit lát. + nutzap fogadási beállítások + A pénzverdék és a kulcs, amelyeket mások a nutzapok küldéséhez használnak az Ön számára. + lista + Egy listaelem ezen az eszközön mentve. + nyilvános átjátszólista + Megmondja mindenkinek, hol találhatók a bejegyzései, és hová küldjék a válaszokat és említéseket. + fizetési címek + A módok, ahogy mások fizethetnek Önnek. + privát átjátszólista + Ahol a piszkozatai és privát adatai tárolódnak. + profil + Az Ön neve, képe, bemutatkozása és fizetési címei, ahogy mindenki látja őket. + nyilvános csevegési lista + Nyilvános csevegések, amelyekhez csatlakozott. + kedvenc átjátszóhírfolyamok + Olyan átjátszók, amelyeket hírfolyamként böngész. + csoportlista + Átjátszó-alapú csoportok, amelyekhez csatlakozott. + kereső átjátszólista + Kereséskor használt átjátszók. + bizalmi szolgáltatólista + A szolgáltatások, amelyekben megbízik, hogy rangsorolják és ellenőrizzék Önnek az embereket. + megbízható átjátszólista + Átjátszók, amelyekhez kérdezés nélkül kapcsolódhat. diff --git a/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml b/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml index 7b53a2b3e2..3ce5510f41 100644 --- a/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-in-rID/strings.xml @@ -266,15 +266,8 @@ Tandai semua yang dikenal sebagai telah dibaca Tandai semua yang baru sebagai telah dibaca Tandai semua sebagai telah dibaca - ## Tips Cadangan Kunci dan Keamanan - \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. - \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. - \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. - \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. - - Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. - \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. - + ## Tips Cadangan Kunci dan Keamanan \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. + Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. Enkripsi dan salin kunci rahasia saya Gambar penghargaan lencana untuk %1$s "Gambar penghargaan lencana @@ -853,13 +846,11 @@ DITUTUP TERJADWAL Mulai %1$s - Keluar akan menghapus semua informasi yang disimpan secara lokal. -Pastikan kunci pribadi Anda telah simpan untuk menghindari kehilangan akun Anda. Apakah Anda ingin melanjutkan? + Keluar akan menghapus semua informasi yang disimpan secara lokal. Pastikan kunci pribadi Anda telah simpan untuk menghindari kehilangan akun Anda. Apakah Anda ingin melanjutkan? Tags yang Diikuti Ini adalah daftar pengguna yang Anda rekomendasikan kepada orang lain. Hanya pengguna publik yang diizinkan. Post yang disetujui - Grup ini tidak memiliki deskripsi atau peraturan. -Beri tahu kepada pemilik untuk menambahnya + Grup ini tidak memiliki deskripsi atau peraturan. Beri tahu kepada pemilik untuk menambahnya Komunitas ini tidak memiliki deskripsi. Beri tahu kepada pemilik untuk menambahnya Preferensi Pengguna Cari pengaturan @@ -951,9 +942,7 @@ Beri tahu kepada pemilik untuk menambahnya Matikan Pemberitahuan Push Memakai aplikasi %1$s Pengaturan Pemberitahuan Push - Untuk menerima Pemberitahuan Push, Install aplikasi yang mendukung [Unified Push](https://unifiedpush.org/), seperti [Ntfy](https://ntfy.sh/). - Setelah diinstall, Pilih aplikasi yang ingin digunakan di pengaturan. - + Untuk menerima Pemberitahuan Push, Install aplikasi yang mendukung [Unified Push](https://unifiedpush.org/), seperti [Ntfy](https://ntfy.sh/). Setelah diinstall, Pilih aplikasi yang ingin digunakan di pengaturan. Utas Kirim pesan ke penjual Halo, apakah ini masih tersedia? @@ -1991,15 +1980,7 @@ Beri tahu kepada pemilik untuk menambahnya Tidak dapat mengambil invoice dari %1$s: %2$s Tidak dapat membuka file terkompresi Dompet tidak ditemukan - Amethyst tidak dapat menemukan aplikasi dompet apa pun yang mendukung Nostr Wallet Connect (NWC). -\n\nYang dapat Anda lakukan: -\n\t1. Verifikasi Dukungan NWC: Pastikan aplikasi dompet pilihan Anda kompatibel dengan Nostr Wallet Connect. -\n\t2. Buat Koneksi: Buka aplikasi dompet Anda dan buat koneksi NWC baru. -\n\t3. Hubungkan ke Amethyst: Dompet Anda biasanya akan memberikan tiga pilihan: -\n\t\t3.1 Tautan Otomatis: Tombol untuk secara otomatis membuka dan terhubung ke Amethyst. Jika ada, klik tombol tersebut, buka Amethyst dan tekan simpan di layar baru. -\n\t\t3.2 Tautan Manual: URI Koneksi yang dapat Anda salin dan klik ikon tempel di layar ini untuk memasukkannya secara langsung. -\n\t\t3.3 Kode QR: Dompet membuat kode QR yang dapat Anda baca dari tombol kode QR di layar ini. - + Amethyst tidak dapat menemukan aplikasi dompet apa pun yang mendukung Nostr Wallet Connect (NWC). \n\nYang dapat Anda lakukan: \n\t1. Verifikasi Dukungan NWC: Pastikan aplikasi dompet pilihan Anda kompatibel dengan Nostr Wallet Connect. \n\t2. Buat Koneksi: Buka aplikasi dompet Anda dan buat koneksi NWC baru. \n\t3. Hubungkan ke Amethyst: Dompet Anda biasanya akan memberikan tiga pilihan: \n\t\t3.1 Tautan Otomatis: Tombol untuk secara otomatis membuka dan terhubung ke Amethyst. Jika ada, klik tombol tersebut, buka Amethyst dan tekan simpan di layar baru. \n\t\t3.2 Tautan Manual: URI Koneksi yang dapat Anda salin dan klik ikon tempel di layar ini untuk memasukkannya secara langsung. \n\t\t3.3 Kode QR: Dompet membuat kode QR yang dapat Anda baca dari tombol kode QR di layar ini. Buat h Zona Berbahaya @@ -2183,8 +2164,7 @@ Beri tahu kepada pemilik untuk menambahnya Gambar disimpan ke galeri Identitas palsu Relay Kotak Masuk - Jumlah faktur salah (%1$s sat) dari %2$s. -Seharusnya %3$s + Jumlah faktur salah (%1$s sat) dari %2$s. Seharusnya %3$s Relay Indeks Relay yang berspesialisasi dalam menyimpan metadata dan daftar relay semua orang, seperti purplepag.es. Amethyst akan menggunakan relay ini untuk menemukan pengguna yang tidak ada dalam daftar Anda. Kumpulan Minat Baru @@ -2618,11 +2598,8 @@ Seharusnya %3$s Relay Proxy Relay agregator yang harus digunakan aplikasi untuk mengunduh feed Anda, seperti filter.nostr.wine. Ini menggantikan model outbox dan akan membuat aplikasi hanya terhubung ke relay dalam daftar Anda. Obrolan Publik - Obrolan publik terlihat oleh semua orang di Nostr dan siapa pun - dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. - Moderasi dapat dilakukan dengan menghapus postingan di relay-nya - Masukkan antara 1–3 relay yang menjadi host grup ini. - Klien Nostr menggunakan pengaturan ini untuk mengetahui tempat mengunduh dan mengirim pesan Anda. + Obrolan publik terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. Moderasi dapat dilakukan dengan menghapus postingan di relay-nya + Masukkan antara 1–3 relay yang menjadi host grup ini. Klien Nostr menggunakan pengaturan ini untuk mengetahui tempat mengunduh dan mengirim pesan Anda. relay Metadata Obrolan Publik Obrolan Publik @@ -2647,10 +2624,7 @@ Seharusnya %3$s Pengguna hanya-baca Tekan dan tahan untuk merekam pesan Obrolan relay - Obrolan relay adalah grup obrolan yang dikendalikan oleh relay induknya. - Obrolan ini terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. - Sangat cocok untuk komunitas terbuka seputar topik tertentu. Beberapa grup ini bersifat sementara - sehingga pesan obrolan akan menghilang seiring waktu + Obrolan relay adalah grup obrolan yang dikendalikan oleh relay induknya. Obrolan ini terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. Beberapa grup ini bersifat sementara sehingga pesan obrolan akan menghilang seiring waktu Obrolan relay Acara IP diff --git a/commonsUI/src/commonMain/composeResources/values-in/strings.xml b/commonsUI/src/commonMain/composeResources/values-in/strings.xml index 7635510369..2fe9f6457e 100644 --- a/commonsUI/src/commonMain/composeResources/values-in/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-in/strings.xml @@ -172,7 +172,7 @@ Nama pengguna Tentang saya URL Avatar - URL Spanduk/Banner + URL Spanduk/Banner URL Situs Web Kata ganti relay sumber mungkin sudah usang @@ -257,17 +257,8 @@ Tandai semua yg dikenal telah dibaca Tandai pesan baru telah dibaca Tandai semua telah dibaca - - ## Tips Cadangan Kunci dan Keamanan - \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. - \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. - \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. - \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. - - - Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. - \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. - + ## Tips Cadangan Kunci dan Keamanan \n\nAkun Anda diamankan dengan kunci rahasia. Kunci ini adalah rangkaian karakter panjang yang diawali dengan **nsec1**. Siapa pun yang memiliki akses ke kunci rahasia ini dapat memposting dan mengubah identitas Anda. \n\n- **Jangan** memasukkan kunci rahasia Anda ke situs web atau perangkat lunak yang tidak Anda percaya. \n- Pengembang Amethyst **tidak akan pernah** meminta kunci rahasia Anda. \n- **Lakukan** pencadangan kunci rahasia Anda secara aman untuk pemulihan akun. Kami merekomendasikan penggunaan pengelola kata sandi. + Untuk keamanan tambahan, Anda dapat mengenkripsi kunci dengan kata sandi. Kunci ini diawali dengan **ncryptsec1** dan tidak dapat digunakan tanpa kata sandi Anda. \n\nJika Anda kehilangan kata sandi, Anda tidak akan dapat memulihkan kunci Anda. Enkripsi dan salin kunci rahasia saya Gambar penghargaan lencana untuk %1$s "Gambar penghargaan lencana @@ -960,10 +951,7 @@ Menonaktifkan Notifikasi Push Menggunakan aplikasi %1$s Pengaturan Notifikasi Push - - Untuk menerima notifikasi push, instal aplikasi yang mendukung [Unified Push](https://unifiedpush.org/), seperti [Ntfy](https://ntfy.sh/). - Setelah menginstal, pilih aplikasi yang ingin Anda gunakan di Pengaturan. - + Untuk menerima notifikasi push, instal aplikasi yang mendukung [Unified Push](https://unifiedpush.org/), seperti [Ntfy](https://ntfy.sh/). Setelah menginstal, pilih aplikasi yang ingin Anda gunakan di Pengaturan. Utas Kirim pesan ke penjual Halo, apakah ini masih tersedia? @@ -2048,15 +2036,7 @@ Tidak dapat mengambil invoice dari %1$s: %2$s Tidak dapat membuka file terkompresi Dompet tidak ditemukan - Amethyst tidak dapat menemukan aplikasi dompet apa pun yang mendukung Nostr Wallet Connect (NWC). -\n\nYang dapat Anda lakukan: -\n\t1. Verifikasi Dukungan NWC: Pastikan aplikasi dompet pilihan Anda kompatibel dengan Nostr Wallet Connect. -\n\t2. Buat Koneksi: Buka aplikasi dompet Anda dan buat koneksi NWC baru. -\n\t3. Hubungkan ke Amethyst: Dompet Anda biasanya akan memberikan tiga pilihan: -\n\t\t3.1 Tautan Otomatis: Tombol untuk secara otomatis membuka dan terhubung ke Amethyst. Jika ada, klik tombol tersebut, buka Amethyst dan tekan simpan di layar baru. -\n\t\t3.2 Tautan Manual: URI Koneksi yang dapat Anda salin dan klik ikon tempel di layar ini untuk memasukkannya secara langsung. -\n\t\t3.3 Kode QR: Dompet membuat kode QR yang dapat Anda baca dari tombol kode QR di layar ini. - + Amethyst tidak dapat menemukan aplikasi dompet apa pun yang mendukung Nostr Wallet Connect (NWC). \n\nYang dapat Anda lakukan: \n\t1. Verifikasi Dukungan NWC: Pastikan aplikasi dompet pilihan Anda kompatibel dengan Nostr Wallet Connect. \n\t2. Buat Koneksi: Buka aplikasi dompet Anda dan buat koneksi NWC baru. \n\t3. Hubungkan ke Amethyst: Dompet Anda biasanya akan memberikan tiga pilihan: \n\t\t3.1 Tautan Otomatis: Tombol untuk secara otomatis membuka dan terhubung ke Amethyst. Jika ada, klik tombol tersebut, buka Amethyst dan tekan simpan di layar baru. \n\t\t3.2 Tautan Manual: URI Koneksi yang dapat Anda salin dan klik ikon tempel di layar ini untuk memasukkannya secara langsung. \n\t\t3.3 Kode QR: Dompet membuat kode QR yang dapat Anda baca dari tombol kode QR di layar ini. Buat hari Zona Berbahaya @@ -2723,11 +2703,8 @@ Relay Proxy Relay agregator yang harus digunakan aplikasi untuk mengunduh feed Anda, seperti filter.nostr.wine. Ini menggantikan model outbox dan akan membuat aplikasi hanya terhubung ke relay dalam daftar Anda. Percakapan Publik - Obrolan publik terlihat oleh semua orang di Nostr dan siapa pun - dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. - Moderasi dapat dilakukan dengan menghapus postingan di relay-nya - Masukkan antara 1–3 relay yang menjadi host grup ini. - Klien Nostr menggunakan pengaturan ini untuk mengetahui tempat mengunduh dan mengirim pesan Anda. + Obrolan publik terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. Moderasi dapat dilakukan dengan menghapus postingan di relay-nya + Masukkan antara 1–3 relay yang menjadi host grup ini. Klien Nostr menggunakan pengaturan ini untuk mengetahui tempat mengunduh dan mengirim pesan Anda. relay Metadata Obrolan Publik Obrolan Publik @@ -2752,10 +2729,7 @@ Pengguna hanya-baca Tekan dan tahan untuk merekam pesan Obrolan relay - Obrolan relay adalah grup obrolan yang dikendalikan oleh relay induknya. - Obrolan ini terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. - Sangat cocok untuk komunitas terbuka seputar topik tertentu. Beberapa grup ini bersifat sementara - sehingga pesan obrolan akan menghilang seiring waktu + Obrolan relay adalah grup obrolan yang dikendalikan oleh relay induknya. Obrolan ini terlihat oleh semua orang di Nostr dan siapa pun dapat berpartisipasi. Sangat cocok untuk komunitas terbuka seputar topik tertentu. Beberapa grup ini bersifat sementara sehingga pesan obrolan akan menghilang seiring waktu Obrolan relay Acara IP diff --git a/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml b/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml index aff7bdaf21..54245dec39 100644 --- a/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-it-rIT/strings.xml @@ -266,15 +266,8 @@ Segna tutti i conosciuti come letti Segna tutti i nuovi come letti Segna tutti come letti - ## Suggerimenti per il backup e la sicurezza della chiave - \n\nIl tuo account è protetto da una chiave segreta. La chiave è una lunga sequenza di caratteri che inizia con **nsec1**. Chiunque abbia accesso a questa chiave segreta può pubblicare e modificare la tua identità. - \n\n- **Non** inserire la tua chiave segreta in nessun sito web o software di cui non ti fidi. - \n- Gli sviluppatori di Amethyst non chiederanno **mai** la tua chiave segreta. - \n- **Conserva** un backup sicuro della tua chiave segreta per il recupero dell'account. Si consiglia l'uso di un gestore di password. - - Per maggiore sicurezza, puoi cifrare la tua chiave con una password. Questa chiave inizia con **ncryptsec1** e non può essere utilizzata senza la tua password. - \n\nSe perdi la password, non potrai recuperare la tua chiave. - + ## Suggerimenti per il backup e la sicurezza della chiave \n\nIl tuo account è protetto da una chiave segreta. La chiave è una lunga sequenza di caratteri che inizia con **nsec1**. Chiunque abbia accesso a questa chiave segreta può pubblicare e modificare la tua identità. \n\n- **Non** inserire la tua chiave segreta in nessun sito web o software di cui non ti fidi. \n- Gli sviluppatori di Amethyst non chiederanno **mai** la tua chiave segreta. \n- **Conserva** un backup sicuro della tua chiave segreta per il recupero dell'account. Si consiglia l'uso di un gestore di password. + Per maggiore sicurezza, puoi cifrare la tua chiave con una password. Questa chiave inizia con **ncryptsec1** e non può essere utilizzata senza la tua password. \n\nSe perdi la password, non potrai recuperare la tua chiave. Cifra e copia la mia chiave segreta Immagine premio badge per %1$s "Immagine del premio badge @@ -947,9 +940,7 @@ Disabilita le notifiche push Usa l'app %1$s Configurazione notifiche push - Per ricevere notifiche push, installa qualsiasi app che supporta [Unified Push](https://unifiedpush.org/), come [Ntfy](https://ntfy.sh/). - Dopo l'installazione, seleziona l'app che desideri usare nelle Impostazioni. - + Per ricevere notifiche push, installa qualsiasi app che supporta [Unified Push](https://unifiedpush.org/), come [Ntfy](https://ntfy.sh/). Dopo l'installazione, seleziona l'app che desideri usare nelle Impostazioni. Invia un messaggio al venditore Ciao, è ancora disponibile? Titolo @@ -1986,15 +1977,7 @@ Impossibile recuperare la fattura da %1$s: %2$s Impossibile aprire il file compresso Wallet non trovato - Amethyst non ha trovato app wallet compatibili con Nostr Wallet Connect (NWC). -\n\nCosa puoi fare: -\n\t1. Verifica il supporto NWC: controlla che la tua app wallet preferita sia compatibile con Nostr Wallet Connect. -\n\t2. Crea connessione: vai nella tua app wallet e crea una nuova connessione NWC. -\n\t3. Collega ad Amethyst: la tua app wallet ti offrirà solitamente tre opzioni: -\n\t\t3.1 Collegamento automatico: un pulsante per aprire e connettersi automaticamente ad Amethyst. In tal caso, clicca quel pulsante, apri Amethyst e premi salva nella nuova schermata. -\n\t\t3.2 Collegamento manuale: un URI di connessione che puoi copiare e incollare tramite l'icona di incolla in questa schermata. -\n\t\t3.3 Codice QR: il wallet crea un codice QR che puoi leggere tramite il pulsante QR in questa schermata. - + Amethyst non ha trovato app wallet compatibili con Nostr Wallet Connect (NWC). \n\nCosa puoi fare: \n\t1. Verifica il supporto NWC: controlla che la tua app wallet preferita sia compatibile con Nostr Wallet Connect. \n\t2. Crea connessione: vai nella tua app wallet e crea una nuova connessione NWC. \n\t3. Collega ad Amethyst: la tua app wallet ti offrirà solitamente tre opzioni: \n\t\t3.1 Collegamento automatico: un pulsante per aprire e connettersi automaticamente ad Amethyst. In tal caso, clicca quel pulsante, apri Amethyst e premi salva nella nuova schermata. \n\t\t3.2 Collegamento manuale: un URI di connessione che puoi copiare e incollare tramite l'icona di incolla in questa schermata. \n\t\t3.3 Codice QR: il wallet crea un codice QR che puoi leggere tramite il pulsante QR in questa schermata. Crea g Zona pericolosa @@ -2645,11 +2628,8 @@ Relay proxy Relay aggregatori che l'app deve usare per scaricare i tuoi feed, come filter.nostr.wine. Questo sostituisce il modello outbox e farà connettere l'app solo ai relay nelle tue liste. Chat Pubblica - Le chat pubbliche sono visibili a tutti su Nostr e chiunque - può parteciparvi. Sono ideali per comunità aperte su argomenti specifici. - La moderazione può essere controllata eliminando i post sui relay associati - Inserisci tra 1 e 3 relay che ospitano questo gruppo. - I client Nostr usano questa impostazione per sapere da dove scaricare i messaggi e dove inviare i tuoi messaggi. + Le chat pubbliche sono visibili a tutti su Nostr e chiunque può parteciparvi. Sono ideali per comunità aperte su argomenti specifici. La moderazione può essere controllata eliminando i post sui relay associati + Inserisci tra 1 e 3 relay che ospitano questo gruppo. I client Nostr usano questa impostazione per sapere da dove scaricare i messaggi e dove inviare i tuoi messaggi. Relay Metadati chat pubblica Chat pubbliche @@ -2674,10 +2654,7 @@ Utente in sola lettura Tieni premuto per registrare un messaggio Chat relay - Le chat relay sono gruppi di chat controllati dal loro relay di riferimento. - Sono visibili a tutti su Nostr e chiunque può parteciparvi. - Sono ideali per comunità aperte su argomenti specifici. Alcuni di questi gruppi sono effimeri - e quindi i messaggi della chat scompaiono nel tempo + Le chat relay sono gruppi di chat controllati dal loro relay di riferimento. Sono visibili a tutti su Nostr e chiunque può parteciparvi. Sono ideali per comunità aperte su argomenti specifici. Alcuni di questi gruppi sono effimeri e quindi i messaggi della chat scompaiono nel tempo Chat relay Eventi IP diff --git a/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml b/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml index 04d9abd43e..089c9f9857 100644 --- a/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ja-rJP/strings.xml @@ -69,7 +69,7 @@ QRコードをスキャン それでも表示する このポストは、非表示にしているユーザーまたはワードが含まれているため隠されています - このユーザによって投稿が不適切なものとしてマークされています: + このユーザによって投稿が不適切なものとしてマークされています: 投稿が見つかりません チャンネル画像 参照先のイベントが見つかりません @@ -271,15 +271,8 @@ すべての「知り合い」を既読にする すべての「新規リクエスト」を既読にする すべて既読にする - ## 鍵のバックアップとセキュリティのヒント - \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 - \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 - \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 - \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 - - さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 - \n\nパスワードを忘れると、鍵を復元できなくなります。 - + ## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 + さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。 秘密鍵を暗号化してコピー %1$sのバッジ授与画像 バッジ授与の画像 @@ -965,9 +958,7 @@ プッシュ通知を無効にします アプリ%1$sを使用 プッシュ通知の設定 - プッシュ通知を受け取るには、[Ntfy](https://ntfy.sh/)など[Unified Push](https://unifiedpush.org/)に対応したアプリをインストールしてください。 - インストール後、設定で使用するアプリを選択してください。 - + プッシュ通知を受け取るには、[Ntfy](https://ntfy.sh/)など[Unified Push](https://unifiedpush.org/)に対応したアプリをインストールしてください。 インストール後、設定で使用するアプリを選択してください。 スレッド 出品者にメッセージを送る こんにちは、こちらはまだ入手可能ですか? @@ -2016,15 +2007,7 @@ %1$s から請求書を取得できませんでした: %2$s 圧縮ファイルを開けませんでした ウォレットが見つかりません - Amethyst は Nostr Wallet Connect(NWC)に対応したウォレットアプリを見つけられませんでした。 -\n\n対処方法: -\n\t1. NWC サポートを確認: お使いのウォレットアプリが Nostr Wallet Connect に対応しているか再確認してください。 -\n\t2. 接続を作成: ウォレットアプリで新しい NWC 接続を作成してください。 -\n\t3. Amethyst にリンク: ウォレットは通常、以下の3つの方法を提供します: -\n\t\t3.1 自動リンク: 自動的に Amethyst を開いて接続するボタン。その場合、ボタンをクリックして Amethyst を開き、新しい画面で保存を押してください。 -\n\t\t3.2 手動リンク: この画面の貼り付けアイコンをクリックして直接入力できる接続 URI。 -\n\t\t3.3 QR コード: ウォレットが作成する QR コード。この画面の QR コードボタンから読み取れます。 - + Amethyst は Nostr Wallet Connect(NWC)に対応したウォレットアプリを見つけられませんでした。 \n\n対処方法: \n\t1. NWC サポートを確認: お使いのウォレットアプリが Nostr Wallet Connect に対応しているか再確認してください。 \n\t2. 接続を作成: ウォレットアプリで新しい NWC 接続を作成してください。 \n\t3. Amethyst にリンク: ウォレットは通常、以下の3つの方法を提供します: \n\t\t3.1 自動リンク: 自動的に Amethyst を開いて接続するボタン。その場合、ボタンをクリックして Amethyst を開き、新しい画面で保存を押してください。 \n\t\t3.2 手動リンク: この画面の貼り付けアイコンをクリックして直接入力できる接続 URI。 \n\t\t3.3 QR コード: ウォレットが作成する QR コード。この画面の QR コードボタンから読み取れます。 作成 日 危険ゾーン @@ -2667,11 +2650,8 @@ Proxy Relay filter.nostr.wine のように、アプリがフィードをダウンロードするために使用するアグリゲーター relay です。これにより outbox モデルが置き換えられ、アプリはリスト内の relay のみに接続するようになります。 公開チャット - パブリックチャットは Nostr 上の全員に公開されており、誰でも - 参加できます。特定のトピックを中心としたオープンなコミュニティに最適です。 - モデレーションは、その relay 上のポストを削除することで管理できます - このグループをホストする relay を 1〜3 件入力してください。 - Nostr クライアントはこの設定を使用して、メッセージのダウンロード先と送信先を決定します。 + パブリックチャットは Nostr 上の全員に公開されており、誰でも 参加できます。特定のトピックを中心としたオープンなコミュニティに最適です。 モデレーションは、その relay 上のポストを削除することで管理できます + このグループをホストする relay を 1〜3 件入力してください。 Nostr クライアントはこの設定を使用して、メッセージのダウンロード先と送信先を決定します。 Relay パブリックチャットのメタデータ パブリックチャット @@ -2696,10 +2676,7 @@ 読み取り専用ユーザー 長押ししてメッセージを録音 relay チャット - relay チャットは、ホスト relay によって管理されるチャットグループです。 - Nostr 上の全員に公開されており、誰でも参加できます。 - 特定のトピックを中心としたオープンなコミュニティに最適です。一部のグループは一時的なもので、 - チャットメッセージは時間とともに消えます + relay チャットは、ホスト relay によって管理されるチャットグループです。 Nostr 上の全員に公開されており、誰でも参加できます。 特定のトピックを中心としたオープンなコミュニティに最適です。一部のグループは一時的なもので、 チャットメッセージは時間とともに消えます relay チャット イベント IP diff --git a/commonsUI/src/commonMain/composeResources/values-ja/strings.xml b/commonsUI/src/commonMain/composeResources/values-ja/strings.xml index a9b6f5afcf..8e2365c27e 100644 --- a/commonsUI/src/commonMain/composeResources/values-ja/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ja/strings.xml @@ -49,7 +49,7 @@ QRコードをスキャン それでも表示する このポストは、非表示にしているユーザーまたはワードが含まれているため隠されています - このユーザによって投稿が不適切なものとしてマークされています: + このユーザによって投稿が不適切なものとしてマークされています: 投稿が見つかりません 👀 チャンネル画像 @@ -257,17 +257,8 @@ すべての「知り合い」を既読にする すべての「新規リクエスト」を既読にする すべて既読にする - - ## 鍵のバックアップとセキュリティのヒント - \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 - \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 - \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 - \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 - - - さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 - \n\nパスワードを忘れると、鍵を復元できなくなります。 - + ## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。 + さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。 秘密鍵を暗号化してコピー %1$sのバッジ授与画像 バッジ授与の画像 @@ -960,10 +951,7 @@ プッシュ通知を無効にします アプリ%1$sを使用 プッシュ通知の設定 - - プッシュ通知を受け取るには、[Ntfy](https://ntfy.sh/)など[Unified Push](https://unifiedpush.org/)に対応したアプリをインストールしてください。 - インストール後、設定で使用するアプリを選択してください。 - + プッシュ通知を受け取るには、[Ntfy](https://ntfy.sh/)など[Unified Push](https://unifiedpush.org/)に対応したアプリをインストールしてください。 インストール後、設定で使用するアプリを選択してください。 スレッド 出品者にメッセージを送る こんにちは、こちらはまだ入手可能ですか? @@ -2048,15 +2036,7 @@ %1$s から請求書を取得できませんでした: %2$s 圧縮ファイルを開けませんでした ウォレットが見つかりません - Amethyst は Nostr Wallet Connect(NWC)に対応したウォレットアプリを見つけられませんでした。 -\n\n対処方法: -\n\t1. NWC サポートを確認: お使いのウォレットアプリが Nostr Wallet Connect に対応しているか再確認してください。 -\n\t2. 接続を作成: ウォレットアプリで新しい NWC 接続を作成してください。 -\n\t3. Amethyst にリンク: ウォレットは通常、以下の3つの方法を提供します: -\n\t\t3.1 自動リンク: 自動的に Amethyst を開いて接続するボタン。その場合、ボタンをクリックして Amethyst を開き、新しい画面で保存を押してください。 -\n\t\t3.2 手動リンク: この画面の貼り付けアイコンをクリックして直接入力できる接続 URI。 -\n\t\t3.3 QR コード: ウォレットが作成する QR コード。この画面の QR コードボタンから読み取れます。 - + Amethyst は Nostr Wallet Connect(NWC)に対応したウォレットアプリを見つけられませんでした。 \n\n対処方法: \n\t1. NWC サポートを確認: お使いのウォレットアプリが Nostr Wallet Connect に対応しているか再確認してください。 \n\t2. 接続を作成: ウォレットアプリで新しい NWC 接続を作成してください。 \n\t3. Amethyst にリンク: ウォレットは通常、以下の3つの方法を提供します: \n\t\t3.1 自動リンク: 自動的に Amethyst を開いて接続するボタン。その場合、ボタンをクリックして Amethyst を開き、新しい画面で保存を押してください。 \n\t\t3.2 手動リンク: この画面の貼り付けアイコンをクリックして直接入力できる接続 URI。 \n\t\t3.3 QR コード: ウォレットが作成する QR コード。この画面の QR コードボタンから読み取れます。 作成 日 危険ゾーン @@ -2723,11 +2703,8 @@ Proxy Relay filter.nostr.wine のように、アプリがフィードをダウンロードするために使用するアグリゲーター relay です。これにより outbox モデルが置き換えられ、アプリはリスト内の relay のみに接続するようになります。 公開チャット - パブリックチャットは Nostr 上の全員に公開されており、誰でも - 参加できます。特定のトピックを中心としたオープンなコミュニティに最適です。 - モデレーションは、その relay 上のポストを削除することで管理できます - このグループをホストする relay を 1〜3 件入力してください。 - Nostr クライアントはこの設定を使用して、メッセージのダウンロード先と送信先を決定します。 + パブリックチャットは Nostr 上の全員に公開されており、誰でも 参加できます。特定のトピックを中心としたオープンなコミュニティに最適です。 モデレーションは、その relay 上のポストを削除することで管理できます + このグループをホストする relay を 1〜3 件入力してください。 Nostr クライアントはこの設定を使用して、メッセージのダウンロード先と送信先を決定します。 Relay パブリックチャットのメタデータ パブリックチャット @@ -2752,10 +2729,7 @@ 読み取り専用ユーザー 長押ししてメッセージを録音 relay チャット - relay チャットは、ホスト relay によって管理されるチャットグループです。 - Nostr 上の全員に公開されており、誰でも参加できます。 - 特定のトピックを中心としたオープンなコミュニティに最適です。一部のグループは一時的なもので、 - チャットメッセージは時間とともに消えます + relay チャットは、ホスト relay によって管理されるチャットグループです。 Nostr 上の全員に公開されており、誰でも参加できます。 特定のトピックを中心としたオープンなコミュニティに最適です。一部のグループは一時的なもので、 チャットメッセージは時間とともに消えます relay チャット イベント IP diff --git a/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml b/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml index 5ef5365607..4e876d3cf0 100644 --- a/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ko-rKR/strings.xml @@ -266,15 +266,8 @@ 알려진 항목 모두 읽음 표시 새 항목 모두 읽음 표시 모두 읽음 표시 - ## 키 백업 및 보안 팁 - \n\n계정은 비밀 키로 보호됩니다. 키는 **nsec1**로 시작하는 긴 문자열입니다. 이 비밀 키에 접근할 수 있는 누구든 게시물 작성 및 신원 변경이 가능합니다. - \n\n- 신뢰하지 않는 웹사이트나 소프트웨어에 비밀 키를 **입력하지** 마세요. - \n- Amethyst 개발자는 **절대** 비밀 키를 요청하지 않습니다. - \n- 계정 복구를 위해 비밀 키를 안전하게 백업해 **두세요**. 비밀번호 관리자 사용을 권장합니다. - - 추가 보안을 위해 비밀번호로 키를 암호화할 수 있습니다. 이 키는 **ncryptsec1**로 시작하며 비밀번호 없이는 사용할 수 없습니다. - \n\n비밀번호를 분실하면 키를 복구할 수 없습니다. - + ## 키 백업 및 보안 팁 \n\n계정은 비밀 키로 보호됩니다. 키는 **nsec1**로 시작하는 긴 문자열입니다. 이 비밀 키에 접근할 수 있는 누구든 게시물 작성 및 신원 변경이 가능합니다. \n\n- 신뢰하지 않는 웹사이트나 소프트웨어에 비밀 키를 **입력하지** 마세요. \n- Amethyst 개발자는 **절대** 비밀 키를 요청하지 않습니다. \n- 계정 복구를 위해 비밀 키를 안전하게 백업해 **두세요**. 비밀번호 관리자 사용을 권장합니다. + 추가 보안을 위해 비밀번호로 키를 암호화할 수 있습니다. 이 키는 **ncryptsec1**로 시작하며 비밀번호 없이는 사용할 수 없습니다. \n\n비밀번호를 분실하면 키를 복구할 수 없습니다. 내 비밀 키 암호화 및 복사 %1$s의 배지 수상 이미지 "배지 수상 이미지 @@ -958,9 +951,7 @@ 푸시 알림 비활성화 앱 %1$s 사용 푸시 알림 설정 - 푸시 알림을 받으려면 [Ntfy](https://ntfy.sh/)와 같은 [Unified Push](https://unifiedpush.org/)를 지원하는 앱을 설치하세요. - 설치 후 설정에서 사용할 앱을 선택하세요. - + 푸시 알림을 받으려면 [Ntfy](https://ntfy.sh/)와 같은 [Unified Push](https://unifiedpush.org/)를 지원하는 앱을 설치하세요. 설치 후 설정에서 사용할 앱을 선택하세요. 스레드 판매자에게 메시지 보내기 안녕하세요, 아직 구매 가능한가요? @@ -2005,15 +1996,7 @@ %1$s에서 인보이스를 가져올 수 없습니다: %2$s 압축 파일을 열 수 없습니다 지갑을 찾을 수 없음 - Amethyst에서 Nostr Wallet Connect (NWC)를 지원하는 지갑 앱을 찾을 수 없습니다. -\n\n할 수 있는 작업: -\n\t1. NWC 지원 확인: 사용하려는 지갑 앱이 Nostr Wallet Connect와 호환되는지 다시 확인하세요. -\n\t2. 연결 생성: 지갑 앱에서 새 NWC 연결을 생성하세요. -\n\t3. Amethyst에 연결: 지갑에서 보통 세 가지 옵션을 제공합니다: -\n\t\t3.1 자동 연결: Amethyst를 자동으로 열고 연결하는 버튼. 해당 버튼을 클릭하고 Amethyst를 열어 새 화면에서 저장을 누르세요. -\n\t\t3.2 수동 연결: 연결 URI를 복사하고 이 화면의 붙여넣기 아이콘을 클릭하여 직접 입력하세요. -\n\t\t3.3 QR 코드: 지갑이 QR 코드를 생성하면 이 화면의 QR 코드 버튼으로 읽을 수 있습니다. - + Amethyst에서 Nostr Wallet Connect (NWC)를 지원하는 지갑 앱을 찾을 수 없습니다. \n\n할 수 있는 작업: \n\t1. NWC 지원 확인: 사용하려는 지갑 앱이 Nostr Wallet Connect와 호환되는지 다시 확인하세요. \n\t2. 연결 생성: 지갑 앱에서 새 NWC 연결을 생성하세요. \n\t3. Amethyst에 연결: 지갑에서 보통 세 가지 옵션을 제공합니다: \n\t\t3.1 자동 연결: Amethyst를 자동으로 열고 연결하는 버튼. 해당 버튼을 클릭하고 Amethyst를 열어 새 화면에서 저장을 누르세요. \n\t\t3.2 수동 연결: 연결 URI를 복사하고 이 화면의 붙여넣기 아이콘을 클릭하여 직접 입력하세요. \n\t\t3.3 QR 코드: 지갑이 QR 코드를 생성하면 이 화면의 QR 코드 버튼으로 읽을 수 있습니다. 만들기 일 위험 구역 @@ -2653,11 +2636,8 @@ 프록시 Relay filter.nostr.wine 같이 피드를 다운로드하는 데 앱이 사용해야 하는 집계 relay입니다. 이 설정은 아웃박스 모델을 대체하며 앱이 목록에 있는 relay에만 연결하도록 합니다. 공개 채팅 - 공개 채팅은 Nostr의 모든 사람에게 공개되며 - 누구나 참여할 수 있습니다. 특정 주제에 관한 열린 커뮤니티에 적합합니다. - relay에서 게시물을 삭제하여 관리할 수 있습니다 - 이 그룹을 호스팅하는 relay를 1~3개 입력하세요. - Nostr 클라이언트는 이 설정을 통해 메시지를 다운로드하고 전송할 위치를 파악합니다. + 공개 채팅은 Nostr의 모든 사람에게 공개되며 누구나 참여할 수 있습니다. 특정 주제에 관한 열린 커뮤니티에 적합합니다. relay에서 게시물을 삭제하여 관리할 수 있습니다 + 이 그룹을 호스팅하는 relay를 1~3개 입력하세요. Nostr 클라이언트는 이 설정을 통해 메시지를 다운로드하고 전송할 위치를 파악합니다. relay 공개 채팅 메타데이터 공개 채팅 @@ -2682,10 +2662,7 @@ 읽기 전용 사용자 길게 눌러 메시지를 녹음하세요 relay 채팅 - relay 채팅은 홈 relay가 관리하는 채팅 그룹입니다. - Nostr의 모든 사람에게 공개되며 누구나 참여할 수 있습니다. - 특정 주제에 관한 열린 커뮤니티에 적합합니다. 일부 그룹은 임시적이라 - 채팅 메시지가 시간이 지나면 사라집니다 + relay 채팅은 홈 relay가 관리하는 채팅 그룹입니다. Nostr의 모든 사람에게 공개되며 누구나 참여할 수 있습니다. 특정 주제에 관한 열린 커뮤니티에 적합합니다. 일부 그룹은 임시적이라 채팅 메시지가 시간이 지나면 사라집니다 relay 채팅 이벤트 IP diff --git a/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml b/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml index 0ce2714a9a..2cb28ecf8f 100644 --- a/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-lv-rLV/strings.xml @@ -277,15 +277,8 @@ Atzīmēt visu zināmo kā lasītu Atzīmēt visu jauno kā lasītu Atzīmēt visu kā lasītu - ## Atslēgas dublēšanas un drošības padomi - \n\nJūsu konts ir aizsargāts ar slepeno atslēgu. Atslēga ir gara rakstzīmju secība, kas sākas ar **nsec1**. Ikviens, kam ir piekļuve šai slepenai atslēgai, var publicēt un mainīt jūsu identitāti. - \n\n- **Neievietojiet** savu slepeno atslēgu nevienā tīmekļa vietnē vai programmatūrā, kurai neuzticaties. - \n- Amethyst izstrādātāji **nekad** neprasīs jūsu slepeno atslēgu. - \n- **Glabājiet** drošu slepenas atslēgas dublējumu konta atjaunošanai. Mēs iesakām izmantot paroļu pārvaldnieku. - - Papildu drošībai variet šifrēt atslēgu ar paroli. Šī atslēga sāksies ar **ncryptsec1** virkni un to nevarēs izmantot bez šīs paroles. - \n\nJa jūs aizmirsīsiet paroli, vairs nevarēsiet atgūt savu atslēgu. - + ## Atslēgas dublēšanas un drošības padomi \n\nJūsu konts ir aizsargāts ar slepeno atslēgu. Atslēga ir gara rakstzīmju secība, kas sākas ar **nsec1**. Ikviens, kam ir piekļuve šai slepenai atslēgai, var publicēt un mainīt jūsu identitāti. \n\n- **Neievietojiet** savu slepeno atslēgu nevienā tīmekļa vietnē vai programmatūrā, kurai neuzticaties. \n- Amethyst izstrādātāji **nekad** neprasīs jūsu slepeno atslēgu. \n- **Glabājiet** drošu slepenas atslēgas dublējumu konta atjaunošanai. Mēs iesakām izmantot paroļu pārvaldnieku. + Papildu drošībai variet šifrēt atslēgu ar paroli. Šī atslēga sāksies ar **ncryptsec1** virkni un to nevarēs izmantot bez šīs paroles. \n\nJa jūs aizmirsīsiet paroli, vairs nevarēsiet atgūt savu atslēgu. Jūsu slepenā atslēga ir vienīgais veids, kā piekļūt šim kontam. Ja to pazaudēsiet, tad nekad nevarēsiet atgūt piekļuvi kontam. Saglabājiet atslēgu drošā vietā tagad. Esiet tās saglabājuši Šifrēt un kopēt manu slepeno atslēgu @@ -970,9 +963,7 @@ Atspējo push paziņojumus Izmanto lietotni %1$s Push paziņojumu iestatīšana - Lai saņemtu push paziņojumus, instalējiet jebkuru lietotni, kas atbalsta [Unified Push](https://unifiedpush.org/), piemēram, [Ntfy](https://ntfy.sh/). - Pēc instalēšanas iestatījumos atlasiet lietotni, kuru vēlaties izmantot. - + Lai saņemtu push paziņojumus, instalējiet jebkuru lietotni, kas atbalsta [Unified Push](https://unifiedpush.org/), piemēram, [Ntfy](https://ntfy.sh/). Pēc instalēšanas iestatījumos atlasiet lietotni, kuru vēlaties izmantot. Diskusija Nosūtīt pārdevējam ziņojumu Sveiki, vai tas joprojām ir pieejams? @@ -2037,15 +2028,7 @@ Nevarēja iegūt rēķinu no %1$s: %2$s Nevarēja atvērt saspiestu failu Maks nav atrasts - Amethyst nevarēja atrast nevienu maka lietotni, kas atbalsta Nostr Wallet Connect (NWC). -\n\nKo varat darīt: -\n\t1. Pārbaudiet NWC atbalstu: Pārliecinieties, vai jūsu vēlamā maka lietotne ir saderīga ar Nostr Wallet Connect. -\n\t2. Izveidojiet savienojumu: Atveriet savu maka lietotni un izveidojiet jaunu NWC savienojumu. -\n\t3. Saistiet ar Amethyst: Jūsu maks parasti piedāvās trīs iespējas: -\n\t\t3.1 Automātiska saistīšana: Poga, lai automātiski atvērtu un savienotu ar Amethyst. Ja tā, noklikšķiniet uz šīs pogas, atveriet Amethyst un nospiediet saglabāt jaunajā ekrānā. -\n\t\t3.2 Manuāla saistīšana: Savienojuma URI, ko varat kopēt un noklikšķināt uz ielīmēšanas ikonas šajā ekrānā, lai to ievadītu tieši. -\n\t\t3.3 QR kods: Maks izveido QR kodu, kuru varat nolasīt ar QR koda pogu šajā ekrānā. - + Amethyst nevarēja atrast nevienu maka lietotni, kas atbalsta Nostr Wallet Connect (NWC). \n\nKo varat darīt: \n\t1. Pārbaudiet NWC atbalstu: Pārliecinieties, vai jūsu vēlamā maka lietotne ir saderīga ar Nostr Wallet Connect. \n\t2. Izveidojiet savienojumu: Atveriet savu maka lietotni un izveidojiet jaunu NWC savienojumu. \n\t3. Saistiet ar Amethyst: Jūsu maks parasti piedāvās trīs iespējas: \n\t\t3.1 Automātiska saistīšana: Poga, lai automātiski atvērtu un savienotu ar Amethyst. Ja tā, noklikšķiniet uz šīs pogas, atveriet Amethyst un nospiediet saglabāt jaunajā ekrānā. \n\t\t3.2 Manuāla saistīšana: Savienojuma URI, ko varat kopēt un noklikšķināt uz ielīmēšanas ikonas šajā ekrānā, lai to ievadītu tieši. \n\t\t3.3 QR kods: Maks izveido QR kodu, kuru varat nolasīt ar QR koda pogu šajā ekrānā. Izveidot Bīstamā zona Tumšs @@ -2724,11 +2707,8 @@ Starpniekservera Relay Agregātori relay, ko lietotnei jāizmanto, lai lejupielādētu jūsu plūsmas, piemēram, filter.nostr.wine. Tas aizstāj izejošo ziņojumu modeli un liks lietotnei pieslēgties tikai jūsu sarakstos esošajiem relay. Publiskā tērzēšana - Publiskās tērzēšanas ir redzamas visiem Nostr lietotājiem un ikviens - var tajās piedalīties. Tās ir lieliski piemērotas atvērtām kopienām par konkrētām tēmām. - Moderēšanu var kontrolēt, dzēšot ierakstus tās relay - Ievadiet no 1 līdz 3 relay, kas mitina šo grupu. - Nostr klienti izmanto šo iestatījumu, lai zinātu, no kurienes lejupielādēt ziņojumus un kur nosūtīt jūsu ziņojumus. + Publiskās tērzēšanas ir redzamas visiem Nostr lietotājiem un ikviens var tajās piedalīties. Tās ir lieliski piemērotas atvērtām kopienām par konkrētām tēmām. Moderēšanu var kontrolēt, dzēšot ierakstus tās relay + Ievadiet no 1 līdz 3 relay, kas mitina šo grupu. Nostr klienti izmanto šo iestatījumu, lai zinātu, no kurienes lejupielādēt ziņojumus un kur nosūtīt jūsu ziņojumus. Relay Publiskās tērzēšanas metadati Publiskie čati @@ -2753,10 +2733,7 @@ Tikai lasāms lietotājs Noklikšķiniet un turiet, lai ierakstītu ziņojumu Relay tērzēšana - Relay tērzēšanas ir tērzēšanas grupas, kuras kontrolē to mājas relay. - Tās ir redzamas visiem Nostr lietotājiem un ikviens var tajās piedalīties. - Tās ir lieliski piemērotas atvērtām kopienām par konkrētām tēmām. Dažas no šīm grupām ir īslaicīgas - un tāpēc tērzēšanas ziņojumi laika gaitā pazūd + Relay tērzēšanas ir tērzēšanas grupas, kuras kontrolē to mājas relay. Tās ir redzamas visiem Nostr lietotājiem un ikviens var tajās piedalīties. Tās ir lieliski piemērotas atvērtām kopienām par konkrētām tēmām. Dažas no šīm grupām ir īslaicīgas un tāpēc tērzēšanas ziņojumi laika gaitā pazūd Relay tērzēšanas Notikumi IP adreses diff --git a/commonsUI/src/commonMain/composeResources/values-nl/strings.xml b/commonsUI/src/commonMain/composeResources/values-nl/strings.xml index 70ca1190a6..5ddca3ba0e 100644 --- a/commonsUI/src/commonMain/composeResources/values-nl/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-nl/strings.xml @@ -211,7 +211,7 @@ Kopieer gebruiker ID Deblokkeer gebruiker Deze gebruiker is geblokkeerd/gedempt. Hun berichten zijn verborgen. - npub, hex, gebruikersnaam + npub, hex, gebruikersnaam Wissen App logo nsec.. of npub.. @@ -259,15 +259,8 @@ Bekende markeren als gelezen Nieuwe markeren als gelezen Alles markeren als gelezen - ## Sleutel back-up en veiligheidstips - \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. - \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. - \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. - \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. - - Voor meer veiligheid kan je je sleutel versleutelen met een wachtwoord. Deze sleutel begint met **ncryptsec1** en kan niet worden gebruikt zonder uw wachtwoord. - \n\nAls je je wachtwoord verliest, je kan je sleutel niet herstellen. - + ## Sleutel back-up en veiligheidstips \n\nUw account is beveiligd met een privésleutel. De sleutel is een lange, willekeurige reeks die begint met **nsec1**. Iedereen die toegang heeft tot uw privésleutel kan inhoud publiceren met uw identiteit. \n\n- Voer uw privésleutel **nooit** in een website of software die u niet vertrouwt. \n- Amethyst ontwikkelaars zullen u **nooit** om uw privésleutel vragen. \n- **Bewaar** een veilige back-up van uw privésleutel voor accountherstel. Wij raden u aan een wachtwoordmanager te gebruiken. + Voor meer veiligheid kan je je sleutel versleutelen met een wachtwoord. Deze sleutel begint met **ncryptsec1** en kan niet worden gebruikt zonder uw wachtwoord. \n\nAls je je wachtwoord verliest, je kan je sleutel niet herstellen. Versleutel en kopieer mijn geheime sleutel Badge award afbeelding voor %1$s Badge-awardafbeelding @@ -960,9 +953,7 @@ Push-notificaties uitschakelen Gebruikt app %1$s Instellen Push-notificaties - Om push-notificaties te ontvangen, installeer een app die [Unified Push] ondersteunt](https://unifiedpush.org/), zoals [Ntfy](https://ntfy.sh/). - Na installatie selecteer de app die je wilt gebruiken in de instellingen. - + Om push-notificaties te ontvangen, installeer een app die [Unified Push] ondersteunt](https://unifiedpush.org/), zoals [Ntfy](https://ntfy.sh/). Na installatie selecteer de app die je wilt gebruiken in de instellingen. Draad Stuur de verkoper een bericht Hallo daar, is dit nog steeds beschikbaar? diff --git a/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml b/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml index 55a0998df3..570f8fc2b1 100644 --- a/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pl-rPL/strings.xml @@ -508,8 +508,7 @@ Informacja o grupie… Szukaj i dodaj użytkownika Dodaj Transmiter - Nieprawidłowy adres transmitera. Użyj nazwy hosta lub adresu IP w nawiasach (na przykład -[201:d0e:9ba5:8bbc::1]:8080). + Nieprawidłowy adres transmitera. Użyj nazwy hosta lub adresu IP w nawiasach (na przykład [201:d0e:9ba5:8bbc::1]:8080). Moje imię @tag Nazwa użytkownika Mój nick @@ -657,15 +656,8 @@ Zaznacz wszystkie popularne jako przeczytane Zaznacz wszystkie nowe jako przeczytane Zaznacz wszystkie jako przeczytane - ## Porady dotyczące kopii zapasowej i bezpieczeństwa - \n\nTwoje konto jest zabezpieczone tajnym kluczem. Kluczem jest długa sekwencja znaków, zaczynająca się od **nsec1**. Każdy, kto ma dostęp do tego tajnego klucza może publikować i zmieniać Twoją tożsamość. - \n\n- **nie** umiejszczaj swojego tajnego klucza na żadnej stronie internetowej lub oprogramowaniu, któremu nie ufasz. - \n- Deweloperzy Ametyst **nigdy** nie będą prosić o Twój tajny klucz. - \n- **Zrób ** bezpieczną kopię zapasową swojego tajnego klucza do ewentualnego odzyskania konta. Zalecamy użycie menedżera haseł. - - Dla dodatkowego bezpieczeństwa możesz zaszyfrować swój klucz hasłem. Ten klucz zaczyna się od **ncryptsec1** i nie może być użyty bez hasła. - \n\nJeśli zgubisz hasło, nie będziesz w stanie odzyskać swojego klucza. - + ## Porady dotyczące kopii zapasowej i bezpieczeństwa \n\nTwoje konto jest zabezpieczone tajnym kluczem. Kluczem jest długa sekwencja znaków, zaczynająca się od **nsec1**. Każdy, kto ma dostęp do tego tajnego klucza może publikować i zmieniać Twoją tożsamość. \n\n- **nie** umiejszczaj swojego tajnego klucza na żadnej stronie internetowej lub oprogramowaniu, któremu nie ufasz. \n- Deweloperzy Ametyst **nigdy** nie będą prosić o Twój tajny klucz. \n- **Zrób ** bezpieczną kopię zapasową swojego tajnego klucza do ewentualnego odzyskania konta. Zalecamy użycie menedżera haseł. + Dla dodatkowego bezpieczeństwa możesz zaszyfrować swój klucz hasłem. Ten klucz zaczyna się od **ncryptsec1** i nie może być użyty bez hasła. \n\nJeśli zgubisz hasło, nie będziesz w stanie odzyskać swojego klucza. Kopia zapasowa kluczy Twój tajny klucz jest jedynym sposobem na dostęp do tego konta. Jeśli go zgubisz, nigdy nie będzie można go odzyskać. Zapisz go w bezpiecznym miejscu. Utwórz kopię zapasową @@ -1849,9 +1841,7 @@ Wyłącz powiadomienia Używa aplikacji %1$s Ustawienia powiadomień - Aby otrzymywać powiadomienia, zainstaluj dowolną aplikację, która obsługuje [Unified Push](https://unifiedpush. rg/), np. [Ntfy](https://ntfy.sh/). - Po zainstalowaniu, wybierz w ustawieniach aplikację, którą chcesz użyć. - + Aby otrzymywać powiadomienia, zainstaluj dowolną aplikację, która obsługuje [Unified Push](https://unifiedpush. rg/), np. [Ntfy](https://ntfy.sh/). Po zainstalowaniu, wybierz w ustawieniach aplikację, którą chcesz użyć. Wątek Wyślij sprzedawcy wiadomość Cześć, czy to jest nadal dostępne? @@ -3656,15 +3646,7 @@ Nie można pobrać faktury od %1$s: %2$s Nie można otworzyć skompresowanego pliku Nie znaleziono portfela - Amethyst nie znalazł żadnej aplikacji portfela obsługującej Nostr Wallet Connect (NWC). -\n\nCo możesz zrobić: -\n\t1. Zweryfikuj wsparcie NWC: Sprawdź, czy preferowana aplikacja portfela jest kompatybilna z Nostr Wallet Connect. -\n\t2. Utwórz połączenie: Przejdź do aplikacji portfela i utwórz nowe połączenie NWC. -\n\t3. Połącz z Amethyst: Twój portfel zazwyczaj oferuje trzy opcje: -\n\t\t3. Automatyczne połączenie: przycisk, który automatycznie otwiera i łączy się z Amethyst. Jeśli tak, kliknij ten przycisk, otwórz Ametyst i naciśnij przycisk "Zapisz" na nowym ekranie. -\n\t\t3. Połączenie ręczne: adres URI połączenia, który można skopiować i wkleić, klikając ikonę wklejania na tym ekranie, aby wprowadzić go bezpośrednio. -\n\t\t3. Kod QR: Portfel tworzy kod QR, który można odczytać z przycisku QR na tym ekranie. - + Amethyst nie znalazł żadnej aplikacji portfela obsługującej Nostr Wallet Connect (NWC). \n\nCo możesz zrobić: \n\t1. Zweryfikuj wsparcie NWC: Sprawdź, czy preferowana aplikacja portfela jest kompatybilna z Nostr Wallet Connect. \n\t2. Utwórz połączenie: Przejdź do aplikacji portfela i utwórz nowe połączenie NWC. \n\t3. Połącz z Amethyst: Twój portfel zazwyczaj oferuje trzy opcje: \n\t\t3. Automatyczne połączenie: przycisk, który automatycznie otwiera i łączy się z Amethyst. Jeśli tak, kliknij ten przycisk, otwórz Ametyst i naciśnij przycisk "Zapisz" na nowym ekranie. \n\t\t3. Połączenie ręczne: adres URI połączenia, który można skopiować i wkleić, klikając ikonę wklejania na tym ekranie, aby wprowadzić go bezpośrednio. \n\t\t3. Kod QR: Portfel tworzy kod QR, który można odczytać z przycisku QR na tym ekranie. Utwórz d Niebezpieczna strefa @@ -4966,10 +4948,7 @@ auth uwierzytelnianie transmiter podpis weryfikacja nip-42 tożsamość Uwierzytelnianie transmitera Czat Transmitera - Czaty transmiterów to grupy czatów kontrolowane przez ich macierzyste transmitery. - Są one widoczne dla wszystkich użytkowników Nostr i każdy może w nich uczestniczyć. - Świetnie nadają się do tworzenia otwartych społeczności wokół określonych tematów. Niektóre z tych grup są efemeryczne - i dlatego wiadomości czatu znikają z czasem + Czaty transmiterów to grupy czatów kontrolowane przez ich macierzyste transmitery. Są one widoczne dla wszystkich użytkowników Nostr i każdy może w nich uczestniczyć. Świetnie nadają się do tworzenia otwartych społeczności wokół określonych tematów. Niektóre z tych grup są efemeryczne i dlatego wiadomości czatu znikają z czasem Czaty Transmitera Twój profil, ustawienia i wersje robocze na Twoich domowych transmiterach. Transmitery, na których każda społeczność publikuje swoje plany. @@ -5178,8 +5157,7 @@ Podcasty Zaplanuj post Anuluj planowanie - Wpisy zaplanowane mogą nie zostać opublikowane, dopóki nie uruchomisz ponownie aplikacji. -Zaplanowane posty z innych kont nie zostaną opublikowane, dopóki to konto jest aktywne. Włącz opcję „Zawsze włączone” w menu Ustawienia → Preferencje interfejsu użytkownika, aby zapewnić niezawodne planowanie zadań w tle. + Wpisy zaplanowane mogą nie zostać opublikowane, dopóki nie uruchomisz ponownie aplikacji. Zaplanowane posty z innych kont nie zostaną opublikowane, dopóki to konto jest aktywne. Włącz opcję „Zawsze włączone” w menu Ustawienia → Preferencje interfejsu użytkownika, aby zapewnić niezawodne planowanie zadań w tle. Zaplanowane posty mogą nie zostać opublikowane, dopóki nie uruchomisz ponownie aplikacji. Aby zapewnić niezawodne planowanie zadań w tle, włącz opcję „Zawsze włączone” w Ustawieniach → Preferencje dotyczące niezawodnego planowania zadań w tle. Zaplanowane posty Wyślij teraz @@ -5507,4 +5485,382 @@ Zaplanowane posty z innych kont nie zostaną opublikowane, dopóki to konto jest Brak podpisu, więc autor to tylko domysł Element typu %1$d, którego ten klient nie wyświetla %1$d bajtów danych, których ten klient nie odczytuje + Zablokuj %1$s ponownie + Zachowaj %1$s + Ponów %1$s + Ponownie wycisz %1$s + Przywróć %1$s + Przywróć kanały + Przywróć miejsca + Przywróć profil + Przywróć dostawców + Przywróć transmitery + Przywróć tematy + Przywróć portfel + Zaakceptuj + + %1$s i dodano %2$d + %1$s i dodano %2$d + %1$s i dodano %2$d + %1$s i dodano %2$d + + + %1$s i zablokowano %2$d + %1$s i zablokowano %2$d + %1$s i zablokowano %2$d + %1$s i zablokowano %2$d + + + %1$s i obserwowany %2$d + %1$s i obserwowanych %2$d + %1$s i obserwowanych %2$d + %1$s i obserwowane %2$d + + + %1$s i dołączono do %2$d + %1$s i dołączono do %2$d + %1$s i dołączono do %2$d + %1$s i dołączono do %2$d + + + %1$s i wyciszony %2$d + %1$s i wyciszono %2$d + %1$s i wyciszono %2$d + %1$s i wyciszone %2$d + + Twoje zsynchronizowane ustawienia aplikacji Amethyst zostały zmienione w innej aplikacji, która nie jest Amethystem. To może powodować problemy. + Opróżniłeś swoją listę Concorda + Zmieniłeś swoją listę Concorda + + Usunąłeś %1$d transmiter DM + Usunąłeś %1$d transmiterów DM + Usunąłeś %1$d transmiterów DM + Usunąłeś %1$d transmitery DM + + + Usunąłeś %1$d ulubiony kanał + Usunąłeś %1$d ulubionych kanałów + Usunąłeś %1$d ulubionych kanałów + Usunięto %1$d ulubione kanały + + + Przestałeś obserwować %1$d osobę + Przestałeś obserwować %1$d osób + Przestałeś obserwować %1$d osób + Przestałeś obserwować %1$d osoby + + + Przestałeś obserwować %1$d hashtag + Przestałeś obserwować %1$d hashtagów + Przestałeś obserwować %1$d hashtagów + Przestałeś obserwować %1$d hashtagi + + + Usunięto %1$d transmiter indeksujący + Usunięto %1$d transmiterów indeksujących + Usunięto %1$d transmiterów indeksujących + Usunięto %1$d transmitery indeksujące + + + Usunięto %1$d transmiter klucza grupowego czatu + Usunięto %1$d transmiterów klucza grupowego czatu + Usunięto %1$d transmiterów klucza grupowego czatu + Usunięto %1$d transmitery klucza grupowego czatu + + + Opuściłeś %1$d czat publiczny + Opuściłeś %1$d czatów publicznych + Opuściłeś %1$d czatów publicznych + Opuściłeś %1$d czaty publiczne + + + Opuściłeś %1$d społeczność + Opuściłeś %1$d społeczności + Opuściłeś %1$d społeczności + Opuściłeś %1$d społeczności + + + Opuściłeś %1$d grupę + Opuściłeś %1$d grup + Opuściłeś %1$d grup + Opuszczono %1$d grupy + + + Opuściłeś %1$d pokój czatu + Opuściłeś %1$d pokoi czatu + Opuściłeś %1$d pokoi czatu + Opuściłeś %1$d pokoje czatu + + + Włączyłeś dźwięk dla %1$d elementu + Włączyłeś dźwięk dla %1$d elementów + Włączyłeś dźwięk dla %1$d elementów + %1$d elementy mają włączony dźwięk + + + Usunąłeś %1$d publiczny transmiter + Usunąłeś %1$d publicznych transmiterów + Usunąłeś %1$d publicznych transmiterów + Usunąłeś %1$d publiczne transmitery + + Usunąłeś swój klucz nutzap + Wymieniłeś swój klucz Nutzap + + Usunięto %1$d nutzap mint + Usunięto %1$d nutzap mintów + Usunięto %1$d nutzap mintów + Usunięto %1$d nutzap minty + + + Usunięto %1$d ofertę BOLT12 + Usunięto %1$d ofert BOLT12 + Usunięto %1$d ofert BOLT12 + Usunięto %1$d oferty BOLT12 + + + Usunięto %1$d sposób na otrzymanie zapłaty + Usunięto %1$d sposobów otrzymywania zapłaty + Usunięto %1$d sposobów otrzymywania zapłaty + Usunięto %1$d sposoby otrzymywania zapłaty + + + Przestałeś obserwować %1$d miejsce + Przestałeś obserwować %1$d miejsc + Przestałeś obserwować %1$d miejsc + Przestałeś obserwować %1$d miejsca + + + Usunięto %1$d prywatny transmiter + Usunięto %1$d prywatnych transmiterów + Usunięto %1$d prywatnych transmiterów + Usunięto %1$d prywatne transmitery + + + Usunąłeś %1$d pole profilu + Usunąłeś %1$d pól profilowych + Usunąłeś %1$d pól profilowych + Usunąłeś %1$d pola profilowe + + + Usunięto %1$d kanał transmitera + Usunięto %1$d kanałów transmitera + Usunięto %1$d kanałów transmitera + Usunięto %1$d kanały transmitera + + + Usunięto %1$d transmiter wyszukiwania + Usunięto %1$d transmiterów wyszukiwania + Usunięto %1$d transmiterów wyszukiwania + Usunięto %1$d transmitery wyszukiwania + + + Zmieniłeś dostawcę %1$d zaufanego serwisu + Zmieniłeś dostawcę %1$d zaufanych serwisów + Zmieniłeś dostawcę %1$d zaufanych serwisów + Zmieniłeś dostawcę %1$d zaufanych serwisów + + + Przestałeś ufać %1$d transmiterowi + Przestałeś ufać %1$d transmiterom + Przestałeś ufać %1$d transmiterom + Przestałeś ufać %1$d transmiterom + + + Odblokowałeś %1$d transmiter + Odblokowałeś %1$d transmiterów + Odblokowałeś %1$d transmiterów + Odblokowałeś %1$d transmitery + + Opróżniłeś swój portfel Cashu + Zmieniłeś swój portfel Cashu + Dodano (%1$s) + Zmieniono (%1$s) + Dodano %1$s + %1$s zmieniono + Usunięto %1$s + Użyj nowej wersji + Dodano prywatne (zaszyfrowane) pozycje. + Zmieniłeś również elementy prywatne (zaszyfrowane). Nie można ich tutaj porównać. + Usunąłeś wszystkie prywatne (zaszyfrowane) elementy. + tylko do odczytu + odczyt i zapis + tylko do zapisu + Usunięto (%1$s) + Przywróć zapisaną wersję + Zmieniłeś %1$s w innej aplikacji + Kanały + Czat pokoje + Społeczności + Hashtagi + Powiązane tożsamości + Lokalizacje + Minty + Klucze Nutzap + Oferty + Inne wpisy + Adresy płatności + Osoby + Pola profilu + Czaty publiczne + Transmitery + Grupy + Wątki + Zaufani dostawcy + Słowa + O profilu + Baner + Data urodzin + Flaga bota + Oferta CLINK + Nazwa wyświetlana + LNURL + Lightning Adres + Nazwa użytkownika + Adres Nostr + Zdjęcie + Zaimki + Strona www + Dozwolona + Zmieniono w innej aplikacji · %1$s + Twoje społeczności w Concord są dla Ciebie zaszyfrowane, więc nie można ich tutaj porównać. Przywrócenie danych powoduje przywrócenie dokładnie tego, co zostało zapisane na tym urządzeniu. + Przeniesiona + %1$s odrzuconych + Usunięta + Utworzyłeś to + Zmieniłeś to + Opróżniłeś to + Kanał + Zniknęła + Hashtagi, które obserwujesz + Skrzynka odbiorcza + gdzie inni docierają do Ciebie + dołączył(a) + zachowane + Zachowano %1$s + Usunięto klucz odbierający + Wymieniono klucz odbierający + Nutzapy zostaną przypisane do tego nowego klucza. Jeśli urządzenie nie posiada tego klucza, może się okazać, że nie będzie można ich tutaj zrealizować. + zostało + Zostało + Na Liście + Przeniesiona + %1$s i %2$s więcej + Nowa wersja + %1$s nowych + nowe + Nowa + Nowo zablokowana + %1$s nowo wyciszonych + Nie jest już zablokowana + Nie ustawiono + Nic tu nie ma! + Oferta BOLT12 + + %1$d oferta usunięta + %1$d ofert usunięto + %1$d ofert usunięto + %1$d oferty usunięte + + Skrzynka nadawcza + gdzie publikujesz + + %1$d sposób płatności został usunięty + %1$d sposobów płatności zostało usuniętych + %1$d sposobów płatności zostało usuniętych + %1$d sposoby płatności zostały usunięte + + Osoby, które Ci płacą, widzą tylko to, co znajduje się na tej liście. + miejsca zniknęły + Miejsca które obserwujesz + Są teraz zaszyfrowane, co prawdopodobnie wyjaśnia, gdzie podziały się powyższe elementy publiczne. + Ustawiłeś te pozycje jako prywatne + Są zaszyfrowane, więc nie można ich tu porównać. + Zmieniłeś prywatne elementy + Są zaszyfrowane, więc tylko Ty możesz zobaczyć, co to było. Odtworzenie przywróci je wszystkie. + Usunąłeś wszystkie prywatne elementy + Pobieranie + zmieniono nazwę + Zmieniono nazwę + Na tym urządzeniu + Szukaj %1$s osób + Szukam + Serwis + Obserwujący + Ranking + Tematy + Zmieniono %1$s z %2$s serwisów + Teraz pochodzą od kogoś innego albo od nikogo + Nadal zablokowana + Przechowywanie + Usunięte · %1$s + Edytowane · %1$s + Nowe · %1$s + %1$s wyczyszczono + %1$s zaktualizowano + tematy zniknęły + Rankingi, liczba obserwujących i filtrowanie spamu, które widzisz, pochodzą od tych dostawców. + Zaufane + %1$s odblokowane + Ametyst ponownie połączy się z nimi + Jednostek + %1$s odblokowanych + Mogą one ponownie pojawić się w Twoich informacjach + Niezaufane + Minty i klucze w Twoim portfelu są zaszyfrowane dla Ciebie, więc nie można ich tutaj porównać pozycja po pozycji. Przywrócenie danych powoduje przywrócenie dokładnie tego, co zostało zapisane na tym urządzeniu. + było „%1$s” + Wyrazy & hasztagi + zsynchronizowane ustawienia aplikacji + Ustawienia Amethyst są synchronizowane na wszystkich Twoich urządzeniach. Są one zaszyfrowane, więc można porównać jedynie sam fakt ich obecności. + lista zablokowanych przekaźników + Transmitery, z którymi ta aplikacja nigdy się nie łączy. + Oferta BOLT12 + Ta możliwość pozwala innym płacić Ci za pomocą Lightning. + Portfel Cashu + Ustawienia portfela ecash oraz minty. Są one zaszyfrowane, więc można porównać jedynie sam fakt ich istnienia. + lista społeczności + Społeczności, do których dołączyłeś. + Lista społeczności Concord + Społeczności Concord, do których dołączyłeś. Są one zaszyfrowane, więc można porównać jedynie fakt ich istnienia. + Lista transmiterów DM + Gdzie inni dostarczają Twoje prywatne wiadomości. + lista czatów efemerycznych + Tymczasowe czaty, do których dołączyłeś. + lista ulubionych kanałów + Zapisane przez Ciebie kanały algorytmiczne. + lista obserwowanych + Określa, czyje posty pojawiają się w Twoim kanale głównym. + obserwowane lokalizacje + Miejsca, z których posty pojawiają się na Twoich kanałach. + obserwowane hashtagi + Hashtagi, z których pochodzą posty wyświetlane w Twoich kanałach. + lista transmiterów indeksujących + Transmitery służące do wyszukiwania profili innych osób oraz list transmiterów. + transmitery kluczy czatu grupowego + Gdzie inni znajdą klucze do dodawania cię do zaszyfrowanych czatów grupowych. + lista zablokowanych + Ukrywa osoby, słowa, hashtagi i wątki we wszystkich wyświetlanych treściach. + ustawienia odbioru nutzap + Minty i klucz, które inni używają do wysyłania ci „nutzapów”. + lista + Lista zapisana na tym urządzeniu. + lista publicznych transmiterów + Informuje wszystkich, gdzie mogą znaleźć Twoje posty oraz gdzie mają wysyłać Ci odpowiedzi i wzmianki. + adresy płatności + Sposoby, w jakie inni mogą Ci zapłacić. + lista prywatnych transmiterów + Gdzie przechowywane są Twoje projekty i prywatne dane. + profil + Twoje imię i nazwisko, zdjęcie, biografia oraz adresy do płatności – tak, jak widzą je wszyscy. + lista czatów publicznych + Publiczne czaty, do których dołączyłeś. + ulubione kanały transmitera + Transmitery, które przeglądasz jako kanały informacyjne. + lista grup + Grupy oparte na transmiterach, do których dołączyłeś. + lista transmiterów wyszukiwania + Transmitery używane podczas wyszukiwania. + lista zaufanych dostawców + Serwisy, którym ufasz, a które zajmują się klasyfikowaniem i weryfikacją osób w Twoim imieniu. + lista zaufanych transmiterów + Zaufane transmitery, z którymi bez wahania nawiązujesz połączenie. diff --git a/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml b/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml index 19715d92c0..1a156efffd 100644 --- a/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pt-rBR/strings.xml @@ -361,7 +361,7 @@ Copiar ID do usuário Desbloquear Usuário Este usuário está bloqueado/silenciado. Suas publicações estão ocultas. - npub, hex, usuário + npub, hex, usuário Limpar Logo do aplicativo nsec / npub / hex chave privada @@ -449,8 +449,8 @@ Retransmissor pago Forçar uso do Tor ao conectar postagens recebidas - Autotraduzido - de + Autotraduzido + de para Mostrar em %1$s primeiro Chat público sobre %1$s @@ -463,13 +463,8 @@ Marcar todos conhecidos como lidos Marcar todas novas solicitações como lidas Marcar todas como lidas - ## Dicas de Backup de Chave e Segurança - \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. - \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. - \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. - \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. - Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. - \n\nSe você perder sua senha, não será possível recuperar sua chave. + ## Dicas de Backup de Chave e Segurança \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. + Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. \n\nSe você perder sua senha, não será possível recuperar sua chave. Faça backup das suas chaves Sua chave secreta é a única forma de acessar esta conta. Se você perdê-la, ela nunca poderá ser recuperada. Guarde-a em um lugar seguro agora. Fazer backup agora @@ -1584,9 +1579,7 @@ Desativa as Notificações Push Usa o aplicativo %1$s Configuração de Notificações Push - Para receber notificações push, instale qualquer aplicativo que suporte [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Após a instalação, selecione o aplicativo que deseja usar nas configurações. - + Para receber notificações push, instale qualquer aplicativo que suporte [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Após a instalação, selecione o aplicativo que deseja usar nas configurações. Linha Envie uma mensagem para o vendedor Olá, ainda está disponível? @@ -3323,14 +3316,7 @@ Não foi possível obter a fatura de %1$s: %2$s Não foi possível abrir o arquivo compactado Carteira não encontrada - O Amethyst não conseguiu encontrar nenhum aplicativo de carteira que suporte Nostr Wallet Connect (NWC). -\n\nO que você pode fazer: -\n\t1. Verifique o suporte NWC: Confirme se o aplicativo da sua carteira é compatível com o Nostr Wallet Connect. -\n\t2. Criar conexão: Vá até o aplicativo da sua carteira e crie uma nova conexão NWC. -\n\t3. Vincular ao Amethyst: Sua carteira geralmente oferece três opções: -\n\t\t3.1 Link Automático: Um botão para abrir e conectar automaticamente ao Amethyst. Clique nele, abra o Amethyst e salve na nova tela. -\n\t\t3.2 Link Manual: Um URI de conexão que você pode copiar e colar usando o ícone de colar nesta tela. -\n\t\t3.3 Código QR: A carteira gera um código QR que você pode ler usando o botão de código QR nesta tela. + O Amethyst não conseguiu encontrar nenhum aplicativo de carteira que suporte Nostr Wallet Connect (NWC). \n\nO que você pode fazer: \n\t1. Verifique o suporte NWC: Confirme se o aplicativo da sua carteira é compatível com o Nostr Wallet Connect. \n\t2. Criar conexão: Vá até o aplicativo da sua carteira e crie uma nova conexão NWC. \n\t3. Vincular ao Amethyst: Sua carteira geralmente oferece três opções: \n\t\t3.1 Link Automático: Um botão para abrir e conectar automaticamente ao Amethyst. Clique nele, abra o Amethyst e salve na nova tela. \n\t\t3.2 Link Manual: Um URI de conexão que você pode copiar e colar usando o ícone de colar nesta tela. \n\t\t3.3 Código QR: A carteira gera um código QR que você pode ler usando o botão de código QR nesta tela. Criar d Zona de Perigo @@ -4427,11 +4413,8 @@ Relays proxy Relays agregadores que o app usa para baixar seus feeds, como filter.nostr.wine. Isso substitui o modelo outbox e faz o app se conectar apenas aos relays das suas listas. Chat público - Os chats públicos são visíveis para todos no Nostr, e qualquer pessoa - pode participar deles. Eles são ótimos para comunidades abertas em torno de tópicos específicos. - A moderação pode ser controlada excluindo postagens em seus relays - Inserir entre 1–3 relés que hospedam esse grupo. - os clientes Nostr usam essa configuração para saber de onde fazer o download de mensagens e enviar suas mensagens. + Os chats públicos são visíveis para todos no Nostr, e qualquer pessoa pode participar deles. Eles são ótimos para comunidades abertas em torno de tópicos específicos. A moderação pode ser controlada excluindo postagens em seus relays + Inserir entre 1–3 relés que hospedam esse grupo. os clientes Nostr usam essa configuração para saber de onde fazer o download de mensagens e enviar suas mensagens. Relés Metadados do Chat Público Chats públicos @@ -4496,10 +4479,7 @@ auth autenticação relay assinar verificar nip-42 identidade Autenticação de relay Chat Relé - Chat Relés são grupos de chat controlados por seu relé de origem. - Eles são visíveis para todos no Nostr e qualquer pessoa pode participar. - São ótimos para comunidades abertas em torno de tópicos específicos. Alguns desses grupos são efêmeros, - portanto, as mensagens desaparecem com o tempo + Chat Relés são grupos de chat controlados por seu relé de origem. Eles são visíveis para todos no Nostr e qualquer pessoa pode participar. São ótimos para comunidades abertas em torno de tópicos específicos. Alguns desses grupos são efêmeros, portanto, as mensagens desaparecem com o tempo Chat Relés Seu próprio perfil, configurações e rascunhos, nos seus relays de origem. Os relays em que cada comunidade publica seus planos. diff --git a/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml b/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml index b1953ebdcd..d722a0814b 100644 --- a/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-pt-rPT/strings.xml @@ -223,7 +223,7 @@ Copiar ID do usuário Desbloquear Usuário Este usuário está bloqueado/silenciado. Suas publicações estão ocultas. - npub, hex, usuário + npub, hex, usuário Limpar Logo do aplicativo nsec / npub / hex chave privada @@ -257,8 +257,8 @@ Retransmissor pago Forçar uso do Tor ao conectar postagens recebidas - Autotraduzido - de + Autotraduzido + de para Mostrar em %1$s primeiro Chat público sobre %1$s @@ -271,13 +271,8 @@ Marcar todos conhecidos como lidos Marcar todas novas solicitações como lidas Marcar todas como lidas - ## Dicas de Backup de Chave e Segurança - \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. - \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. - \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. - \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. - Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. - \n\nSe você perder sua senha, não será possível recuperar sua chave. + ## Dicas de Backup de Chave e Segurança \n\nSua conta é protegida por uma chave secreta. A chave é uma sequência longa de caracteres que começa com **nsec1**. Qualquer pessoa que tenha acesso a esta chave secreta pode postar e alterar sua identidade. \n\n- **Não** coloque sua chave secreta em nenhum site ou software que você não confie. \n- Os desenvolvedores da Amethyst **nunca** pedirão sua chave secreta. \n- **Mantenha** uma cópia de segurança segura de sua chave secreta para recuperação da conta. Recomendamos o uso de um gerenciador de senhas. + Para segurança adicional, você pode criptografar sua chave com uma senha. Esta chave começa com **ncryptsec1** e não pode ser usada sem sua senha. \n\nSe você perder sua senha, não será possível recuperar sua chave. Criptografar e copiar minha chave secreta Imagem da medalha para %1$s Imagem do prêmio @@ -958,9 +953,7 @@ Desativa as Notificações Push Usa o aplicativo %1$s Configuração de Notificações Push - Para receber notificações push, instale qualquer aplicativo que suporte [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). - Após a instalação, selecione o aplicativo que deseja usar nas configurações. - + Para receber notificações push, instale qualquer aplicativo que suporte [Unified Push](https://unifiedpush.org/), como [Ntfy](https://ntfy.sh/). Após a instalação, selecione o aplicativo que deseja usar nas configurações. Linha Envie uma mensagem para o vendedor Olá, ainda está disponível? @@ -2003,14 +1996,7 @@ Não foi possível obter a fatura de %1$s: %2$s Não foi possível abrir o arquivo compactado Carteira não encontrada - O Amethyst não conseguiu encontrar nenhum aplicativo de carteira que suporte Nostr Wallet Connect (NWC). -\n\nO que você pode fazer: -\n\t1. Verifique o suporte NWC: Confirme se o aplicativo da sua carteira é compatível com o Nostr Wallet Connect. -\n\t2. Criar conexão: Vá até o aplicativo da sua carteira e crie uma nova conexão NWC. -\n\t3. Vincular ao Amethyst: Sua carteira geralmente oferece três opções: -\n\t\t3.1 Link Automático: Um botão para abrir e conectar automaticamente ao Amethyst. Clique nele, abra o Amethyst e salve na nova tela. -\n\t\t3.2 Link Manual: Um URI de conexão que você pode copiar e colar usando o ícone de colar nesta tela. -\n\t\t3.3 Código QR: A carteira gera um código QR que você pode ler usando o botão de código QR nesta tela. + O Amethyst não conseguiu encontrar nenhum aplicativo de carteira que suporte Nostr Wallet Connect (NWC). \n\nO que você pode fazer: \n\t1. Verifique o suporte NWC: Confirme se o aplicativo da sua carteira é compatível com o Nostr Wallet Connect. \n\t2. Criar conexão: Vá até o aplicativo da sua carteira e crie uma nova conexão NWC. \n\t3. Vincular ao Amethyst: Sua carteira geralmente oferece três opções: \n\t\t3.1 Link Automático: Um botão para abrir e conectar automaticamente ao Amethyst. Clique nele, abra o Amethyst e salve na nova tela. \n\t\t3.2 Link Manual: Um URI de conexão que você pode copiar e colar usando o ícone de colar nesta tela. \n\t\t3.3 Código QR: A carteira gera um código QR que você pode ler usando o botão de código QR nesta tela. Criar Zona de Perigo Escuro @@ -2662,11 +2648,8 @@ Relays proxy Relays agregadores que o app usa para baixar seus feeds, como filter.nostr.wine. Isso substitui o modelo outbox e faz o app se conectar apenas aos relays das suas listas. Chat público - Os chats públicos são visíveis para todos no Nostr, e qualquer pessoa - pode participar deles. Eles são ótimos para comunidades abertas em torno de tópicos específicos. - A moderação pode ser controlada excluindo postagens em seus relays - Inserir entre 1–3 relés que hospedam esse grupo. - os clientes Nostr usam essa configuração para saber de onde fazer o download de mensagens e enviar suas mensagens. + Os chats públicos são visíveis para todos no Nostr, e qualquer pessoa pode participar deles. Eles são ótimos para comunidades abertas em torno de tópicos específicos. A moderação pode ser controlada excluindo postagens em seus relays + Inserir entre 1–3 relés que hospedam esse grupo. os clientes Nostr usam essa configuração para saber de onde fazer o download de mensagens e enviar suas mensagens. Relés Metadados do Chat Público Chats públicos @@ -2691,10 +2674,7 @@ Usuário somente leitura Clique e segure para gravar uma mensagem Chat Relé - Chat Relés são grupos de chat controlados por seu relé de origem. - Eles são visíveis para todos no Nostr e qualquer pessoa pode participar. - São ótimos para comunidades abertas em torno de tópicos específicos. Alguns desses grupos são efêmeros, - portanto, as mensagens desaparecem com o tempo + Chat Relés são grupos de chat controlados por seu relé de origem. Eles são visíveis para todos no Nostr e qualquer pessoa pode participar. São ótimos para comunidades abertas em torno de tópicos específicos. Alguns desses grupos são efêmeros, portanto, as mensagens desaparecem com o tempo Chat Relés Eventos Tipos diff --git a/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml index 42c411c558..d89352fd93 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru-rRU/strings.xml @@ -226,7 +226,7 @@ Копировать ID пользователя Разблокировать Этот пользователь заблокирован/заглушён. Его посты скрыты. - npub, hex, никнейм + npub, hex, никнейм Очистить Логотип приложения nsec / npub / приватный ключ в hex @@ -274,15 +274,8 @@ Отметить все известные прочитанными Отметить все новые прочитанными Отметить всё прочитанным - ## Советы по резервному копированию и безопасности ключей - \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. - \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. - \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. - \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - - Для дополнительной безопасности вы можете зашифровать ваш ключ с помощью пароля. Этот ключ начинается с **ncryptsec1** и не может быть использован без пароля. - \n\nЕсли вы потеряете свой пароль, вы не сможете восстановить ваш ключ. - + ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. + Для дополнительной безопасности вы можете зашифровать ваш ключ с помощью пароля. Этот ключ начинается с **ncryptsec1** и не может быть использован без пароля. \n\nЕсли вы потеряете свой пароль, вы не сможете восстановить ваш ключ. Зашифровать и копировать мой секретный ключ Картинка значка-награды %1$s Изображение награды за значок @@ -970,9 +963,7 @@ Отключает push-уведомления Использует приложение %1$s Настройки push-уведомлений - Для получения push-уведомлений, установите приложение, которое поддерживает [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). - После установки выберите приложение, которое хотите использовать, в настройках. - + Для получения push-уведомлений, установите приложение, которое поддерживает [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). После установки выберите приложение, которое хотите использовать, в настройках. Ветка Написать продавцу Привет, это ещё в наличии? @@ -2046,15 +2037,7 @@ Не удалось получить счёт от %1$s: %2$s Не удалось открыть сжатый файл Кошелёк не найден - Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). -\n\nЧто можно сделать: -\n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. -\n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. -\n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: -\n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. -\n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. -\n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. - + Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). \n\nЧто можно сделать: \n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. \n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. \n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: \n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. \n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. \n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. Создать д Опасная зона @@ -2737,11 +2720,8 @@ Предложить изменение Агрегирующие relay-серверы, которые приложение использует для загрузки ваших лент, например filter.nostr.wine. Это заменяет модель outbox и позволит приложению подключаться только к relay-серверам из ваших списков. Публичный чат - Публичные чаты видны всем в Nostr и открыты - для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. - Модерация осуществляется путём удаления постов на relay - Укажите от 1 до 3 relay, на которых размещена эта группа. - Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. + Публичные чаты видны всем в Nostr и открыты для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. Модерация осуществляется путём удаления постов на relay + Укажите от 1 до 3 relay, на которых размещена эта группа. Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. Relay Метаданные публичного чата Публичные чаты @@ -2766,10 +2746,7 @@ Пользователь только для чтения Нажмите и удерживайте, чтобы записать сообщение Чат relay - Чаты relay — это групповые чаты, управляемые их домашним relay. - Они видны всем в Nostr, и любой может в них участвовать. - Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, - поэтому сообщения исчезают со временем + Чаты relay — это групповые чаты, управляемые их домашним relay. Они видны всем в Nostr, и любой может в них участвовать. Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, поэтому сообщения исчезают со временем Чаты relay События IP-адреса diff --git a/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml index f88269516e..4b2c8833b7 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru-rUA/strings.xml @@ -267,15 +267,8 @@ Отметить все известные как прочитанные Отметить все новые как прочитанные Отметить все как прочитанные - ## Советы по резервному копированию и безопасности ключей - \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. - \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. - \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. - \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - - Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. - \n\nЕсли вы потеряете пароль, вы не сможете восстановить ключ. - + ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. + Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ключ. Зашифровать и скопировать мой секретный ключ Изображение награды для %1$s Изображение награды за значок @@ -960,9 +953,7 @@ Отключает push-уведомления Использует приложение %1$s Настройка push-уведомлений - Для получения push-уведомлений установите любое приложение, поддерживающее [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). - После установки выберите нужное приложение в Настройках. - + Для получения push-уведомлений установите любое приложение, поддерживающее [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). После установки выберите нужное приложение в Настройках. Тред Написать продавцу Привет, это ещё в наличии? @@ -2032,15 +2023,7 @@ Не удалось получить счёт от %1$s: %2$s Не удалось открыть сжатый файл Кошелёк не найден - Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). -\n\nЧто можно сделать: -\n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. -\n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. -\n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: -\n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. -\n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. -\n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. - + Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). \n\nЧто можно сделать: \n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. \n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. \n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: \n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. \n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. \n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. Создать Опасная зона Тёмная @@ -2719,11 +2702,8 @@ Предложить правку Агрегирующие relay-серверы, которые приложение использует для загрузки ваших лент, например filter.nostr.wine. Это заменяет модель outbox и позволит приложению подключаться только к relay-серверам из ваших списков. Публичный чат - Публичные чаты видны всем в Nostr и открыты - для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. - Модерация осуществляется путём удаления постов на relay - Укажите от 1 до 3 relay, на которых размещена эта группа. - Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. + Публичные чаты видны всем в Nostr и открыты для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. Модерация осуществляется путём удаления постов на relay + Укажите от 1 до 3 relay, на которых размещена эта группа. Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. Relay Метаданные публичного чата Публичные чаты @@ -2748,10 +2728,7 @@ Пользователь только для чтения Нажмите и удерживайте для записи сообщения Чат relay - Чаты relay — это групповые чаты, управляемые их домашним relay. - Они видны всем в Nostr, и любой может в них участвовать. - Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, - поэтому сообщения исчезают со временем + Чаты relay — это групповые чаты, управляемые их домашним relay. Они видны всем в Nostr, и любой может в них участвовать. Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, поэтому сообщения исчезают со временем Чаты relay События IP-адреса diff --git a/commonsUI/src/commonMain/composeResources/values-ru/strings.xml b/commonsUI/src/commonMain/composeResources/values-ru/strings.xml index 5a3a0ea0eb..9ceaec1f2a 100644 --- a/commonsUI/src/commonMain/composeResources/values-ru/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ru/strings.xml @@ -215,7 +215,7 @@ Копировать ID пользователя Разблокировать Этот пользователь заблокирован/заглушён. Его посты скрыты. - npub, hex, никнейм + npub, hex, никнейм Очистить Логотип приложения nsec / npub / приватный ключ в hex @@ -263,17 +263,8 @@ Отметить все известные прочитанными Отметить все новые прочитанными Отметить всё прочитанным - - ## Советы по резервному копированию и безопасности ключей - \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. - \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. - \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. - \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. - - - Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. - \n\nЕсли вы потеряете пароль, вы не сможете восстановить ваш ключ. - + ## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей. + Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ваш ключ. Зашифровать и скопировать секретный ключ Картинка значка-награды %1$s Изображение награды за значок @@ -966,9 +957,7 @@ Отключает push-уведомления Использует приложение %1$s Настройки push-уведомлений - Для получения push-уведомлений, установите приложение, которое поддерживает [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). - После установки выберите приложение, которое хотите использовать, в настройках. - + Для получения push-уведомлений, установите приложение, которое поддерживает [Unified Push](https://unifiedpush.org/), например [Ntfy](https://ntfy.sh/). После установки выберите приложение, которое хотите использовать, в настройках. Ветка Написать продавцу Привет, это ещё в наличии? @@ -2077,15 +2066,7 @@ Не удалось получить счёт от %1$s: %2$s Не удалось открыть сжатый файл Кошелёк не найден - Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). -\n\nЧто можно сделать: -\n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. -\n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. -\n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: -\n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. -\n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. -\n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. - + Amethyst не нашёл ни одного приложения кошелька с поддержкой Nostr Wallet Connect (NWC). \n\nЧто можно сделать: \n\t1. Проверьте поддержку NWC: убедитесь, что ваш кошелёк совместим с Nostr Wallet Connect. \n\t2. Создайте подключение: откройте приложение кошелька и создайте новое NWC-подключение. \n\t3. Привяжите к Amethyst: обычно кошелёк предлагает три варианта: \n\t\t3.1 Автоматическая привязка: кнопка для автоматического открытия и подключения к Amethyst. Нажмите её, откройте Amethyst и сохраните новый экран. \n\t\t3.2 Ручная привязка: URI подключения, который можно скопировать и вставить с помощью значка вставки на этом экране. \n\t\t3.3 QR-код: кошелёк создаёт QR-код, который можно считать кнопкой QR-кода на этом экране. Создать д Опасная зона @@ -2815,11 +2796,8 @@ Proxy Relays Агрегирующие relay-серверы, которые приложение использует для загрузки ваших лент, например filter.nostr.wine. Это заменяет модель outbox и позволит приложению подключаться только к relay-серверам из ваших списков. Публичный чат - Публичные чаты видны всем в Nostr и открыты - для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. - Модерация осуществляется путём удаления постов на relay - Укажите от 1 до 3 relay, на которых размещена эта группа. - Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. + Публичные чаты видны всем в Nostr и открыты для участия любого желающего. Они отлично подходят для открытых сообществ по определённым темам. Модерация осуществляется путём удаления постов на relay + Укажите от 1 до 3 relay, на которых размещена эта группа. Клиенты Nostr используют эту настройку, чтобы знать, откуда загружать сообщения и куда их отправлять. Relay Метаданные публичного чата Публичные чаты @@ -2844,10 +2822,7 @@ Пользователь только для чтения Нажмите и удерживайте для записи сообщения Чат relay - Чаты relay — это групповые чаты, управляемые их домашним relay. - Они видны всем в Nostr, и любой может в них участвовать. - Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, - поэтому сообщения исчезают со временем + Чаты relay — это групповые чаты, управляемые их домашним relay. Они видны всем в Nostr, и любой может в них участвовать. Они отлично подходят для открытых сообществ по определённым темам. Некоторые группы эфемерны, поэтому сообщения исчезают со временем Чаты relay События IP-адреса diff --git a/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml b/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml index 2f5ff233bb..8ae6e95125 100644 --- a/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sl-rSI/strings.xml @@ -472,16 +472,8 @@ Označi vse znane kot prebrane Označi vse nove kot prebrane Označi vse kot prebrane - - ## Varnostna kopija ključev in varnostni nasveti - \n\nVaš račun je zaščiten z privatnim ključem. Ta ključ ima dolgo sekvenco znakov kateri se začnejo z **nsec1**. Kdorkoli ima dostop, do tega privatnega ključa, lahko pošiljajo zapiske in spremenijo vašo digitalno identiteto. - \n\n- Nikoli in **Nikdar** ne vpisuj svojega privatnega ključa v spletne strani in aplikacije katerim ne zaupaš. - \n- Amethyst ustvarjalci vas ne bojo **nikoli** vprašali po vašem privatnem ključu. - \n- Ustvari **varnostno kopijo** svojega privatnega ključa, za obnovitev računa. Priporoča se uporaba upravljalnika gesel. - - Za dodatno varnost, lahko šifriraš svoj ključ z dodatnim geslom. Ta ključ se začne z **ncryptsec1** in ne more bit uporabljen brez dodatnega gesla. - \n\nČe izgubiš geslo, obnova ključa ni več mogoča. - + ## Varnostna kopija ključev in varnostni nasveti \n\nVaš račun je zaščiten z privatnim ključem. Ta ključ ima dolgo sekvenco znakov kateri se začnejo z **nsec1**. Kdorkoli ima dostop, do tega privatnega ključa, lahko pošiljajo zapiske in spremenijo vašo digitalno identiteto. \n\n- Nikoli in **Nikdar** ne vpisuj svojega privatnega ključa v spletne strani in aplikacije katerim ne zaupaš. \n- Amethyst ustvarjalci vas ne bojo **nikoli** vprašali po vašem privatnem ključu. \n- Ustvari **varnostno kopijo** svojega privatnega ključa, za obnovitev računa. Priporoča se uporaba upravljalnika gesel. + Za dodatno varnost, lahko šifriraš svoj ključ z dodatnim geslom. Ta ključ se začne z **ncryptsec1** in ne more bit uporabljen brez dodatnega gesla. \n\nČe izgubiš geslo, obnova ključa ni več mogoča. Varno shrani ključe Vaš zasebni ključ je edini način za dostop do tega računa. Če ga izgubite, ga ne boste mogli več obnoviti. Shranite ga na varno mesto. Varno shrani zdaj @@ -1593,9 +1585,7 @@ Onemogoči potisna obvestila Uporablja aplikacijo %1$s Nastavitev potisnih obvestil - Za prejemanje potisnih obvestil namestite aplikacijo, ki podpira [Unified Push](https://unifiedpush.org/), na primer [Ntfy](https://ntfy.sh/). - Po namestitvi izberite aplikacijo, ki jo želite uporabljati, v nastavitvah. - + Za prejemanje potisnih obvestil namestite aplikacijo, ki podpira [Unified Push](https://unifiedpush.org/), na primer [Ntfy](https://ntfy.sh/). Po namestitvi izberite aplikacijo, ki jo želite uporabljati, v nastavitvah. Niz objav Pošlji prodajalcu sporočilo Živjo, je to še na voljo? @@ -1856,7 +1846,7 @@ danes izbrano Ustvari nov koledarski dogodek - Ustvari novo zbirko koledarjev + Ustvari novo zbirko koledarjev Ustvari novo zbirko koledarjev (neimenovano) Ves dan @@ -2042,7 +2032,7 @@ Več Dodaj člana Dodaj nekoga v to ZS - Neveljaven npub ali hex ključ + Neveljaven npub ali hex ključ Samo vi Delovni prostor Za @@ -2091,8 +2081,7 @@ Nastavite releje za predal zasebnih sporočil Ta nastavitev omogoča vsem, da vedo, katere releje uporabiti, ko vam pošiljajo sporočila. Brez njih bi lahko zgrešili nekatera sporočila. Dobre možnosti so:\n - auth.nostr1.com (brezplačen)\n - inbox.nostr.wine (plačljiv)\n - relay.0xchat.com (brezplačen) - Vnesite 1–3 releje, ki bodo služili kot vaš predal - za zasebna sporočila. Releji za zasebna sporočila bi morali sprejeti katero koli sporočilo od kogar koli, vendar samo vam dovoliti njihov prenos. + Vnesite 1–3 releje, ki bodo služili kot vaš predal za zasebna sporočila. Releji za zasebna sporočila bi morali sprejeti katero koli sporočilo od kogar koli, vendar samo vam dovoliti njihov prenos. Nastavi zdaj Releji za prejeto pošto (ZS) niso bili najdeni. Sporočil ni mogoče dostaviti, dokler uporabnik ne nastavi seznama svojih relejev. Nastavi iskalne releje @@ -2339,7 +2328,7 @@ Nova partija šaha Nalagam partijo\u2026 Partija ni najdena - Ta partija je zaključena ali pa, čaka na nasprotnika + Ta partija je zaključena ali pa, čaka na nasprotnika ID Partije: %1$s\u2026 in %1$d ostalih Odstrani %1$s @@ -2664,9 +2653,7 @@ committed the change, %2$s the member it concerns, %3$s the new name. --> Odstrani fotografijo KeyPackage releji niso nastavljeni - Še nimate seznama relejev za KeyPackage (MIP-00). Ta seznam drugim sporoča, kje je objavljen vaš KeyPackage, da vas lahko povabijo v skupinske klepete. - -Ali želite za to uporabiti trenutne releje iz odhodnega predala? + Še nimate seznama relejev za KeyPackage (MIP-00). Ta seznam drugim sporoča, kje je objavljen vaš KeyPackage, da vas lahko povabijo v skupinske klepete. Ali želite za to uporabiti trenutne releje iz odhodnega predala? Uporabi odhodne releje Zaenkrat preskoči Podatki o skupini @@ -3337,15 +3324,7 @@ Ali želite za to uporabiti trenutne releje iz odhodnega predala? Ni bilo mogoče pridobiti fakture od %1$s: %2$s Stisnjene datoteke ni bilo mogoče odpreti Ne najdem denarnice - Amethyst ni našel nobene denarnice, ki podpira Nostr Wallet Connect (NWC). -\n\nKaj lahko storiš: -\n\t1. Preverite podporo za NWC: Ponovno\t preverite, ali vaša priljubljena denarnica podpira Nostr Wallet Connect. -\n\t2. Ustvari povezavo: Odprite svojo denarnico in ustvarite novo NWC povezavo. -\n\t3. Povežite z Amethyst: Vaša denarnica vam bo ponavadi ponudila tri možnosti: -\n\t\t3.1 Samodejna povezava: Gumb za samodejno odprtje in povezavo z Amethyst. Če je na voljo, kliknite ta gumb, odprite Amethyst in na novem zaslonu pritisnite shrani. -\n\t\tRočna povezava: Povezovalni URI, ki ga lahko kopirate, nato pa na tem zaslonu kliknite ikono za lepljenje, da ga neposredno vnesete. -\n\t\tQR koda: Denarnica ustvari QR-kodo, ki jo skenirajte z gumbom za QR na tem zaslonu. - + Amethyst ni našel nobene denarnice, ki podpira Nostr Wallet Connect (NWC). \n\nKaj lahko storiš: \n\t1. Preverite podporo za NWC: Ponovno\t preverite, ali vaša priljubljena denarnica podpira Nostr Wallet Connect. \n\t2. Ustvari povezavo: Odprite svojo denarnico in ustvarite novo NWC povezavo. \n\t3. Povežite z Amethyst: Vaša denarnica vam bo ponavadi ponudila tri možnosti: \n\t\t3.1 Samodejna povezava: Gumb za samodejno odprtje in povezavo z Amethyst. Če je na voljo, kliknite ta gumb, odprite Amethyst in na novem zaslonu pritisnite shrani. \n\t\tRočna povezava: Povezovalni URI, ki ga lahko kopirate, nato pa na tem zaslonu kliknite ikono za lepljenje, da ga neposredno vnesete. \n\t\tQR koda: Denarnica ustvari QR-kodo, ki jo skenirajte z gumbom za QR na tem zaslonu. Ustvari d Nevarno območje @@ -3804,26 +3783,16 @@ Ali želite za to uporabiti trenutne releje iz odhodnega predala? Spremeni lokacijo na karti Lokacijski kanali Izberi lokacijo na karti - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem za posredovanje sporočila - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem, za sledenje uporabnika - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem, za cenzuro besed ali stavkov - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem, da omogočiš tudi pisanje - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavite se s privatnim ključem, da boste lahko pošiljali Zape - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Za podpisovanje se je potrebno prijaviti s privatnim ključem - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem, za odstranitev iz seznama sledljivih - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Za nalaganje se je potrebno prijaviti s privatnim ključem - Uporabljaš javni ključ in javni ključi omogočajo le branje. -Prijavi se s privatnim ključem za všečkanje sporočila + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem za posredovanje sporočila + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem, za sledenje uporabnika + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem, za cenzuro besed ali stavkov + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem, da omogočiš tudi pisanje + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavite se s privatnim ključem, da boste lahko pošiljali Zape + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem, za prikaz skritih besed in stavkov + Uporabljaš javni ključ in javni ključi omogočajo le branje. Za podpisovanje se je potrebno prijaviti s privatnim ključem + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem, za odstranitev iz seznama sledljivih + Uporabljaš javni ključ in javni ključi omogočajo le branje. Za nalaganje se je potrebno prijaviti s privatnim ključem + Uporabljaš javni ključ in javni ključi omogočajo le branje. Prijavi se s privatnim ključem za všečkanje sporočila Videoposnetki m Moji emoji paketi @@ -4122,7 +4091,7 @@ Prijavi se s privatnim ključem za všečkanje sporočila Brez moderacije Ustvari nov javen klepet Pridruži se lahko kdorkoli - Preprosto in zlahka dosegljivo + Preprosto in zlahka dosegljivo Javna sporočila na releju Javni klepet Skupine, ki jih moderira njihov gostiteljski rele @@ -4531,11 +4500,8 @@ Prijavi se s privatnim ključem za všečkanje sporočila Proxy releji Agregatorji, ki jih mora aplikacija uporabljati za prenos vaših vsebin, na primer filter.nostr.wine. To nadomesti model odhodne pošte (outbox model) in bo prisililo aplikacijo k povezovanju prek relejev iz vašega seznama. Javni pogovor - Javni klepeti so vidni vsem na Nostru in vsakdo - se lahko pridruži. So odlični za odprte skupnosti o specifičnih temah. - Moderiranje je možno z brisanjem objav na njihovih relejih - Vnesi 1–3 releje, ki gostijo to skupino. - Nostr odjemalci uporabljajo to nastavitev, da vedo, od kod prenesti vaša sporočila in kam jih poslati. + Javni klepeti so vidni vsem na Nostru in vsakdo se lahko pridruži. So odlični za odprte skupnosti o specifičnih temah. Moderiranje je možno z brisanjem objav na njihovih relejih + Vnesi 1–3 releje, ki gostijo to skupino. Nostr odjemalci uporabljajo to nastavitev, da vedo, od kod prenesti vaša sporočila in kam jih poslati. Releji Metapodatki Javnega Klepeta Javni klepeti @@ -4595,10 +4561,7 @@ Prijavi se s privatnim ključem za všečkanje sporočila Preverjanje pristnosti (Auth), rele (Relay), podpis (Sign), preverjanje (Verify), NIP-42, identiteta Avtentikacija releja Rele klepet - Pogovori prek relejev so pogovorne skupine, ki jih nadzoruje njihov domači rele. - Vidne so vsem na Nostru in v njih lahko sodeluje kdorkoli. - So odlične za odprte skupnosti, povezane s specifičnimi temami. Nekatere od teh skupin so kratkotrajne - zato sporočila v klepetu sčasoma izginejo + Pogovori prek relejev so pogovorne skupine, ki jih nadzoruje njihov domači rele. Vidne so vsem na Nostru in v njih lahko sodeluje kdorkoli. So odlične za odprte skupnosti, povezane s specifičnimi temami. Nekatere od teh skupin so kratkotrajne zato sporočila v klepetu sčasoma izginejo Rele klepeti Vaš profil, nastavitve in osnutki na vaših domačih relejih. Releji, kamor vsaka skupnost objavlja svoje načrte. @@ -4732,7 +4695,7 @@ Prijavi se s privatnim ključem za všečkanje sporočila Lokalni pomnilnik Zapiski v pomnilniku Trenutni pomnilnik - Profili v pomnilniku + Profili v pomnilniku Čas v zvočnih sobah Rudarjenje PoW Obuditve radijskega modula za prenose (ocena) diff --git a/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml b/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml index 6ea50394e6..9aee9b1e4d 100644 --- a/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sr-rSP/strings.xml @@ -271,15 +271,8 @@ Označi sve poznate kao pročitano Označi sve novo kao pročitano Označi sve kao pročitano - ## Saveti za bekap ključa i bezbednost - \n\nVaš nalog je zaštićen tajnim ključem. Ključ je dugačak niz znakova koji počinje sa **nsec1**. Svako ko ima pristup ovom tajnom ključu može da objavljuje i menja vaš identitet. - \n\n- **Ne** unosite vaš tajni ključ ni na jedan veb-sajt ili softver kojemu ne verujete. - \n- Amethyst programeri **nikada** neće tražiti vaš tajni ključ. - \n- **Čuvajte** bezbednu kopiju vašeg tajnog ključa radi oporavka naloga. Preporučujemo korišćenje menadžera lozinki. - - Za dodatnu bezbednost, možete šifrovati vaš ključ lozinkom. Ovaj ključ počinje sa **ncryptsec1** i ne može se koristiti bez vaše lozinke. - \n\nAko izgubite lozinku, nećete moći da obnovite ključ. - + ## Saveti za bekap ključa i bezbednost \n\nVaš nalog je zaštićen tajnim ključem. Ključ je dugačak niz znakova koji počinje sa **nsec1**. Svako ko ima pristup ovom tajnom ključu može da objavljuje i menja vaš identitet. \n\n- **Ne** unosite vaš tajni ključ ni na jedan veb-sajt ili softver kojemu ne verujete. \n- Amethyst programeri **nikada** neće tražiti vaš tajni ključ. \n- **Čuvajte** bezbednu kopiju vašeg tajnog ključa radi oporavka naloga. Preporučujemo korišćenje menadžera lozinki. + Za dodatnu bezbednost, možete šifrovati vaš ključ lozinkom. Ovaj ključ počinje sa **ncryptsec1** i ne može se koristiti bez vaše lozinke. \n\nAko izgubite lozinku, nećete moći da obnovite ključ. Šifruj i kopiraj moj tajni ključ Slika značke za %1$s "Slika značke @@ -959,9 +952,7 @@ Onemogućava push obaveštenja Koristi aplikaciju %1$s Podešavanje push obaveštenja - Da biste primali push obaveštenja, instalirajte bilo koju aplikaciju koja podržava [Unified Push](https://unifiedpush.org/), kao što je [Ntfy](https://ntfy.sh/). - Nakon instalacije, izaberite aplikaciju koju želite da koristite u Postavkama. - + Da biste primali push obaveštenja, instalirajte bilo koju aplikaciju koja podržava [Unified Push](https://unifiedpush.org/), kao što je [Ntfy](https://ntfy.sh/). Nakon instalacije, izaberite aplikaciju koju želite da koristite u Postavkama. Nit Pošaljite prodavcu poruku Zdravo, da li je ovo još uvek dostupno? @@ -2014,15 +2005,7 @@ Nije moguće dohvatiti fakturu od %1$s: %2$s Komprimovana datoteka se ne može otvoriti Novčanik nije pronađen - Amethyst nije mogao da pronađe nijednu aplikaciju novčanika koja podržava Nostr Wallet Connect (NWC). -\n\nŠta možete da uradite: -\n\t1. Proverite NWC podršku: Proverite da li vaša preferovana aplikacija novčanika podržava Nostr Wallet Connect. -\n\t2. Kreirajte vezu: Idite na aplikaciju novčanika i kreirajte novu NWC vezu. -\n\t3. Povežite sa Amethyst: Vaš novčanik će obično ponuditi tri opcije: -\n\t\t3.1 Automatska veza: Dugme za automatsko otvaranje i povezivanje sa Amethyst. Ako postoji, kliknite to dugme, otvorite Amethyst i pritisnite sačuvaj na novom ekranu. -\n\t\t3.2 Ručna veza: URI veze koji možete kopirati i kliknuti ikonu za nalepljivanje na ovom ekranu da ga direktno unesete. -\n\t\t3.3 QR kod: Novčanik kreira QR kod koji možete očitati dugmetom za QR kod na ovom ekranu. - + Amethyst nije mogao da pronađe nijednu aplikaciju novčanika koja podržava Nostr Wallet Connect (NWC). \n\nŠta možete da uradite: \n\t1. Proverite NWC podršku: Proverite da li vaša preferovana aplikacija novčanika podržava Nostr Wallet Connect. \n\t2. Kreirajte vezu: Idite na aplikaciju novčanika i kreirajte novu NWC vezu. \n\t3. Povežite sa Amethyst: Vaš novčanik će obično ponuditi tri opcije: \n\t\t3.1 Automatska veza: Dugme za automatsko otvaranje i povezivanje sa Amethyst. Ako postoji, kliknite to dugme, otvorite Amethyst i pritisnite sačuvaj na novom ekranu. \n\t\t3.2 Ručna veza: URI veze koji možete kopirati i kliknuti ikonu za nalepljivanje na ovom ekranu da ga direktno unesete. \n\t\t3.3 QR kod: Novčanik kreira QR kod koji možete očitati dugmetom za QR kod na ovom ekranu. Napravi Opasna zona Tamno @@ -2703,11 +2686,8 @@ Proxy Relay-i Agregatorni relay-i koje aplikacija mora koristiti za preuzimanje vaših feedova, poput filter.nostr.wine. Ovo zamenjuje outbox model i čini da se aplikacija povezuje samo na relay-e u vašim listama. Javni čet - Javni četovi vidljivi su svima na Nostr-u i svako - može da učestvuje. Odlični su za otvorene zajednice oko specifičnih tema. - Moderacija se može kontrolisati brisanjem objava na relay-ima - Unesite između 1 i 3 relay-a koji hostuju ovu grupu. - Nostr klijenti koriste ovo podešavanje da znaju odakle da preuzmu poruke i kuda da ih šalju. + Javni četovi vidljivi su svima na Nostr-u i svako može da učestvuje. Odlični su za otvorene zajednice oko specifičnih tema. Moderacija se može kontrolisati brisanjem objava na relay-ima + Unesite između 1 i 3 relay-a koji hostuju ovu grupu. Nostr klijenti koriste ovo podešavanje da znaju odakle da preuzmu poruke i kuda da ih šalju. Relay-i Metapodaci javnog četa Javni razgovori @@ -2732,10 +2712,7 @@ Korisnik samo za čitanje Kliknite i držite za snimanje poruke Relay čet - Relay četovi su grupe za razgovor kojima upravlja njihov matični relay. - Vidljivi su svima na Nostr-u i svako može da učestvuje. - Odlični su za otvorene zajednice oko specifičnih tema. Neke od ovih grupa su efemeralne - i stoga poruke nestaju s vremenom + Relay četovi su grupe za razgovor kojima upravlja njihov matični relay. Vidljivi su svima na Nostr-u i svako može da učestvuje. Odlični su za otvorene zajednice oko specifičnih tema. Neke od ovih grupa su efemeralne i stoga poruke nestaju s vremenom Relay četovi Događaji IP adrese diff --git a/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml b/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml index f591cc0177..0b434776f0 100644 --- a/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sv-rSE/strings.xml @@ -361,7 +361,7 @@ Kopiera Användarens ID Sluta blockera Användare Den här användaren är blockerad/tystad. Deras inlägg är dolda. - npub, hex, användarnamn + npub, hex, användarnamn Rensa Appens logo nsec / npub / hex privat nyckel @@ -463,13 +463,8 @@ Markera alla kända som lästa Markera alla nya som lästa Markera allt som läst - ## Nyckelsäkerhetsråd - \n\nDitt konto är säkrat med en hemlig nyckel. Nyckeln är en lång följd av tecken som börjar med **nsec1**. Den som har tillgång till denna hemliga nyckel kan posta och ändra din identitet. - \n\n- **Lägg inte** din hemliga nyckel på någon webbplats eller i någon mjukvara som du inte litar på. - \n- Utvecklarna av Amethyst kommer **aldrig** att be om din hemliga nyckel. - \n- **Spara** en säkerhetskopia av din hemliga nyckel för återställning av kontot. Vi rekommenderar att du använder en lösenordshanterare. - För extra säkerhet kan du kryptera din nyckel med ett lösenord. Denna nyckel börjar med **ncryptsec1** och kan inte användas utan ditt lösenord. - \n\nOm du tappar bort ditt lösenord kommer du inte att kunna återställa din nyckel. + ## Nyckelsäkerhetsråd \n\nDitt konto är säkrat med en hemlig nyckel. Nyckeln är en lång följd av tecken som börjar med **nsec1**. Den som har tillgång till denna hemliga nyckel kan posta och ändra din identitet. \n\n- **Lägg inte** din hemliga nyckel på någon webbplats eller i någon mjukvara som du inte litar på. \n- Utvecklarna av Amethyst kommer **aldrig** att be om din hemliga nyckel. \n- **Spara** en säkerhetskopia av din hemliga nyckel för återställning av kontot. Vi rekommenderar att du använder en lösenordshanterare. + För extra säkerhet kan du kryptera din nyckel med ett lösenord. Denna nyckel börjar med **ncryptsec1** och kan inte användas utan ditt lösenord. \n\nOm du tappar bort ditt lösenord kommer du inte att kunna återställa din nyckel. Säkerhetskopiera dina nycklar Din hemliga nyckel är enda sättet att komma åt det här kontot. Om du förlorar den kan den aldrig återskapas. Spara den på ett säkert ställe nu. Säkerhetskopiera nu @@ -478,7 +473,7 @@ Kryptera och kopiera min hemliga nyckel Tilldelad Badge för %1$s Bild på utmärkelse - Du har blivit tilldelad en ny Badge + Du har blivit tilldelad en ny Badge Badge utmärkelse tilldelas Lägg till nytt konto Välj konto @@ -1584,9 +1579,7 @@ Inaktivera Push-meddelande Använder appen %1$s Inställning av Push-aviseringar - För att ta emot push-aviseringar, installera vilken app som helst som stöder [Unified Push](https://unifiedpush.org), till exempel [Ntfy](https://ntfy.sh/). - Efter installationen väljer du den app du vill använda i inställningarna. - + För att ta emot push-aviseringar, installera vilken app som helst som stöder [Unified Push](https://unifiedpush.org), till exempel [Ntfy](https://ntfy.sh/). Efter installationen väljer du den app du vill använda i inställningarna. Tråd Skicka ett meddelande till säljaren Hallå där, är detta fortfarande tillgängligt? @@ -3323,14 +3316,7 @@ Kunde inte hämta faktura från %1$s: %2$s Kunde inte öppna den komprimerade filen Plånbok hittades inte - Amethyst kunde inte hitta några plånboksappar som stöder Nostr Wallet Connect (NWC). -\n\nVad du kan göra: -\n\t1. Verifiera NWC-stöd: Kontrollera att din föredragna plånbok stöder Nostr Wallet Connect. -\n\t2. Skapa anslutning: Gå till din plånbok och skapa en ny NWC-anslutning. -\n\t3. Länka till Amethyst: Din plånbok erbjuder vanligtvis tre alternativ: -\n\t\t3.1 Automatisk länk: En knapp för att automatiskt öppna och ansluta till Amethyst. Klicka på den, öppna Amethyst och spara på den nya skärmen. -\n\t\t3.2 Manuell länk: En anslutnings-URI som du kan kopiera och klistra in via klistra-ikonen på den här skärmen. -\n\t\t3.3 QR-kod: Plånboken skapar en QR-kod som du kan skanna med QR-knappens funktion på den här skärmen. + Amethyst kunde inte hitta några plånboksappar som stöder Nostr Wallet Connect (NWC). \n\nVad du kan göra: \n\t1. Verifiera NWC-stöd: Kontrollera att din föredragna plånbok stöder Nostr Wallet Connect. \n\t2. Skapa anslutning: Gå till din plånbok och skapa en ny NWC-anslutning. \n\t3. Länka till Amethyst: Din plånbok erbjuder vanligtvis tre alternativ: \n\t\t3.1 Automatisk länk: En knapp för att automatiskt öppna och ansluta till Amethyst. Klicka på den, öppna Amethyst och spara på den nya skärmen. \n\t\t3.2 Manuell länk: En anslutnings-URI som du kan kopiera och klistra in via klistra-ikonen på den här skärmen. \n\t\t3.3 QR-kod: Plånboken skapar en QR-kod som du kan skanna med QR-knappens funktion på den här skärmen. Skapa d Riskzon @@ -4427,11 +4413,8 @@ Proxyreläer Aggregeringsreläer som används för att hämta flöden, t.ex. filter.nostr.wine Publik Chat - Offentliga chattar är synliga för alla på Nostr och alla - kan delta på dem. De är bra för öppna samhällen kring specifika ämnen. - Moderation kan kontrolleras genom att ta bort inlägg på reläerna - Infoga mellan 1–3 reläer som är värd för denna grupp. - Nostr klienter använder denna inställning för att veta var du kan ladda ner meddelanden från och skicka dina meddelanden till. + Offentliga chattar är synliga för alla på Nostr och alla kan delta på dem. De är bra för öppna samhällen kring specifika ämnen. Moderation kan kontrolleras genom att ta bort inlägg på reläerna + Infoga mellan 1–3 reläer som är värd för denna grupp. Nostr klienter använder denna inställning för att veta var du kan ladda ner meddelanden från och skicka dina meddelanden till. Reläer Metadata för offentlig chatt Offentliga chattar @@ -4496,10 +4479,7 @@ auth autentisering relä signera verifiera nip-42 identitet Reläautentisering Relä Chatt - Relä chattar är chattgrupper som kontrolleras av deras hem relä. - De är synliga för alla på Nostr och vem som helst kan delta på dem. - De är bra för öppna gemenskaper kring specifika ämnen. Några av dessa grupper är kortlivade - och därmed försvinner chattmeddelanden över tiden + Relä chattar är chattgrupper som kontrolleras av deras hem relä. De är synliga för alla på Nostr och vem som helst kan delta på dem. De är bra för öppna gemenskaper kring specifika ämnen. Några av dessa grupper är kortlivade och därmed försvinner chattmeddelanden över tiden Relä Chattar Din egen profil, dina inställningar och utkast, på dina hemreläer. Reläerna som varje gemenskap publicerar sina plan till. diff --git a/commonsUI/src/commonMain/composeResources/values-sw/strings.xml b/commonsUI/src/commonMain/composeResources/values-sw/strings.xml index 9c24ec5784..439b9c7be0 100644 --- a/commonsUI/src/commonMain/composeResources/values-sw/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-sw/strings.xml @@ -268,15 +268,8 @@ Funga kama Zimejulikana Funga kama Mpya Funga kama Zimejulikana - ## Vidokezo vya Nakala Rudufu ya Ufunguo na Usalama - \n\nAkaunti yako inalindwa na ufunguo wa siri. Ufunguo ni mfululizo mrefu wa herufi unaoanza na **nsec1**. Mtu yeyote anayepata ufunguo huu wa siri anaweza kuchapisha na kubadilisha utambulisho wako. - \n\n- **Usiweke** ufunguo wako wa siri katika tovuti yoyote au programu unayoitembelewa. - \n- Watengenezaji wa Amethyst **hawatawahi** kuomba ufunguo wako wa siri. - \n- **Hifadhi** nakala salama ya ufunguo wako wa siri kwa ajili ya kurejesha akaunti. Tunapendekeza kutumia kidhibiti cha nenosiri. - - Kwa usalama zaidi, unaweza kusimba ufunguo wako kwa nenosiri. Ufunguo huu unaanza na **ncryptsec1** na hauwezi kutumika bila nenosiri lako. - \n\nUkipoteza nenosiri lako, hutaweza kurejesha ufunguo wako. - + ## Vidokezo vya Nakala Rudufu ya Ufunguo na Usalama \n\nAkaunti yako inalindwa na ufunguo wa siri. Ufunguo ni mfululizo mrefu wa herufi unaoanza na **nsec1**. Mtu yeyote anayepata ufunguo huu wa siri anaweza kuchapisha na kubadilisha utambulisho wako. \n\n- **Usiweke** ufunguo wako wa siri katika tovuti yoyote au programu unayoitembelewa. \n- Watengenezaji wa Amethyst **hawatawahi** kuomba ufunguo wako wa siri. \n- **Hifadhi** nakala salama ya ufunguo wako wa siri kwa ajili ya kurejesha akaunti. Tunapendekeza kutumia kidhibiti cha nenosiri. + Kwa usalama zaidi, unaweza kusimba ufunguo wako kwa nenosiri. Ufunguo huu unaanza na **ncryptsec1** na hauwezi kutumika bila nenosiri lako. \n\nUkipoteza nenosiri lako, hutaweza kurejesha ufunguo wako. Simba na nakili ufunguo wangu wa siri Picha ya tuzo ya alama kwa %1$s "Picha ya tuzo ya beji @@ -961,9 +954,7 @@ Inazima Arifa za Push Inatumia programu %1$s Mpangilio wa Arifa za Push - Ili kupokea arifa za kusukuma, sakinisha programu yoyote inayounga mkono [Unified Push](https://unifiedpush.org/), kama vile [Ntfy](https://ntfy.sh/). - Baada ya kusakinisha, chagua programu unayotaka kutumia katika Mipangilio. - + Ili kupokea arifa za kusukuma, sakinisha programu yoyote inayounga mkono [Unified Push](https://unifiedpush.org/), kama vile [Ntfy](https://ntfy.sh/). Baada ya kusakinisha, chagua programu unayotaka kutumia katika Mipangilio. Nyuzi Tuma ujumbe kwa muuzaji Habari, je, hii bado inapatikana? @@ -2016,15 +2007,7 @@ Haikuweza kupata ankara kutoka kwa %1$s: %2$s Haikuweza kufungua faili lililosinyazwa Mkoba haukupatikana - Amethyst haikupata programu yoyote ya mkoba inayounga mkono Nostr Wallet Connect (NWC). -\n\nUnachoweza kufanya: -\n\t1. Thibitisha Usaidizi wa NWC: Hakikisha kuwa programu yako ya mkoba inaoana na Nostr Wallet Connect. -\n\t2. Unda Muunganisho: Nenda kwenye programu yako ya mkoba na unda muunganisho mpya wa NWC. -\n\t3. Unganisha na Amethyst: Mkoba wako kwa kawaida utakupa chaguo tatu: -\n\t\t3.1 Kiungo cha Kiotomatiki: Kitufe cha kufungua na kuunganisha moja kwa moja na Amethyst. Ikiwa ndivyo, bonyeza kitufe hicho, fungua Amethyst na bonyeza hifadhi kwenye skrini mpya. -\n\t\t3.2 Kiungo cha Mkono: URI ya Muunganisho unayoweza kunakili na kubonyeza ikoni ya kubandika kwenye skrini hii kuiingiza moja kwa moja. -\n\t\t3.3 Msimbo wa QR: Mkoba unaunda msimbo wa QR ambao unaweza kuusoma kutoka kwa kitufe cha msimbo wa QR kwenye skrini hii. - + Amethyst haikupata programu yoyote ya mkoba inayounga mkono Nostr Wallet Connect (NWC). \n\nUnachoweza kufanya: \n\t1. Thibitisha Usaidizi wa NWC: Hakikisha kuwa programu yako ya mkoba inaoana na Nostr Wallet Connect. \n\t2. Unda Muunganisho: Nenda kwenye programu yako ya mkoba na unda muunganisho mpya wa NWC. \n\t3. Unganisha na Amethyst: Mkoba wako kwa kawaida utakupa chaguo tatu: \n\t\t3.1 Kiungo cha Kiotomatiki: Kitufe cha kufungua na kuunganisha moja kwa moja na Amethyst. Ikiwa ndivyo, bonyeza kitufe hicho, fungua Amethyst na bonyeza hifadhi kwenye skrini mpya. \n\t\t3.2 Kiungo cha Mkono: URI ya Muunganisho unayoweza kunakili na kubonyeza ikoni ya kubandika kwenye skrini hii kuiingiza moja kwa moja. \n\t\t3.3 Msimbo wa QR: Mkoba unaunda msimbo wa QR ambao unaweza kuusoma kutoka kwa kitufe cha msimbo wa QR kwenye skrini hii. Unda siku Eneo Hatari @@ -2686,11 +2669,8 @@ Relay za Wakala Relay za mkusanyaji ambazo programu lazima itumie kupakua malisho yako, kama filter.nostr.wine. Hii inabadilisha mfano wa sanduku la nje na itafanya programu iunganike na relay zilizo kwenye orodha zako tu. Mazungumzo ya Umma - Mazungumzo ya umma yanaweza kuonekana na kila mtu kwenye Nostr na mtu yeyote - anaweza kushiriki. Ni mazuri kwa jamii wazi kuhusu mada maalum. - Udhibiti unaweza kufanywa kwa kufuta machapisho kwenye relay zake - Ingiza kati ya relay 1–3 zinazohifadhi kikundi hiki. - Wateja wa Nostr hutumia mipangilio hii kujua mahali pa kupakua ujumbe na kutuma ujumbe wako. + Mazungumzo ya umma yanaweza kuonekana na kila mtu kwenye Nostr na mtu yeyote anaweza kushiriki. Ni mazuri kwa jamii wazi kuhusu mada maalum. Udhibiti unaweza kufanywa kwa kufuta machapisho kwenye relay zake + Ingiza kati ya relay 1–3 zinazohifadhi kikundi hiki. Wateja wa Nostr hutumia mipangilio hii kujua mahali pa kupakua ujumbe na kutuma ujumbe wako. Metadata ya Mazungumzo ya Umma Mazungumzo ya Umma Relay za Sanduku la Nje/Nyumbani za Umma @@ -2714,10 +2694,7 @@ Mtumiaji wa kusoma tu Bonyeza na ushikilie kurekodi ujumbe Mazungumzo ya Relay - Mazungumzo ya relay ni vikundi vya mazungumzo vinavyodhibitiwa na relay yao ya nyumbani. - Yanaweza kuonekana na kila mtu kwenye Nostr na mtu yeyote anaweza kushiriki. - Ni mazuri kwa jamii wazi kuhusu mada maalum. Baadhi ya vikundi hivi ni vya muda mfupi - na hivyo ujumbe wa mazungumzo huisha baada ya muda + Mazungumzo ya relay ni vikundi vya mazungumzo vinavyodhibitiwa na relay yao ya nyumbani. Yanaweza kuonekana na kila mtu kwenye Nostr na mtu yeyote anaweza kushiriki. Ni mazuri kwa jamii wazi kuhusu mada maalum. Baadhi ya vikundi hivi ni vya muda mfupi na hivyo ujumbe wa mazungumzo huisha baada ya muda Mazungumzo ya Relay Matukio Aina diff --git a/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml b/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml index 3b46dde816..106be142e3 100644 --- a/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ta-rIN/strings.xml @@ -224,7 +224,7 @@ பயனர் IDயை நகலெடுக்கவும் பயனரைத் தடைநீக்கு இந்த பயனர் தடுக்கப்பட்டு/முடக்கப்பட்டுள்ளார். அவர்களின் இடுகைகள் மறைக்கப்பட்டுள்ளன. - npub, hex, பயனர்பெயர் + npub, hex, பயனர்பெயர் அழி பயன்பாட்டு இலச்சினை nsec / npub / hex தனிப்பட்ட சாவி @@ -272,17 +272,10 @@ தெரிந்தவற்றைப் படித்ததாகக் குறி புதியனவற்றைப் படித்ததாகக் குறி அனைத்தையும் படித்ததாகக் குறி - ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் - \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். - \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. - \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். - \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். - - கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. - \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. - + ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். + கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும் - %1$s க்கான பேட்ஜ் விருது படம் + %1$s க்கான பேட்ஜ் விருது படம் "பேட்ஜ் விருது படம் நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள் பேட்ஜ் விருது வழங்கப்பட்டது. பெறுநர்: @@ -304,7 +297,7 @@ தடைசெய் அழி தடைசெய் - புகார் + புகார் மீண்டும் காட்டாதே எரிதம் அல்லது மோசடிகள் அவதூறு அல்லது வெறுக்கத்தக்க நடத்தை @@ -871,7 +864,7 @@ பின்பற்றப்படும் சிட்டைகள் இவை நீங்கள் மற்றவர்களுக்கு பரிந்துரைக்கும் பயனர்களின் பட்டியல்கள். பொது பயனர்கள் மட்டுமே அனுமதிக்கப்படுவர். அங்கீகரிக்கப்பட்ட குறிப்பு - இந்த அரட்டைக் குழுவின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் + இந்த அரட்டைக் குழுவின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் இந்த சமூகத்தின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் பயனர் விருப்பங்கள் அமைப்புகளை தேடு @@ -965,9 +958,7 @@ புஷ் அறிவிப்புகளை முடக்கும் %1$s ஆப்பை பயன்படுத்துகிறது புஷ் அறிவிப்பு அமைவு - Push அறிவிப்புகளை பெற, [Unified Push](https://unifiedpush.org/) ஆதரிக்கும் எந்த பயன்பாட்டையும் நிறுவுங்கள், எடுத்துக்காட்டாக [Ntfy](https://ntfy.sh/). - நிறுவிய பின், அமைப்புகளில் நீங்கள் பயன்படுத்த விரும்பும் பயன்பாட்டை தேர்ந்தெடுங்கள். - + Push அறிவிப்புகளை பெற, [Unified Push](https://unifiedpush.org/) ஆதரிக்கும் எந்த பயன்பாட்டையும் நிறுவுங்கள், எடுத்துக்காட்டாக [Ntfy](https://ntfy.sh/). நிறுவிய பின், அமைப்புகளில் நீங்கள் பயன்படுத்த விரும்பும் பயன்பாட்டை தேர்ந்தெடுங்கள். நூல் விற்பனையாளருக்கு ஒரு செய்தி அனுப்பவும் வணக்கம், இது இன்னும் கிடைக்கிறதா? @@ -2016,15 +2007,7 @@ %1$s இலிருந்து இன்வாய்ஸை பெற முடியவில்லை: %2$s சுருக்கப்பட்ட கோப்பை திறக்க முடியவில்லை வாலட் கிடைக்கவில்லை - Nostr Wallet Connect (NWC)-ஐ ஆதரிக்கும் எந்த பணப்பை பயன்பாடுகளையும் Amethyst கண்டுபிடிக்கவில்லை. -\n\nநீங்கள் செய்யக்கூடியவை: -\n\t1. NWC ஆதரவை சரிபாருங்கள்: உங்கள் விருப்பமான பணப்பை பயன்பாடு Nostr Wallet Connect-உடன் இணக்கமானதா என இரட்டிப்பு சரிபாருங்கள். -\n\t2. இணைப்பை உருவாக்குங்கள்: உங்கள் பணப்பை பயன்பாட்டிற்கு சென்று புதிய NWC இணைப்பை உருவாக்குங்கள். -\n\t3. Amethyst-உடன் இணைக்குங்கள்: உங்கள் பணப்பை பொதுவாக மூன்று விருப்பங்களை வழங்கும்: -\n\t\t3.1 தானியங்கி இணைப்பு: Amethyst-ஐ தானாக திறந்து இணைக்க ஒரு பொத்தான். அவ்வாறிருந்தால், அந்த பொத்தானை அழுத்தி Amethyst-ஐ திறந்து புதிய திரையில் சேமி அழுத்துங்கள். -\n\t\t3.2 கைமுறை இணைப்பு: நீங்கள் நகலெடுக்கக்கூடிய Connection URI, இந்த திரையில் ஒட்டு ஐகானை அழுத்தி நேரடியாக உள்ளிடலாம். -\n\t\t3.3 QR குறியீடு: பணப்பை ஒரு QR குறியீட்டை உருவாக்கும், இந்த திரையில் QR குறியீடு பொத்தானிலிருந்து படிக்கலாம். - + Nostr Wallet Connect (NWC)-ஐ ஆதரிக்கும் எந்த பணப்பை பயன்பாடுகளையும் Amethyst கண்டுபிடிக்கவில்லை. \n\nநீங்கள் செய்யக்கூடியவை: \n\t1. NWC ஆதரவை சரிபாருங்கள்: உங்கள் விருப்பமான பணப்பை பயன்பாடு Nostr Wallet Connect-உடன் இணக்கமானதா என இரட்டிப்பு சரிபாருங்கள். \n\t2. இணைப்பை உருவாக்குங்கள்: உங்கள் பணப்பை பயன்பாட்டிற்கு சென்று புதிய NWC இணைப்பை உருவாக்குங்கள். \n\t3. Amethyst-உடன் இணைக்குங்கள்: உங்கள் பணப்பை பொதுவாக மூன்று விருப்பங்களை வழங்கும்: \n\t\t3.1 தானியங்கி இணைப்பு: Amethyst-ஐ தானாக திறந்து இணைக்க ஒரு பொத்தான். அவ்வாறிருந்தால், அந்த பொத்தானை அழுத்தி Amethyst-ஐ திறந்து புதிய திரையில் சேமி அழுத்துங்கள். \n\t\t3.2 கைமுறை இணைப்பு: நீங்கள் நகலெடுக்கக்கூடிய Connection URI, இந்த திரையில் ஒட்டு ஐகானை அழுத்தி நேரடியாக உள்ளிடலாம். \n\t\t3.3 QR குறியீடு: பணப்பை ஒரு QR குறியீட்டை உருவாக்கும், இந்த திரையில் QR குறியீடு பொத்தானிலிருந்து படிக்கலாம். உருவாக்கு நா ஆபத்து மண்டலம் @@ -2416,7 +2399,7 @@ மீடியாவிலிருந்து தனிப்பட்ட மெட்டாடேட்டாவை நீக்கத் தோல்வியடைந்தது. பதிவேற்றம் ரத்துசெய்யப்பட்டது. புக்மார்க்குகள் வெற்றிகரமாக இடம்பெயர்க்கப்பட்டன Lightning அமைப்பு இல்லை - மேலும் + மேலும் தனிப்பட்டதிற்கு நகர்த்து பொதுவிற்கு நகர்த்து அட்டை படத்தை பதிவேற்று @@ -2648,7 +2631,7 @@ இந்த இடுகையில் %1$d hashtag-ஐ விட அதிகம் உள்ளது இந்த இடுகையில் %1$d hashtags-ஐ விட அதிகம் உள்ளது - %1$s க்கான முன்னோட்ட அட்டைப் படம் + %1$s க்கான முன்னோட்ட அட்டைப் படம் தனியுரிமை விருப்பங்கள் தனியுரிமைக் கொள்கை தனிப்பட்ட செய்தியை மறைக்குறியாக்க இயலவில்லை \n \n %1$s மற்றும் %2$s க்கு இடையே தனிப்பட்ட/ குறியாக்கப்பட்ட உரையாடலில் நீங்கள் மேற்கோள் காட்டப்பட்டீர்கள். @@ -2673,11 +2656,8 @@ திருத்தத்தை முன்மொழிக filter.nostr.wine போன்ற ஒருங்கிணைப்பு relays, பயன்பாடு உங்கள் ஊட்டங்களை பதிவிறக்க பயன்படுத்த வேண்டும். இது அவுட்பாக்ஸ் மாதிரியை மாற்றுகிறது, பயன்பாட்டை உங்கள் பட்டியல்களில் உள்ள relays மட்டுமே இணைக்கும். பொது அரட்டை - பொது அரட்டைகள் Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் - அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. - அதன் relays-ல் இடுகைகளை நீக்குவதன் மூலம் மிதவாண்மையை கட்டுப்படுத்தலாம் - இந்த குழுவை ஹோஸ்ட் செய்யும் 1–3 relays-ஐ உள்ளிடவும். - Nostr கிளையன்கள் செய்திகளை எங்கிருந்து பதிவிறக்கம் செய்வது மற்றும் உங்கள் செய்திகளை எங்கே அனுப்புவது என்பதை அறிய இந்த அமைப்பை பயன்படுத்துகின்றன. + பொது அரட்டைகள் Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. அதன் relays-ல் இடுகைகளை நீக்குவதன் மூலம் மிதவாண்மையை கட்டுப்படுத்தலாம் + இந்த குழுவை ஹோஸ்ட் செய்யும் 1–3 relays-ஐ உள்ளிடவும். Nostr கிளையன்கள் செய்திகளை எங்கிருந்து பதிவிறக்கம் செய்வது மற்றும் உங்கள் செய்திகளை எங்கே அனுப்புவது என்பதை அறிய இந்த அமைப்பை பயன்படுத்துகின்றன. Relay கள் பொது அரட்டை மெட்டாடேட்டா பொது அரட்டைகள் @@ -2702,10 +2682,7 @@ படிக்க மட்டும் பயனர் செய்தி பதிவு செய்ய கிளிக் செய்து பிடிக்கவும் Relay அரட்டை - Relay அரட்டைகள் என்பவை அவற்றின் முகப்பு relay-ஆல் கட்டுப்படுத்தப்படும் அரட்டை குழுக்கள். - அவை Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். - அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. இந்த குழுக்களில் சில தற்காலிகமானவை - எனவே அரட்டை செய்திகள் காலப்போக்கில் மறைந்துவிடும் + Relay அரட்டைகள் என்பவை அவற்றின் முகப்பு relay-ஆல் கட்டுப்படுத்தப்படும் அரட்டை குழுக்கள். அவை Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. இந்த குழுக்களில் சில தற்காலிகமானவை எனவே அரட்டை செய்திகள் காலப்போக்கில் மறைந்துவிடும் Relay அரட்டைகள் நிகழ்வுகள் வகைகள் diff --git a/commonsUI/src/commonMain/composeResources/values-ta/strings.xml b/commonsUI/src/commonMain/composeResources/values-ta/strings.xml index 18a9e71315..210f73485f 100644 --- a/commonsUI/src/commonMain/composeResources/values-ta/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-ta/strings.xml @@ -211,7 +211,7 @@ பயனர் IDயை நகலெடுக்கவும் பயனரைத் தடைநீக்கு இந்த பயனர் தடுக்கப்பட்டு/முடக்கப்பட்டுள்ளார். அவர்களின் இடுகைகள் மறைக்கப்பட்டுள்ளன. - npub, hex, பயனர்பெயர் + npub, hex, பயனர்பெயர் அழி பயன்பாட்டு இலச்சினை nsec / npub / hex தனிப்பட்ட சாவி @@ -259,19 +259,10 @@ தெரிந்தவற்றைப் படித்ததாகக் குறி புதியனவற்றைப் படித்ததாகக் குறி அனைத்தையும் படித்ததாகக் குறி - - ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் - \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். - \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. - \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். - \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். - - - கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. - \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. - + ## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம். + கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது. என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும் - %1$s க்கான பேட்ஜ் விருது படம் + %1$s க்கான பேட்ஜ் விருது படம் "பேட்ஜ் விருது படம் நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள் பேட்ஜ் விருது வழங்கப்பட்டது. பெறுநர்: @@ -293,7 +284,7 @@ தடைசெய் அழி தடைசெய் - புகார் + புகார் மீண்டும் காட்டாதே எரிதம் அல்லது மோசடிகள் அவதூறு அல்லது வெறுக்கத்தக்க நடத்தை @@ -867,7 +858,7 @@ பின்பற்றப்படும் சிட்டைகள் இவை நீங்கள் மற்றவர்களுக்கு பரிந்துரைக்கும் பயனர்களின் பட்டியல்கள். பொது பயனர்கள் மட்டுமே அனுமதிக்கப்படுவர். அங்கீகரிக்கப்பட்ட குறிப்பு - இந்த அரட்டைக் குழுவின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் + இந்த அரட்டைக் குழுவின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் இந்த சமூகத்தின் விளக்கமும் விதிகளும் இன்னும் சேர்க்கபடவில்லை. உரிமையாளரை அணுகி அவற்றை சேர்க்க கோரவும் பயனர் விருப்பங்கள் அமைப்புகளை தேடு @@ -962,10 +953,7 @@ புஷ் அறிவிப்புகளை முடக்கும் %1$s ஆப்பை பயன்படுத்துகிறது புஷ் அறிவிப்பு அமைவு - - Push அறிவிப்புகளை பெற, [Unified Push](https://unifiedpush.org/) ஆதரிக்கும் எந்த பயன்பாட்டையும் நிறுவுங்கள், எடுத்துக்காட்டாக [Ntfy](https://ntfy.sh/). - நிறுவிய பின், அமைப்புகளில் நீங்கள் பயன்படுத்த விரும்பும் பயன்பாட்டை தேர்ந்தெடுங்கள். - + Push அறிவிப்புகளை பெற, [Unified Push](https://unifiedpush.org/) ஆதரிக்கும் எந்த பயன்பாட்டையும் நிறுவுங்கள், எடுத்துக்காட்டாக [Ntfy](https://ntfy.sh/). நிறுவிய பின், அமைப்புகளில் நீங்கள் பயன்படுத்த விரும்பும் பயன்பாட்டை தேர்ந்தெடுங்கள். நூல் விற்பனையாளருக்கு ஒரு செய்தி அனுப்பவும் வணக்கம், இது இன்னும் கிடைக்கிறதா? @@ -2058,15 +2046,7 @@ %1$s இலிருந்து இன்வாய்ஸை பெற முடியவில்லை: %2$s சுருக்கப்பட்ட கோப்பை திறக்க முடியவில்லை வாலட் கிடைக்கவில்லை - Nostr Wallet Connect (NWC)-ஐ ஆதரிக்கும் எந்த பணப்பை பயன்பாடுகளையும் Amethyst கண்டுபிடிக்கவில்லை. -\n\nநீங்கள் செய்யக்கூடியவை: -\n\t1. NWC ஆதரவை சரிபாருங்கள்: உங்கள் விருப்பமான பணப்பை பயன்பாடு Nostr Wallet Connect-உடன் இணக்கமானதா என இரட்டிப்பு சரிபாருங்கள். -\n\t2. இணைப்பை உருவாக்குங்கள்: உங்கள் பணப்பை பயன்பாட்டிற்கு சென்று புதிய NWC இணைப்பை உருவாக்குங்கள். -\n\t3. Amethyst-உடன் இணைக்குங்கள்: உங்கள் பணப்பை பொதுவாக மூன்று விருப்பங்களை வழங்கும்: -\n\t\t3.1 தானியங்கி இணைப்பு: Amethyst-ஐ தானாக திறந்து இணைக்க ஒரு பொத்தான். அவ்வாறிருந்தால், அந்த பொத்தானை அழுத்தி Amethyst-ஐ திறந்து புதிய திரையில் சேமி அழுத்துங்கள். -\n\t\t3.2 கைமுறை இணைப்பு: நீங்கள் நகலெடுக்கக்கூடிய Connection URI, இந்த திரையில் ஒட்டு ஐகானை அழுத்தி நேரடியாக உள்ளிடலாம். -\n\t\t3.3 QR குறியீடு: பணப்பை ஒரு QR குறியீட்டை உருவாக்கும், இந்த திரையில் QR குறியீடு பொத்தானிலிருந்து படிக்கலாம். - + Nostr Wallet Connect (NWC)-ஐ ஆதரிக்கும் எந்த பணப்பை பயன்பாடுகளையும் Amethyst கண்டுபிடிக்கவில்லை. \n\nநீங்கள் செய்யக்கூடியவை: \n\t1. NWC ஆதரவை சரிபாருங்கள்: உங்கள் விருப்பமான பணப்பை பயன்பாடு Nostr Wallet Connect-உடன் இணக்கமானதா என இரட்டிப்பு சரிபாருங்கள். \n\t2. இணைப்பை உருவாக்குங்கள்: உங்கள் பணப்பை பயன்பாட்டிற்கு சென்று புதிய NWC இணைப்பை உருவாக்குங்கள். \n\t3. Amethyst-உடன் இணைக்குங்கள்: உங்கள் பணப்பை பொதுவாக மூன்று விருப்பங்களை வழங்கும்: \n\t\t3.1 தானியங்கி இணைப்பு: Amethyst-ஐ தானாக திறந்து இணைக்க ஒரு பொத்தான். அவ்வாறிருந்தால், அந்த பொத்தானை அழுத்தி Amethyst-ஐ திறந்து புதிய திரையில் சேமி அழுத்துங்கள். \n\t\t3.2 கைமுறை இணைப்பு: நீங்கள் நகலெடுக்கக்கூடிய Connection URI, இந்த திரையில் ஒட்டு ஐகானை அழுத்தி நேரடியாக உள்ளிடலாம். \n\t\t3.3 QR குறியீடு: பணப்பை ஒரு QR குறியீட்டை உருவாக்கும், இந்த திரையில் QR குறியீடு பொத்தானிலிருந்து படிக்கலாம். உருவாக்கு நா ஆபத்து மண்டலம் @@ -2486,7 +2466,7 @@ மீடியாவிலிருந்து தனிப்பட்ட மெட்டாடேட்டாவை நீக்கத் தோல்வியடைந்தது. பதிவேற்றம் ரத்துசெய்யப்பட்டது. புக்மார்க்குகள் வெற்றிகரமாக இடம்பெயர்க்கப்பட்டன Lightning அமைப்பு இல்லை - மேலும் + மேலும் தனிப்பட்டதிற்கு நகர்த்து பொதுவிற்கு நகர்த்து அட்டை படத்தை பதிவேற்று @@ -2728,7 +2708,7 @@ இந்த இடுகையில் %1$d hashtag-ஐ விட அதிகம் உள்ளது இந்த இடுகையில் %1$d hashtags-ஐ விட அதிகம் உள்ளது - %1$s க்கான முன்னோட்ட அட்டைப் படம் + %1$s க்கான முன்னோட்ட அட்டைப் படம் தனியுரிமை விருப்பங்கள் தனியுரிமைக் கொள்கை தனிப்பட்ட செய்தியை மறைக்குறியாக்க இயலவில்லை \n \n %1$s மற்றும் %2$s க்கு இடையே தனிப்பட்ட/ குறியாக்கப்பட்ட உரையாடலில் நீங்கள் மேற்கோள் காட்டப்பட்டீர்கள். @@ -2754,11 +2734,8 @@ Proxy Relays filter.nostr.wine போன்ற ஒருங்கிணைப்பு relays, பயன்பாடு உங்கள் ஊட்டங்களை பதிவிறக்க பயன்படுத்த வேண்டும். இது அவுட்பாக்ஸ் மாதிரியை மாற்றுகிறது, பயன்பாட்டை உங்கள் பட்டியல்களில் உள்ள relays மட்டுமே இணைக்கும். பொது அரட்டை - பொது அரட்டைகள் Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் - அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. - அதன் relays-ல் இடுகைகளை நீக்குவதன் மூலம் மிதவாண்மையை கட்டுப்படுத்தலாம் - இந்த குழுவை ஹோஸ்ட் செய்யும் 1–3 relays-ஐ உள்ளிடவும். - Nostr கிளையன்கள் செய்திகளை எங்கிருந்து பதிவிறக்கம் செய்வது மற்றும் உங்கள் செய்திகளை எங்கே அனுப்புவது என்பதை அறிய இந்த அமைப்பை பயன்படுத்துகின்றன. + பொது அரட்டைகள் Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. அதன் relays-ல் இடுகைகளை நீக்குவதன் மூலம் மிதவாண்மையை கட்டுப்படுத்தலாம் + இந்த குழுவை ஹோஸ்ட் செய்யும் 1–3 relays-ஐ உள்ளிடவும். Nostr கிளையன்கள் செய்திகளை எங்கிருந்து பதிவிறக்கம் செய்வது மற்றும் உங்கள் செய்திகளை எங்கே அனுப்புவது என்பதை அறிய இந்த அமைப்பை பயன்படுத்துகின்றன. Relay கள் பொது அரட்டை மெட்டாடேட்டா பொது அரட்டைகள் @@ -2783,10 +2760,7 @@ படிக்க மட்டும் பயனர் செய்தி பதிவு செய்ய கிளிக் செய்து பிடிக்கவும் Relay அரட்டை - Relay அரட்டைகள் என்பவை அவற்றின் முகப்பு relay-ஆல் கட்டுப்படுத்தப்படும் அரட்டை குழுக்கள். - அவை Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். - அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. இந்த குழுக்களில் சில தற்காலிகமானவை - எனவே அரட்டை செய்திகள் காலப்போக்கில் மறைந்துவிடும் + Relay அரட்டைகள் என்பவை அவற்றின் முகப்பு relay-ஆல் கட்டுப்படுத்தப்படும் அரட்டை குழுக்கள். அவை Nostr-ல் அனைவருக்கும் தெரியும் மற்றும் யாரும் அவற்றில் பங்கேற்கலாம். அவை குறிப்பிட்ட தலைப்புகளை சுற்றிய திறந்த சமூகங்களுக்கு மிகவும் ஏற்றவை. இந்த குழுக்களில் சில தற்காலிகமானவை எனவே அரட்டை செய்திகள் காலப்போக்கில் மறைந்துவிடும் Relay அரட்டைகள் நிகழ்வுகள் IPs diff --git a/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml b/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml index 79bd7785d6..ae6a8e1778 100644 --- a/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-th-rTH/strings.xml @@ -158,7 +158,7 @@ การ zap แบบ on-chain ต้องใช้อย่างน้อย %1$s sats ยอดคงเหลือใน mint ที่ผู้รับยอมรับไม่เพียงพอ เติมเงินในกระเป๋า Cashu ก่อน ค่าธรรมเนียมเครือข่าย - ส่งทิปให้เบา ๆ + ส่งทิปให้เบา ๆ โน้ตถึงผู้รับ ขอบคุณมาก! จำนวนในหน่วย sat @@ -269,14 +269,8 @@ ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่ ทพเครื่องหมายว่าอ่านแล้วทั้งหมด - ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ - \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ - - \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ - \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ - \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน - สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ - \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ + ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน + สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน ภาพเหรียญตราสําหรับ %1$s "รูปภาพรางวัลป้าย @@ -1831,7 +1825,7 @@ ย้อนกลับ สำรองข้อมูลรหัสลับ แบดจ์ - เกิดข้อผิดพลาดในการตรวจสอบ + เกิดข้อผิดพลาดในการตรวจสอบ เกิดข้อผิดพลาดจากการยืนยันตนด้วยชีวภาพ เกิดข้อผิดพลาดจากการยืนยันตนด้วยชีวภาพ: Error: %1$s บล๊อก @@ -1894,7 +1888,7 @@ โทเคน Cashu กำลังตรวจสอบ mint… ไม่สามารถใช้งาน Cashu - ผู้ให้บริการ Mint เกิดข้อผิดพลาด : %1$s + ผู้ให้บริการ Mint เกิดข้อผิดพลาด : %1$s รับแล้ว ส่งแล้ว Mints ที่ตรงกัน @@ -1986,15 +1980,7 @@ ไม่สามารถดึงใบแจ้งหนี้จาก %1$s: %2$s ไม่สามารถเปิดดูข้อมูลที่ถูกบีบอัดได้ ไม่พบกระเป๋าเงิน - Amethyst ไม่พบแอปกระเป๋าเงินที่รองรับ Nostr Wallet Connect (NWC) -\n\nสิ่งที่คุณทำได้: -\n\t1. ตรวจสอบการรองรับ NWC: ตรวจสอบอีกครั้งว่าแอปกระเป๋าเงินที่คุณต้องการใช้รองรับ Nostr Wallet Connect หรือไม่ -\n\t2. สร้างการเชื่อมต่อ: ไปที่แอปกระเป๋าเงินของคุณและสร้างการเชื่อมต่อ NWC ใหม่ -\n\t3. เชื่อมกับ Amethyst: กระเป๋าเงินของคุณมักจะให้ตัวเลือกสามแบบ: -\n\t\t3.1 ลิงก์อัตโนมัติ: ปุ่มเพื่อเปิดและเชื่อมต่อกับ Amethyst โดยอัตโนมัติ หากมี ให้กดปุ่มนั้น เปิด Amethyst และกดบันทึกที่หน้าจอใหม่ -\n\t\t3.2 ลิงก์ด้วยตนเอง: URI การเชื่อมต่อที่คุณสามารถคัดลอกและกดไอคอนวางบนหน้าจอนี้เพื่อป้อนโดยตรง -\n\t\t3.3 QR Code: กระเป๋าเงินสร้าง QR Code ที่คุณสามารถอ่านได้จากปุ่ม QR code ในหน้าจอนี้ - + Amethyst ไม่พบแอปกระเป๋าเงินที่รองรับ Nostr Wallet Connect (NWC) \n\nสิ่งที่คุณทำได้: \n\t1. ตรวจสอบการรองรับ NWC: ตรวจสอบอีกครั้งว่าแอปกระเป๋าเงินที่คุณต้องการใช้รองรับ Nostr Wallet Connect หรือไม่ \n\t2. สร้างการเชื่อมต่อ: ไปที่แอปกระเป๋าเงินของคุณและสร้างการเชื่อมต่อ NWC ใหม่ \n\t3. เชื่อมกับ Amethyst: กระเป๋าเงินของคุณมักจะให้ตัวเลือกสามแบบ: \n\t\t3.1 ลิงก์อัตโนมัติ: ปุ่มเพื่อเปิดและเชื่อมต่อกับ Amethyst โดยอัตโนมัติ หากมี ให้กดปุ่มนั้น เปิด Amethyst และกดบันทึกที่หน้าจอใหม่ \n\t\t3.2 ลิงก์ด้วยตนเอง: URI การเชื่อมต่อที่คุณสามารถคัดลอกและกดไอคอนวางบนหน้าจอนี้เพื่อป้อนโดยตรง \n\t\t3.3 QR Code: กระเป๋าเงินสร้าง QR Code ที่คุณสามารถอ่านได้จากปุ่ม QR code ในหน้าจอนี้ สร้าง วัน เขตอันตราย diff --git a/commonsUI/src/commonMain/composeResources/values-th/strings.xml b/commonsUI/src/commonMain/composeResources/values-th/strings.xml index 60a0ddb5c5..a4d606f00b 100644 --- a/commonsUI/src/commonMain/composeResources/values-th/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-th/strings.xml @@ -144,7 +144,7 @@ การ zap แบบ on-chain ต้องใช้อย่างน้อย %1$s sats ยอดคงเหลือใน mint ที่ผู้รับยอมรับไม่เพียงพอ เติมเงินในกระเป๋า Cashu ก่อน ค่าธรรมเนียมเครือข่าย - ส่งทิปให้เบา ๆ + ส่งทิปให้เบา ๆ โน้ตถึงผู้รับ ขอบคุณมาก! จำนวนในหน่วย sat @@ -257,14 +257,8 @@ ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่ ทพเครื่องหมายว่าอ่านแล้วทั้งหมด - ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ - \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ - - \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ - \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ - \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน - สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ - \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ + ## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน + สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้ เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน ภาพเหรียญตราสําหรับ %1$s "รูปภาพรางวัลป้าย @@ -1883,7 +1877,7 @@ ย้อนกลับ สำรองข้อมูลรหัสลับ แบดจ์ - เกิดข้อผิดพลาดในการตรวจสอบ + เกิดข้อผิดพลาดในการตรวจสอบ เกิดข้อผิดพลาดจากการยืนยันตนด้วยชีวภาพ เกิดข้อผิดพลาดจากการยืนยันตนด้วยชีวภาพ: Error: %1$s บล๊อก @@ -1950,7 +1944,7 @@ โทเคน Cashu กำลังตรวจสอบ mint… ไม่สามารถใช้งาน Cashu - ผู้ให้บริการ Mint เกิดข้อผิดพลาด : %1$s + ผู้ให้บริการ Mint เกิดข้อผิดพลาด : %1$s รับแล้ว ส่งแล้ว Mints ที่ตรงกัน @@ -2042,15 +2036,7 @@ ไม่สามารถดึงใบแจ้งหนี้จาก %1$s: %2$s ไม่สามารถเปิดดูข้อมูลที่ถูกบีบอัดได้ ไม่พบกระเป๋าเงิน - Amethyst ไม่พบแอปกระเป๋าเงินที่รองรับ Nostr Wallet Connect (NWC) -\n\nสิ่งที่คุณทำได้: -\n\t1. ตรวจสอบการรองรับ NWC: ตรวจสอบอีกครั้งว่าแอปกระเป๋าเงินที่คุณต้องการใช้รองรับ Nostr Wallet Connect หรือไม่ -\n\t2. สร้างการเชื่อมต่อ: ไปที่แอปกระเป๋าเงินของคุณและสร้างการเชื่อมต่อ NWC ใหม่ -\n\t3. เชื่อมกับ Amethyst: กระเป๋าเงินของคุณมักจะให้ตัวเลือกสามแบบ: -\n\t\t3.1 ลิงก์อัตโนมัติ: ปุ่มเพื่อเปิดและเชื่อมต่อกับ Amethyst โดยอัตโนมัติ หากมี ให้กดปุ่มนั้น เปิด Amethyst และกดบันทึกที่หน้าจอใหม่ -\n\t\t3.2 ลิงก์ด้วยตนเอง: URI การเชื่อมต่อที่คุณสามารถคัดลอกและกดไอคอนวางบนหน้าจอนี้เพื่อป้อนโดยตรง -\n\t\t3.3 QR Code: กระเป๋าเงินสร้าง QR Code ที่คุณสามารถอ่านได้จากปุ่ม QR code ในหน้าจอนี้ - + Amethyst ไม่พบแอปกระเป๋าเงินที่รองรับ Nostr Wallet Connect (NWC) \n\nสิ่งที่คุณทำได้: \n\t1. ตรวจสอบการรองรับ NWC: ตรวจสอบอีกครั้งว่าแอปกระเป๋าเงินที่คุณต้องการใช้รองรับ Nostr Wallet Connect หรือไม่ \n\t2. สร้างการเชื่อมต่อ: ไปที่แอปกระเป๋าเงินของคุณและสร้างการเชื่อมต่อ NWC ใหม่ \n\t3. เชื่อมกับ Amethyst: กระเป๋าเงินของคุณมักจะให้ตัวเลือกสามแบบ: \n\t\t3.1 ลิงก์อัตโนมัติ: ปุ่มเพื่อเปิดและเชื่อมต่อกับ Amethyst โดยอัตโนมัติ หากมี ให้กดปุ่มนั้น เปิด Amethyst และกดบันทึกที่หน้าจอใหม่ \n\t\t3.2 ลิงก์ด้วยตนเอง: URI การเชื่อมต่อที่คุณสามารถคัดลอกและกดไอคอนวางบนหน้าจอนี้เพื่อป้อนโดยตรง \n\t\t3.3 QR Code: กระเป๋าเงินสร้าง QR Code ที่คุณสามารถอ่านได้จากปุ่ม QR code ในหน้าจอนี้ สร้าง วัน เขตอันตราย diff --git a/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml b/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml index ac074b789c..59fd97ae80 100644 --- a/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-tr-rTR/strings.xml @@ -71,7 +71,7 @@ QR Tara Yine De Göster Bu gönderi, gizlediğiniz kullanıcıları veya kelimeleri içerdiği için gizlendi - Gönderi uygun değil olarak işaretlendi tarafından: + Gönderi uygun değil olarak işaretlendi tarafından: Gönderi bulunamadı Kanal Resmi Referanslı etkinlik bulunamadı @@ -272,15 +272,8 @@ Tüm bilinenleri okundu olarak işaretle Tüm yenileri okundu olarak işaretle Tümünü okundu olarak işaretle - ## Anahtar Yedekleme ve Güvenlik İpuçları - \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. - \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. - \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. - \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. - - Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. - \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. - + ## Anahtar Yedekleme ve Güvenlik İpuçları \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. + Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. Gizli anahtarımı şifrele ve kopyala %1$s için rozet ödülü görseli "Rozet ödülü görseli @@ -966,9 +959,7 @@ Push Bildirimlerini Devre Dışı Bırakır %1$s uygulamasını kullanır Push Bildirim Kurulumu - Push bildirimleri almak için [Ntfy](https://ntfy.sh/) gibi [Unified Push](https://unifiedpush.org/) destekleyen herhangi bir uygulama yükleyin. - Yükledikten sonra, Ayarlar'da kullanmak istediğiniz uygulamayı seçin. - + Push bildirimleri almak için [Ntfy](https://ntfy.sh/) gibi [Unified Push](https://unifiedpush.org/) destekleyen herhangi bir uygulama yükleyin. Yükledikten sonra, Ayarlar'da kullanmak istediğiniz uygulamayı seçin. Konu Satıcıya mesaj gönderin Merhaba, bu hâlâ mevcut mu? @@ -2024,15 +2015,7 @@ %1$s'den fatura alınamadı: %2$s Sıkıştırılmış dosya açılamadı Cüzdan bulunamadı - Amethyst, Nostr Wallet Connect (NWC) destekleyen herhangi bir cüzdan uygulaması bulamadı. -\n\nYapabilecekleriniz: -\n\t1. NWC Desteğini Doğrulayın: Tercih ettiğiniz cüzdan uygulamasının Nostr Wallet Connect ile uyumlu olup olmadığını iki kez kontrol edin. -\n\t2. Bağlantı Oluşturun: Cüzdan uygulamanıza gidin ve yeni bir NWC bağlantısı oluşturun. -\n\t3. Amethyst'e Bağlayın: Cüzdanınız genellikle size üç seçenek sunar: -\n\t\t3.1 Otomatik Bağlantı: Amethyst'i otomatik olarak açıp bağlamak için bir düğme. Öyleyse o düğmeye tıklayın, Amethyst'i açın ve yeni ekranda kaydet'e basın. -\n\t\t3.2 Manuel Bağlantı: Doğrudan girmek için bu ekrandaki yapıştır simgesine tıklayabileceğiniz bir Bağlantı URI'si kopyalayın. -\n\t\t3.3 QR Kodu: Cüzdan, bu ekrandaki QR kodu düğmesiyle okuyabileceğiniz bir QR kodu oluşturur. - + Amethyst, Nostr Wallet Connect (NWC) destekleyen herhangi bir cüzdan uygulaması bulamadı. \n\nYapabilecekleriniz: \n\t1. NWC Desteğini Doğrulayın: Tercih ettiğiniz cüzdan uygulamasının Nostr Wallet Connect ile uyumlu olup olmadığını iki kez kontrol edin. \n\t2. Bağlantı Oluşturun: Cüzdan uygulamanıza gidin ve yeni bir NWC bağlantısı oluşturun. \n\t3. Amethyst'e Bağlayın: Cüzdanınız genellikle size üç seçenek sunar: \n\t\t3.1 Otomatik Bağlantı: Amethyst'i otomatik olarak açıp bağlamak için bir düğme. Öyleyse o düğmeye tıklayın, Amethyst'i açın ve yeni ekranda kaydet'e basın. \n\t\t3.2 Manuel Bağlantı: Doğrudan girmek için bu ekrandaki yapıştır simgesine tıklayabileceğiniz bir Bağlantı URI'si kopyalayın. \n\t\t3.3 QR Kodu: Cüzdan, bu ekrandaki QR kodu düğmesiyle okuyabileceğiniz bir QR kodu oluşturur. Oluştur g Tehlike Bölgesi @@ -2677,11 +2660,8 @@ Proxy Relay'leri Uygulamanın akışlarınızı indirmek için kullanması gereken filter.nostr.wine gibi toplayıcı relay'ler. Bu, giden kutusu modelinin yerini alır ve uygulamanın yalnızca listelerinizdeki relay'lere bağlanmasını sağlar. Herkese Açık Chat - Genel sohbetler Nostr'daki herkese görünürdür ve herkes - katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. - Moderasyon, relay'lerindeki gönderilerin silinmesiyle kontrol edilebilir - Bu grubu barındıran 1–3 relay ekleyin. - Nostr istemcileri mesajları nereden indireceğini ve mesajlarınızı nereye göndereceğini öğrenmek için bu ayarı kullanır. + Genel sohbetler Nostr'daki herkese görünürdür ve herkes katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. Moderasyon, relay'lerindeki gönderilerin silinmesiyle kontrol edilebilir + Bu grubu barındıran 1–3 relay ekleyin. Nostr istemcileri mesajları nereden indireceğini ve mesajlarınızı nereye göndereceğini öğrenmek için bu ayarı kullanır. relay'ler Genel Sohbet Meta Verisi Genel Sohbetler @@ -2706,10 +2686,7 @@ Salt okunur kullanıcı Sesli mesaj kaydetmek için tıklayıp basılı tutun relay Sohbeti - relay sohbetleri, ana relay'leri tarafından kontrol edilen sohbet gruplarıdır. - Nostr'daki herkese görünürdür ve herkes katılabilir. - Belirli konular etrafında açık topluluklar için idealdirler. Bu grupların bir kısmı geçici niteliktedir - ve bu nedenle sohbet mesajları zamanla silinir + relay sohbetleri, ana relay'leri tarafından kontrol edilen sohbet gruplarıdır. Nostr'daki herkese görünürdür ve herkes katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. Bu grupların bir kısmı geçici niteliktedir ve bu nedenle sohbet mesajları zamanla silinir relay Sohbetleri Etkinlikler IP'ler diff --git a/commonsUI/src/commonMain/composeResources/values-tr/strings.xml b/commonsUI/src/commonMain/composeResources/values-tr/strings.xml index 989465fdb4..7716fa9b4b 100644 --- a/commonsUI/src/commonMain/composeResources/values-tr/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-tr/strings.xml @@ -51,7 +51,7 @@ QR Tara Yine De Göster Bu gönderi, gizlediğiniz kullanıcıları veya kelimeleri içerdiği için gizlendi - Gönderi uygun değil olarak işaretlendi tarafından: + Gönderi uygun değil olarak işaretlendi tarafından: Gönderi bulunamadı 👀 Kanal Resmi @@ -259,17 +259,8 @@ Tüm bilinenleri okundu olarak işaretle Tüm yenileri okundu olarak işaretle Tümünü okundu olarak işaretle - - ## Anahtar Yedekleme ve Güvenlik İpuçları - \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. - \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. - \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. - \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. - - - Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. - \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. - + ## Anahtar Yedekleme ve Güvenlik İpuçları \n\nHesabınız bir gizli anahtarla korunmaktadır. Anahtar, **nsec1** ile başlayan uzun bir karakter dizisidir. Bu gizli anahtara erişimi olan herkes kimliğiniz adına gönderi yapabilir ve kimliğinizi değiştirebilir. \n\n- Gizli anahtarınızı güvenmediğiniz herhangi bir web sitesine veya yazılıma **koymayın**. \n- Amethyst geliştiricileri gizli anahtarınızı **asla** istemez. \n- Hesap kurtarma için gizli anahtarınızın güvenli bir yedeğini **alın**. Bir parola yöneticisi kullanmanızı öneririz. + Ek güvenlik için anahtarınızı bir parola ile şifreleyebilirsiniz. Bu anahtar **ncryptsec1** ile başlar ve parolanız olmadan kullanılamaz. \n\nParolanızı kaybederseniz anahtarınızı kurtaramazsınız. Gizli anahtarımı şifrele ve kopyala %1$s için rozet ödülü görseli "Rozet ödülü görseli @@ -962,10 +953,7 @@ Push Bildirimlerini Devre Dışı Bırakır %1$s uygulamasını kullanır Push Bildirim Kurulumu - - Push bildirimleri almak için [Ntfy](https://ntfy.sh/) gibi [Unified Push](https://unifiedpush.org/) destekleyen herhangi bir uygulama yükleyin. - Yükledikten sonra, Ayarlar'da kullanmak istediğiniz uygulamayı seçin. - + Push bildirimleri almak için [Ntfy](https://ntfy.sh/) gibi [Unified Push](https://unifiedpush.org/) destekleyen herhangi bir uygulama yükleyin. Yükledikten sonra, Ayarlar'da kullanmak istediğiniz uygulamayı seçin. Konu Satıcıya mesaj gönderin Merhaba, bu hâlâ mevcut mu? @@ -2058,15 +2046,7 @@ %1$s'den fatura alınamadı: %2$s Sıkıştırılmış dosya açılamadı Cüzdan bulunamadı - Amethyst, Nostr Wallet Connect (NWC) destekleyen herhangi bir cüzdan uygulaması bulamadı. -\n\nYapabilecekleriniz: -\n\t1. NWC Desteğini Doğrulayın: Tercih ettiğiniz cüzdan uygulamasının Nostr Wallet Connect ile uyumlu olup olmadığını iki kez kontrol edin. -\n\t2. Bağlantı Oluşturun: Cüzdan uygulamanıza gidin ve yeni bir NWC bağlantısı oluşturun. -\n\t3. Amethyst'e Bağlayın: Cüzdanınız genellikle size üç seçenek sunar: -\n\t\t3.1 Otomatik Bağlantı: Amethyst'i otomatik olarak açıp bağlamak için bir düğme. Öyleyse o düğmeye tıklayın, Amethyst'i açın ve yeni ekranda kaydet'e basın. -\n\t\t3.2 Manuel Bağlantı: Doğrudan girmek için bu ekrandaki yapıştır simgesine tıklayabileceğiniz bir Bağlantı URI'si kopyalayın. -\n\t\t3.3 QR Kodu: Cüzdan, bu ekrandaki QR kodu düğmesiyle okuyabileceğiniz bir QR kodu oluşturur. - + Amethyst, Nostr Wallet Connect (NWC) destekleyen herhangi bir cüzdan uygulaması bulamadı. \n\nYapabilecekleriniz: \n\t1. NWC Desteğini Doğrulayın: Tercih ettiğiniz cüzdan uygulamasının Nostr Wallet Connect ile uyumlu olup olmadığını iki kez kontrol edin. \n\t2. Bağlantı Oluşturun: Cüzdan uygulamanıza gidin ve yeni bir NWC bağlantısı oluşturun. \n\t3. Amethyst'e Bağlayın: Cüzdanınız genellikle size üç seçenek sunar: \n\t\t3.1 Otomatik Bağlantı: Amethyst'i otomatik olarak açıp bağlamak için bir düğme. Öyleyse o düğmeye tıklayın, Amethyst'i açın ve yeni ekranda kaydet'e basın. \n\t\t3.2 Manuel Bağlantı: Doğrudan girmek için bu ekrandaki yapıştır simgesine tıklayabileceğiniz bir Bağlantı URI'si kopyalayın. \n\t\t3.3 QR Kodu: Cüzdan, bu ekrandaki QR kodu düğmesiyle okuyabileceğiniz bir QR kodu oluşturur. Oluştur g Tehlike Bölgesi @@ -2754,11 +2734,8 @@ Proxy Relay'leri Uygulamanın akışlarınızı indirmek için kullanması gereken filter.nostr.wine gibi toplayıcı relay'ler. Bu, giden kutusu modelinin yerini alır ve uygulamanın yalnızca listelerinizdeki relay'lere bağlanmasını sağlar. Herkese Açık Chat - Genel sohbetler Nostr'daki herkese görünürdür ve herkes - katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. - Moderasyon, relay'lerindeki gönderilerin silinmesiyle kontrol edilebilir - Bu grubu barındıran 1–3 relay ekleyin. - Nostr istemcileri mesajları nereden indireceğini ve mesajlarınızı nereye göndereceğini öğrenmek için bu ayarı kullanır. + Genel sohbetler Nostr'daki herkese görünürdür ve herkes katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. Moderasyon, relay'lerindeki gönderilerin silinmesiyle kontrol edilebilir + Bu grubu barındıran 1–3 relay ekleyin. Nostr istemcileri mesajları nereden indireceğini ve mesajlarınızı nereye göndereceğini öğrenmek için bu ayarı kullanır. relay'ler Genel Sohbet Meta Verisi Genel Sohbetler @@ -2783,10 +2760,7 @@ Salt okunur kullanıcı Sesli mesaj kaydetmek için tıklayıp basılı tutun relay Sohbeti - relay sohbetleri, ana relay'leri tarafından kontrol edilen sohbet gruplarıdır. - Nostr'daki herkese görünürdür ve herkes katılabilir. - Belirli konular etrafında açık topluluklar için idealdirler. Bu grupların bir kısmı geçici niteliktedir - ve bu nedenle sohbet mesajları zamanla silinir + relay sohbetleri, ana relay'leri tarafından kontrol edilen sohbet gruplarıdır. Nostr'daki herkese görünürdür ve herkes katılabilir. Belirli konular etrafında açık topluluklar için idealdirler. Bu grupların bir kısmı geçici niteliktedir ve bu nedenle sohbet mesajları zamanla silinir relay Sohbetleri Etkinlikler IP'ler diff --git a/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml b/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml index a6e1bee6c5..5e60c8e1da 100644 --- a/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uk-rUA/strings.xml @@ -225,7 +225,7 @@ Скопіювати ID користувача Розблокувати користувача Цього користувача заблоковано/заглушено. Їхні публікації приховано. - npub, hex, нікнейм + npub, hex, нікнейм Очистити Логотип додатка nsec / npub / приватний ключ в hex @@ -273,15 +273,8 @@ Позначити всі відомі прочитаними Позначити всі нові прочитаними Позначити все прочитаним - ## Поради щодо резервного копіювання та безпеки ключа - \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. - \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. - \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. - \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. - - Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. - \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. - + ## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. + Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. Зашифрувати та скопіювати мій секретний ключ Картинка значка-нагороди %1$s "Зображення нагороди значком @@ -970,9 +963,7 @@ Вимикає push-сповіщення Використовує додаток %1$s Налаштування push-сповіщень - Щоб отримувати push-сповіщення, встановіть будь-який додаток з підтримкою [Unified Push](https://unifiedpush.org/), наприклад [Ntfy](https://ntfy.sh/). - Після встановлення виберіть потрібний додаток у налаштуваннях. - + Щоб отримувати push-сповіщення, встановіть будь-який додаток з підтримкою [Unified Push](https://unifiedpush.org/), наприклад [Ntfy](https://ntfy.sh/). Після встановлення виберіть потрібний додаток у налаштуваннях. Тема Надіслати продавцю повідомлення Привіт, це ще доступно? @@ -2037,15 +2028,7 @@ Не вдалося отримати інвойс від %1$s: %2$s Не вдалося відкрити стиснутий файл Гаманець не знайдено - Amethyst не знайшов жодного гаманця, який підтримує Nostr Wallet Connect (NWC). -\n\nЩо можна зробити: -\n\t1. Перевірте підтримку NWC: переконайтеся, що ваш гаманець сумісний з Nostr Wallet Connect. -\n\t2. Створіть підключення: відкрийте гаманець і створіть нове NWC-підключення. -\n\t3. Прив'яжіть до Amethyst: зазвичай гаманець надає три варіанти: -\n\t\t3.1 Автоматичне підключення: кнопка для автоматичного відкриття та підключення до Amethyst. Якщо так — натисніть її, відкрийте Amethyst і збережіть налаштування на новому екрані. -\n\t\t3.2 Ручне підключення: URI підключення, який можна скопіювати та вставити за допомогою значка вставки на цьому екрані. -\n\t\t3.3 QR-код: гаманець створює QR-код, який можна зчитати за допомогою кнопки QR-коду на цьому екрані. - + Amethyst не знайшов жодного гаманця, який підтримує Nostr Wallet Connect (NWC). \n\nЩо можна зробити: \n\t1. Перевірте підтримку NWC: переконайтеся, що ваш гаманець сумісний з Nostr Wallet Connect. \n\t2. Створіть підключення: відкрийте гаманець і створіть нове NWC-підключення. \n\t3. Прив'яжіть до Amethyst: зазвичай гаманець надає три варіанти: \n\t\t3.1 Автоматичне підключення: кнопка для автоматичного відкриття та підключення до Amethyst. Якщо так — натисніть її, відкрийте Amethyst і збережіть налаштування на новому екрані. \n\t\t3.2 Ручне підключення: URI підключення, який можна скопіювати та вставити за допомогою значка вставки на цьому екрані. \n\t\t3.3 QR-код: гаманець створює QR-код, який можна зчитати за допомогою кнопки QR-коду на цьому екрані. Створити дн Небезпечна зона @@ -2726,11 +2709,8 @@ Proxy relay-сервери Агрегаторні relay-сервери, які застосунок має використовувати для завантаження ваших стрічок, наприклад filter.nostr.wine. Це замінює модель outbox і змусить застосунок підключатися лише до relay-серверів у ваших списках. Публічний чат - Публічні чати видимі всім у Nostr, і кожен - може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. - Модерацію можна здійснювати, видаляючи публікації на відповідних relay - Вкажіть від 1 до 3 relay, що розміщують цю групу. - Клієнти Nostr використовують це налаштування, щоб знати, звідки завантажувати повідомлення та куди їх надсилати. + Публічні чати видимі всім у Nostr, і кожен може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. Модерацію можна здійснювати, видаляючи публікації на відповідних relay + Вкажіть від 1 до 3 relay, що розміщують цю групу. Клієнти Nostr використовують це налаштування, щоб знати, звідки завантажувати повідомлення та куди їх надсилати. Relay Метадані публічного чату Публічні чати @@ -2755,10 +2735,7 @@ Користувач лише для читання Натисніть і утримуйте, щоб записати повідомлення Чат relay - Чати relay — це групи чатів, керовані їхнім домашнім relay. - Вони видимі всім у Nostr, і кожен може брати в них участь. - Вони чудово підходять для відкритих спільнот за певними темами. Деякі з цих груп є тимчасовими, - і тому повідомлення чату зникають з часом + Чати relay — це групи чатів, керовані їхнім домашнім relay. Вони видимі всім у Nostr, і кожен може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. Деякі з цих груп є тимчасовими, і тому повідомлення чату зникають з часом Чати relay Події IP-адреси diff --git a/commonsUI/src/commonMain/composeResources/values-uk/strings.xml b/commonsUI/src/commonMain/composeResources/values-uk/strings.xml index 53159e447e..bc7b9935b3 100644 --- a/commonsUI/src/commonMain/composeResources/values-uk/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uk/strings.xml @@ -215,7 +215,7 @@ Скопіювати ID користувача Розблокувати користувача Цього користувача заблоковано/заглушено. Їхні публікації приховано. - npub, hex, нікнейм + npub, hex, нікнейм Очистити Логотип додатка nsec / npub / приватний ключ в hex @@ -263,17 +263,8 @@ Позначити всі відомі прочитаними Позначити всі нові прочитаними Позначити все прочитаним - - ## Поради щодо резервного копіювання та безпеки ключа - \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. - \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. - \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. - \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. - - - Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. - \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. - + ## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів. + Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ. Зашифрувати та скопіювати мій секретний ключ Картинка значка-нагороди %1$s "Зображення нагороди значком @@ -966,10 +957,7 @@ Вимикає push-сповіщення Використовує додаток %1$s Налаштування push-сповіщень - - Щоб отримувати push-сповіщення, встановіть будь-який додаток з підтримкою [Unified Push](https://unifiedpush.org/), наприклад [Ntfy](https://ntfy.sh/). - Після встановлення виберіть потрібний додаток у налаштуваннях. - + Щоб отримувати push-сповіщення, встановіть будь-який додаток з підтримкою [Unified Push](https://unifiedpush.org/), наприклад [Ntfy](https://ntfy.sh/). Після встановлення виберіть потрібний додаток у налаштуваннях. Тема Надіслати продавцю повідомлення Привіт, це ще доступно? @@ -2078,15 +2066,7 @@ Не вдалося отримати інвойс від %1$s: %2$s Не вдалося відкрити стиснутий файл Гаманець не знайдено - Amethyst не знайшов жодного гаманця, який підтримує Nostr Wallet Connect (NWC). -\n\nЩо можна зробити: -\n\t1. Перевірте підтримку NWC: переконайтеся, що ваш гаманець сумісний з Nostr Wallet Connect. -\n\t2. Створіть підключення: відкрийте гаманець і створіть нове NWC-підключення. -\n\t3. Прив'яжіть до Amethyst: зазвичай гаманець надає три варіанти: -\n\t\t3.1 Автоматичне підключення: кнопка для автоматичного відкриття та підключення до Amethyst. Якщо так — натисніть її, відкрийте Amethyst і збережіть налаштування на новому екрані. -\n\t\t3.2 Ручне підключення: URI підключення, який можна скопіювати та вставити за допомогою значка вставки на цьому екрані. -\n\t\t3.3 QR-код: гаманець створює QR-код, який можна зчитати за допомогою кнопки QR-коду на цьому екрані. - + Amethyst не знайшов жодного гаманця, який підтримує Nostr Wallet Connect (NWC). \n\nЩо можна зробити: \n\t1. Перевірте підтримку NWC: переконайтеся, що ваш гаманець сумісний з Nostr Wallet Connect. \n\t2. Створіть підключення: відкрийте гаманець і створіть нове NWC-підключення. \n\t3. Прив'яжіть до Amethyst: зазвичай гаманець надає три варіанти: \n\t\t3.1 Автоматичне підключення: кнопка для автоматичного відкриття та підключення до Amethyst. Якщо так — натисніть її, відкрийте Amethyst і збережіть налаштування на новому екрані. \n\t\t3.2 Ручне підключення: URI підключення, який можна скопіювати та вставити за допомогою значка вставки на цьому екрані. \n\t\t3.3 QR-код: гаманець створює QR-код, який можна зчитати за допомогою кнопки QR-коду на цьому екрані. Створити дн Небезпечна зона @@ -2816,11 +2796,8 @@ Proxy relay-сервери Агрегаторні relay-сервери, які застосунок має використовувати для завантаження ваших стрічок, наприклад filter.nostr.wine. Це замінює модель outbox і змусить застосунок підключатися лише до relay-серверів у ваших списках. Публічний чат - Публічні чати видимі всім у Nostr, і кожен - може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. - Модерацію можна здійснювати, видаляючи публікації на відповідних relay - Вкажіть від 1 до 3 relay, що розміщують цю групу. - Клієнти Nostr використовують це налаштування, щоб знати, звідки завантажувати повідомлення та куди їх надсилати. + Публічні чати видимі всім у Nostr, і кожен може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. Модерацію можна здійснювати, видаляючи публікації на відповідних relay + Вкажіть від 1 до 3 relay, що розміщують цю групу. Клієнти Nostr використовують це налаштування, щоб знати, звідки завантажувати повідомлення та куди їх надсилати. Relay Метадані публічного чату Публічні чати @@ -2845,10 +2822,7 @@ Користувач лише для читання Натисніть і утримуйте, щоб записати повідомлення Чат relay - Чати relay — це групи чатів, керовані їхнім домашнім relay. - Вони видимі всім у Nostr, і кожен може брати в них участь. - Вони чудово підходять для відкритих спільнот за певними темами. Деякі з цих груп є тимчасовими, - і тому повідомлення чату зникають з часом + Чати relay — це групи чатів, керовані їхнім домашнім relay. Вони видимі всім у Nostr, і кожен може брати в них участь. Вони чудово підходять для відкритих спільнот за певними темами. Деякі з цих груп є тимчасовими, і тому повідомлення чату зникають з часом Чати relay Події IP-адреси diff --git a/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml b/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml index 332e2bae8f..3c8e9daa2a 100644 --- a/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-uz-rUZ/strings.xml @@ -273,15 +273,8 @@ Barcha ma'lumlarni o'qilgan deb belgilash Barcha yangilarni o'qilgan deb belgilash Barchasini o'qilgan deb belgilash - ## Kalit zaxiralash va xavfsizlik maslahatlari - \n\nHisobingiz maxfiy kalit bilan himoyalangan. Kalit **nsec1** bilan boshlanadigan uzun belgilar ketma-ketligidir. Ushbu maxfiy kalitga kirish huquqiga ega bo'lgan har kim sizning nomingizdan post qo'yishi va identifikatoringizni o'zgartirishi mumkin. - \n\n- Maxfiy kalitingizni ishonmagan veb-sayt yoki dasturga **kiritmang**. - \n- Amethyst ishlab chiquvchilari maxfiy kalitingizni hech **qachon** so'ramaydi. - \n- Hisob tiklash uchun maxfiy kalitingizning xavfsiz zaxira nusxasini saqlang. Parol menejeridan foydalanishni tavsiya qilamiz. - - Qo'shimcha xavfsizlik uchun kalitingizni parol bilan shifrlashingiz mumkin. Bu kalit **ncryptsec1** bilan boshlanadi va parolsiz ishlatib bo'lmaydi. - \n\nParolingizni unutsangiz, kalitingizni tiklay olmaysiz. - + ## Kalit zaxiralash va xavfsizlik maslahatlari \n\nHisobingiz maxfiy kalit bilan himoyalangan. Kalit **nsec1** bilan boshlanadigan uzun belgilar ketma-ketligidir. Ushbu maxfiy kalitga kirish huquqiga ega bo'lgan har kim sizning nomingizdan post qo'yishi va identifikatoringizni o'zgartirishi mumkin. \n\n- Maxfiy kalitingizni ishonmagan veb-sayt yoki dasturga **kiritmang**. \n- Amethyst ishlab chiquvchilari maxfiy kalitingizni hech **qachon** so'ramaydi. \n- Hisob tiklash uchun maxfiy kalitingizning xavfsiz zaxira nusxasini saqlang. Parol menejeridan foydalanishni tavsiya qilamiz. + Qo'shimcha xavfsizlik uchun kalitingizni parol bilan shifrlashingiz mumkin. Bu kalit **ncryptsec1** bilan boshlanadi va parolsiz ishlatib bo'lmaydi. \n\nParolingizni unutsangiz, kalitingizni tiklay olmaysiz. Maxfiy kalitni shifrlash va nusxalash %1$s uchun nishon mukofoti rasmi "Nishon mukofoti rasmi @@ -962,9 +955,7 @@ Push bildirishnomalarini o'chiradi %1$s ilovasidan foydalanadi Push bildirishnoma sozlamasi - Push bildirishnomalarni olish uchun [Ntfy](https://ntfy.sh/) kabi [Unified Push](https://unifiedpush.org/) ni qo'llab-quvvatlaydigan ilovani o'rnating. - O'rnatgandan so'ng, Sozlamalarda foydalanmoqchi bo'lgan ilovani tanlang. - + Push bildirishnomalarni olish uchun [Ntfy](https://ntfy.sh/) kabi [Unified Push](https://unifiedpush.org/) ni qo'llab-quvvatlaydigan ilovani o'rnating. O'rnatgandan so'ng, Sozlamalarda foydalanmoqchi bo'lgan ilovani tanlang. Ip Sotuvchiga xabar yuborish Salom, bu hali ham mavjudmi? @@ -2012,15 +2003,7 @@ %1$s dan hisob-faktura olishda xato: %2$s Siqilgan faylni ochib bo'lmadi Hamyon topilmadi - Amethyst Nostr Wallet Connect (NWC) ni qo'llab-quvvatlaydigan hech qanday hamyon ilovasini topa olmadi. -\n\nNima qilishingiz mumkin: -\n\t1. NWC qo'llab-quvvatlashini tekshirish: Tanlagan hamyon ilovangiz Nostr Wallet Connect bilan mos kelishini ikki marta tekshiring. -\n\t2. Ulanish yaratish: Hamyon ilovangizga o'ting va yangi NWC ulanishini yarating. -\n\t3. Amethyst ga bog'lash: Hamyoningiz odatda uchta variant taqdim etadi: -\n\t\t3.1 Avtomatik bog'lash: Amethyst ni avtomatik ochish va ulash tugmasi. Agar shunday bo'lsa, ushbu tugmani bosing, Amethyst ni oching va yangi ekranda saqlash tugmasini bosing. -\n\t\t3.2 Qo'lda bog'lash: Nusxa olishingiz va to'g'ridan-to'g'ri kiritish uchun ushbu ekrandagi joylashtirish belgisini bosishingiz mumkin bo'lgan Ulanish URI si. -\n\t\t3.3 QR kod: Hamyon ushbu ekrandagi QR kod tugmasidan o'qishingiz mumkin bo'lgan QR kod yaratadi. - + Amethyst Nostr Wallet Connect (NWC) ni qo'llab-quvvatlaydigan hech qanday hamyon ilovasini topa olmadi. \n\nNima qilishingiz mumkin: \n\t1. NWC qo'llab-quvvatlashini tekshirish: Tanlagan hamyon ilovangiz Nostr Wallet Connect bilan mos kelishini ikki marta tekshiring. \n\t2. Ulanish yaratish: Hamyon ilovangizga o'ting va yangi NWC ulanishini yarating. \n\t3. Amethyst ga bog'lash: Hamyoningiz odatda uchta variant taqdim etadi: \n\t\t3.1 Avtomatik bog'lash: Amethyst ni avtomatik ochish va ulash tugmasi. Agar shunday bo'lsa, ushbu tugmani bosing, Amethyst ni oching va yangi ekranda saqlash tugmasini bosing. \n\t\t3.2 Qo'lda bog'lash: Nusxa olishingiz va to'g'ridan-to'g'ri kiritish uchun ushbu ekrandagi joylashtirish belgisini bosishingiz mumkin bo'lgan Ulanish URI si. \n\t\t3.3 QR kod: Hamyon ushbu ekrandagi QR kod tugmasidan o'qishingiz mumkin bo'lgan QR kod yaratadi. Yaratish k Xavfli zona @@ -2686,11 +2669,8 @@ Proksi Relay lar Ilovaning tasmalangizni yuklab olish uchun foydalanishi kerak bo'lgan agregator relay lar, masalan filter.nostr.wine. Bu chiqib ketish modelini almashtiradi va ilovani faqat ro'yxatlaringizdagi relay larga ulanishga majbur qiladi. Ommaviy chat - Ommaviy chatlar Nostr dagi hamma uchun ko'rinadi va har kim - ularda ishtirok eta oladi. Ular muayyan mavzular bo'yicha ochiq jamoalar uchun juda mos keladi. - Moderatsiya relay'larida postlarni o'chirish orqali boshqarilishi mumkin - Ushbu guruhni joylashtiradigan 1-3 ta relay kiriting. - Nostr klientlari xabarlarni qayerdan yuklab olishini va xabarlaringizni qayerga yuborishini bilish uchun ushbu sozlamadan foydalanadi. + Ommaviy chatlar Nostr dagi hamma uchun ko'rinadi va har kim ularda ishtirok eta oladi. Ular muayyan mavzular bo'yicha ochiq jamoalar uchun juda mos keladi. Moderatsiya relay'larida postlarni o'chirish orqali boshqarilishi mumkin + Ushbu guruhni joylashtiradigan 1-3 ta relay kiriting. Nostr klientlari xabarlarni qayerdan yuklab olishini va xabarlaringizni qayerga yuborishini bilish uchun ushbu sozlamadan foydalanadi. Relay lar Ommaviy chat metama'lumotlari Ommaviy chatlar @@ -2715,10 +2695,7 @@ Faqat o'qish foydalanuvchisi Xabar yozib olish uchun bosib ushlab turing Relay chati - Relay chatlari o'z uy relay'lari tomonidan boshqariladigan chat guruhlaridir. - Ular Nostr dagi hamma uchun ko'rinadi va har kim ularda ishtirok eta oladi. - Ular muayyan mavzular bo'yicha ochiq jamoalar uchun juda mos keladi. Bu guruhlarning bir qismi vaqtinchalik bo'lib, - shuning uchun chat xabarlari vaqt o'tishi bilan yo'qoladi + Relay chatlari o'z uy relay'lari tomonidan boshqariladigan chat guruhlaridir. Ular Nostr dagi hamma uchun ko'rinadi va har kim ularda ishtirok eta oladi. Ular muayyan mavzular bo'yicha ochiq jamoalar uchun juda mos keladi. Bu guruhlarning bir qismi vaqtinchalik bo'lib, shuning uchun chat xabarlari vaqt o'tishi bilan yo'qoladi Relay chatlari Hodisalar IP lar diff --git a/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml b/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml index a875b48f0e..e39e556680 100644 --- a/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-vi-rVN/strings.xml @@ -267,15 +267,8 @@ Đánh dấu tất cả đã biết là đã đọc Đánh dấu tất cả mới là đã đọc Đánh dấu tất cả là đã đọc - ## Mẹo sao lưu khóa và bảo mật - \n\nTài khoản của bạn được bảo mật bằng một khóa bí mật. Khóa là một chuỗi ký tự dài bắt đầu bằng **nsec1**. Bất kỳ ai có quyền truy cập vào khóa bí mật này đều có thể đăng bài và thay đổi danh tính của bạn. - \n\n- **Không** đưa khóa bí mật của bạn vào bất kỳ trang web hoặc phần mềm nào mà bạn không tin tưởng. - \n- Các nhà phát triển Amethyst sẽ **không bao giờ** yêu cầu khóa bí mật của bạn. - \n- **Hãy** giữ bản sao lưu an toàn của khóa bí mật để khôi phục tài khoản. Chúng tôi khuyến nghị sử dụng trình quản lý mật khẩu. - - Để bảo mật thêm, bạn có thể mã hóa khóa của mình bằng mật khẩu. Khóa này bắt đầu bằng **ncryptsec1** và không thể sử dụng nếu không có mật khẩu của bạn. - \n\nNếu bạn mất mật khẩu, bạn sẽ không thể khôi phục khóa của mình. - + ## Mẹo sao lưu khóa và bảo mật \n\nTài khoản của bạn được bảo mật bằng một khóa bí mật. Khóa là một chuỗi ký tự dài bắt đầu bằng **nsec1**. Bất kỳ ai có quyền truy cập vào khóa bí mật này đều có thể đăng bài và thay đổi danh tính của bạn. \n\n- **Không** đưa khóa bí mật của bạn vào bất kỳ trang web hoặc phần mềm nào mà bạn không tin tưởng. \n- Các nhà phát triển Amethyst sẽ **không bao giờ** yêu cầu khóa bí mật của bạn. \n- **Hãy** giữ bản sao lưu an toàn của khóa bí mật để khôi phục tài khoản. Chúng tôi khuyến nghị sử dụng trình quản lý mật khẩu. + Để bảo mật thêm, bạn có thể mã hóa khóa của mình bằng mật khẩu. Khóa này bắt đầu bằng **ncryptsec1** và không thể sử dụng nếu không có mật khẩu của bạn. \n\nNếu bạn mất mật khẩu, bạn sẽ không thể khôi phục khóa của mình. Mã hóa và sao chép khóa bí mật của tôi Hình ảnh huy hiệu được trao cho %1$s "Hình ảnh huy hiệu được trao @@ -954,9 +947,7 @@ Tắt thông báo Push Sử dụng ứng dụng %1$s Cài đặt thông báo Push - Để nhận thông báo push, hãy cài đặt ứng dụng hỗ trợ [Unified Push](https://unifiedpush.org/), chẳng hạn như [Ntfy](https://ntfy.sh/). - Sau khi cài đặt, hãy chọn ứng dụng bạn muốn sử dụng trong Cài đặt. - + Để nhận thông báo push, hãy cài đặt ứng dụng hỗ trợ [Unified Push](https://unifiedpush.org/), chẳng hạn như [Ntfy](https://ntfy.sh/). Sau khi cài đặt, hãy chọn ứng dụng bạn muốn sử dụng trong Cài đặt. Luồng Gửi tin nhắn cho người bán Xin chào, mặt hàng này còn không? @@ -2000,15 +1991,7 @@ Không thể tải hóa đơn từ %1$s: %2$s Không thể mở tệp nén Không tìm thấy ví - Amethyst không tìm thấy ứng dụng ví nào hỗ trợ Nostr Wallet Connect (NWC). -\n\nBạn có thể thực hiện: -\n\t1. Xác minh hỗ trợ NWC: Kiểm tra lại xem ứng dụng ví của bạn có tương thích với Nostr Wallet Connect không. -\n\t2. Tạo kết nối: Vào ứng dụng ví của bạn và tạo kết nối NWC mới. -\n\t3. Liên kết với Amethyst: Ví của bạn thường cung cấp ba tùy chọn: -\n\t\t3.1 Liên kết tự động: Nút để tự động mở và kết nối với Amethyst. Nếu có, nhấn nút đó, mở Amethyst và nhấn lưu trên màn hình mới. -\n\t\t3.2 Liên kết thủ công: URI kết nối mà bạn có thể sao chép và nhấn biểu tượng dán trên màn hình này để nhập trực tiếp. -\n\t\t3.3 Mã QR: Ví tạo mã QR mà bạn có thể đọc bằng nút mã QR trên màn hình này. - + Amethyst không tìm thấy ứng dụng ví nào hỗ trợ Nostr Wallet Connect (NWC). \n\nBạn có thể thực hiện: \n\t1. Xác minh hỗ trợ NWC: Kiểm tra lại xem ứng dụng ví của bạn có tương thích với Nostr Wallet Connect không. \n\t2. Tạo kết nối: Vào ứng dụng ví của bạn và tạo kết nối NWC mới. \n\t3. Liên kết với Amethyst: Ví của bạn thường cung cấp ba tùy chọn: \n\t\t3.1 Liên kết tự động: Nút để tự động mở và kết nối với Amethyst. Nếu có, nhấn nút đó, mở Amethyst và nhấn lưu trên màn hình mới. \n\t\t3.2 Liên kết thủ công: URI kết nối mà bạn có thể sao chép và nhấn biểu tượng dán trên màn hình này để nhập trực tiếp. \n\t\t3.3 Mã QR: Ví tạo mã QR mà bạn có thể đọc bằng nút mã QR trên màn hình này. Tạo n Vùng nguy hiểm @@ -2642,11 +2625,8 @@ Relay Proxy Các relay tổng hợp mà ứng dụng phải sử dụng để tải feed của bạn, như filter.nostr.wine. Tùy chọn này thay thế mô hình outbox và sẽ khiến ứng dụng chỉ kết nối đến các relay trong danh sách của bạn. Trò chuyện công khai - Trò chuyện công khai hiển thị với mọi người trên Nostr và bất kỳ ai - cũng có thể tham gia. Chúng rất phù hợp cho các cộng đồng mở xung quanh các chủ đề cụ thể. - Kiểm duyệt có thể được kiểm soát bằng cách xóa bài đăng trên các relay của nó - Nhập từ 1–3 relay lưu trữ nhóm này. - Các ứng dụng Nostr sử dụng cài đặt này để biết nơi tải xuống tin nhắn và gửi tin nhắn của bạn. + Trò chuyện công khai hiển thị với mọi người trên Nostr và bất kỳ ai cũng có thể tham gia. Chúng rất phù hợp cho các cộng đồng mở xung quanh các chủ đề cụ thể. Kiểm duyệt có thể được kiểm soát bằng cách xóa bài đăng trên các relay của nó + Nhập từ 1–3 relay lưu trữ nhóm này. Các ứng dụng Nostr sử dụng cài đặt này để biết nơi tải xuống tin nhắn và gửi tin nhắn của bạn. Relay Siêu dữ liệu trò chuyện công khai Trò chuyện công khai @@ -2670,10 +2650,7 @@ Lượng dữ liệu tính bằng byte đã nhận được từ relay này, bao gồm các bộ lọc và sự kiện Người dùng chỉ đọc Nhấn và giữ để ghi âm tin nhắn - Relay chat là các nhóm trò chuyện được kiểm soát bởi relay chủ quản. - Chúng hiển thị với mọi người trên Nostr và bất kỳ ai cũng có thể tham gia. - Chúng rất phù hợp cho các cộng đồng mở xung quanh các chủ đề cụ thể. Một số nhóm này là tạm thời - và do đó tin nhắn trò chuyện sẽ biến mất theo thời gian + Relay chat là các nhóm trò chuyện được kiểm soát bởi relay chủ quản. Chúng hiển thị với mọi người trên Nostr và bất kỳ ai cũng có thể tham gia. Chúng rất phù hợp cho các cộng đồng mở xung quanh các chủ đề cụ thể. Một số nhóm này là tạm thời và do đó tin nhắn trò chuyện sẽ biến mất theo thời gian Relay Chat Sự kiện IP diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml index d16f98dff4..36527eeeaf 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rCN/strings.xml @@ -389,15 +389,8 @@ 将所有已知内容标记为已读 将所有新内容标记为已读 将所有内容标记为已读 - ## 备份与安全提示 - \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 - \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 - \n- Amethyst 开发人员**永远不会**要求你提供私钥。 - \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 - \n\n如果你丢失密码, 你将无法恢复你的密钥。 - + ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 + 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 加密并复制我的密钥。 颁发给 %1$s 的徽章图片 "徽章图片 @@ -478,7 +471,7 @@ 轻触以允许一种类型。长按一种类型来设置每个事件的大小或每日帖子的限制。 自定义类型 添加类型 - %1$d 类型的限制 + %1$d 类型的限制 最大事件大小(字节) 每位作者每天最多发帖数 留空为无限制 @@ -1356,9 +1349,7 @@ 关闭推送通知 使用应用 %1$s 推送通知设置 - 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 - 安装后,请在设置中选择你想要使用的应用程序。 - + 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 安装后,请在设置中选择你想要使用的应用程序。 主题帖 向卖方发送消息 你好,这个还能买到吗? @@ -2640,15 +2631,7 @@ 无法从 %1$s 获取发票:%2$s 无法打开压缩文件 未找到钱包 - Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. -\n\n你可以做的事情: -\n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 -\n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 -\n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: -\n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 -\n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 -\n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 - + Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. \n\n你可以做的事情: \n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 \n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 \n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: \n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 \n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 \n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 创建 天 危险区 @@ -3552,11 +3535,8 @@ 代理中继 聚合器中继是应用获取资讯源时使用的中继(例如:filter.nostr.wine),设置这个列表将覆盖信箱模型的行为,使得应用只会连接到这个列表中的中继以获取内容。 公共聊天 - 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: - 参与这些聊天。这对特定话题建立的开放式社区来说很重要 - 通过删除中继上的帖子实现内容审核控制 - 使用 1~3 个中继托管这个群组。 - 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 + 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: 参与这些聊天。这对特定话题建立的开放式社区来说很重要 通过删除中继上的帖子实现内容审核控制 + 使用 1~3 个中继托管这个群组。 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 中继器 公开聊天元数据 公共聊天 @@ -3589,10 +3569,7 @@ auth authentication relay sign verify nip-42 identity 中继身份认证 中继聊天 - 中继聊天是由聊天所属中继控制的聊天群组。 - Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 - 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, - 因此聊天信息会随着时间的推移而消失。 + 中继聊天是由聊天所属中继控制的聊天群组。 Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, 因此聊天信息会随着时间的推移而消失。 中继聊天 建群 编辑群 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml index 9eb6ba5bc8..4ee4682e0a 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rHK/strings.xml @@ -228,7 +228,7 @@ 複製用户ID 隱藏該用户 此用户被屏蔽/静音。他们的帖子被隐藏。 - npub,hex,用户名 + npub,hex,用户名 清除 應用標誌 nsec/ npub/ hex 私鑰 @@ -276,15 +276,8 @@ 將所有已知內容標記為已讀 將所有新內容標記為已讀 將所有內容標記為已讀 - ## 备份与安全提示 - \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 - \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 - \n- Amethyst 开发人员**永远不会**要求你提供私钥。 - \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 - \n\n如果你丢失密码, 你将无法恢复你的密钥。 - + ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 + 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 加密并复制我的密钥。 頒發給 %1$s 的徽章圖片 "徽章图片 @@ -365,7 +358,7 @@ 轻触以允许一种类型。长按一种类型来设置每个事件的大小或每日帖子的限制。 自定义类型 添加类型 - %1$d 类型的限制 + %1$d 类型的限制 最大事件大小(字节) 每位作者每天最多发帖数 留空为无限制 @@ -976,9 +969,7 @@ 关闭推送通知 使用应用 %1$s 推送通知设置 - 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 - 安装后,请在设置中选择你想要使用的应用程序。 - + 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 安装后,请在设置中选择你想要使用的应用程序。 主题帖 向卖方发送消息 你好,这个还能买到吗? @@ -2037,15 +2028,7 @@ 无法从 %1$s 获取发票:%2$s 无法打开压缩文件 未找到钱包 - Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. -\n\n你可以做的事情: -\n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 -\n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 -\n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: -\n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 -\n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 -\n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 - + Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. \n\n你可以做的事情: \n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 \n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 \n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: \n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 \n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 \n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 創建 天 危险区 @@ -2700,11 +2683,8 @@ 代理中继 聚合器中继是应用获取资讯源时使用的中继(例如:filter.nostr.wine),设置这个列表将覆盖信箱模型的行为,使得应用只会连接到这个列表中的中继以获取内容。 公共聊天 - 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: - 参与这些聊天。这对特定话题建立的开放式社区来说很重要 - 通过删除中继上的帖子实现内容审核控制 - 使用 1~3 个中继托管这个群组。 - 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 + 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: 参与这些聊天。这对特定话题建立的开放式社区来说很重要 通过删除中继上的帖子实现内容审核控制 + 使用 1~3 个中继托管这个群组。 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 中继器 公开聊天元数据 公共聊天 @@ -2729,10 +2709,7 @@ 仅读用户 点按以录制消息 中继聊天 - 中继聊天是由聊天所属中继控制的聊天群组。 - Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 - 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, - 因此聊天信息会随着时间的推移而消失。 + 中继聊天是由聊天所属中继控制的聊天群组。 Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, 因此聊天信息会随着时间的推移而消失。 中继聊天 事件 IP地址 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml index 4649ff00d5..0d0a9f7f9e 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rSG/strings.xml @@ -276,15 +276,8 @@ 将所有已知内容标记为已读 将所有新内容标记为已读 将所有内容标记为已读 - ## 备份与安全提示 - \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 - \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 - \n- Amethyst 开发人员**永远不会**要求你提供私钥。 - \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 - \n\n如果你丢失密码, 你将无法恢复你的密钥。 - + ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 + 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 加密并复制我的密钥。 颁发给 %1$s 的徽章图片 "徽章图片 @@ -365,7 +358,7 @@ 轻触以允许一种类型。长按一种类型来设置每个事件的大小或每日帖子的限制。 自定义类型 添加类型 - %1$d 类型的限制 + %1$d 类型的限制 最大事件大小(字节) 每位作者每天最多发帖数 留空为无限制 @@ -976,9 +969,7 @@ 关闭推送通知 使用应用 %1$s 推送通知设置 - 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 - 安装后,请在设置中选择你想要使用的应用程序。 - + 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 安装后,请在设置中选择你想要使用的应用程序。 主题帖 向卖方发送消息 你好,这个还能买到吗? @@ -2037,15 +2028,7 @@ 无法从 %1$s 获取发票:%2$s 无法打开压缩文件 未找到钱包 - Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. -\n\n你可以做的事情: -\n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 -\n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 -\n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: -\n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 -\n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 -\n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 - + Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. \n\n你可以做的事情: \n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 \n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 \n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: \n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 \n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 \n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 创建 天 危险区 @@ -2700,11 +2683,8 @@ 代理中继 聚合器中继是应用获取资讯源时使用的中继(例如:filter.nostr.wine),设置这个列表将覆盖信箱模型的行为,使得应用只会连接到这个列表中的中继以获取内容。 公共聊天 - 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: - 参与这些聊天。这对特定话题建立的开放式社区来说很重要 - 通过删除中继上的帖子实现内容审核控制 - 使用 1~3 个中继托管这个群组。 - 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 + 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: 参与这些聊天。这对特定话题建立的开放式社区来说很重要 通过删除中继上的帖子实现内容审核控制 + 使用 1~3 个中继托管这个群组。 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 中继器 公开聊天元数据 公共聊天 @@ -2729,10 +2709,7 @@ 仅读用户 点按以录制消息 中继聊天 - 中继聊天是由聊天所属中继控制的聊天群组。 - Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 - 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, - 因此聊天信息会随着时间的推移而消失。 + 中继聊天是由聊天所属中继控制的聊天群组。 Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, 因此聊天信息会随着时间的推移而消失。 中继聊天 事件 IP地址 diff --git a/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml index 6bd229d72c..65c10efd5d 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh-rTW/strings.xml @@ -223,7 +223,7 @@ 複製用户ID 隱藏該用户 此使用者已被封鎖/靜音。其貼文已隱藏。 - npub,hex,用户名 + npub,hex,用户名 清除 應用標誌 nsec/ npub/ hex 私鑰 @@ -271,15 +271,8 @@ 將所有已知內容標記為已讀 將所有新內容標記為已讀 將所有內容標記為已讀 - ## 備份與安全提示 - \n\n你的帳戶由一個私鑰保護。私鑰是以 **nsec1** 開頭的隨機字符串。任何擁有你的私鑰的人都可以使用你的身份發佈內容。 - \n\n- **不要**將你的私鑰添加到任何你不信任的網站或軟件,亦不要在網上公開。 - \n- Amethyst 開發人員**永遠不會**要求你提供私鑰。 - \n- **請**保留你的私鑰的安全備份,以備帳戶恢復。我們建議使用密碼管理器。 - - 爲了額外的安全性,你可以用密碼加密你的密鑰。此密鑰以 **ncryptsec1** 開頭,沒有密碼就不能使用。 - \n\n如果你丟失密碼,你將無法恢復你的密鑰。 - + ## 備份與安全提示 \n\n你的帳戶由一個私鑰保護。私鑰是以 **nsec1** 開頭的隨機字符串。任何擁有你的私鑰的人都可以使用你的身份發佈內容。 \n\n- **不要**將你的私鑰添加到任何你不信任的網站或軟件,亦不要在網上公開。 \n- Amethyst 開發人員**永遠不會**要求你提供私鑰。 \n- **請**保留你的私鑰的安全備份,以備帳戶恢復。我們建議使用密碼管理器。 + 爲了額外的安全性,你可以用密碼加密你的密鑰。此密鑰以 **ncryptsec1** 開頭,沒有密碼就不能使用。 \n\n如果你丟失密碼,你將無法恢復你的密鑰。 加密並複製我的密鑰 頒發給 %1$s 的徽章圖片 "徽章獎勵圖片 @@ -968,9 +961,7 @@ 關閉推送通知 使用應用 %1$s 推送通知設置 - 若要接收推送通知,請安裝任何支持 [Unified Push](https://unifiedpush.org/)的應用,例如 [Ntfy](https://ntfy.sh/)。 - 安裝後,請在設備中選擇你想要使用的應用程式。 - + 若要接收推送通知,請安裝任何支持 [Unified Push](https://unifiedpush.org/)的應用,例如 [Ntfy](https://ntfy.sh/)。 安裝後,請在設備中選擇你想要使用的應用程式。 主題帖 向賣方發送消息 你好,這個還能買到嗎? @@ -2022,7 +2013,7 @@ 無法從 %1$s 取得發票:%2$s 無法打開壓縮文件 找不到錢包 - Amethyst 找不到任何支援 Nostr Wallet Connect (NWC) 的錢包應用程式。\n\n您可以這樣做:\n\t1. 確認 NWC 支援:請再次確認您偏好的錢包應用程式是否與 Nostr Wallet Connect 相容。\n\t2. 建立連線:前往您的錢包應用程式並建立新的 NWC 連線。\n\t3. 連結至 Amethyst:您的錢包通常會提供三種選項:\n\t\t3.1 自動連結:點擊按鈕自動開啟並連接到 Amethyst。若有此選項,請點擊該按鈕,開啟 Amethyst 並在新畫面上點擊儲存。\n\t\t3.2 手動連結:複製連線 URI,然後點擊此畫面上的貼上圖示直接輸入。\n\t\t3.3 QR 碼:錢包會產生 QR 碼,您可透過此畫面上的 QR 碼按鈕掃描。\n + Amethyst 找不到任何支援 Nostr Wallet Connect (NWC) 的錢包應用程式。\n\n您可以這樣做:\n\t1. 確認 NWC 支援:請再次確認您偏好的錢包應用程式是否與 Nostr Wallet Connect 相容。\n\t2. 建立連線:前往您的錢包應用程式並建立新的 NWC 連線。\n\t3. 連結至 Amethyst:您的錢包通常會提供三種選項:\n\t\t3.1 自動連結:點擊按鈕自動開啟並連接到 Amethyst。若有此選項,請點擊該按鈕,開啟 Amethyst 並在新畫面上點擊儲存。\n\t\t3.2 手動連結:複製連線 URI,然後點擊此畫面上的貼上圖示直接輸入。\n\t\t3.3 QR 碼:錢包會產生 QR 碼,您可透過此畫面上的 QR 碼按鈕掃描。\n 創建 天 危險區域 @@ -2664,11 +2655,8 @@ 代理 Relay 應用程式必須用來下載您的動態的聚合器 relay,例如 filter.nostr.wine。這將取代發件匣模式,使應用程式僅連線至您清單中的 relay。 公共聊天 - 公開聊天室對所有 Nostr 使用者可見, - 任何人皆可參與。非常適合圍繞特定主題的開放社群。 - 可透過在其 relay 上刪除貼文來進行內容管理 - 請輸入 1–3 個託管此群組的 relay。 - Nostr 客戶端使用此設定來確認下載訊息及傳送訊息的位置。 + 公開聊天室對所有 Nostr 使用者可見, 任何人皆可參與。非常適合圍繞特定主題的開放社群。 可透過在其 relay 上刪除貼文來進行內容管理 + 請輸入 1–3 個託管此群組的 relay。 Nostr 客戶端使用此設定來確認下載訊息及傳送訊息的位置。 Relay 公開聊天室元資料 公開聊天室 @@ -2693,10 +2681,7 @@ 只讀用戶 按住以錄製訊息 Relay 聊天 - Relay 聊天室是由其所屬 relay 管控的聊天群組。 - 所有 Nostr 使用者均可看見,任何人皆可參與。 - 非常適合圍繞特定主題的開放社群。部分群組為臨時性質, - 因此聊天訊息會隨時間消失 + Relay 聊天室是由其所屬 relay 管控的聊天群組。 所有 Nostr 使用者均可看見,任何人皆可參與。 非常適合圍繞特定主題的開放社群。部分群組為臨時性質, 因此聊天訊息會隨時間消失 Relay 聊天室 事件 IP diff --git a/commonsUI/src/commonMain/composeResources/values-zh/strings.xml b/commonsUI/src/commonMain/composeResources/values-zh/strings.xml index 643d37c01f..17be4c460b 100644 --- a/commonsUI/src/commonMain/composeResources/values-zh/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values-zh/strings.xml @@ -337,7 +337,7 @@ 轻触以允许一种类型。长按一种类型来设置每个事件的大小或每日帖子的限制。 自定义类型 添加类型 - %1$d 类型的限制 + %1$d 类型的限制 最大事件大小(字节) 每位作者每天最多发帖数 留空为无限制 @@ -949,9 +949,7 @@ 关闭推送通知 使用应用 %1$s 推送通知设置 - 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 - 安装后,请在设置中选择你想要使用的应用程序。 - + 若要接收推送通知,请安装任何支持 [Unified Push](https://unifiedpus)的应用, 例如 [Ntfy](https://ntfy.sh/)。 安装后,请在设置中选择你想要使用的应用程序。 主题帖 向卖方发送消息 你好,这个还能买到吗? @@ -1801,15 +1799,8 @@ Explorer API 基础URL 支付来自DVM的发票 支付 %1$s sats 到 DVM - ## 备份与安全提示 - \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 - \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 - \n- Amethyst 开发人员**永远不会**要求你提供私钥。 - \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 - - 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 - \n\n如果你丢失密码, 你将无法恢复你的密钥。 - + ## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。 + 为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。 使用直接链接 静态网站: %1$s nApple: %1$s @@ -2054,15 +2045,7 @@ 无法从 %1$s 获取发票:%2$s 无法打开压缩文件 未找到钱包 - Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. -\n\n你可以做的事情: -\n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 -\n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 -\n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: -\n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 -\n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 -\n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 - + Amethyst 找不到任何支持 Nostr Wallet Connect (NWC) 的钱包应用. \n\n你可以做的事情: \n\t1. 验证 NWC 支持:仔细确认偏好的钱包应用和 Nostr Wallet Connect 兼容。 \n\t2. 创建连接:前往钱包应用并创建新的 NWC 连接。 \n\t3.链接到 Amethyst: 你的钱包通常会给你三个选项: \n\t\t3.1 自动链接:自动打开并连接到 Amethyst 的按钮。如果是这样, 单击那个按钮,打开 Amethyst 并在新屏上按保存。 \n\t\t3.2 手动链接: 你可以复制的连接 URI,单击这个屏幕上的粘贴图标直接输入它。 \n\t\t3.3 二维码: 钱包会创建一个你可以从这个屏幕中的二维码按钮那里读取的二维码。 创建 天 危险区 @@ -2745,11 +2728,8 @@ 代理中继 聚合器中继是应用获取资讯源时使用的中继(例如:filter.nostr.wine),设置这个列表将覆盖信箱模型的行为,使得应用只会连接到这个列表中的中继以获取内容。 公共聊天 - 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: - 参与这些聊天。这对特定话题建立的开放式社区来说很重要 - 通过删除中继上的帖子实现内容审核控制 - 使用 1~3 个中继托管这个群组。 - 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 + 公开聊天对所有 Nostr 用户都是可见的,任何人都可以: 参与这些聊天。这对特定话题建立的开放式社区来说很重要 通过删除中继上的帖子实现内容审核控制 + 使用 1~3 个中继托管这个群组。 让 Nostr 客户端知道应该使用这些中继配置来发送和下载消息。 中继器 公开聊天元数据 公共聊天 @@ -2776,10 +2756,7 @@ 仅读用户 点按以录制消息 中继聊天 - 中继聊天是由聊天所属中继控制的聊天群组。 - Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 - 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, - 因此聊天信息会随着时间的推移而消失。 + 中继聊天是由聊天所属中继控制的聊天群组。 Nostr 上的每个人都可以看到这些群组,任何人都可以加入群组。 这非常适合围绕特定主题而建立的开放社区。其中一些群组是临时的, 因此聊天信息会随着时间的推移而消失。 中继聊天 事件 IP地址 diff --git a/commonsUI/src/commonMain/composeResources/values/strings.xml b/commonsUI/src/commonMain/composeResources/values/strings.xml index a0b587b986..8422630d31 100644 --- a/commonsUI/src/commonMain/composeResources/values/strings.xml +++ b/commonsUI/src/commonMain/composeResources/values/strings.xml @@ -660,17 +660,8 @@ Mark all Known as read Mark all New as read Mark all as read - - ## Key Backup and Safety Tips - \n\nYour account is secured by a secret key. The key is a long sequence of characters starting with **nsec1**. Anyone who has access to this secret key can post and change your identity. - \n\n- Do **not** put your secret key in any website or software you do not trust. - \n- Amethyst developers will **never** ask for your secret key. - \n- **Do** keep a secure backup of your secret key for account recovery. We recommend using a password manager. - - - For additional security, you can encrypt your key with a password. This key starts with **ncryptsec1** and cannot be used without your password. - \n\nIf you lose your password, you will not be able to recover your key. - + ## Key Backup and Safety Tips \n\nYour account is secured by a secret key. The key is a long sequence of characters starting with **nsec1**. Anyone who has access to this secret key can post and change your identity. \n\n- Do **not** put your secret key in any website or software you do not trust. \n- Amethyst developers will **never** ask for your secret key. \n- **Do** keep a secure backup of your secret key for account recovery. We recommend using a password manager. + For additional security, you can encrypt your key with a password. This key starts with **ncryptsec1** and cannot be used without your password. \n\nIf you lose your password, you will not be able to recover your key. Back up your keys Your secret key is the only way to access this account. If you lose it, it can never be recovered. Save it somewhere safe now. Back up now @@ -1853,10 +1844,7 @@ Disables Push Notifications Uses app %1$s Push Notification Setup - - To receive push notifications, install any app that supports [Unified Push](https://unifiedpush.org/), such as [Ntfy](https://ntfy.sh/). - After installing, select the app you want to use in the Settings. - + To receive push notifications, install any app that supports [Unified Push](https://unifiedpush.org/), such as [Ntfy](https://ntfy.sh/). After installing, select the app you want to use in the Settings. Thread Send the seller a message Hi there, is this still available? @@ -3629,15 +3617,7 @@ Could not fetch invoice from %1$s: %2$s Could not open the compressed file Wallet not found - Amethyst couldn't find any wallet apps that support Nostr Wallet Connect (NWC). -\n\nWhat you can do: -\n\t1. Verify NWC Support: Double-check that your preferred wallet app is compatible with Nostr Wallet Connect. -\n\t2. Create Connection: Go to your wallet app and create a new NWC connection. -\n\t3. Link to Amethyst: Your wallet will usually give you three options: -\n\t\t3.1 Automatic Link: A button to automatically open and connect to Amethyst. If so, click that button, open Amethyst and hit save on the new screen. -\n\t\t3.2 Manual Link: A Connection URI you can copy and click the paste icon on this screen to directly input it. -\n\t\t3.3 QR Code: The wallet creates a QR code which you can read from the QR code button in this screen. - + Amethyst couldn't find any wallet apps that support Nostr Wallet Connect (NWC). \n\nWhat you can do: \n\t1. Verify NWC Support: Double-check that your preferred wallet app is compatible with Nostr Wallet Connect. \n\t2. Create Connection: Go to your wallet app and create a new NWC connection. \n\t3. Link to Amethyst: Your wallet will usually give you three options: \n\t\t3.1 Automatic Link: A button to automatically open and connect to Amethyst. If so, click that button, open Amethyst and hit save on the new screen. \n\t\t3.2 Manual Link: A Connection URI you can copy and click the paste icon on this screen to directly input it. \n\t\t3.3 QR Code: The wallet creates a QR code which you can read from the QR code button in this screen. Create d Danger Zone @@ -4773,11 +4753,8 @@ Proxy Relays Aggregator relays the app must use to download your feeds from, like filter.nostr.wine. This replaces the outbox model and will make the app connect to only the relays in your lists. Public Chat - Public chats are visible to everyone on Nostr and anyone - can participate on them. They are great for open communities around specific topics. - Moderation can be controlled by deleting posts on its relays - Insert between 1–3 relays that host this group. - Nostr clients use this setting to know where to download messages from and send your messages to. + Public chats are visible to everyone on Nostr and anyone can participate on them. They are great for open communities around specific topics. Moderation can be controlled by deleting posts on its relays + Insert between 1–3 relays that host this group. Nostr clients use this setting to know where to download messages from and send your messages to. Relays Public Chat Metadata Public Chats @@ -4844,10 +4821,7 @@ auth authentication login relay sign verify nip-42 identity Relay login Relay Chat - Relay chats are chat groups controlled by their home relay. - They are visible to everyone on Nostr and anyone can participate on them. - They are great for open communities around specific topics. Some of these groups are ephemeral - and thus chat messages disappear over time + Relay chats are chat groups controlled by their home relay. They are visible to everyone on Nostr and anyone can participate on them. They are great for open communities around specific topics. Some of these groups are ephemeral and thus chat messages disappear over time Relay Chats Your own profile, settings and drafts, on your home relays. The relays each community publishes its planes to. @@ -5482,4 +5456,574 @@ Unsigned, so this author is a claim An item of kind %1$d, which this client does not draw %1$d bytes of something this client does not read + Block %1$s again + Keep %1$s + Rejoin %1$s + Re-mute %1$s + Restore %1$s + Restore feeds + Restore places + Restore profile + Restore providers + Restore relays + Restore topics + Restore wallet + Accept + + %1$s and added %2$d + %1$s and added %2$d + + + %1$s and blocked %2$d + %1$s and blocked %2$d + + + %1$s and followed %2$d + %1$s and followed %2$d + + + %1$s and joined %2$d + %1$s and joined %2$d + + + %1$s and muted %2$d + %1$s and muted %2$d + + Your Amethyst synced app settings changed in another app that is not Amethyst. This can create problems. + You emptied your Concord list + You changed your Concord list + + You removed %1$d DM relay + You removed %1$d DM relays + + + You removed %1$d favorite feed + You removed %1$d favorite feeds + + + You unfollowed %1$d person + You unfollowed %1$d people + + + You unfollowed %1$d hashtag + You unfollowed %1$d hashtags + + + You removed %1$d indexer relay + You removed %1$d indexer relays + + + You removed %1$d group-chat key relay + You removed %1$d group-chat key relays + + + You left %1$d public chat + You left %1$d public chats + + + You left %1$d community + You left %1$d communities + + + You left %1$d group + You left %1$d groups + + + You left %1$d chat room + You left %1$d chat rooms + + + You unmuted %1$d thing + You unmuted %1$d things + + + You removed %1$d public relay + You removed %1$d public relays + + You removed your nutzap key + You replaced your nutzap key + + You removed %1$d nutzap mint + You removed %1$d nutzap mints + + + You removed %1$d BOLT12 offer + You removed %1$d BOLT12 offers + + + You removed %1$d way to get paid + You removed %1$d ways to get paid + + + You unfollowed %1$d place + You unfollowed %1$d places + + + You removed %1$d private relay + You removed %1$d private relays + + + You removed %1$d profile field + You removed %1$d profile fields + + + You removed %1$d relay feed + You removed %1$d relay feeds + + + You removed %1$d search relay + You removed %1$d search relays + + + You changed the provider of %1$d trust service + You changed the provider of %1$d trust services + + + You stopped trusting %1$d relay + You stopped trusting %1$d relays + + + You unblocked %1$d relay + You unblocked %1$d relays + + You emptied your Cashu wallet + You changed your Cashu wallet + Added (%1$s) + Changed (%1$s) + %1$s added + %1$s changed + %1$s removed + Use new version + You added private (encrypted) items. + You also changed private (encrypted) items. They can't be compared here. + You removed all private (encrypted) items. + read only + read and write + write only + Removed (%1$s) + Restore saved version + You changed your %1$s in another app + Feeds + Chat rooms + Communities + Hashtags + Linked identities + Locations + Mints + Nutzap keys + Offers + Other entries + Payment addresses + People + Profile fields + Public chats + Relays + Groups + Threads + Trust providers + Words + About + Banner + Birthday + Bot flag + CLINK offer + Display name + LNURL + Lightning address + Username + Nostr address + Picture + Pronouns + Website + Allowed + Changed in another app · %1$s + Your Concord communities are encrypted to you, so they can't be compared here. Restoring puts back exactly what this device saved. + Moved + %1$s dropped + Dropped + You created it + You changed it + You emptied it + Feed + Gone + Hashtags you follow + Inbox + where others reach you + joined + kept + %1$s kept + Receiving key removed + Receiving key replaced + Nutzaps will be locked to this new key. If this device doesn't have it, you may not be able to redeem them here. + left + Left + Listed + Moved + %1$s and %2$s more + New version + %1$s new + new + New + Newly blocked + %1$s newly muted + No longer blocked + Not set + Nothing here + BOLT12 offer + + %1$d offer removed + %1$d offers removed + + Outbox + where you publish + + %1$d way to pay you removed + %1$d ways to pay you removed + + People paying you only see what's in this list. + places gone + Places you follow + They're encrypted now, which is likely where the public items above went. + You made items private + They're encrypted, so they can't be compared here. + You changed private items + They're encrypted, so only you can see what they were. Restoring brings them all back. + You removed all private items + Receiving + renamed + Renamed + On this device + Search %1$s people + Searching + Service + Followers + Rank + Topics + %1$s of %2$s services changed + They now come from someone else, or no one + Still blocked + Storing + Dropped · %1$s + Edited · %1$s + New · %1$s + %1$s cleared + %1$s updated + topics gone + Ranks, follower counts and spam filtering you see come from these providers. + Trusted + %1$s unblocked + Amethyst will connect to them again + Units + %1$s unmuted + These can reach your feeds again + Untrusted + Your wallet's mints and keys are encrypted to you, so they can't be compared item by item here. Restoring puts back exactly what this device saved. + was “%1$s” + Words & hashtags + synced app settings + Amethyst settings synced across your devices. They are encrypted, so only their presence can be compared. + blocked relay list + Relays this app never connects to. + BOLT12 offers + The lightning offers others use to pay you. + Cashu wallet + Your ecash wallet settings and mints. They are encrypted, so only their presence can be compared. + community list + The communities you joined. + Concord community list + The Concord communities you joined. They are encrypted, so only their presence can be compared. + DM relay list + Where others deliver your private messages. + ephemeral chat list + The ephemeral chat rooms you joined. + favorite feeds list + The algorithmic feeds you saved. + follow list + Decides whose posts appear in your home feed. + followed locations + Locations whose posts appear in your feeds. + followed hashtags + Hashtags whose posts appear in your feeds. + indexer relay list + The relays used to find other people's profiles and relay lists. + group-chat key relays + Where others find the keys to add you to encrypted group chats. + mute list + Hides people, words, hashtags and threads from everything you see. + nutzap receiving settings + The mints and key others use to send you nutzaps. + list + A list saved on this device. + public relay list + Tells everyone where to find your posts and where to send you replies and mentions. + payment addresses + The ways other people can pay you. + private relay list + Where your drafts and private data are stored. + profile + Your name, picture, bio and payment addresses, as everyone sees them. + public chat list + The public chats you joined. + favorite relay feeds + The relays you browse as feeds. + group list + The relay-based groups you joined. + search relay list + The relays used when you search. + trust provider list + The services you trust to rank and verify people for you. + trusted relay list + Relays you trust to connect to without asking. + Delete + Edit + Editing your message + Go to message + Pin + Reply + Unpin + That change could not be made. + The coordinator did not answer, so nothing was changed. Try again in a moment. + %1$s has not published a key package to this coordinator, so they cannot be added yet. Ask them to open cordn on this coordinator first. + You cannot remove yourself from a cordn group. + %1$s could not be given a way into the group, so the add was abandoned. + %1$s is not in this group. + That person + This coordinator served a key package that belongs to someone else, so %1$s was not added. Nothing was changed. + Your group encryption keys, your key packages, and every message in those groups. Anyone who opens it can read the conversations. The passphrase is the only thing protecting it once it leaves Amethyst. + What is in the file + Your nsec cannot bring cordn groups back. A cordn group lives as encryption state on this device and an ordered stream on a coordinator that cannot read it — lose the device without a backup and the group is gone, including everything already said in it. + Export + Backup saved. + That did not work. Check the passphrase and the file. + Passphrase + Restore + Restoring replaces the cordn groups on this device with the ones in the file. It is for a phone that has taken over from another — not a way to use the same groups on two devices at once. + Every cordn group now on this device will be removed and replaced by the ones in the file.\n\nDo not restore onto a second phone while the first is still in use. Both would hold the same group keys, and once both have sent a message the group breaks for everyone — silently, and with no way back. + Replace this device's cordn groups? + Restore + Restored. + Anything sent here is encrypted for this group. The coordinator relays it without being able to read it. + No messages yet + New messages + Yesterday + Message + Add + Could not open that coordinator. + Copy the coordinator's npub + Look for coordinators + Add + Reads announcements your relays already carry. No coordinator is contacted, so none of them learns you looked. + Could not read announcements + Nobody is announcing on your relays. + Announced %1$s ago + Last announced %1$s + Nothing found, and %1$d of your relays did not answer. + A coordinator orders one group's messages and is the only thing that can. Losing it loses the ordering, and a second one does not mirror the first — so these are named things you choose, not interchangeable relays. + Not answering — %1$d calls in a row have failed. Groups on it are not syncing. + Answering. + A call failed; retrying. + Nothing asked of it yet. + Hide the ones that stopped announcing + Ask who it is + Coordinator key + A name for it (yours, optional) + This name is yours and stays on this device. A coordinator cannot prove a name, so it is never asked for one. + More actions + No coordinators yet. + Purge + Removing keeps the groups on this device, so adding the coordinator back brings them with it. Purging deletes them: the group keys, the read positions and your key packages all go, and those groups can only be re-entered by a fresh invitation.\n\nThe coordinator is not told and keeps whatever it already had. + Purge this coordinator? + %1$s + Answers on + %1$s +%2$d more + Remove + Rename + Says it is: %1$s + A coordinator's name and version are strings it chose. Its public key is the only thing that identifies it. + Answered, but named nothing. + Show all %1$d + Show fewer + Show %1$d that stopped announcing + These have not announced in over a month. Creating a group on one that has gone away will fail. + Create group + + Create and invite %1$d person + Create and invite %1$d people + + Add someone + Admin + + %1$d person can add and remove + %1$d people can add and remove + + Only I manage this group + Only you can invite, remove members or change the group's details. You can hand that to someone else later. + Coordinator + Change + Find coordinators + Done + Another coordinator + Coordinator public key (hex or npub) + Relays it answers on, one per line + Reaches all %1$d of your people + Reaches %1$d of %2$d — the rest would be left out + Not checked — picking it will ask + Description (optional) + Everyone can add and remove + Everyone in the group can invite, remove members and change its details. Any member can name admins later, which ends that. + A cordn group is ordered by one coordinator you choose. Creating the group happens on this device — the coordinator only learns the group exists once you invite someone or send a message. + The group could not be created. + Group name + No coordinator chosen + Each invitation is a Welcome left on the coordinator, so they can fail one at a time. Nobody has been notified: they see it next time they open their app. + The coordinator refused the invitation + Send a link + Added to the group, but the invitation did not reach them — try again from the group screen + Open the chat + No key here, so no Welcome could be left + The group exists + Waiting for them + Done + Nobody added yet. A group can be created empty and invitations sent later, but naming people now is what shows which coordinator can reach them. + Nobody yet — tap to add people + Naming people now is what tells us which coordinator can reach them. Each one gets a Welcome left on that coordinator, which they pick up next time they open their app. + + Reachable on %1$d coordinator + Reachable on %1$d coordinators + + No key on any coordinator you use + Not checked yet + Who can add and remove + Name it + Who is in it + Where it lives + New Cordn group + + %1$d person cannot be reached by any coordinator you use + %1$d people cannot be reached by any coordinator you use + + You, always an admin + Everyone in the group will see this message as withdrawn, and Amethyst will stop showing its text. The coordinator still holds the encrypted copy it was sent as, and anyone who already read it has already read it. + Withdraw message + Accepted by the coordinator + Got it + What this coordinator can see + Group info + This group is not available. Its coordinator may have been removed. + Add a coordinator in Settings to start using cordn groups. + + %1$d group + %1$d groups + + Nothing is arriving from these groups. Amethyst keeps retrying. + Coordinators + No cordn groups yet + A cordn group lives on one coordinator that holds its membership and passes messages along, without ever seeing what anyone writes. + Start one + Add someone + Nobody found by that name. + They can only be added if they published a key package to this coordinator. + Name, npub or name@domain + Admin + + The group's %1$d admin stays as it is. + The group's %1$d admins stay as they are. + + Coordinator + Coordinator key + Coordinator link + Copy the coordinator's nprofile + Edit details + This group has no admins: everyone can add, remove and rename, permanently. + Epoch + Group id + Can be added on this coordinator + Members + %1$s stops receiving messages from here. They keep what they have already read, and this cannot be undone — they would have to be invited again. + Remove from group? + Remove + Save + Technical details + Join + Decline + Declining is permanent. Getting back in means being invited again. + Checked when you open this screen, and at no other time — asking a coordinator whether anyone invited you tells it you are here, so Amethyst does not do it in the background. + Could not read invitations. + + %1$d person is already in this group + %1$d people are already in this group + + +%1$d more + You have no coordinator open. cordn invitations arrive through a coordinator, so there is nowhere to look yet. + No invitations waiting. + Check again + An invitation was left for another device + Cordn invitations + %1$s did not answer + Through %1$s + Publishing signs a record under your own account key. That coordinator then knows this account exists and is invitable — permanently, and whether or not anyone invites you. + Others can only add you to a cordn group by taking a key package you published to that coordinator. cordn has no other place to keep one, so with none published nobody can invite you — and nothing tells them why. + Could not read the key packages. + No last-resort package. Once the single-use ones run out, invitations fail. + A last-resort package is published, so an invitation can still be made once the single-use ones run out. + + %1$d package this device cannot open + %1$d packages this device cannot open + + The coordinator will hand these to anyone inviting you, but the private half is not on this device — it belongs to another install. If that install is gone, an invitation using one of these produces a welcome nobody can ever open. + Publish one + Publish last-resort + + %1$d single-use package available. + %1$d single-use packages available. + + Once you have published here, Amethyst quietly replaces packages as they are used up. It never publishes the first one for you. + Withdraw all + Withdraw those + Ask to join this group + This publishes a key package under your own account key and tells the coordinator you want into this group — whether or not anyone answers. + Could not ask to join. + Asked. A member of the group has to add you; the invitation will show up under cordn invitations. + Scan + Could not open that file. + No media server is set for this account, so there is nowhere to put the file. Pick one in Settings. + That file could not be read. + Could not send that file. + + %1$d member + %1$d members + + Message deleted + Coordinator + Cursor + Sent + Message details + edited + Pinned by %1$s + + %1$d pinned message in this group + %1$d pinned messages in this group + + Next pinned message + Previous pinned message + Show all pinned messages + Pinned messages + Reactions + Add + Only an admin can accept. In a group with no admins, that is everyone. + Check for requests + Dismiss + Could not read the requests. + Nobody is waiting to join. + Requests to join + Send + That did not send. + This group's coordinator is not open, so nothing can be sent yet. + Copied + Copy link + Anyone with this link can ask to join. An admin still has to let them in. + Share this group + Play voice note + Record a voice note + Stop and send diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBuzzInviteLink.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableBuzzInviteLink.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBuzzInviteLink.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableBuzzInviteLink.kt index 7779422d4b..089ff137a3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableBuzzInviteLink.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableBuzzInviteLink.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.combinedClickable import androidx.compose.material3.MaterialTheme diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableConcordInviteLink.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableConcordInviteLink.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableConcordInviteLink.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableConcordInviteLink.kt index 3212e52163..e18ff60ff8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableConcordInviteLink.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableConcordInviteLink.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.combinedClickable import androidx.compose.material3.MaterialTheme diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableLinks.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableLinks.kt index beedb404fc..c50279a930 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableLinks.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableLinks.kt @@ -87,7 +87,32 @@ fun ClickableEmail( textDecoration = if (underline) TextDecoration.Underline else null, modifier = modifier.pointerHoverIcon(PointerIcon.Hand).clickable { - runCatching { uriHandler.openUri("mailto:$display") } + // '%' is legal in an address but starts an escape in a mailto: URI (RFC 6068). + runCatching { uriHandler.openUri("mailto:" + display.replace("%", "%25")) } + }, + ) +} + +/** + * A primary-colored clickable phone number that opens the platform dialer via + * [LocalUriHandler] (`tel:`). Strips a leading `tel:` from the display text. + * [underline] + hover cursor are the Desktop mouse-first affordances. + */ +@Composable +fun ClickablePhone( + number: String, + modifier: Modifier = Modifier, + underline: Boolean = false, +) { + val uriHandler = LocalUriHandler.current + val display = remember(number) { number.removePrefix("tel:") } + Text( + text = display, + color = MaterialTheme.colorScheme.primary, + textDecoration = if (underline) TextDecoration.Underline else null, + modifier = + modifier.pointerHoverIcon(PointerIcon.Hand).clickable { + runCatching { uriHandler.openUri("tel:$display") } }, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayGroupLink.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayGroupLink.kt similarity index 98% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayGroupLink.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayGroupLink.kt index d968ab300b..72a1104bed 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayGroupLink.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayGroupLink.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.combinedClickable import androidx.compose.material3.MaterialTheme diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayUrl.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayUrl.kt similarity index 97% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayUrl.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayUrl.kt index 303fd67251..60e3668e5c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableRelayUrl.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/ClickableRelayUrl.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.combinedClickable import androidx.compose.material3.MaterialTheme diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NewItemsBubble.kt similarity index 63% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NewItemsBubble.kt index 3eb265a4e7..0d7b070240 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickablePhone.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/NewItemsBubble.kt @@ -18,30 +18,15 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components -import android.content.Context -import android.content.Intent -import android.net.Uri +import androidx.compose.foundation.layout.Box +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import com.vitorpamplona.amethyst.commons.ui.components.ClickableTextPrimary +import com.vitorpamplona.amethyst.commons.ui.theme.newItemBubbleModifier +/** The small dot that marks a row with unread items. */ @Composable -fun ClickablePhone(phone: String) { - val context = LocalContext.current - - ClickableTextPrimary( - text = phone, - onClick = { context.dial(phone) }, - ) -} - -fun Context.dial(phone: String) { - try { - val intent = Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phone, null)) - startActivity(intent) - } catch (t: Throwable) { - // TODO: Handle potential exceptions - } +fun NewItemsBubble() { + Box(MaterialTheme.colorScheme.newItemBubbleModifier) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/OutlinedThinPaddingTextField.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/OutlinedThinPaddingTextField.kt similarity index 99% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/OutlinedThinPaddingTextField.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/OutlinedThinPaddingTextField.kt index 3ee7f3cc0a..d7e7a537ec 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/OutlinedThinPaddingTextField.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/components/OutlinedThinPaddingTextField.kt @@ -18,7 +18,7 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.components +package com.vitorpamplona.amethyst.commons.ui.components import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.interaction.MutableInteractionSource diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/StickToTopOnPrepend.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/StickToTopOnPrepend.kt index 9074a494dd..7ba0fb5eed 100644 --- a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/StickToTopOnPrepend.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/StickToTopOnPrepend.kt @@ -24,10 +24,10 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.snapshotFlow +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.vitorpamplona.amethyst.commons.feeds.FeedContentState import com.vitorpamplona.amethyst.commons.feeds.FeedState import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -59,11 +59,14 @@ import kotlinx.coroutines.flow.map * with an instant (non-animated) scroll so the prepend appears as * in-place growth rather than a visible jump-then-scroll. * - * Commons port of `amethyst/.../WatchScrollToTop.kt` so Desktop and any - * other multiplatform front-end can use the same auto-stick behavior. - * Uses plain `collectAsState` instead of the Android-only - * `collectAsStateWithLifecycle` — equivalent here because the effect's - * lifecycle is already bound to composition via `LaunchedEffect`. + * Most callers should not invoke this directly: `SaveableFeedContentState`, + * `SaveableGridFeedContentState`, and the analogous wrappers in the app's + * `ui/screen/FeedView.kt` already apply auto-stick to every feed they + * own. Invoke the explicit overload only when the listState is + * constructed outside one of those wrappers, or when the key that + * should trigger the snap is not the default `items.list[0].idHex` + * (e.g. notifications, chats, or feeds keyed on something other than a + * Note's hex id). */ @Composable fun StickToTopOnPrepend( @@ -142,7 +145,7 @@ private fun rememberFirstItemIdHex(feedContentState: FeedContentState): String? } } } - val key by flow.collectAsState(initial = null) + val key by flow.collectAsStateWithLifecycle(initialValue = null) return key } diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/WatchScrollToTop.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/WatchScrollToTop.kt new file mode 100644 index 0000000000..5bd267e8f5 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/feeds/WatchScrollToTop.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.feeds + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.pager.PagerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.vitorpamplona.amethyst.commons.feeds.FeedContentState + +@Composable +fun WatchScrollToTop( + feedContentState: FeedContentState, + listState: LazyListState, +) { + val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && feedContentState.scrollToTopPending) { + listState.scrollToItem(index = 0) + feedContentState.sentToTop() + } + } +} + +@Composable +fun WatchScrollToTop( + feedContentState: FeedContentState, + listState: LazyGridState, +) { + val scrollToTop by feedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && feedContentState.scrollToTopPending) { + listState.scrollToItem(index = 0) + feedContentState.sentToTop() + } + } +} + +@Composable +fun WatchScrollToTop( + videoFeedContentState: FeedContentState, + pagerState: PagerState, +) { + val scrollToTop by videoFeedContentState.scrollToTop.collectAsStateWithLifecycle() + + LaunchedEffect(scrollToTop) { + if (scrollToTop > 0 && videoFeedContentState.scrollToTopPending) { + pagerState.scrollToPage(page = 0) + videoFeedContentState.sentToTop() + } + } +} diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/ChatHeaderLayout.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/ChatHeaderLayout.kt new file mode 100644 index 0000000000..76fc5b6425 --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/ChatHeaderLayout.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.layouts + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.combinedClickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +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.ui.theme.DoubleHorzSpacer +import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier +import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun ChatHeaderLayout( + channelPicture: @Composable () -> Unit, + firstRow: @Composable RowScope.() -> Unit, + secondRow: @Composable RowScope.() -> Unit, + onClick: () -> Unit, + onLongClick: (() -> Unit)? = null, +) { + Row( + modifier = + Modifier + .combinedClickable(onClick = onClick, onLongClick = onLongClick) + .padding(10.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Box(Size55Modifier) { channelPicture() } + + Spacer(modifier = DoubleHorzSpacer) + + Column( + modifier = Modifier.fillMaxWidth(), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + firstRow() + } + + Spacer(modifier = Height4dpModifier) + + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + secondRow() + } + } + } +} diff --git a/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/LeftPictureLayout.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/LeftPictureLayout.kt new file mode 100644 index 0000000000..2d7102877c --- /dev/null +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/LeftPictureLayout.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.amethyst.commons.ui.layouts + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.vitorpamplona.amethyst.commons.ui.theme.DoubleHorzSpacer + +@Composable +fun LeftPictureLayout( + onImage: @Composable () -> Unit, + onTitleRow: @Composable RowScope.() -> Unit, + onDescription: @Composable () -> Unit, + onBottomRow: @Composable RowScope.() -> Unit, + imageFraction: Float = 0.25f, +) { + Row(Modifier.aspectRatio(ratio = 1 / imageFraction)) { + Column( + modifier = Modifier.fillMaxWidth(imageFraction).aspectRatio(ratio = 1f), + ) { + onImage() + } + + Spacer(modifier = DoubleHorzSpacer) + + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.SpaceBetween, + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + onTitleRow() + } + + Row( + modifier = Modifier.fillMaxWidth().weight(1f), + ) { + onDescription() + } + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + ) { + onBottomRow() + } + } + } +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemLayout.kt b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/listItem/SlimListItemLayout.kt similarity index 81% rename from amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemLayout.kt rename to commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/listItem/SlimListItemLayout.kt index ed6f0b1a5d..b7ac7505f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/layouts/listItem/SlimListItemLayout.kt +++ b/commonsUI/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/layouts/listItem/SlimListItemLayout.kt @@ -18,31 +18,22 @@ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package com.vitorpamplona.amethyst.ui.layouts.listItem +package com.vitorpamplona.amethyst.commons.ui.layouts.listItem -import androidx.annotation.VisibleForTesting -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.ListItem import androidx.compose.material3.ListItemColors import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.FirstBaseline import androidx.compose.ui.layout.IntrinsicMeasurable import androidx.compose.ui.layout.IntrinsicMeasureScope @@ -55,117 +46,20 @@ import androidx.compose.ui.layout.MultiContentMeasurePolicy import androidx.compose.ui.layout.Placeable import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.offset import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.commons.resources.Res -import com.vitorpamplona.amethyst.commons.resources.profile_banner -import com.vitorpamplona.amethyst.commons.ui.stringRes -import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness -import com.vitorpamplona.amethyst.commons.ui.theme.Height4dpModifier -import com.vitorpamplona.amethyst.commons.ui.theme.Size55Modifier -import com.vitorpamplona.amethyst.commons.ui.theme.ThemeComparisonColumn -import com.vitorpamplona.amethyst.ui.layouts.ChatHeaderLayout -import com.vitorpamplona.amethyst.ui.layouts.listItem.ListTokens.ListItemContainerElevation -import com.vitorpamplona.amethyst.ui.note.elements.TimeAgo -import com.vitorpamplona.amethyst.ui.painterRes -import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.NewItemsBubble -import com.vitorpamplona.quartz.utils.TimeUtils +import com.vitorpamplona.amethyst.commons.ui.layouts.listItem.ListTokens.ListItemContainerElevation +import kotlin.jvm.JvmInline import kotlin.math.max /** * This is a copy of Material3's ListItemLayout.kt file, with the only change being the padding change from 16.dp to 10.dp */ -private const val PREVIEW_AUTHOR = "This is my author" -private const val PREVIEW_MESSAGE = "This is a message from this person" - -@Composable -@Preview -fun ChannelNamePreview() { - ThemeComparisonColumn { - Column { - ChatHeaderLayout( - channelPicture = { - Image( - painter = painterRes(R.drawable.github, 1), - contentDescription = stringRes(id = Res.string.profile_banner), - contentScale = ContentScale.FillWidth, - ) - }, - firstRow = { - Text(PREVIEW_AUTHOR, Modifier.weight(1f)) - TimeAgo(TimeUtils.now()) - }, - secondRow = { - Text(PREVIEW_MESSAGE, Modifier.weight(1f)) - NewItemsBubble() - }, - onClick = {}, - ) - - HorizontalDivider(thickness = DividerThickness) - - SlimListItem( - headlineContent = { - Row(verticalAlignment = CenterVertically) { - Text(PREVIEW_AUTHOR, Modifier.weight(1f)) - TimeAgo(TimeUtils.now()) - } - }, - supportingContent = { - Row(verticalAlignment = CenterVertically) { - Text(PREVIEW_MESSAGE, Modifier.weight(1f)) - Spacer(modifier = Height4dpModifier) - NewItemsBubble() - } - }, - leadingContent = { - Image( - painter = painterRes(R.drawable.github, 2), - contentDescription = stringRes(id = Res.string.profile_banner), - contentScale = ContentScale.FillWidth, - modifier = Size55Modifier, - ) - }, - ) - - HorizontalDivider(thickness = DividerThickness) - - ListItem( - headlineContent = { - Row(verticalAlignment = CenterVertically) { - Text(PREVIEW_AUTHOR, Modifier.weight(1f)) - TimeAgo(TimeUtils.now()) - } - }, - supportingContent = { - Row(verticalAlignment = CenterVertically) { - Text(PREVIEW_MESSAGE, Modifier.weight(1f)) - Spacer(modifier = Height4dpModifier) - NewItemsBubble() - } - }, - leadingContent = { - Image( - painter = painterRes(R.drawable.github, 2), - contentDescription = stringRes(id = Res.string.profile_banner), - contentScale = ContentScale.FillWidth, - modifier = Size55Modifier, - ) - }, - ) - - HorizontalDivider(thickness = DividerThickness) - } - } -} - @Composable fun SlimListItem( headlineContent: @Composable () -> Unit, @@ -688,22 +582,22 @@ object ListTokens { // Container related defaults // TODO: Make sure these values stay up to date until replaced with tokens. -@VisibleForTesting internal val ListItemVerticalPadding = 8.dp +internal val ListItemVerticalPadding = 8.dp -@VisibleForTesting internal val ListItemThreeLineVerticalPadding = 12.dp +internal val ListItemThreeLineVerticalPadding = 12.dp -@VisibleForTesting internal val ListItemStartPadding = 10.dp +internal val ListItemStartPadding = 10.dp -@VisibleForTesting internal val ListItemEndPadding = 10.dp +internal val ListItemEndPadding = 10.dp // Icon related defaults. // TODO: Make sure these values stay up to date until replaced with tokens. -@VisibleForTesting internal val LeadingContentEndPadding = Modifier.padding(end = 10.dp) +internal val LeadingContentEndPadding = Modifier.padding(end = 10.dp) // Icon related defaults. // TODO: Make sure these values stay up to date until replaced with tokens. -@VisibleForTesting internal val SupportingContentTopPadding = Modifier.padding(top = 2.dp) +internal val SupportingContentTopPadding = Modifier.padding(top = 2.dp) // Trailing related defaults. // TODO: Make sure these values stay up to date until replaced with tokens. -@VisibleForTesting internal val TrailingContentStartPadding = Modifier.padding(start = 10.dp) +internal val TrailingContentStartPadding = Modifier.padding(start = 10.dp) diff --git a/desktopApp/plans/2026-06-21-napplet-desktop-host.md b/desktopApp/plans/2026-06-21-napplet-desktop-host.md index b7b53f4ce8..03be3b0bc8 100644 --- a/desktopApp/plans/2026-06-21-napplet-desktop-host.md +++ b/desktopApp/plans/2026-06-21-napplet-desktop-host.md @@ -19,7 +19,7 @@ doc is the map: what already works for free, what desktop must build, and the de `NappletIdentity`, `NappletRequest`/`NappletResponse`, the permissions `Ledger`/`Store`/`GrantState`, and the gateway **interfaces** (`NappletRelayGateway`, `NappletStorage`, `NappletWalletGateway`, `NappletResourceGateway`, `NappletUploadGateway`, `NappletIdentityGateway`, `NappletConsentPrompt`). -- **`NappletProtocolJson`** (`commons/jvmAndroid`) — the wire codec. Desktop's host marshals through +- **`NappletProtocolJson`** (`commons/commonMain`) — the wire codec. Desktop's host marshals through the same object, so request/result/push shapes can never drift between platforms. **The web contract (`commons/commonMain/composeResources/files/napplet/` + `NappletWebContract`)** — diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/DesktopScheduledPostStore.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/DesktopScheduledPostStore.kt index ebd05606b5..96ccc66328 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/DesktopScheduledPostStore.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/DesktopScheduledPostStore.kt @@ -52,7 +52,7 @@ object DesktopScheduledPostStore { if (file.exists()) { setOwnerOnly(file, PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE) } - return ScheduledPostStore(file) + return ScheduledPostStore(file.path) } private fun setDirPermissions(dir: File) = diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/HeadlessScheduledPublish.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/HeadlessScheduledPublish.kt index 9c5fb8ee77..49b554ba66 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/HeadlessScheduledPublish.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/service/scheduledposts/HeadlessScheduledPublish.kt @@ -82,7 +82,7 @@ fun runHeadlessPublish(): Int { } private fun headlessDrain(log: (String) -> Unit): Int { - val store = ScheduledPostStore(File(scheduledDir(), ScheduledPostStore.FILE_NAME)) + val store = ScheduledPostStore(File(scheduledDir(), ScheduledPostStore.FILE_NAME).path) // Build a plain OkHttp client for websockets — no Tor, no proxy. Headless mode // reads no settings, so we cannot know Tor preferences; scheduled posts that diff --git a/tools/strings-migrate/fix_escapes.py b/tools/strings-migrate/fix_escapes.py index 34a48089f8..65c7a7c566 100755 --- a/tools/strings-migrate/fix_escapes.py +++ b/tools/strings-migrate/fix_escapes.py @@ -19,6 +19,17 @@ It does not handle these Android conventions, so this script applies them itself \\n, \\t, \\uXXXX and \\\\ are deliberately left alone -- Compose already resolves them, and converting them here would double-process. +Whitespace is the other half. aapt collapses every whitespace run in an unquoted +value to one space and trims the ends; Compose keeps the XML text verbatim. A value +wrapped over several indented lines therefore showed on Android as one line, and in +Compose as a leading line break plus eight spaces -- which CommonMark renders as a +code block (`account_backup_tips2_md`). This script applies aapt's rule to runs that +contain a line break or tab, which only XML layout produces (a deliberate newline is +written \\n). In a translation it also trims a leading/trailing space the source +string does not have: Crowdin exports a translator's stray edge space, aapt used to +drop it, Compose would draw it (" miejsca zniknęły" beside "tematy zniknęły"). +Deliberate edge spaces (" and ") exist in the source too, and are kept. + Usage: fix_escapes.py [...] (idempotent; safe to re-run) """ import re @@ -35,9 +46,28 @@ TOOLS_ATTR = re.compile(r'\s+tools:[\w.-]+="[^"]*"') TOOLS_NS = re.compile(r'\s+xmlns:tools="[^"]*"') # a backslash escape NOT itself preceded by a backslash ANDROID_ONLY = re.compile(r"(?]*\bname="([^"]+)"') -def fix_text(text: str, unwrap_quotes: bool = True) -> str: +def normalize_whitespace(text: str, source: str = None) -> str: + """Apply the aapt whitespace handling that Compose lacks. Idempotent. + + [source] is the default-locale value of the same key when [text] is a translation. + """ + if " str: """Convert one element's text. NOTE: quote-unwrapping is NOT idempotent and must run exactly once per file, at @@ -47,8 +77,9 @@ def fix_text(text: str, unwrap_quotes: bool = True) -> str: already-migrated files must therefore pass unwrap_quotes=False. """ if unwrap_quotes and len(text) >= 2 and text.startswith('"') and text.endswith('"'): - text = text[1:-1] - return ANDROID_ONLY.sub(r"\1", text) + # Quoted: aapt kept this whitespace exactly, so Compose keeps it too. + return ANDROID_ONLY.sub(r"\1", text[1:-1]) + return normalize_whitespace(ANDROID_ONLY.sub(r"\1", text), source) def strip_android_only_attrs(src: str) -> tuple: @@ -58,13 +89,31 @@ def strip_android_only_attrs(src: str) -> tuple: return out, n + m +def source_values(path: str) -> dict: + """The default-locale values beside a `values-/strings.xml`, else {}.""" + parent = os.path.dirname(os.path.abspath(path)) + if not os.path.basename(parent).startswith("values-"): + return {} + default = os.path.join(os.path.dirname(parent), "values", os.path.basename(path)) + if not os.path.exists(default): + return {} + out = {} + for m in STRING_EL.finditer(open(default, encoding="utf-8").read()): + name = STRING_NAME.match(m.group(1)) + if name: + out[name.group(1)] = m.group(2) + return out + + def fix_file(path: str, unwrap_quotes: bool = True) -> int: src = open(path, encoding="utf-8").read() + sources = source_values(path) changed = 0 def repl(m): nonlocal changed - fixed = fix_text(m.group(2), unwrap_quotes) + name = STRING_NAME.match(m.group(1)) + fixed = fix_text(m.group(2), unwrap_quotes, sources.get(name.group(1)) if name else None) if fixed != m.group(2): changed += 1 return m.group(1) + fixed + m.group(3)