mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 11:18:24 +00:00
Merge remote-tracking branch 'origin/main' into claude/serene-lamport-3eyza2
# Conflicts: # geode/README.md
This commit is contained in:
@@ -140,6 +140,12 @@ android {
|
||||
buildConfigField("String", "RELEASE_NOTES_ID", "\"f7914e7a7e293988485439eb2bea29c09c388d54c452c4a19f89e106dbf1969e\"")
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// ARM Memory Tagging Extension for our native code (WebRTC, zxing-cpp, SQLite,
|
||||
// secp256k1, Arti). Async is the low-overhead production mode; debug overrides
|
||||
// it to sync so a tag fault crashes at the exact faulting access. Ignored on
|
||||
// devices without MTE hardware or with it switched off.
|
||||
manifestPlaceholders["memtagMode"] = "async"
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
@@ -267,6 +273,7 @@ android {
|
||||
applicationIdSuffix = ".debug"
|
||||
versionNameSuffix = "-DEBUG"
|
||||
resValue("string", "app_name", "@string/app_name_debug")
|
||||
manifestPlaceholders["memtagMode"] = "sync"
|
||||
}
|
||||
create("benchmark") {
|
||||
initWith(getByName("release"))
|
||||
|
||||
@@ -184,6 +184,7 @@
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:hardwareAccelerated="true"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:memtagMode="${memtagMode}"
|
||||
tools:targetApi="34">
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
|
||||
@@ -1543,6 +1543,12 @@ class Account(
|
||||
note: Note,
|
||||
reaction: String,
|
||||
) {
|
||||
// A Marmot message reacts inside its MLS group; see AccountMarmotActions.reactToMarmotMessage.
|
||||
marmot.marmotGroupOf(note)?.let { groupId ->
|
||||
marmot.reactToMarmotMessage(groupId, note, reaction)
|
||||
return
|
||||
}
|
||||
|
||||
// Reactions to NIP-17 groups and unsealed rumors are gift-wrapped: the
|
||||
// inner kind-7 only ever travels as ciphertext, so mining it is pure
|
||||
// waste — those targets skip the queue and sign with the plain signer.
|
||||
@@ -1708,7 +1714,14 @@ class Account(
|
||||
suspend fun delete(notes: List<Note>) {
|
||||
if (!isWriteable()) return
|
||||
|
||||
val myNotes = notes.filter { it.author == userProfile() && it.event != null }
|
||||
// Marmot messages are retracted inside their group. A public NIP-09 here would e-tag
|
||||
// the group's private rumor ids onto public relays.
|
||||
val (marmotNotes, otherNotes) = notes.partition { marmot.marmotGroupOf(it) != null }
|
||||
marmotNotes.groupBy { marmot.marmotGroupOf(it)!! }.forEach { (groupId, groupNotes) ->
|
||||
marmot.deleteMarmotMessages(groupId, groupNotes)
|
||||
}
|
||||
|
||||
val myNotes = otherNotes.filter { it.author == userProfile() && it.event != null }
|
||||
if (myNotes.isNotEmpty()) {
|
||||
// chunks in 200 elements to avoid going over the 65KB limit for events.
|
||||
myNotes.chunked(200).forEach { chunkedList ->
|
||||
@@ -1738,6 +1751,12 @@ class Account(
|
||||
if (!isWriteable()) return
|
||||
val targetEvent = target.event ?: return
|
||||
|
||||
// In a Marmot group the deletion goes to the group, not to the target's author as a DM.
|
||||
marmot.marmotGroupOf(target)?.let { groupId ->
|
||||
marmot.deleteMarmotMessages(groupId, notes)
|
||||
return
|
||||
}
|
||||
|
||||
val myRumors = notes.filter { it.author == userProfile() }.mapNotNull { it.event }
|
||||
if (myRumors.isEmpty()) return
|
||||
|
||||
@@ -4025,11 +4044,9 @@ class Account(
|
||||
// via wasVerified=false) would silently drop
|
||||
// kind:7 reactions / kind:5 deletions since
|
||||
// they never carry a Schnorr signature.
|
||||
val isNew = cache.justConsume(innerEvent, null, true)
|
||||
val innerNote = cache.getOrCreateNote(innerEvent.id)
|
||||
if (isNew) {
|
||||
innerNote.event = innerEvent
|
||||
}
|
||||
// Same indexing as live decryption, so a restored
|
||||
// kind:1009 edit is re-linked to its message too.
|
||||
val innerNote = marmot.indexMarmotInnerEvent(innerEvent).note
|
||||
marmotGroupList.addMessage(groupId, innerNote)
|
||||
} catch (e: Exception) {
|
||||
Log.w(
|
||||
|
||||
@@ -20,12 +20,15 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.model
|
||||
|
||||
import com.vitorpamplona.amethyst.commons.model.Note
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.BlobStoreEndpointV2
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.EncryptedMediaPolicyV2
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.GroupAvatarUrlV1
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.GroupProfileV1
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.MarmotWebUrl
|
||||
import com.vitorpamplona.quartz.marmot.appComponents.MessageRetentionV1
|
||||
import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotAppEvent
|
||||
import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotMessageEdit
|
||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageEvent
|
||||
import com.vitorpamplona.quartz.marmot.mip00KeyPackages.KeyPackageFetcher
|
||||
import com.vitorpamplona.quartz.marmot.protocolCore.GroupLifecycleState
|
||||
@@ -246,6 +249,95 @@ class AccountMarmotActions(
|
||||
manager.persistDecryptedMessage(nostrGroupId, innerEvent.toJson())
|
||||
}
|
||||
|
||||
/**
|
||||
* Index a decrypted Marmot inner event: cache it, hold it on its note, and link an
|
||||
* edit to the message it replaces. Shared by live decryption and the startup restore
|
||||
* of the stored message log, so both see the same thing.
|
||||
*
|
||||
* A kind:1009 edit has no typed class, so `LocalCache` has no case for it and
|
||||
* `justConsume` drops it ("Event Not Supported"). The note then had no event and
|
||||
* `Note.latestMarmotEdit`, which matches on the event's kind, skipped it: an edit
|
||||
* from White Noise decrypted fine and never showed. An edit needs nothing from the
|
||||
* cache but its note, so it is attached directly.
|
||||
*/
|
||||
fun indexMarmotInnerEvent(innerEvent: Event): IndexedInnerEvent {
|
||||
val cache = account.cache
|
||||
val isEdit = innerEvent.kind == MarmotAppEvent.KIND_EDIT
|
||||
val innerNote = cache.getOrCreateNote(innerEvent.id)
|
||||
// wasVerified=true: MIP-03 inner events are unsigned rumors; MLS authenticated the sender.
|
||||
// For an edit, "new" is whether its note was empty — which also decides whether it is
|
||||
// persisted, so an edit is kept in the local log and survives a restart.
|
||||
val isNew = if (isEdit) innerNote.event == null else cache.justConsume(innerEvent, null, true)
|
||||
if (isNew || innerNote.event == null) {
|
||||
// loadEvent, not a bare `event =`: the overlay also matches the edit's AUTHOR to the
|
||||
// message's, and only loadEvent sets it.
|
||||
innerNote.loadEvent(innerEvent, cache.getOrCreateUser(innerEvent.pubKey), emptyList())
|
||||
}
|
||||
|
||||
// The overlay's rules (author-only, latest wins) are applied at render time by
|
||||
// `Note.latestMarmotEdit`: the target's author may not be known yet.
|
||||
if (isEdit) {
|
||||
MarmotMessageEdit.fromAppEvent(MarmotAppEvent.fromEvent(innerEvent))?.let { edit ->
|
||||
cache.getOrCreateNote(edit.targetId).addEdit(innerNote)
|
||||
}
|
||||
}
|
||||
return IndexedInnerEvent(innerNote, isNew)
|
||||
}
|
||||
|
||||
/** [note] holds the inner event; [isNew] is true the first time this client indexed it. */
|
||||
class IndexedInnerEvent(
|
||||
val note: Note,
|
||||
val isNew: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
* The Marmot group [note] was received or sent in, or null when it is not a
|
||||
* Marmot message.
|
||||
*
|
||||
* Only chat rows are indexed, so pass the MESSAGE a reaction or deletion is
|
||||
* about, not the reaction itself.
|
||||
*/
|
||||
fun marmotGroupOf(note: Note): HexKey? = account.marmotGroupList.groupIdForNote(note.idHex)
|
||||
|
||||
/**
|
||||
* React to a Marmot message inside its group.
|
||||
*
|
||||
* A Marmot message is an unsigned rumor, which the generic reaction path
|
||||
* handles as a NIP-17 private note: it gift-wrapped the kind:7 to the
|
||||
* author as a DM. That never reached the group, so no other client showed
|
||||
* it, and it moved group activity out of the group's channel. The reaction
|
||||
* is an ordinary inner kind:7 (MIP-03), encrypted to the group like any
|
||||
* message.
|
||||
*/
|
||||
suspend fun reactToMarmotMessage(
|
||||
nostrGroupId: HexKey,
|
||||
target: Note,
|
||||
reaction: String,
|
||||
) {
|
||||
val manager = account.marmotManager ?: return
|
||||
val targetEvent = target.event ?: return
|
||||
if (target.hasReacted(account.userProfile(), reaction)) return
|
||||
val rumor = manager.buildReactionRumor(targetEvent, reaction)
|
||||
sendMarmotGroupMessage(nostrGroupId, rumor, marmotGroupRelays(nostrGroupId))
|
||||
}
|
||||
|
||||
/**
|
||||
* Retract our own messages or reactions in a Marmot group with an inner
|
||||
* kind:5, for the same reason [reactToMarmotMessage] exists: the generic
|
||||
* private path sent a gift-wrapped NIP-09 to the target's author, so the
|
||||
* other members never saw the deletion.
|
||||
*/
|
||||
suspend fun deleteMarmotMessages(
|
||||
nostrGroupId: HexKey,
|
||||
notes: List<Note>,
|
||||
) {
|
||||
val manager = account.marmotManager ?: return
|
||||
val mine = notes.filter { it.author == account.userProfile() }.mapNotNull { it.event }
|
||||
if (mine.isEmpty()) return
|
||||
val rumor = manager.buildDeletionRumor(mine)
|
||||
sendMarmotGroupMessage(nostrGroupId, rumor, marmotGroupRelays(nostrGroupId))
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a user's KeyPackage from relays and add them to a Marmot group.
|
||||
* Returns a status message describing the outcome.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
package com.vitorpamplona.amethyst.service.cast
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
|
||||
@Immutable
|
||||
data class CastDevice(
|
||||
@@ -34,8 +35,36 @@ data class CastRequest(
|
||||
val mimeType: String? = null,
|
||||
val title: String? = null,
|
||||
val artworkUri: String? = null,
|
||||
/**
|
||||
* Whether the receiver should treat this as an endless live stream rather than a seekable
|
||||
* recording. Resolve it with [resolveCastLiveness] — never from the URL, which cannot tell a
|
||||
* live `.m3u8` from an on-demand one.
|
||||
*/
|
||||
val isLive: Boolean = false,
|
||||
/**
|
||||
* What the video is — "H.265 (HEVC) 1920x1080" — taken from the local player, which has already
|
||||
* decoded it. Reported when a cast fails, because the receiver itself rarely says why. See
|
||||
* [summarizeCastFormat].
|
||||
*/
|
||||
val formatSummary: String? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* Decides what to tell the Cast receiver about a stream's liveness.
|
||||
*
|
||||
* [learned] is ExoPlayer's verdict for this URL (see HlsLivenessCache), recorded once it has parsed
|
||||
* the playlist — the only signal that actually distinguishes a live `.m3u8` from an on-demand one.
|
||||
* It wins whenever we have it. [metadataFlag] is the kind:30311 live-activity flag, which is right
|
||||
* when set but absent for a live stream shared in a plain kind:1 note, so it is only the fallback.
|
||||
*
|
||||
* Defaulting to non-live when we know nothing keeps the previous behaviour for the common case
|
||||
* (progressive MP4), where a live claim would cost the receiver its seek bar and duration.
|
||||
*/
|
||||
fun resolveCastLiveness(
|
||||
learned: Boolean?,
|
||||
metadataFlag: Boolean,
|
||||
): Boolean = learned ?: metadataFlag
|
||||
|
||||
// Critical for HLS: sending an `.m3u8` URL with `video/mp4` makes the default
|
||||
// Cast receiver try to demux a playlist as MP4 and crash, wiping the TV's Cast
|
||||
// service from the network in the process. Strip query/fragment first so
|
||||
@@ -66,6 +95,21 @@ sealed class CastSessionState {
|
||||
|
||||
data class Error(
|
||||
val device: CastDevice?,
|
||||
val message: String,
|
||||
val message: CastErrorMessage,
|
||||
) : CastSessionState()
|
||||
}
|
||||
|
||||
/**
|
||||
* What went wrong, in a form the picker resolves in composition. The caster reports failures from
|
||||
* Cast SDK callbacks, where there is no blocking way to read a Compose resource, so it hands over
|
||||
* the resource and the UI formats it.
|
||||
*
|
||||
* [text] names the receiver as `%1$s`: the picker supplies the [CastSessionState.Error] device's
|
||||
* name, or a generic noun when the failure happens before or after we know which device it was.
|
||||
* A `_detail` resource also takes [detail] — what the video was — as `%2$s`.
|
||||
*/
|
||||
@Immutable
|
||||
data class CastErrorMessage(
|
||||
val text: StringResource,
|
||||
val detail: String? = null,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.service.cast
|
||||
|
||||
/**
|
||||
* Short human-readable description of what a video actually is — "H.265 (HEVC) 1920x1080".
|
||||
*
|
||||
* A Cast receiver that dislikes a video usually says nothing useful: an LG webOS TV accepts the
|
||||
* load, reports LOADING, and then goes silent, with no error and no reason. The phone, meanwhile,
|
||||
* has already decoded the same file locally and knows exactly what it is. Reporting that turns "it
|
||||
* didn't play" into "it's HEVC", which is the fact that explains the failure and tells the user
|
||||
* whether another device or another copy would do better.
|
||||
*
|
||||
* Codec names are the ones people recognise from device spec sheets rather than the raw mime types,
|
||||
* because the point of the message is to be recognisable. Anything unrecognised passes through
|
||||
* unchanged — a mime type we don't have a friendly name for is still better than nothing.
|
||||
*/
|
||||
fun summarizeCastFormat(
|
||||
sampleMimeType: String?,
|
||||
codecs: String?,
|
||||
width: Int,
|
||||
height: Int,
|
||||
): String? {
|
||||
val codec = friendlyCodecName(sampleMimeType) ?: codecs?.takeIf { it.isNotBlank() }
|
||||
val resolution = if (width > 0 && height > 0) "${width}x$height" else null
|
||||
return when {
|
||||
codec != null && resolution != null -> "$codec $resolution"
|
||||
codec != null -> codec
|
||||
resolution != null -> resolution
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun friendlyCodecName(sampleMimeType: String?): String? {
|
||||
val mime = sampleMimeType?.takeIf { it.isNotBlank() } ?: return null
|
||||
return when (mime.lowercase()) {
|
||||
"video/avc" -> "H.264"
|
||||
"video/hevc", "video/dolby-vision" -> "H.265 (HEVC)"
|
||||
"video/av01" -> "AV1"
|
||||
"video/x-vnd.on2.vp9" -> "VP9"
|
||||
"video/x-vnd.on2.vp8" -> "VP8"
|
||||
"video/mp4v-es" -> "MPEG-4"
|
||||
"video/mpeg2" -> "MPEG-2"
|
||||
else -> mime
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.service.cast
|
||||
|
||||
/**
|
||||
* How a cast request should reach its target receiver, given what is already connected.
|
||||
*
|
||||
* @param needsRouteSelection whether MediaRouter has to be asked to move.
|
||||
* @param expectsPreviousSessionToEnd whether an existing session will be torn down as a *result* of
|
||||
* that move. The caller must not read that teardown as the new attempt failing.
|
||||
*/
|
||||
enum class CastRoutePlan(
|
||||
val needsRouteSelection: Boolean,
|
||||
val expectsPreviousSessionToEnd: Boolean,
|
||||
) {
|
||||
/** Already connected to this very receiver — load straight onto the live session. */
|
||||
REUSE_SESSION(needsRouteSelection = false, expectsPreviousSessionToEnd = false),
|
||||
|
||||
/** Connected to a *different* receiver — selecting the target ends that session first. */
|
||||
SWAP_RECEIVER(needsRouteSelection = true, expectsPreviousSessionToEnd = true),
|
||||
|
||||
/** Nothing connected — select the route and wait for the session to start. */
|
||||
SELECT_FRESH(needsRouteSelection = true, expectsPreviousSessionToEnd = false),
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses the [CastRoutePlan] for a cast to [targetRouteId].
|
||||
*
|
||||
* The distinction that matters is between reusing a session and swapping receivers. Treating any
|
||||
* connected session as reusable — as this used to — means a session on the soundbar is taken as
|
||||
* proof that a cast to the TV is already connected: the start completes instantly, `selectRoute()`
|
||||
* then tears that session down, and by the time the media is loaded the session is gone, so the
|
||||
* load is skipped and the TV sits on its splash screen having "connected" successfully.
|
||||
*
|
||||
* [hasConnectedSession] must reflect a session that is actually connected; a stale or suspended one
|
||||
* cannot take a load and has to go through a fresh start.
|
||||
*/
|
||||
fun planRouteSelection(
|
||||
targetRouteId: String,
|
||||
selectedRouteId: String?,
|
||||
hasConnectedSession: Boolean,
|
||||
): CastRoutePlan =
|
||||
when {
|
||||
!hasConnectedSession -> CastRoutePlan.SELECT_FRESH
|
||||
selectedRouteId == targetRouteId -> CastRoutePlan.REUSE_SESSION
|
||||
else -> CastRoutePlan.SWAP_RECEIVER
|
||||
}
|
||||
+25
-2
@@ -74,12 +74,15 @@ import com.vitorpamplona.amethyst.model.VideoButtonLocation
|
||||
import com.vitorpamplona.amethyst.model.VideoPlayerAction
|
||||
import com.vitorpamplona.amethyst.service.cast.CastRequest
|
||||
import com.vitorpamplona.amethyst.service.cast.CastSessionState
|
||||
import com.vitorpamplona.amethyst.service.cast.resolveCastLiveness
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.DEFAULT_MUTED_SETTING
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemData
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.isHlsMedia
|
||||
import com.vitorpamplona.amethyst.service.playback.diskCache.HlsLivenessCache
|
||||
import com.vitorpamplona.amethyst.service.playback.pip.PipVideoActivity
|
||||
import com.vitorpamplona.amethyst.ui.cast.CastDevicePickerDialog
|
||||
import com.vitorpamplona.amethyst.ui.cast.rememberCastWithLocalNetworkPermission
|
||||
import com.vitorpamplona.amethyst.ui.components.ShareMediaAction
|
||||
import com.vitorpamplona.amethyst.ui.components.getActivity
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -229,6 +232,7 @@ fun RenderTopButtons(
|
||||
RenderTopButtons(
|
||||
mediaData = mediaData,
|
||||
hasMultipleQualities = hasMultipleQualities,
|
||||
castFormatSummary = castFormatSummary(videoGroup),
|
||||
qualityButton = {
|
||||
VideoQualityButton(
|
||||
player = player,
|
||||
@@ -294,6 +298,9 @@ fun RenderTopButtons(
|
||||
fun RenderTopButtons(
|
||||
mediaData: MediaItemData,
|
||||
hasMultipleQualities: Boolean,
|
||||
// What the local player decoded this as. Only the Cast failure messages use it: a receiver that
|
||||
// refuses a video usually will not say why, so this is the only description of it available.
|
||||
castFormatSummary: String? = null,
|
||||
qualityButton: @Composable () -> Unit,
|
||||
controllerVisible: MutableState<Boolean>,
|
||||
startingMuteState: Boolean,
|
||||
@@ -313,6 +320,7 @@ fun RenderTopButtons(
|
||||
val captionsContentDescription =
|
||||
stringRes(if (captionsEnabled) Res.string.captions_turn_off else Res.string.captions_turn_on)
|
||||
val shareDialogVisible = remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
val castDialogVisible = remember { mutableStateOf(false) }
|
||||
val castSessionState by Amethyst.instance.castRegistry.sessionState
|
||||
.collectAsStateWithLifecycle()
|
||||
@@ -321,15 +329,19 @@ fun RenderTopButtons(
|
||||
val castIcon = if (isThisVideoCasting) MaterialSymbols.CastConnected else MaterialSymbols.Cast
|
||||
val castContentDescription =
|
||||
stringRes(if (isThisVideoCasting) Res.string.cast_stop_casting else Res.string.cast_to_device)
|
||||
// Android 17 Local Network Protection blocks Cast device discovery until the
|
||||
// user grants ACCESS_LOCAL_NETWORK, so gate the picker behind the request.
|
||||
val showCastPicker = remember { { castDialogVisible.value = true } }
|
||||
val openCastPicker = rememberCastWithLocalNetworkPermission(context, showCastPicker)
|
||||
val onCastButtonClick =
|
||||
remember(isThisVideoCasting) {
|
||||
remember(isThisVideoCasting, openCastPicker) {
|
||||
{
|
||||
if (isThisVideoCasting) {
|
||||
Amethyst.instance.applicationIOScope.launch {
|
||||
Amethyst.instance.castRegistry.stopCasting()
|
||||
}
|
||||
} else {
|
||||
castDialogVisible.value = true
|
||||
openCastPicker()
|
||||
}
|
||||
Unit
|
||||
}
|
||||
@@ -495,6 +507,17 @@ fun RenderTopButtons(
|
||||
mimeType = mediaData.mimeType,
|
||||
title = mediaData.title,
|
||||
artworkUri = mediaData.artworkUri,
|
||||
// By the time the cast button is reachable the player has already parsed the
|
||||
// playlist, so the learned verdict is normally available here.
|
||||
isLive =
|
||||
resolveCastLiveness(
|
||||
learned = HlsLivenessCache.verdict(mediaData.videoUri),
|
||||
metadataFlag = mediaData.isLiveStream,
|
||||
),
|
||||
// The local player has already decoded this, so it knows what the receiver
|
||||
// is about to be handed — the only description of the media available when
|
||||
// the receiver refuses it without saying why.
|
||||
formatSummary = castFormatSummary,
|
||||
),
|
||||
onDismiss = { castDialogVisible.value = false },
|
||||
)
|
||||
|
||||
+19
@@ -26,10 +26,12 @@ import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.Format
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.TrackSelectionOverride
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.vitorpamplona.amethyst.service.cast.summarizeCastFormat
|
||||
import com.vitorpamplona.amethyst.service.playback.PLAYBACK_DIAG_TAG
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.LogLevel
|
||||
@@ -37,6 +39,23 @@ import kotlin.math.ceil
|
||||
|
||||
internal fun getVideoTrackGroup(tracks: Tracks): Tracks.Group? = tracks.groups.firstOrNull { it.type == C.TRACK_TYPE_VIDEO && it.length > 0 }
|
||||
|
||||
// Describes the video being played, for the Cast failure messages. Uses the highest-resolution
|
||||
// track in the group: that is the one an adaptive stream will climb to, so it is the one a
|
||||
// receiver with limited codec or resolution support will choke on.
|
||||
@OptIn(UnstableApi::class)
|
||||
internal fun castFormatSummary(group: Tracks.Group?): String? {
|
||||
if (group == null) return null
|
||||
var best: Format? = null
|
||||
for (i in 0 until group.length) {
|
||||
val format = group.getTrackFormat(i)
|
||||
if (best == null || format.width.toLong() * format.height > best!!.width.toLong() * best!!.height) {
|
||||
best = format
|
||||
}
|
||||
}
|
||||
val format = best ?: return null
|
||||
return summarizeCastFormat(format.sampleMimeType, format.codecs, format.width, format.height)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrains adaptive selection to the area the player is actually drawn in.
|
||||
*
|
||||
|
||||
+6
@@ -136,6 +136,7 @@ import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.allGoodColor
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.grayText
|
||||
import com.vitorpamplona.amethyst.service.playback.composable.VideoViewInner
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
@@ -221,6 +222,11 @@ fun BlossomBlobManagerScreen(
|
||||
},
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.ManageBlossomBlobs, nav, accountViewModel) { route ->
|
||||
if (route != Route.ManageBlossomBlobs) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier =
|
||||
|
||||
+12
-2
@@ -31,6 +31,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_generic_receiver
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_searching_for_devices
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_to_device_dialog_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.components.M3ActionDialog
|
||||
@@ -105,9 +106,10 @@ fun CastDevicePickerDialog(
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionState is CastSessionState.Error) {
|
||||
val error = sessionState as? CastSessionState.Error
|
||||
if (error != null) {
|
||||
Text(
|
||||
text = (sessionState as CastSessionState.Error).message,
|
||||
text = castErrorText(error),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp),
|
||||
@@ -115,3 +117,11 @@ fun CastDevicePickerDialog(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun castErrorText(error: CastSessionState.Error): String =
|
||||
stringRes(
|
||||
error.message.text,
|
||||
error.device?.name ?: stringRes(Res.string.cast_generic_receiver),
|
||||
error.message.detail,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.cast
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.cancel
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_local_network_permission_message
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_local_network_permission_open_settings
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_local_network_permission_title
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.call.hasPermission
|
||||
import com.vitorpamplona.amethyst.ui.call.openAppSettings
|
||||
|
||||
// Android 17 (API 37) Local Network Protection gates the mDNS/multicast device
|
||||
// discovery the Cast SDK relies on behind the dangerous ACCESS_LOCAL_NETWORK
|
||||
// runtime permission. Without it the picker silently finds zero receivers.
|
||||
// Older OSes have no LNP and never define the permission, so the gate is a
|
||||
// no-op there.
|
||||
private const val LOCAL_NETWORK_PROTECTION_SDK = 37
|
||||
|
||||
private fun needsLocalNetworkPermission(): Boolean = Build.VERSION.SDK_INT >= LOCAL_NETWORK_PROTECTION_SDK
|
||||
|
||||
fun hasLocalNetworkPermission(context: Context): Boolean = !needsLocalNetworkPermission() || hasPermission(context, Manifest.permission.ACCESS_LOCAL_NETWORK)
|
||||
|
||||
/**
|
||||
* Returns a click handler that ensures [Manifest.permission.ACCESS_LOCAL_NETWORK]
|
||||
* is granted before running [onGranted] (which opens the Cast device picker).
|
||||
*
|
||||
* On Android 17+ the permission is requested on first tap; if the user denies
|
||||
* it, a dialog deep-links to app settings. On older OSes the permission does
|
||||
* not exist, so [onGranted] runs immediately.
|
||||
*/
|
||||
@Composable
|
||||
fun rememberCastWithLocalNetworkPermission(
|
||||
context: Context,
|
||||
onGranted: () -> Unit,
|
||||
): () -> Unit {
|
||||
var showDeniedDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val launcher =
|
||||
rememberLauncherForActivityResult(
|
||||
ActivityResultContracts.RequestPermission(),
|
||||
) { granted ->
|
||||
// A silent deny (permanently-denied, where Android skips the dialog)
|
||||
// also lands here with granted=false, so surface the deep-link
|
||||
// dialog rather than failing silently with an empty picker.
|
||||
if (granted) onGranted() else showDeniedDialog = true
|
||||
}
|
||||
|
||||
if (showDeniedDialog) {
|
||||
LocalNetworkPermissionDeniedDialog(
|
||||
onDismiss = { showDeniedDialog = false },
|
||||
onOpenSettings = {
|
||||
showDeniedDialog = false
|
||||
openAppSettings(context)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return remember(onGranted) {
|
||||
{
|
||||
if (hasLocalNetworkPermission(context)) {
|
||||
onGranted()
|
||||
} else {
|
||||
launcher.launch(Manifest.permission.ACCESS_LOCAL_NETWORK)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LocalNetworkPermissionDeniedDialog(
|
||||
onDismiss: () -> Unit,
|
||||
onOpenSettings: () -> Unit,
|
||||
) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringRes(Res.string.cast_local_network_permission_title)) },
|
||||
text = { Text(stringRes(Res.string.cast_local_network_permission_message)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = onOpenSettings) {
|
||||
Text(stringRes(Res.string.cast_local_network_permission_open_settings))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringRes(Res.string.cancel))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -54,6 +54,14 @@ const val BOTTOM_NAV_ROOT_KEY = "bottomNavRoot"
|
||||
|
||||
fun NavBackStackEntry.isBottomNavRoot(): Boolean = savedStateHandle.get<Boolean>(BOTTOM_NAV_ROOT_KEY) == true
|
||||
|
||||
// Per-entry hint stamped by Nav.navDrawer marking that the entry was opened
|
||||
// from the navigation drawer. It sits on top of the stack like any push (back
|
||||
// arrow, slide animation), but Nav.showsBottomBar keeps the bottom bar on it:
|
||||
// a drawer destination is a top-level section, not a detail screen.
|
||||
const val DRAWER_ROOT_KEY = "drawerRoot"
|
||||
|
||||
fun NavBackStackEntry.isDrawerRoot(): Boolean = savedStateHandle.get<Boolean>(DRAWER_ROOT_KEY) == true
|
||||
|
||||
/**
|
||||
* The shell's current layout tier, mirrored for the transition specs below. Transition
|
||||
* lambdas run when a navigation starts — outside composition — so they can't read
|
||||
|
||||
+4
-4
@@ -68,7 +68,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
|
||||
/** Content height of the [AppBottomBar] (the 50.dp Column inside [RenderBottomMenu]),
|
||||
* exclusive of the system navigation-bar inset. Used by FAB callers that want to
|
||||
* reserve the same vertical space when the bar hides itself on canPop entries. */
|
||||
* reserve the same vertical space when the bar hides itself on in-app pushes. */
|
||||
val AppBottomBarHeight = 50.dp
|
||||
|
||||
@Composable
|
||||
@@ -94,9 +94,9 @@ fun AppBottomBar(
|
||||
// permanently docked drawer (Expanded).
|
||||
if (LocalScreenLayout.current.isLargeScreen) return
|
||||
|
||||
// Hide the bar on entries that aren't a tab root (drawer or in-app
|
||||
// pushes). Mirrors the back-arrow rule in canPop().
|
||||
if (nav.canPop()) return
|
||||
// Hide the bar on in-app pushes. Tab roots, Home and screens opened from
|
||||
// the drawer keep it, even though the drawer ones still show a back arrow.
|
||||
if (!nav.showsBottomBar()) return
|
||||
|
||||
val items by accountViewModel.account.settings.syncedSettings.navigation.bottomBarItems
|
||||
.collectAsStateWithLifecycle()
|
||||
|
||||
+21
-13
@@ -210,7 +210,7 @@ private fun DrawerContentBody(
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
val onClickUser = {
|
||||
nav.nav(routeFor(accountViewModel.userProfile()))
|
||||
nav.navDrawer(routeFor(accountViewModel.userProfile()))
|
||||
nav.closeDrawer()
|
||||
}
|
||||
|
||||
@@ -641,24 +641,32 @@ fun ListContent(
|
||||
}
|
||||
}
|
||||
|
||||
/** The Create section's rows — composer entry points, none of which is a catalog destination. */
|
||||
/**
|
||||
* The Create section's rows — composer entry points, none of which is a catalog destination. They
|
||||
* open as plain pushes rather than through [INav.navDrawer]: those screens host no bottom bar, and
|
||||
* a drawer stamp would tell FabBottomBarPadding that one is showing.
|
||||
*/
|
||||
@Composable
|
||||
private fun CreateRows(nav: INav) {
|
||||
NavigationRow(
|
||||
IconRow(
|
||||
title = Res.string.share_hls_video,
|
||||
icon = MaterialSymbols.SettingsInputAntenna,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.NewHlsVideo,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(Route.NewHlsVideo)
|
||||
},
|
||||
)
|
||||
|
||||
if (isDebug) {
|
||||
NavigationRow(
|
||||
IconRow(
|
||||
title = Res.string.route_chess,
|
||||
icon = MaterialSymbols.ChessKnight,
|
||||
tint = MaterialTheme.colorScheme.onBackground,
|
||||
nav = nav,
|
||||
route = Route.Chess,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(Route.Chess)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -742,7 +750,7 @@ private fun ScheduledPostsNavigationRow(
|
||||
badgeCount = pendingCount,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav { def.resolveRoute(accountViewModel) }
|
||||
nav.navDrawer { def.resolveRoute(accountViewModel) }
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -850,7 +858,7 @@ fun NavigationRow(
|
||||
tint,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(route)
|
||||
nav.navDrawer(route)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -871,7 +879,7 @@ fun NavigationRow(
|
||||
tint,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(computeRoute)
|
||||
nav.navDrawer(computeRoute)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -890,7 +898,7 @@ fun NavigationRow(
|
||||
tint = tint,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(route)
|
||||
nav.navDrawer(route)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -909,7 +917,7 @@ fun NavigationRow(
|
||||
tint = tint,
|
||||
onClick = {
|
||||
nav.closeDrawer()
|
||||
nav.nav(computeRoute)
|
||||
nav.navDrawer(computeRoute)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ import androidx.navigation.NavHostController
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.BOTTOM_NAV_ROOT_KEY
|
||||
import com.vitorpamplona.amethyst.ui.navigation.DRAWER_ROOT_KEY
|
||||
import com.vitorpamplona.amethyst.ui.navigation.isBottomNavRoot
|
||||
import com.vitorpamplona.amethyst.ui.navigation.isDrawerRoot
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.getRouteWithArguments
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -89,6 +91,31 @@ class Nav(
|
||||
}
|
||||
}
|
||||
|
||||
override fun navDrawer(route: Route) {
|
||||
navigationScope.launch {
|
||||
ime.settle()
|
||||
navigateFromDrawer(route)
|
||||
}
|
||||
}
|
||||
|
||||
override fun navDrawer(computeRoute: suspend () -> Route?) {
|
||||
navigationScope.launch {
|
||||
ime.settle()
|
||||
computeRoute()?.let { navigateFromDrawer(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same push as [nav], then stamps the new entry [DRAWER_ROOT_KEY] so [showsBottomBar] keeps
|
||||
* the bottom bar on it. The stamp lands in the same frame as the navigate, before the entry
|
||||
* composes, the way [navBottomBar] stamps its tab roots.
|
||||
*/
|
||||
private fun navigateFromDrawer(route: Route) {
|
||||
if (getRouteWithArguments(route::class, controller) == route) return
|
||||
controller.navigate(route)
|
||||
controller.currentBackStackEntry?.savedStateHandle?.set(DRAWER_ROOT_KEY, true)
|
||||
}
|
||||
|
||||
override fun newStack(route: Route) {
|
||||
navigationScope.launch {
|
||||
ime.settle()
|
||||
@@ -107,9 +134,10 @@ class Nav(
|
||||
|
||||
// A nav-bar tap asks for a tab, never for whatever the user pushed on top of one. Drop
|
||||
// those pushes first, and without saving them, so the restoreState below can never hand
|
||||
// a deep stack back. On phones this is always a no-op — AppBottomBar hides itself off
|
||||
// tab roots, so the bar is only ever tapped from one — but the large-screen rail stays
|
||||
// on screen the whole time and is routinely tapped from three screens deep.
|
||||
// a deep stack back. On phones the bar shows only on tab roots and on screens opened
|
||||
// from the drawer (dropped here, back to the tab they were opened over), but the
|
||||
// large-screen rail stays on screen the whole time and is routinely tapped from three
|
||||
// screens deep.
|
||||
popPushesAboveTabRoot()
|
||||
|
||||
// Dropping those pushes is often the whole job — re-tapping the tab the user is inside,
|
||||
@@ -211,11 +239,24 @@ class Nav(
|
||||
// Outside a NavHost destination (shell chrome, drawer) the current owner
|
||||
// is the account-scoped ViewModelStoreOwner, not an entry; fall back to
|
||||
// the globally-current entry so those callers keep their prior behavior.
|
||||
val entry =
|
||||
(LocalViewModelStoreOwner.current as? NavBackStackEntry)
|
||||
?: controller.currentBackStackEntry
|
||||
?: return false
|
||||
val entry = ownEntry() ?: return false
|
||||
return canPop(entry)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun showsBottomBar(): Boolean {
|
||||
val entry = ownEntry() ?: return true
|
||||
// Drawer destinations can pop (they sit on whatever screen the drawer was opened over),
|
||||
// but they are top-level sections, so they keep the bar the tab roots have.
|
||||
return entry.isDrawerRoot() || !canPop(entry)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ownEntry(): NavBackStackEntry? =
|
||||
(LocalViewModelStoreOwner.current as? NavBackStackEntry)
|
||||
?: controller.currentBackStackEntry
|
||||
|
||||
private fun canPop(entry: NavBackStackEntry): Boolean {
|
||||
// Hidden on tab roots (reached via the bottom nav) and on Home (the
|
||||
// graph's start destination): nothing sits below either that a back
|
||||
// arrow could return to. Every other entry is a push on top of Home,
|
||||
|
||||
+12
-8
@@ -37,6 +37,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerSync
|
||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client
|
||||
import com.vitorpamplona.quartz.nip06KeyDerivation.Nip06
|
||||
import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription
|
||||
import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser
|
||||
import com.vitorpamplona.quartz.nip19Bech32.decodePrivateKeyAsHexOrNull
|
||||
import com.vitorpamplona.quartz.nip19Bech32.decodePublicKeyAsHexOrNull
|
||||
@@ -202,14 +203,17 @@ class AccountSessionManager(
|
||||
packageName: String = "",
|
||||
onError: (String?) -> Unit,
|
||||
) {
|
||||
// Accepts keys copied by hand from the backup screen: UPPERCASE, and split
|
||||
// into groups by spaces, dashes or line breaks.
|
||||
val cleanKey = Bech32Transcription.normalize(key)
|
||||
scope.launch(Dispatchers.IO) {
|
||||
if (key.startsWith("ncryptsec")) {
|
||||
if (cleanKey.startsWith("ncryptsec")) {
|
||||
val newKey =
|
||||
try {
|
||||
if (key.isEmpty() || password.isEmpty()) {
|
||||
if (cleanKey.isEmpty() || password.isEmpty()) {
|
||||
null
|
||||
} else {
|
||||
Nip49().decrypt(key, password)
|
||||
Nip49().decrypt(cleanKey, password)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) throw e
|
||||
@@ -223,24 +227,24 @@ class AccountSessionManager(
|
||||
} else {
|
||||
loginSync(newKey, transientAccount, loginWithExternalSigner, packageName, onError)
|
||||
}
|
||||
} else if (EMAIL_PATTERN.matcher(key).matches()) {
|
||||
} else if (EMAIL_PATTERN.matcher(cleanKey).matches()) {
|
||||
// Delegate to the shared quartz resolver so NIP-05 handling stays in
|
||||
// lockstep with the CLI and anywhere else we accept user identifiers.
|
||||
try {
|
||||
val hex =
|
||||
com.vitorpamplona.quartz.nip05DnsIdentifiers
|
||||
.resolveUserHexOrNull(key, nip05ClientBuilder())
|
||||
.resolveUserHexOrNull(cleanKey, nip05ClientBuilder())
|
||||
if (hex == null) {
|
||||
onError("User not found in the nip05 server: $key")
|
||||
onError("User not found in the nip05 server: $cleanKey")
|
||||
} else {
|
||||
loginSync(Hex.decode(hex).toNpub(), transientAccount, loginWithExternalSigner, packageName, onError)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) throw e
|
||||
onError("Could not load nip05 address from the server: $key. ${e.message}")
|
||||
onError("Could not load nip05 address from the server: $cleanKey. ${e.message}")
|
||||
}
|
||||
} else {
|
||||
loginSync(key, transientAccount, loginWithExternalSigner, packageName, onError)
|
||||
loginSync(cleanKey, transientAccount, loginWithExternalSigner, packageName, onError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-29
@@ -32,8 +32,6 @@ import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent
|
||||
import com.vitorpamplona.quartz.marmot.GroupEventResult
|
||||
import com.vitorpamplona.quartz.marmot.MarmotInboundProcessor
|
||||
import com.vitorpamplona.quartz.marmot.WelcomeResult
|
||||
import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotAppEvent
|
||||
import com.vitorpamplona.quartz.marmot.foundation.appEvents.MarmotMessageEdit
|
||||
import com.vitorpamplona.quartz.marmot.mip02Welcome.WelcomeEvent
|
||||
import com.vitorpamplona.quartz.marmot.mip03GroupMessages.GroupEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
@@ -672,15 +670,9 @@ class GroupEventHandler(
|
||||
// needs this path to surface the note (otherwise the
|
||||
// operator saw nothing but a misleading "inner event
|
||||
// already in cache" log and the message never rendered).
|
||||
val isNew = cache.justConsume(innerEvent, null, true)
|
||||
val innerNote = cache.getOrCreateNote(innerEvent.id)
|
||||
if (isNew) {
|
||||
innerNote.event = innerEvent
|
||||
} else {
|
||||
Log.d("MarmotDbg") {
|
||||
"GroupEventHandler.add: inner event already in cache — surfacing in chatroom anyway"
|
||||
}
|
||||
}
|
||||
val indexed = account.marmot.indexMarmotInnerEvent(innerEvent)
|
||||
val innerNote = indexed.note
|
||||
val isNew = indexed.isNew
|
||||
|
||||
// Link the envelope to its inner note and copy over the
|
||||
// relays that delivered/accepted the kind-445 so far, so
|
||||
@@ -694,24 +686,8 @@ class GroupEventHandler(
|
||||
cache.copyRelaysFromTo(outerNote, innerEvent.id)
|
||||
}
|
||||
|
||||
// A kind:1009 edit is anchored to the message it replaces,
|
||||
// exactly like a Concord edit or a reaction: the bubble reads
|
||||
// `Note.edits`, and holding the edit as a hard-referenced
|
||||
// child of its target is what keeps it alive as long as that
|
||||
// target is. A Marmot inner event is decrypted exactly once —
|
||||
// the ratchet has moved on by the time anyone could re-fetch
|
||||
// it — so an edit left orphaned in the soft cache could be
|
||||
// collected and never come back.
|
||||
//
|
||||
// The overlay's own rules (author-only, latest wins) are
|
||||
// applied at render time by `Note.latestMarmotEdit`, not here:
|
||||
// the target's author is not necessarily known yet when the
|
||||
// edit arrives, and a link is not an endorsement.
|
||||
if (innerEvent.kind == MarmotAppEvent.KIND_EDIT) {
|
||||
MarmotMessageEdit.fromAppEvent(MarmotAppEvent.fromEvent(innerEvent))?.let { edit ->
|
||||
cache.getOrCreateNote(edit.targetId).addEdit(innerNote)
|
||||
}
|
||||
}
|
||||
// A kind:1009 edit was linked to the message it replaces by
|
||||
// indexMarmotInnerEvent, which also holds it on its note.
|
||||
|
||||
// Push token gossip (kinds 447/448/449) is routing data for
|
||||
// a notification server, addressed to the other members'
|
||||
|
||||
+6
@@ -64,6 +64,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.model.cordn.CordnRuntime
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.CordnGroupRoomCompose
|
||||
@@ -125,6 +126,11 @@ fun CordnGroupListScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.CordnGroupList, nav, accountViewModel) { route ->
|
||||
if (route != Route.CordnGroupList) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
if (runtime == null) {
|
||||
EmptyState(
|
||||
|
||||
+14
-5
@@ -91,6 +91,7 @@ import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.Size55dp
|
||||
import com.vitorpamplona.amethyst.service.relayClient.reqCommand.user.observeUserInfo
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.note.NonClickableUserPictures
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.feed.types.hasEncryptedMediaV2
|
||||
@@ -136,16 +137,24 @@ fun MarmotGroupListScreen(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { nav.popBack() }) {
|
||||
Icon(
|
||||
symbol = MaterialSymbols.AutoMirrored.ArrowBack,
|
||||
contentDescription = stringRes(Res.string.back),
|
||||
)
|
||||
// No arrow as a bottom-nav tab root: there is nothing below it to return to.
|
||||
if (nav.canPop()) {
|
||||
IconButton(onClick = { nav.popBack() }) {
|
||||
Icon(
|
||||
symbol = MaterialSymbols.AutoMirrored.ArrowBack,
|
||||
contentDescription = stringRes(Res.string.back),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
title = { Text(stringRes(Res.string.marmot_groups_title)) },
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.MarmotGroupList, nav, accountViewModel) { route ->
|
||||
if (route != Route.MarmotGroupList) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
FabBottomBarPadded(nav) {
|
||||
FloatingActionButton(onClick = { nav.nav(Route.CreateMarmotGroup) }, shape = CircleShape) {
|
||||
|
||||
+1
-1
@@ -353,7 +353,7 @@ fun ConcordChannelListScreen(
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
// Renders only when this is a bottom-nav root (AppBottomBar hides itself when canPop),
|
||||
// Hidden on in-app pushes (AppBottomBar renders only when nav.showsBottomBar()),
|
||||
// so a pinned Concord community works both as a pushed detail and as a bottom-nav tab.
|
||||
AppBottomBar(Route.ConcordServer(communityId), nav, accountViewModel) { route ->
|
||||
if (route != Route.ConcordServer(communityId)) nav.navBottomBar(route)
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ fun ConcordHomeScreen(
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
// Renders only when this is a bottom-nav root (AppBottomBar hides itself when canPop),
|
||||
// Hidden on in-app pushes (AppBottomBar renders only when nav.showsBottomBar()),
|
||||
// so the same screen works both as a pushed destination and a bottom-nav tab.
|
||||
AppBottomBar(Route.Concords, nav, accountViewModel) { route ->
|
||||
if (route != Route.Concords) nav.navBottomBar(route)
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ fun PublicChatChannelScreen(
|
||||
PublicChatTopBar(it, accountViewModel, nav)
|
||||
}
|
||||
},
|
||||
// Renders only when this is a bottom-nav root (AppBottomBar hides itself when canPop),
|
||||
// Hidden on in-app pushes (AppBottomBar renders only when nav.showsBottomBar()),
|
||||
// so a pinned public chat works both as a pushed detail and as a bottom-nav tab.
|
||||
bottomBar = {
|
||||
AppBottomBar(selfRoute, nav, accountViewModel) { route ->
|
||||
|
||||
+1
-1
@@ -439,7 +439,7 @@ fun RelayGroupChannelListScreen(
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
// Renders only when this is a bottom-nav root (AppBottomBar hides itself when canPop),
|
||||
// Hidden on in-app pushes (AppBottomBar renders only when nav.showsBottomBar()),
|
||||
// so a pinned NIP-29 relay works both as a pushed detail and as a bottom-nav tab.
|
||||
AppBottomBar(selfRoute, nav, accountViewModel) { route ->
|
||||
if (route != selfRoute) nav.navBottomBar(route)
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ fun RelayGroupChatScreen(
|
||||
RelayGroupTopBar(it, inviteCode, accountViewModel, nav)
|
||||
}
|
||||
},
|
||||
// Renders only when this is a bottom-nav root (AppBottomBar hides itself when canPop),
|
||||
// Hidden on in-app pushes (AppBottomBar renders only when nav.showsBottomBar()),
|
||||
// so a pinned relay group works both as a pushed detail and as a bottom-nav tab.
|
||||
bottomBar = {
|
||||
AppBottomBar(selfRoute, nav, accountViewModel) { route ->
|
||||
|
||||
+22
-4
@@ -90,9 +90,10 @@ class RemoteImeView(
|
||||
private val flush = Runnable { flushState() }
|
||||
|
||||
init {
|
||||
// Invisible but focusable: the IME needs a laid-out, visible target, but the user must never see
|
||||
// this field or its cursor/selection handles — only the embedded page.
|
||||
isFocusableInTouchMode = true
|
||||
// Invisible: the IME needs a laid-out, visible target, but the user must never see this field or its
|
||||
// cursor/selection handles — only the embedded page. Focusable only while it mirrors a page field
|
||||
// (see [setFocusTarget]).
|
||||
setFocusTarget(false)
|
||||
alpha = 0f
|
||||
background = null
|
||||
setTextColor(0x00000000)
|
||||
@@ -186,6 +187,7 @@ class RemoteImeView(
|
||||
) {
|
||||
configureFor(focus)
|
||||
mirroring = true
|
||||
setFocusTarget(true)
|
||||
fieldReadOnly = focus.readOnly
|
||||
// Focus the EditText BEFORE seeding text/selection. An EditText jumps its caret to the end when it
|
||||
// gains focus; if we seed first, that end-position then overrides the seed and gets shipped to the
|
||||
@@ -313,12 +315,28 @@ class RemoteImeView(
|
||||
// whatever arrives to the field focused THEN, not the one it was computed from. Nothing this mirror
|
||||
// holds belongs to the page once the field has blurred, so suppress the echo and drop the queue.
|
||||
applyingRemote = true
|
||||
clearFocus()
|
||||
// Not focusable again until the next page focus. Dropping the flag clears our focus as well, so no
|
||||
// separate clearFocus() is needed (and one alone could hand focus straight back to us).
|
||||
setFocusTarget(false)
|
||||
applyingRemote = false
|
||||
removeCallbacks(flush)
|
||||
imm.hideSoftInputFromWindow(windowToken, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this view can take focus. It lives in the main window whether or not a browser tab is open, so
|
||||
* while it is focusable it is the fallback focus target for the whole window: when a Compose text field
|
||||
* elsewhere loses focus (clearFocus(), or its screen being popped), Android hands focus to this EditText.
|
||||
* It then becomes the IME's target, so the keyboard stays up over a screen with no field, and it comes
|
||||
* back every time the app resumes. So it is focusable only while it actually mirrors a page field.
|
||||
* Both flags are set: `isFocusable` alone would still let it take focus outside touch mode (a hardware
|
||||
* keyboard or D-pad).
|
||||
*/
|
||||
private fun setFocusTarget(enabled: Boolean) {
|
||||
isFocusable = enabled
|
||||
isFocusableInTouchMode = enabled
|
||||
}
|
||||
|
||||
private fun applyRemote(
|
||||
newText: String,
|
||||
selStart: Int,
|
||||
|
||||
+6
-2
@@ -107,8 +107,12 @@ fun GeocachesScreen(
|
||||
}
|
||||
},
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Geocaches(), nav, accountViewModel) { route ->
|
||||
if (route is Route.Geocaches) {
|
||||
// Geocaches and Hunts are two separate pinnable tabs of this one screen, so match the
|
||||
// exact route: a class check highlighted the wrong one and turned a tap on the other
|
||||
// into a scroll-to-top instead of a tab switch.
|
||||
val selfRoute = Route.Geocaches(initialTab)
|
||||
AppBottomBar(selfRoute, nav, accountViewModel) { route ->
|
||||
if (route == selfRoute) {
|
||||
nearby.sendToTop()
|
||||
} else {
|
||||
nav.navBottomBar(route)
|
||||
|
||||
+600
-360
File diff suppressed because it is too large
Load Diff
+7
@@ -37,11 +37,13 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.napplet_none_found
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.napplet.NappletLauncher
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.napplets.datasource.NappletsFilterAssemblerSubscription
|
||||
@@ -90,6 +92,11 @@ fun NappletsScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = { NappletsTopBar(accountViewModel, nav) },
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Napplets, nav, accountViewModel) { route ->
|
||||
if (route != Route.Napplets) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
if (visible.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize().padding(padding), contentAlignment = Alignment.Center) {
|
||||
|
||||
+7
@@ -37,10 +37,12 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.nsite_none_found
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.nsites.datasource.NsitesFilterAssemblerSubscription
|
||||
@@ -88,6 +90,11 @@ fun NsitesScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = { NsitesTopBar(accountViewModel, nav) },
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Nsites, nav, accountViewModel) { route ->
|
||||
if (route != Route.Nsites) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
if (visible.isEmpty()) {
|
||||
Box(Modifier.fillMaxSize().padding(padding), contentAlignment = Alignment.Center) {
|
||||
|
||||
+6
@@ -125,6 +125,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackBu
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.model.nip46Signer.Nip46SignerState
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.QrCodeDrawer
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.SimpleQrCodeScanner
|
||||
@@ -193,6 +194,11 @@ fun Nip46SignerScreen(
|
||||
|
||||
Scaffold(
|
||||
topBar = { TopBarWithBackButton(stringRes(Res.string.nip46_signer_title), nav) },
|
||||
bottomBar = {
|
||||
AppBottomBar(Route.Nip46Signer(), nav, accountViewModel) { route ->
|
||||
if (route != Route.Nip46Signer()) nav.navBottomBar(route)
|
||||
}
|
||||
},
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier =
|
||||
|
||||
+2
-1
@@ -39,6 +39,7 @@ import com.vitorpamplona.amethyst.commons.resources.password_is_required
|
||||
import com.vitorpamplona.amethyst.commons.resources.sign_request_rejected_description
|
||||
import com.vitorpamplona.amethyst.commons.tor.TorSettingsFlow
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountSessionManager
|
||||
import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription
|
||||
|
||||
@Stable
|
||||
class LoginViewModel : ViewModel() {
|
||||
@@ -58,7 +59,7 @@ class LoginViewModel : ViewModel() {
|
||||
|
||||
var password by mutableStateOf(TextFieldValue(""))
|
||||
val needsPassword by derivedStateOf {
|
||||
key.text.startsWith("ncryptsec1")
|
||||
Bech32Transcription.normalize(key.text).startsWith("ncryptsec1")
|
||||
}
|
||||
|
||||
var isFirstLogin by mutableStateOf(false)
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Android 17 (API 37) Local Network Protection gates the mDNS/multicast
|
||||
device discovery the Cast SDK relies on behind this dangerous runtime
|
||||
permission; without it the picker silently finds zero receivers.
|
||||
Play flavor only — F-Droid ships no casting at all. Older OSes have no
|
||||
LNP and ignore the unknown permission. -->
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
|
||||
|
||||
<application
|
||||
android:name=".Amethyst">
|
||||
|
||||
|
||||
+352
-39
@@ -20,13 +20,19 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.service.cast.chromecast
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.mediarouter.media.MediaRouteSelector
|
||||
import androidx.mediarouter.media.MediaRouter
|
||||
import com.google.android.gms.cast.CastMediaControlIntent
|
||||
import com.google.android.gms.cast.CastStatusCodes
|
||||
import com.google.android.gms.cast.MediaError
|
||||
import com.google.android.gms.cast.MediaInfo
|
||||
import com.google.android.gms.cast.MediaLoadRequestData
|
||||
import com.google.android.gms.cast.MediaMetadata
|
||||
@@ -38,16 +44,31 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.google.android.gms.common.images.WebImage
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_connect_failed
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_device_offline
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_load_failed
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_play_services_unavailable
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_playback_failed
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_playback_failed_detail
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_receiver_not_responding
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_receiver_not_responding_detail
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_unsupported_media
|
||||
import com.vitorpamplona.amethyst.commons.resources.cast_error_unsupported_media_detail
|
||||
import com.vitorpamplona.amethyst.service.cast.CastDevice
|
||||
import com.vitorpamplona.amethyst.service.cast.CastErrorMessage
|
||||
import com.vitorpamplona.amethyst.service.cast.CastRequest
|
||||
import com.vitorpamplona.amethyst.service.cast.CastRoutePlan
|
||||
import com.vitorpamplona.amethyst.service.cast.CastSessionState
|
||||
import com.vitorpamplona.amethyst.service.cast.effectiveMimeType
|
||||
import com.vitorpamplona.amethyst.service.cast.planRouteSelection
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
|
||||
@@ -55,6 +76,29 @@ private const val TAG = "ChromecastCaster"
|
||||
private const val SESSION_START_TIMEOUT_MS = 30_000L
|
||||
private const val STOP_AWAIT_TIMEOUT_MS = 5_000L
|
||||
|
||||
/**
|
||||
* How long to wait for the session to actually end after asking the receiver app to stop.
|
||||
*
|
||||
* Unselecting the route drops the connection, so doing it before the receiver has processed
|
||||
* STOP_APP leaves the app running and the TV parked on the Default Media Receiver splash — the
|
||||
* "default renderer" screen the user has to leave with the TV remote. Observed at ~25-170ms on a
|
||||
* webOS TV, longer the more playback there was to flush, so this is generous.
|
||||
*/
|
||||
private const val SESSION_END_TIMEOUT_MS = 5_000L
|
||||
|
||||
/**
|
||||
* How long the receiver gets to move off LOADING before we call it stalled.
|
||||
*
|
||||
* A healthy receiver takes ~1s. A wedged one — the state an LG webOS TV lands in after its Cast
|
||||
* service crashes, cleared only by power-cycling the TV — accepts the load, reports LOADING, and
|
||||
* then reports nothing ever again: no progress, no error, no session end. Generous by design, since
|
||||
* overshooting only delays an error message while undershooting aborts a slow but working load.
|
||||
*/
|
||||
private const val LOAD_PROGRESS_TIMEOUT_MS = 20_000L
|
||||
|
||||
/** Android 17 — the first release to enforce Local Network Protection. See [ChromecastCaster.localNetworkState]. */
|
||||
private const val LOCAL_NETWORK_PROTECTION_SDK = 37
|
||||
|
||||
/**
|
||||
* Google Cast (Chromecast) caster.
|
||||
*
|
||||
@@ -123,15 +167,29 @@ class ChromecastCaster(
|
||||
override fun onStatusUpdated() {
|
||||
val client = currentMediaClient ?: return
|
||||
val status = client.mediaStatus
|
||||
Log.d(TAG) {
|
||||
val idleReason = status?.idleReason ?: -1
|
||||
Log.i(TAG) {
|
||||
"media.onStatusUpdated playerState=${playerStateName(client.playerState)} " +
|
||||
"idleReason=${idleReasonName(status?.idleReason ?: -1)} " +
|
||||
"idleReason=${idleReasonName(idleReason)} " +
|
||||
"pos=${client.approximateStreamPosition}/${client.streamDuration}ms"
|
||||
}
|
||||
// Any real progress means the receiver is alive and the watchdog has done its job.
|
||||
if (client.playerState == MediaStatus.PLAYER_STATE_PLAYING || client.playerState == MediaStatus.PLAYER_STATE_BUFFERING) {
|
||||
cancelLoadWatchdog()
|
||||
}
|
||||
// The receiver can also fail without ever calling onMediaError — dropping to IDLE
|
||||
// with an ERROR reason is the terminal signal in that case.
|
||||
if (client.playerState == MediaStatus.PLAYER_STATE_IDLE && idleReason == MediaStatus.IDLE_REASON_ERROR) {
|
||||
reportMediaFailure(null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMediaError(mediaError: com.google.android.gms.cast.MediaError) {
|
||||
Log.w(TAG) { "media.onMediaError code=${mediaError.detailedErrorCode} reason=${mediaError.reason} type=${mediaError.type}" }
|
||||
override fun onMediaError(mediaError: MediaError) {
|
||||
Log.w(TAG) {
|
||||
"media.onMediaError code=${mediaError.detailedErrorCode} reason=${mediaError.reason} " +
|
||||
"type=${mediaError.type} media=${castingFormat ?: "unknown"} customData=${mediaError.customData}"
|
||||
}
|
||||
reportMediaFailure(mediaError.detailedErrorCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +213,14 @@ class ChromecastCaster(
|
||||
currentMediaClient = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast surfaces failures as bare ints spread across several unrelated ranges (CommonStatusCodes,
|
||||
* CastStatusCodes, and internal codes documented nowhere). [CastStatusCodes.getStatusCodeString]
|
||||
* is the SDK's own lookup, so it decodes far more than the public constants do — keep the raw
|
||||
* number alongside it for the ones it doesn't recognise either.
|
||||
*/
|
||||
private fun statusName(code: Int): String = "$code(${CastStatusCodes.getStatusCodeString(code)})"
|
||||
|
||||
private fun playerStateName(state: Int): String =
|
||||
when (state) {
|
||||
MediaStatus.PLAYER_STATE_IDLE -> "IDLE"
|
||||
@@ -185,7 +251,7 @@ class ChromecastCaster(
|
||||
session: CastSession,
|
||||
sessionId: String,
|
||||
) {
|
||||
Log.d(TAG) { "session.onStarted id=$sessionId connected=${session.isConnected} hasClient=${session.remoteMediaClient != null}" }
|
||||
Log.i(TAG) { "session.onStarted id=$sessionId connected=${session.isConnected} hasClient=${session.remoteMediaClient != null}" }
|
||||
attachMediaClientCallback(session)
|
||||
pendingSessionStart?.complete(true)
|
||||
pendingSessionStart = null
|
||||
@@ -195,10 +261,22 @@ class ChromecastCaster(
|
||||
session: CastSession,
|
||||
error: Int,
|
||||
) {
|
||||
Log.w(TAG) { "session.onStartFailed error=$error" }
|
||||
Log.w(TAG) { "session.onStartFailed error=${statusName(error)}" }
|
||||
cancelLoadWatchdog()
|
||||
pendingSessionStart?.complete(false)
|
||||
pendingSessionStart = null
|
||||
sessionFlow.value = CastSessionState.Error(currentDevice(), "Cast session failed (code $error)")
|
||||
if (error == CastStatusCodes.CANCELED) {
|
||||
// The user backed out of the connection; that is not a failure to report.
|
||||
sessionFlow.value = CastSessionState.Idle
|
||||
return
|
||||
}
|
||||
// The raw SDK integer belongs in the log, not in front of the user. Every code that
|
||||
// reaches here means the same thing to them — the device would not accept a
|
||||
// connection — and on a webOS TV whose Cast service has died (2252, seen repeatedly
|
||||
// once it wedges) restarting it is genuinely the fix.
|
||||
val device = currentDevice()
|
||||
sessionFlow.value =
|
||||
CastSessionState.Error(device, CastErrorMessage(Res.string.cast_error_connect_failed))
|
||||
}
|
||||
|
||||
override fun onSessionEnding(session: CastSession) {
|
||||
@@ -209,12 +287,25 @@ class ChromecastCaster(
|
||||
session: CastSession,
|
||||
error: Int,
|
||||
) {
|
||||
Log.d(TAG) { "session.onEnded error=$error" }
|
||||
detachMediaClientCallback()
|
||||
// Whoever is tearing down gets told first, before any of the swap/failure handling
|
||||
// below decides to return early — stopCasting() is blocked on this.
|
||||
pendingSessionEnd?.complete(Unit)
|
||||
// Moving to a different receiver ends the outgoing session by design, and that
|
||||
// callback lands *after* cast() has installed the pending start for the incoming
|
||||
// one. Failing it here is what made every device-to-device switch report
|
||||
// "session start refused" and skip the load.
|
||||
if (expectingSessionSwapEnd) {
|
||||
expectingSessionSwapEnd = false
|
||||
Log.i(TAG) { "session.onEnded error=${statusName(error)} — expected teardown while switching receivers" }
|
||||
return
|
||||
}
|
||||
Log.i(TAG) { "session.onEnded error=${statusName(error)}" }
|
||||
cancelLoadWatchdog()
|
||||
// If a cast() was awaiting a session start, this is also a terminal
|
||||
// outcome — the session never reached a usable state. Without
|
||||
// completing here the cast coroutine hangs and the discovery
|
||||
// ref-count leaks +1 for every failed attempt.
|
||||
detachMediaClientCallback()
|
||||
pendingSessionStart?.complete(false)
|
||||
pendingSessionStart = null
|
||||
sessionFlow.value = CastSessionState.Idle
|
||||
@@ -242,7 +333,7 @@ class ChromecastCaster(
|
||||
session: CastSession,
|
||||
error: Int,
|
||||
) {
|
||||
Log.w(TAG) { "session.onResumeFailed error=$error" }
|
||||
Log.w(TAG) { "session.onResumeFailed error=${statusName(error)}" }
|
||||
pendingSessionStart?.complete(false)
|
||||
pendingSessionStart = null
|
||||
}
|
||||
@@ -263,6 +354,102 @@ class ChromecastCaster(
|
||||
@Volatile
|
||||
private var pendingSessionStart: CompletableDeferred<Boolean>? = null
|
||||
|
||||
/**
|
||||
* Armed while a [CastRoutePlan.SWAP_RECEIVER] is in flight — between asking MediaRouter to move
|
||||
* to a different receiver and the outgoing session's teardown callback. That teardown is the
|
||||
* expected consequence of the move, not the new attempt failing, and must not complete the
|
||||
* pending start. Cleared as soon as the attempt resolves, so a later genuine end still counts.
|
||||
*/
|
||||
@Volatile
|
||||
private var expectingSessionSwapEnd = false
|
||||
|
||||
/**
|
||||
* Fires when the receiver accepted a load and then went quiet — see [LOAD_PROGRESS_TIMEOUT_MS].
|
||||
* Nothing else covers this: the media callbacks only speak when the receiver does, and the
|
||||
* session is still perfectly connected, so without this the picker claims to be casting forever
|
||||
* while the device sits on its splash screen.
|
||||
*/
|
||||
private val loadWatchdog =
|
||||
Runnable {
|
||||
val state = currentMediaClient?.playerState
|
||||
val progressed = state == MediaStatus.PLAYER_STATE_PLAYING || state == MediaStatus.PLAYER_STATE_BUFFERING
|
||||
if (progressed || sessionFlow.value is CastSessionState.Error) return@Runnable
|
||||
|
||||
val device = watchedDevice ?: currentDevice() ?: castingDevice
|
||||
Log.w(TAG) {
|
||||
"load watchdog: still ${playerStateName(state ?: -1)} after ${LOAD_PROGRESS_TIMEOUT_MS}ms on ${device?.name}"
|
||||
}
|
||||
val format = castingFormat
|
||||
val message =
|
||||
if (format != null) {
|
||||
Res.string.cast_error_receiver_not_responding_detail
|
||||
} else {
|
||||
Res.string.cast_error_receiver_not_responding
|
||||
}
|
||||
sessionFlow.value = CastSessionState.Error(device, CastErrorMessage(message, format))
|
||||
watchedDevice = null
|
||||
}
|
||||
|
||||
/** The device a load is currently being watched for, so the message can name it. */
|
||||
@Volatile
|
||||
private var watchedDevice: CastDevice? = null
|
||||
|
||||
/** What the in-flight cast is, so a failure can say what the receiver refused. */
|
||||
@Volatile
|
||||
private var castingFormat: String? = null
|
||||
|
||||
/**
|
||||
* Which device the in-flight cast targets. [currentDevice] reads it back off the session state,
|
||||
* which a teardown has usually already reset by the time a late failure arrives — leaving the
|
||||
* message to name "the cast device" instead of the TV the user was looking at.
|
||||
*/
|
||||
@Volatile
|
||||
private var castingDevice: CastDevice? = null
|
||||
|
||||
/** Set while [stopCasting] waits for the receiver app to actually go away. */
|
||||
@Volatile
|
||||
private var pendingSessionEnd: CompletableDeferred<Unit>? = null
|
||||
|
||||
private fun armLoadWatchdog(device: CastDevice) {
|
||||
main.removeCallbacks(loadWatchdog)
|
||||
watchedDevice = device
|
||||
main.postDelayed(loadWatchdog, LOAD_PROGRESS_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
private fun cancelLoadWatchdog() {
|
||||
main.removeCallbacks(loadWatchdog)
|
||||
watchedDevice = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a receiver-side playback failure into a [CastSessionState.Error] the picker can show.
|
||||
*
|
||||
* Without this the UI stays on [CastSessionState.Casting] — set the moment `load()` is
|
||||
* submitted — while the receiver has already given up, so a rejected video looks exactly like a
|
||||
* working one: the device sits on its splash screen and nothing ever explains why.
|
||||
*
|
||||
* The first report wins. A failure usually arrives twice (onMediaError, then IDLE/ERROR) and the
|
||||
* earlier one carries the detailed code, so it is the more specific of the two.
|
||||
*/
|
||||
private fun reportMediaFailure(detailedErrorCode: Int?) {
|
||||
cancelLoadWatchdog()
|
||||
if (sessionFlow.value is CastSessionState.Error) return
|
||||
val device = currentDevice() ?: castingDevice
|
||||
val unsupported =
|
||||
detailedErrorCode == MediaError.DetailedErrorCode.MEDIA_SRC_NOT_SUPPORTED ||
|
||||
detailedErrorCode == MediaError.DetailedErrorCode.MEDIA_DECODE
|
||||
val format = castingFormat
|
||||
val message =
|
||||
when {
|
||||
unsupported && format != null -> Res.string.cast_error_unsupported_media_detail
|
||||
unsupported -> Res.string.cast_error_unsupported_media
|
||||
format != null -> Res.string.cast_error_playback_failed_detail
|
||||
else -> Res.string.cast_error_playback_failed
|
||||
}
|
||||
Log.w(TAG) { "media failure surfaced to UI: code=$detailedErrorCode device=${device?.name}" }
|
||||
sessionFlow.value = CastSessionState.Error(device, CastErrorMessage(message, format))
|
||||
}
|
||||
|
||||
private fun currentDevice(): CastDevice? =
|
||||
when (val s = sessionFlow.value) {
|
||||
is CastSessionState.Connecting -> s.device
|
||||
@@ -275,7 +462,7 @@ class ChromecastCaster(
|
||||
val gms = GoogleApiAvailability.getInstance()
|
||||
val status = gms.isGooglePlayServicesAvailable(appContext)
|
||||
if (status != ConnectionResult.SUCCESS) {
|
||||
Log.d(TAG) { "Google Play services unavailable (status=$status); Chromecast disabled." }
|
||||
Log.w(TAG) { "Google Play services unavailable (status=$status); Chromecast disabled." }
|
||||
return null
|
||||
}
|
||||
return try {
|
||||
@@ -301,15 +488,15 @@ class ChromecastCaster(
|
||||
}
|
||||
|
||||
fun startDiscovery() {
|
||||
Log.d(TAG) { "startDiscovery (already registered? $registered)" }
|
||||
Log.i(TAG) { "startDiscovery (already registered? $registered) ${localNetworkState()}" }
|
||||
main.post {
|
||||
if (registered) {
|
||||
Log.d(TAG) { "startDiscovery: already registered, no-op" }
|
||||
Log.i(TAG) { "startDiscovery: already registered, no-op" }
|
||||
return@post
|
||||
}
|
||||
val ctx = ensureCastContext()
|
||||
if (ctx == null) {
|
||||
Log.d(TAG) { "startDiscovery: CastContext unavailable, aborting" }
|
||||
Log.w(TAG) { "startDiscovery: CastContext unavailable, aborting" }
|
||||
return@post
|
||||
}
|
||||
val router = MediaRouter.getInstance(appContext)
|
||||
@@ -322,11 +509,25 @@ class ChromecastCaster(
|
||||
mediaRouter = router
|
||||
routeSelector = selector
|
||||
registered = true
|
||||
Log.d(TAG) { "startDiscovery: registered router callback (sessionListener already attached)" }
|
||||
Log.i(TAG) { "startDiscovery: registered router callback (sessionListener already attached)" }
|
||||
updateRoutes(router)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Android 17 (API 37) Local Network Protection gates the mDNS/multicast traffic the Cast SDK
|
||||
* uses for discovery behind [Manifest.permission.ACCESS_LOCAL_NETWORK]. When it is denied the
|
||||
* SDK reports no error at all — the picker simply stays empty forever — so the grant state is
|
||||
* the single most important thing a discovery log can tell us apart from the route count.
|
||||
*/
|
||||
private fun localNetworkState(): String {
|
||||
if (Build.VERSION.SDK_INT < LOCAL_NETWORK_PROTECTION_SDK) return "lnp=n/a(sdk${Build.VERSION.SDK_INT})"
|
||||
val granted =
|
||||
ContextCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_LOCAL_NETWORK) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
return "lnp=sdk${Build.VERSION.SDK_INT} ACCESS_LOCAL_NETWORK=${if (granted) "GRANTED" else "DENIED"}"
|
||||
}
|
||||
|
||||
fun stopDiscovery() {
|
||||
Log.d(TAG) { "stopDiscovery (registered=$registered)" }
|
||||
main.post {
|
||||
@@ -357,7 +558,11 @@ class ChromecastCaster(
|
||||
name = route.name,
|
||||
)
|
||||
}
|
||||
Log.d(TAG) { "updateRoutes: count=${list.size} -> [${list.joinToString { it.name }}]" }
|
||||
// Log the unfiltered router total alongside the kept count: an empty picker with
|
||||
// seen=0 means discovery itself never saw anything (LNP / Wi-Fi / mDNS), whereas
|
||||
// seen>0 with count=0 means the routes exist but none advertises the Cast control
|
||||
// category — two completely different faults that look identical from the UI.
|
||||
Log.i(TAG) { "updateRoutes: seen=${router.routes.size} kept=${list.size} -> [${list.joinToString { it.name }}]" }
|
||||
devicesFlow.value = list
|
||||
}
|
||||
|
||||
@@ -365,11 +570,12 @@ class ChromecastCaster(
|
||||
device: CastDevice,
|
||||
request: CastRequest,
|
||||
) {
|
||||
Log.d(TAG) { "cast device=${device.name} url=${request.url}" }
|
||||
Log.i(TAG) { "cast device=${device.name} url=${request.url}" }
|
||||
val ctx = withContext(Dispatchers.Main) { ensureCastContext() }
|
||||
if (ctx == null) {
|
||||
Log.w(TAG, "cast: CastContext unavailable")
|
||||
sessionFlow.value = CastSessionState.Error(device, "Google Play services unavailable")
|
||||
sessionFlow.value =
|
||||
CastSessionState.Error(device, CastErrorMessage(Res.string.cast_error_play_services_unavailable))
|
||||
return
|
||||
}
|
||||
val route =
|
||||
@@ -378,7 +584,7 @@ class ChromecastCaster(
|
||||
}
|
||||
if (route == null) {
|
||||
Log.w(TAG) { "cast: route ${device.id} not in current set; offline?" }
|
||||
sessionFlow.value = CastSessionState.Error(device, "Device went offline")
|
||||
sessionFlow.value = CastSessionState.Error(device, CastErrorMessage(Res.string.cast_error_device_offline))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -390,21 +596,34 @@ class ChromecastCaster(
|
||||
Log.d(TAG) {
|
||||
"cast: existing session connected=${existing?.isConnected} hasClient=${existing?.remoteMediaClient != null}"
|
||||
}
|
||||
val plan =
|
||||
planRouteSelection(
|
||||
targetRouteId = route.id,
|
||||
selectedRouteId = mediaRouter?.selectedRoute?.id,
|
||||
hasConnectedSession = existing?.isConnected == true,
|
||||
)
|
||||
Log.i(TAG) { "cast: plan=$plan target=${route.id} selected=${mediaRouter?.selectedRoute?.id}" }
|
||||
|
||||
val pending = CompletableDeferred<Boolean>()
|
||||
// If a previous cast() is still awaiting a callback, fail it
|
||||
// before swapping in our deferred — otherwise the earlier call
|
||||
// hangs to the 30s timeout.
|
||||
pendingSessionStart?.complete(false)
|
||||
pendingSessionStart = pending
|
||||
// Arm this before selectRoute, not after: the teardown callback for the outgoing
|
||||
// session can arrive on the very next main-thread tick.
|
||||
expectingSessionSwapEnd = plan.expectsPreviousSessionToEnd
|
||||
try {
|
||||
Log.d(TAG) { "cast: selectRoute id=${route.id}" }
|
||||
mediaRouter?.selectRoute(route)
|
||||
if (existing?.isConnected == true) {
|
||||
Log.d(TAG) { "cast: reusing already-connected session, completing immediately" }
|
||||
if (plan.needsRouteSelection) {
|
||||
Log.i(TAG) { "cast: selectRoute id=${route.id}" }
|
||||
mediaRouter?.selectRoute(route)
|
||||
} else {
|
||||
Log.i(TAG) { "cast: reusing the session already connected to this receiver" }
|
||||
pending.complete(true)
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
Log.w(TAG, "cast: selectRoute threw", t)
|
||||
expectingSessionSwapEnd = false
|
||||
pending.complete(false)
|
||||
}
|
||||
// Defence in depth: if a callback is somehow missed (SDK bug,
|
||||
@@ -417,12 +636,18 @@ class ChromecastCaster(
|
||||
Log.w(TAG) { "cast: session start timed out after ${SESSION_START_TIMEOUT_MS}ms" }
|
||||
pendingSessionStart = null
|
||||
}
|
||||
// However this attempt ended, the swap it was waiting on is over. Leaving the flag
|
||||
// armed would make the *next* genuine session end get swallowed as an expected one.
|
||||
expectingSessionSwapEnd = false
|
||||
outcome ?: false
|
||||
}
|
||||
|
||||
if (!started) {
|
||||
Log.w(TAG, "cast: session start refused")
|
||||
sessionFlow.value = CastSessionState.Error(device, "Cast session refused")
|
||||
// onSessionStartFailed usually got here first with a better-informed message; keep it.
|
||||
sessionFlow.value =
|
||||
sessionFlow.value as? CastSessionState.Error
|
||||
?: CastSessionState.Error(device, CastErrorMessage(Res.string.cast_error_connect_failed))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -438,21 +663,57 @@ class ChromecastCaster(
|
||||
false
|
||||
} else {
|
||||
try {
|
||||
client.load(buildLoadRequest(request))
|
||||
Log.d(TAG) { "cast: load() submitted (status=${client.playerState})" }
|
||||
val loadRequest = buildLoadRequest(request)
|
||||
val info = loadRequest.mediaInfo
|
||||
castingFormat = request.formatSummary
|
||||
castingDevice = device
|
||||
Log.i(TAG) {
|
||||
"cast: load() submitting contentType=${info?.contentType} " +
|
||||
"streamType=${info?.streamType} media=${request.formatSummary ?: "unknown"} " +
|
||||
"url=${info?.contentId}"
|
||||
}
|
||||
// load() returns a PendingResult carrying the receiver's verdict. Dropping it
|
||||
// (as this used to) makes a refused load indistinguishable from a successful
|
||||
// one: the coroutine reports Casting, the TV sits on its splash screen, and
|
||||
// nothing anywhere records why. This callback is the only place the receiver
|
||||
// ever tells us what it disliked about the media.
|
||||
armLoadWatchdog(device)
|
||||
client.load(loadRequest).setResultCallback { result ->
|
||||
val status = result.status
|
||||
if (status.isSuccess) {
|
||||
Log.i(TAG) { "cast: load() accepted by receiver" }
|
||||
} else {
|
||||
Log.w(TAG) {
|
||||
"cast: load() REFUSED by receiver code=${statusName(status.statusCode)} " +
|
||||
"msg=${status.statusMessage}"
|
||||
}
|
||||
// CANCELED is what the receiver answers when the load was
|
||||
// abandoned because we tore the session down — i.e. the user pressed
|
||||
// stop. That is the outcome they asked for, not a failure to report.
|
||||
if (status.statusCode != CastStatusCodes.CANCELED) {
|
||||
reportMediaFailure(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
} catch (t: Throwable) {
|
||||
cancelLoadWatchdog()
|
||||
Log.w(TAG, "cast: remoteMediaClient.load failed", t)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A receiver can reject the media before this coroutine gets here — onMediaError has been
|
||||
// seen ~150ms after load(). This attempt set Connecting on entry, so any Error sitting here
|
||||
// now came from its own callbacks and carries the receiver's reason; don't paper over it
|
||||
// with a Casting state that claims a video is playing when it already failed.
|
||||
val reportedFailure = sessionFlow.value as? CastSessionState.Error
|
||||
sessionFlow.value =
|
||||
if (ok) {
|
||||
CastSessionState.Casting(device, request)
|
||||
} else {
|
||||
CastSessionState.Error(device, "Could not load media on receiver")
|
||||
when {
|
||||
reportedFailure != null -> reportedFailure
|
||||
ok -> CastSessionState.Casting(device, request)
|
||||
else -> CastSessionState.Error(device, CastErrorMessage(Res.string.cast_error_load_failed))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,10 +723,19 @@ class ChromecastCaster(
|
||||
request.artworkUri?.let {
|
||||
runCatching { metadata.addImage(WebImage(it.toUri())) }
|
||||
}
|
||||
// A live HLS playlist has no #EXT-X-ENDLIST and no duration. Declaring it BUFFERED asks the
|
||||
// receiver for a seekable stream of known length, which it cannot resolve — the LG webOS
|
||||
// receiver sits in LOADING forever rather than reporting an error.
|
||||
val streamType =
|
||||
if (request.isLive) {
|
||||
MediaInfo.STREAM_TYPE_LIVE
|
||||
} else {
|
||||
MediaInfo.STREAM_TYPE_BUFFERED
|
||||
}
|
||||
val info =
|
||||
MediaInfo
|
||||
.Builder(request.url)
|
||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||
.setStreamType(streamType)
|
||||
.setContentType(request.effectiveMimeType())
|
||||
.setMetadata(metadata)
|
||||
.build()
|
||||
@@ -476,8 +746,30 @@ class ChromecastCaster(
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialises teardown. A stop against an unresponsive receiver can take seconds to ack, so the
|
||||
* user reasonably presses stop again — and two overlapping teardowns wreck each other: both
|
||||
* call `stop()` (the second erroring), both call `endCurrentSession`, and the later one installs
|
||||
* its session-end wait after `onSessionEnded` has already fired, so it waits out the full
|
||||
* timeout for an event that will never come again.
|
||||
*/
|
||||
private val stopInFlight = Mutex()
|
||||
|
||||
suspend fun stopCasting() {
|
||||
Log.d(TAG) { "stopCasting (hasClient=${currentMediaClient != null})" }
|
||||
if (!stopInFlight.tryLock()) {
|
||||
Log.i(TAG) { "stopCasting: a teardown is already running; ignoring the repeat request" }
|
||||
return
|
||||
}
|
||||
try {
|
||||
stopCastingLocked()
|
||||
} finally {
|
||||
stopInFlight.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun stopCastingLocked() {
|
||||
Log.i(TAG) { "stopCasting (hasClient=${currentMediaClient != null})" }
|
||||
withContext(Dispatchers.Main) { cancelLoadWatchdog() }
|
||||
// Await MEDIA_STOP before endCurrentSession() — racing them on the
|
||||
// same main-thread tick loses the stop on some receivers (LG webOS).
|
||||
val client = currentMediaClient
|
||||
@@ -487,8 +779,8 @@ class ChromecastCaster(
|
||||
try {
|
||||
client.stop().setResultCallback { result ->
|
||||
val status = result.status
|
||||
Log.d(TAG) {
|
||||
"remoteMediaClient.stop ack code=${status.statusCode} msg=${status.statusMessage}"
|
||||
Log.i(TAG) {
|
||||
"remoteMediaClient.stop ack code=${statusName(status.statusCode)} msg=${status.statusMessage}"
|
||||
}
|
||||
stopAck.complete(status.statusCode)
|
||||
}
|
||||
@@ -502,16 +794,37 @@ class ChromecastCaster(
|
||||
Log.w(TAG) { "remoteMediaClient.stop did not ack within ${STOP_AWAIT_TIMEOUT_MS}ms" }
|
||||
}
|
||||
}
|
||||
val ended = CompletableDeferred<Unit>()
|
||||
withContext(Dispatchers.Main) {
|
||||
pendingSessionEnd = ended
|
||||
try {
|
||||
// false: receiver app already halted media via stop() above.
|
||||
// true previously triggered an extra teardown that compounded
|
||||
// the race — keep the receiver running on its splash screen
|
||||
// so the next cast can reuse the connection cleanly.
|
||||
castContext?.sessionManager?.endCurrentSession(false)
|
||||
// true: shut the receiver application down, don't just detach from it.
|
||||
//
|
||||
// This was false, to "keep the receiver running on its splash screen so the next
|
||||
// cast can reuse the connection cleanly". That is what strands an LG webOS TV on the
|
||||
// Default Media Receiver holding screen instead of returning it to its home screen,
|
||||
// and the reused connection is not clean: the SDK hands the same session id back to
|
||||
// later casts, and after a few stop/start cycles the receiver stops accepting
|
||||
// connections at all (every start fails 2252) until the TV is power-cycled.
|
||||
//
|
||||
// The race that motivated false is now handled directly — the MEDIA_STOP ack is
|
||||
// awaited above before we get here, and a receiver swap no longer mistakes the
|
||||
// outgoing session's teardown for a failure of the incoming one.
|
||||
Log.i(TAG) { "stopCasting: ending session and stopping the receiver app" }
|
||||
castContext?.sessionManager?.endCurrentSession(true)
|
||||
} catch (t: Throwable) {
|
||||
Log.w(TAG, "endCurrentSession failed", t)
|
||||
ended.complete(Unit)
|
||||
}
|
||||
}
|
||||
// Wait for the session to be gone before unselecting. Unselecting drops the connection the
|
||||
// STOP_APP message travels over, so doing it on the same tick — as this used to — can beat
|
||||
// the message to the TV and leave the receiver running on its splash screen.
|
||||
if (withTimeoutOrNull(SESSION_END_TIMEOUT_MS) { ended.await() } == null) {
|
||||
Log.w(TAG) { "stopCasting: session did not end within ${SESSION_END_TIMEOUT_MS}ms; unselecting anyway" }
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
pendingSessionEnd = null
|
||||
mediaRouter?.unselect(MediaRouter.UNSELECT_REASON_STOPPED)
|
||||
}
|
||||
sessionFlow.value = CastSessionState.Idle
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.service.cast
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class CastLivenessTest {
|
||||
@Test
|
||||
fun playerVerdictWinsOverMetadataWhenItSaysLive() {
|
||||
// A live .m3u8 shared in a plain kind:1 note carries no live-activity flag, so only
|
||||
// ExoPlayer's parsed verdict can save it from being cast as a seekable recording.
|
||||
assertTrue(resolveCastLiveness(learned = true, metadataFlag = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun playerVerdictWinsOverMetadataWhenItSaysOnDemand() {
|
||||
// A kind:30311 recording stays flagged live long after the broadcast ended; the parsed
|
||||
// playlist is the ground truth and must override it.
|
||||
assertFalse(resolveCastLiveness(learned = false, metadataFlag = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fallsBackToMetadataWhileTheUrlIsStillUnclassified() {
|
||||
assertTrue(resolveCastLiveness(learned = null, metadataFlag = true))
|
||||
assertFalse(resolveCastLiveness(learned = null, metadataFlag = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun progressiveMediaStaysBufferedWhenNothingIsKnown() {
|
||||
// The common case: an MP4 with no verdict and no flag must keep its seek bar.
|
||||
assertFalse(resolveCastLiveness(learned = null, metadataFlag = false))
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.service.cast
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
|
||||
class CastMediaSummaryTest {
|
||||
@Test
|
||||
fun namesTheCodecTheReceiverIsMostLikelyToRefuse() {
|
||||
// The whole point: "HEVC" is the word that explains why a TV took the file and went quiet.
|
||||
assertEquals(
|
||||
"H.265 (HEVC) 1920x1080",
|
||||
summarizeCastFormat("video/hevc", codecs = "hev1.1.6.L93.B0", width = 1920, height = 1080),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun namesTheCommonCodecsInTermsPeopleRecognise() {
|
||||
assertEquals("H.264 640x480", summarizeCastFormat("video/avc", null, 640, 480))
|
||||
assertEquals("AV1 3840x2160", summarizeCastFormat("video/av01", null, 3840, 2160))
|
||||
assertEquals("VP9 1280x720", summarizeCastFormat("video/x-vnd.on2.vp9", null, 1280, 720))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fallsBackToTheRawMimeTypeForCodecsWeDoNotNameOurselves() {
|
||||
assertEquals("video/quirky 100x50", summarizeCastFormat("video/quirky", null, 100, 50))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun omitsTheResolutionWhenItIsNotKnown() {
|
||||
assertEquals("H.264", summarizeCastFormat("video/avc", null, width = -1, height = -1))
|
||||
assertEquals("H.264", summarizeCastFormat("video/avc", null, width = 0, height = 0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fallsBackToTheCodecStringWhenTheMimeTypeIsMissing() {
|
||||
// ExoPlayer can report a codec string without a sample mime type on some containers.
|
||||
assertEquals("hev1.1.6.L93.B0 1920x1080", summarizeCastFormat(null, "hev1.1.6.L93.B0", 1920, 1080))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isNullWhenThereIsNothingWorthSaying() {
|
||||
assertNull(summarizeCastFormat(null, null, -1, -1))
|
||||
assertNull(summarizeCastFormat("", "", 0, 0))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.service.cast
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class CastRoutePlanTest {
|
||||
private val tv = "route-tv"
|
||||
private val soundbar = "route-soundbar"
|
||||
|
||||
@Test
|
||||
fun reusesTheSessionOnlyWhenItBelongsToTheTargetRoute() {
|
||||
assertEquals(
|
||||
CastRoutePlan.REUSE_SESSION,
|
||||
planRouteSelection(targetRouteId = tv, selectedRouteId = tv, hasConnectedSession = true),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun switchingReceiversIsASwapNotAReuse() {
|
||||
// The regression: a session connected to the soundbar was treated as reusable for the TV.
|
||||
// cast() completed its start immediately, selectRoute() then tore that session down, and the
|
||||
// load was skipped against a dead session — the TV connected and showed nothing.
|
||||
assertEquals(
|
||||
CastRoutePlan.SWAP_RECEIVER,
|
||||
planRouteSelection(targetRouteId = tv, selectedRouteId = soundbar, hasConnectedSession = true),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aDisconnectedSessionOnTheTargetRouteStillNeedsAFreshStart() {
|
||||
assertEquals(
|
||||
CastRoutePlan.SELECT_FRESH,
|
||||
planRouteSelection(targetRouteId = tv, selectedRouteId = tv, hasConnectedSession = false),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theFirstCastOfTheSessionSelectsFresh() {
|
||||
assertEquals(
|
||||
CastRoutePlan.SELECT_FRESH,
|
||||
planRouteSelection(targetRouteId = tv, selectedRouteId = null, hasConnectedSession = false),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onlyASwapExpectsTheOldSessionToEnd() {
|
||||
// This is what stops the outgoing session's onSessionEnded from failing the incoming
|
||||
// attempt, which is why switching devices used to report "session start refused".
|
||||
assertEquals(true, CastRoutePlan.SWAP_RECEIVER.expectsPreviousSessionToEnd)
|
||||
assertEquals(false, CastRoutePlan.SELECT_FRESH.expectsPreviousSessionToEnd)
|
||||
assertEquals(false, CastRoutePlan.REUSE_SESSION.expectsPreviousSessionToEnd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onlyReuseSkipsTheRouteSelection() {
|
||||
assertEquals(false, CastRoutePlan.REUSE_SESSION.needsRouteSelection)
|
||||
assertEquals(true, CastRoutePlan.SWAP_RECEIVER.needsRouteSelection)
|
||||
assertEquals(true, CastRoutePlan.SELECT_FRESH.needsRouteSelection)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -42,8 +42,8 @@ import org.junit.Test
|
||||
/**
|
||||
* A nav-bar tap must land on the tab itself, never on whatever the user had pushed on top of one.
|
||||
*
|
||||
* The phone bottom bar gets this for free — it hides itself off tab roots, so it can only ever be
|
||||
* tapped from one. The large-screen navigation rail stays on screen the whole time, which is where
|
||||
* The phone bottom bar shows only on tab roots and drawer destinations, so it is tapped from at most
|
||||
* one screen above a tab. The large-screen navigation rail stays on screen the whole time, which is where
|
||||
* the gap showed: tapping Home from a thread three screens deep came back to that thread instead of
|
||||
* the feed.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.navigation
|
||||
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.NavHostController
|
||||
import com.vitorpamplona.amethyst.commons.model.navigation.Route
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* A screen opened from the navigation drawer is a top-level section: it keeps the bottom bar
|
||||
* (issue #4141, where Pictures and every other drawer destination lost it). It still sits on top of
|
||||
* the screen the drawer was opened over, so it keeps its back arrow too; the bar is told apart
|
||||
* from an in-app push by the [DRAWER_ROOT_KEY] stamp these tests pin down.
|
||||
*/
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class NavDrawerTest {
|
||||
private fun entry(
|
||||
isTabRoot: Boolean = false,
|
||||
isDrawerRoot: Boolean = false,
|
||||
): NavBackStackEntry =
|
||||
mockk<NavBackStackEntry>(relaxed = true) {
|
||||
every { savedStateHandle.get<Boolean>(BOTTOM_NAV_ROOT_KEY) } returns isTabRoot
|
||||
every { savedStateHandle.get<Boolean>(DRAWER_ROOT_KEY) } returns isDrawerRoot
|
||||
}
|
||||
|
||||
/** A controller whose current entry becomes [pushed] once [route] is navigated to. */
|
||||
private fun controllerPushing(
|
||||
route: Route,
|
||||
pushed: NavBackStackEntry,
|
||||
): NavHostController {
|
||||
var current = entry(isTabRoot = true)
|
||||
return mockk<NavHostController>(relaxed = true) {
|
||||
every { currentBackStackEntry } answers { current }
|
||||
every { navigate(route) } answers { current = pushed }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stampsTheEntryItOpens() =
|
||||
runTest {
|
||||
val pushed = entry()
|
||||
val controller = controllerPushing(Route.Pictures(), pushed)
|
||||
|
||||
Nav(controller, this).navDrawer(Route.Pictures())
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(exactly = 1) { controller.navigate(Route.Pictures()) }
|
||||
verify(exactly = 1) { pushed.savedStateHandle[DRAWER_ROOT_KEY] = true }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stampsTheEntryOfAResolvedRoute() =
|
||||
runTest {
|
||||
val pushed = entry()
|
||||
val controller = controllerPushing(Route.Articles, pushed)
|
||||
|
||||
Nav(controller, this).navDrawer { Route.Articles }
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(exactly = 1) { pushed.savedStateHandle[DRAWER_ROOT_KEY] = true }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plainPushesAreNotStamped() =
|
||||
runTest {
|
||||
val pushed = entry()
|
||||
val controller = controllerPushing(Route.Pictures(), pushed)
|
||||
|
||||
Nav(controller, this).nav(Route.Pictures())
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(exactly = 0) { pushed.savedStateHandle[DRAWER_ROOT_KEY] = any<Boolean>() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aTabTappedFromADrawerScreenDropsItFirst() =
|
||||
runTest {
|
||||
// Home > Pictures (from the drawer): the bar now shows on Pictures, so it can be tapped
|
||||
// from there. The drawer entry is not a tab root and must not be saved into the tab.
|
||||
val controller =
|
||||
mockk<NavHostController>(relaxed = true) {
|
||||
every { currentBackStackEntry } returnsMany
|
||||
listOf(entry(isDrawerRoot = true), entry(isTabRoot = true))
|
||||
every { popBackStack() } returns true
|
||||
}
|
||||
|
||||
Nav(controller, this).navBottomBar(Route.Message)
|
||||
advanceUntilIdle()
|
||||
|
||||
verify(exactly = 1) { controller.popBackStack() }
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import com.vitorpamplona.amethyst.cli.Identity
|
||||
import com.vitorpamplona.amethyst.cli.Output
|
||||
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription
|
||||
import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes
|
||||
import com.vitorpamplona.quartz.nip19Bech32.toNpub
|
||||
import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49
|
||||
@@ -121,7 +122,7 @@ object KeyCommands {
|
||||
|
||||
private fun decrypt(rest: Array<String>): Int {
|
||||
val args = Args(rest)
|
||||
val ncryptsec = args.positional(0, "ncryptsec").trim()
|
||||
val ncryptsec = Bech32Transcription.normalize(args.positional(0, "ncryptsec"))
|
||||
if (!ncryptsec.startsWith("ncryptsec")) return Output.error("bad_args", "expected an ncryptsec1… string")
|
||||
// Read both spellings eagerly so passing both doesn't trip rejectUnknown().
|
||||
val pwAlias = args.flag("pw")
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Client
|
||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.OkHttpNip05Fetcher
|
||||
import com.vitorpamplona.quartz.nip05DnsIdentifiers.resolveUserHexOrNull
|
||||
import com.vitorpamplona.quartz.nip06KeyDerivation.Nip06
|
||||
import com.vitorpamplona.quartz.nip19Bech32.Bech32Transcription
|
||||
import com.vitorpamplona.quartz.nip19Bech32.toNpub
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.signer.NostrSignerRemote
|
||||
import com.vitorpamplona.quartz.nip49PrivKeyEnc.Nip49
|
||||
@@ -90,7 +91,7 @@ object LoginCommand {
|
||||
args.rejectUnknown("password", "pw", "private")
|
||||
|
||||
val identity =
|
||||
resolveIdentity(key, args)
|
||||
resolveIdentity(Bech32Transcription.normalize(key), args)
|
||||
?: return Output.error(
|
||||
"bad_key",
|
||||
"could not parse '$key' as any supported identifier",
|
||||
|
||||
@@ -210,6 +210,8 @@ ALL_TESTS=(
|
||||
test_27_deletion_wn_to_amy
|
||||
test_28_retention_wn_to_amy
|
||||
test_29_disband_amy_to_wn
|
||||
test_30_wn_commit_after_app_data_update
|
||||
test_31_reaction_materializes_on_wn
|
||||
)
|
||||
|
||||
# --tests runs a subset in the order given. Most tests read state a previous
|
||||
|
||||
@@ -250,3 +250,90 @@ test_17_group_image_commit() {
|
||||
record_result "$id" fail "wn could not decrypt A's post-image message — image commit not applied"
|
||||
fi
|
||||
}
|
||||
|
||||
# The device sequence that forked Amethyst out of a group White Noise joined:
|
||||
# amy creates, invites wn, commits an AppDataUpdate (the app's "Use encrypted
|
||||
# attachments" is one; set-retention is the same proposal type), promotes wn,
|
||||
# and then wn makes its FIRST commit — a rename carrying an UpdatePath. On the
|
||||
# device Amethyst refused that commit ("UpdatePath at common ancestor carries
|
||||
# no ciphertext for us") and every later wn message failed to decrypt.
|
||||
test_30_wn_commit_after_app_data_update() {
|
||||
banner "Test 30 — wn's first commit after an amy AppDataUpdate commit"
|
||||
local id="30 wn commit after app-data"
|
||||
|
||||
local out gid mls_gid b_gid
|
||||
out=$(amy_json marmot group create --name "Interop-30") || {
|
||||
record_result "$id" fail "amy group create failed"; return
|
||||
}
|
||||
gid=$(printf '%s' "$out" | jq -r '.group_id')
|
||||
mls_gid=$(printf '%s' "$out" | jq -r '.mls_group_id')
|
||||
amy_json marmot group add "$gid" "$B_NPUB" >/dev/null || {
|
||||
record_result "$id" fail "amy could not invite wn"; return
|
||||
}
|
||||
b_gid=$(wait_for_invite B 60) || { record_result "$id" fail "wn never received the Welcome"; return; }
|
||||
wn_b groups accept "$b_gid" >/dev/null 2>&1 || true
|
||||
wn_group_field_becomes "$mls_gid" '.group.group_id // empty' "$mls_gid" 120 || {
|
||||
record_result "$id" fail "wn never surfaced the group"; return
|
||||
}
|
||||
|
||||
wn_b messages send "$mls_gid" "30 before" >/dev/null 2>&1 || true
|
||||
amy_json marmot await message "$gid" --match "30 before" --timeout 90 >/dev/null || {
|
||||
record_result "$id" fail "amy never received wn's first message"; return
|
||||
}
|
||||
|
||||
amy_json marmot group set-retention "$gid" 3600 >/dev/null || {
|
||||
record_result "$id" fail "amy set-retention failed"; return
|
||||
}
|
||||
sleep 3
|
||||
amy_json marmot group promote "$gid" "$B_NPUB" >/dev/null || {
|
||||
record_result "$id" fail "amy promote failed"; return
|
||||
}
|
||||
sleep 5
|
||||
|
||||
wn_b groups rename "$mls_gid" "Interop-30-by-wn" >/dev/null 2>&1 || true
|
||||
if ! amy_json marmot await rename "$gid" --name "Interop-30-by-wn" --timeout 120 >/dev/null; then
|
||||
record_result "$id" fail "amy did not apply wn's rename (commit after app-data update)"; return
|
||||
fi
|
||||
wn_b messages send "$mls_gid" "30 after" >/dev/null 2>&1 || true
|
||||
if amy_json marmot await message "$gid" --match "30 after" --timeout 90 >/dev/null; then
|
||||
record_result "$id" pass
|
||||
else
|
||||
record_result "$id" fail "amy applied the rename but cannot decrypt wn's next message (forked)"
|
||||
fi
|
||||
}
|
||||
|
||||
# A reaction White Noise can SEE. Test 09 only proves wn's raw event log holds a
|
||||
# kind:7; the app renders the materialized timeline, which attaches a reaction
|
||||
# to its target by its own rules. An amy reaction the raw log kept but the
|
||||
# timeline dropped read as a pass there and as "no reaction" in the app.
|
||||
test_31_reaction_materializes_on_wn() {
|
||||
banner "Test 31 — amy's reaction shows in wn's materialized timeline"
|
||||
local id="31 reaction materialized"
|
||||
|
||||
local out gid mls_gid b_gid anchor_id
|
||||
out=$(amy_json marmot group create --name "Interop-31") || { record_result "$id" fail "amy group create failed"; return; }
|
||||
gid=$(printf '%s' "$out" | jq -r '.group_id')
|
||||
mls_gid=$(printf '%s' "$out" | jq -r '.mls_group_id')
|
||||
amy_json marmot group add "$gid" "$B_NPUB" >/dev/null || { record_result "$id" fail "amy could not invite wn"; return; }
|
||||
b_gid=$(wait_for_invite B 60) || { record_result "$id" fail "wn never received the Welcome"; return; }
|
||||
wn_b groups accept "$b_gid" >/dev/null 2>&1 || true
|
||||
wn_group_field_becomes "$mls_gid" '.group.group_id // empty' "$mls_gid" 120 || { record_result "$id" fail "wn never surfaced the group"; return; }
|
||||
|
||||
wn_b messages send "$mls_gid" "31 anchor" >/dev/null 2>&1 || true
|
||||
amy_json marmot await message "$gid" --match "31 anchor" --timeout 90 >/dev/null || { record_result "$id" fail "amy never got the anchor"; return; }
|
||||
anchor_id=$(amy_json marmot message list "$gid" --limit 50 2>/dev/null | jq_list messages \
|
||||
| jq -r 'select((.plaintext // .content // "") == "31 anchor") | (.message_id // .event_id)' | head -n 1)
|
||||
[[ -n "$anchor_id" && "$anchor_id" != "null" ]] || { record_result "$id" fail "no anchor id in amy's log"; return; }
|
||||
amy_json marmot message react "$gid" "$anchor_id" "🍕" >/dev/null || { record_result "$id" fail "amy react failed"; return; }
|
||||
|
||||
local deadline=$(( $(date +%s) + 90 )) tl=""
|
||||
while [[ $(date +%s) -lt $deadline ]]; do
|
||||
tl=$(wn_b --json messages timeline list "$mls_gid" --limit 50 2>/dev/null || true)
|
||||
if printf '%s' "$tl" | grep -q '🍕'; then
|
||||
record_result "$id" pass; return
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
printf '%s\n' "$tl" >> "$LOG_FILE"
|
||||
record_result "$id" fail "wn's timeline never showed amy's reaction (timeline JSON in the log)"
|
||||
}
|
||||
|
||||
+84
-34
@@ -87,6 +87,7 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.pTags
|
||||
import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.QEventTag
|
||||
import com.vitorpamplona.quartz.nip18Reposts.quotes.quote
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
@@ -97,6 +98,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
|
||||
@@ -276,32 +278,11 @@ class MarmotManager(
|
||||
}
|
||||
}
|
||||
val state =
|
||||
publishGate.resolve(
|
||||
obligation.obligationId,
|
||||
if (confirmed) PublishOutcome.CONFIRMED else PublishOutcome.UNKNOWN,
|
||||
)
|
||||
// A confirmed retry makes the commit canonical exactly as
|
||||
// [commitAndPublish] would, so it owes the same follow-up. Resolving
|
||||
// the obligation and stopping there was enough to install the state
|
||||
// and no more: the relay's echo of THIS event was never marked
|
||||
// processed, so the inbound pipeline met an unknown kind:445 at an
|
||||
// epoch we had already merged and opened a convergence pass against
|
||||
// ourselves — a restart could put a healthy group into Recovering
|
||||
// purely by succeeding.
|
||||
if (confirmed) {
|
||||
val framedCommit = framedCommitOf(obligation, event)
|
||||
if (framedCommit != null) {
|
||||
inboundProcessor.markMessageProcessed(sha256(framedCommit).toHexKey())
|
||||
inboundProcessor.recordLocalCommit(
|
||||
groupId = obligation.groupId,
|
||||
framedCommitBytes = framedCommit,
|
||||
sourceEpoch = obligation.priorState.groupContext.epoch,
|
||||
preState = obligation.priorState,
|
||||
)
|
||||
if (confirmed) {
|
||||
confirmObligation(obligation, event)
|
||||
} else {
|
||||
publishGate.resolve(obligation.obligationId, PublishOutcome.UNKNOWN)
|
||||
}
|
||||
recordRetentionForCurrentEpoch(obligation.groupId)
|
||||
syncGroupSystemRows(obligation.groupId, actor = signer.pubKey)
|
||||
}
|
||||
Log.d("MarmotManager") {
|
||||
"retryPendingPublishObligations(): ${obligation.groupId.take(8)}… " +
|
||||
"confirmed=$confirmed lifecycle=$state"
|
||||
@@ -309,6 +290,58 @@ class MarmotManager(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a confirmed obligation's commit canonical, with every follow-up
|
||||
* [commitAndPublish] owes a commit a relay acknowledged.
|
||||
*
|
||||
* Resolving the obligation alone installs the state and no more: the
|
||||
* relay's echo of THIS event would not be marked processed, so the inbound
|
||||
* pipeline would meet an unknown kind:445 at an epoch we had already merged
|
||||
* and open a convergence pass against ourselves.
|
||||
*/
|
||||
private suspend fun confirmObligation(
|
||||
obligation: MarmotPublishObligation,
|
||||
event: Event,
|
||||
): GroupLifecycleState {
|
||||
val state = publishGate.resolve(obligation.obligationId, PublishOutcome.CONFIRMED)
|
||||
val framedCommit = framedCommitOf(obligation, event)
|
||||
if (framedCommit != null) {
|
||||
inboundProcessor.markMessageProcessed(sha256(framedCommit).toHexKey())
|
||||
inboundProcessor.recordLocalCommit(
|
||||
groupId = obligation.groupId,
|
||||
framedCommitBytes = framedCommit,
|
||||
sourceEpoch = obligation.priorState.groupContext.epoch,
|
||||
preState = obligation.priorState,
|
||||
)
|
||||
}
|
||||
recordRetentionForCurrentEpoch(obligation.groupId)
|
||||
syncGroupSystemRows(obligation.groupId, actor = signer.pubKey)
|
||||
return state
|
||||
}
|
||||
|
||||
/**
|
||||
* The relay's copy of one of our own unconfirmed commits, or null.
|
||||
*
|
||||
* A relay only echoes what it stored, so seeing our pending kind:445 come
|
||||
* back is the acceptance whose OK never arrived (a timeout, a dropped
|
||||
* socket, a slow Tor circuit). It must confirm the obligation. Handed to
|
||||
* the inbound pipeline instead, it reads as a peer's commit whose sender is
|
||||
* our own leaf; a committer never encrypts the path secret to itself, so it
|
||||
* fails ("no ciphertext for us") while every peer applies it, and the group
|
||||
* forks with us one epoch behind.
|
||||
*/
|
||||
private suspend fun pendingObligationEchoed(groupEvent: GroupEvent): MarmotPublishObligation? {
|
||||
val groupId = groupEvent.groupId() ?: return null
|
||||
return publishGate.pendingFor(groupId).firstOrNull { obligation ->
|
||||
try {
|
||||
Event.fromJson(obligation.outboundBytes.decodeToString()).id == groupEvent.id
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) throw e
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover the framed MLS commit from a stored obligation.
|
||||
*
|
||||
@@ -390,6 +423,12 @@ class MarmotManager(
|
||||
* Returns the inner event JSON if it was an application message.
|
||||
*/
|
||||
suspend fun processGroupEvent(groupEvent: GroupEvent): GroupEventResult {
|
||||
pendingObligationEchoed(groupEvent)?.let { obligation ->
|
||||
confirmObligation(obligation, groupEvent)
|
||||
subscriptionManager.updateGroupSince(obligation.groupId, groupEvent.createdAt)
|
||||
return GroupEventResult.CommitProcessed(obligation.groupId, obligation.pendingState.groupContext.epoch)
|
||||
}
|
||||
|
||||
val result = inboundProcessor.processGroupEvent(groupEvent)
|
||||
|
||||
// A fork just opened a bounded pass. Inbound traffic settles it
|
||||
@@ -570,13 +609,20 @@ class MarmotManager(
|
||||
targetEvent: Event,
|
||||
reaction: String,
|
||||
): Event {
|
||||
val hint =
|
||||
com.vitorpamplona.quartz.nip01Core.hints
|
||||
.EventHintBundle(targetEvent)
|
||||
// A custom-emoji reaction (":name:url") carries its image in an emoji
|
||||
// tag, exactly as the public NIP-25 path builds it.
|
||||
val emojiUrl = if (reaction.startsWith(":")) EmojiUrlTag.decode(reaction) else null
|
||||
val template =
|
||||
com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
.build(
|
||||
reaction,
|
||||
com.vitorpamplona.quartz.nip01Core.hints
|
||||
.EventHintBundle(targetEvent),
|
||||
)
|
||||
if (emojiUrl != null) {
|
||||
com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
.build(emojiUrl, hint)
|
||||
} else {
|
||||
com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
.build(reaction, hint)
|
||||
}
|
||||
return com.vitorpamplona.quartz.nip59Giftwrap.rumors.RumorAssembler
|
||||
.assembleRumor<com.vitorpamplona.quartz.nip25Reactions.ReactionEvent>(
|
||||
signer.pubKey,
|
||||
@@ -739,14 +785,18 @@ class MarmotManager(
|
||||
targetEvents: List<Event>,
|
||||
persistOwn: Boolean = true,
|
||||
): TextMessageBundle {
|
||||
require(targetEvents.isNotEmpty()) { "buildDeletionMessage: targetEvents must not be empty" }
|
||||
val template = DeletionRequestEvent.build(targetEvents)
|
||||
val innerEvent = RumorAssembler.assembleRumor<DeletionRequestEvent>(signer.pubKey, template)
|
||||
val innerEvent = buildDeletionRumor(targetEvents)
|
||||
val outbound = buildGroupMessage(nostrGroupId, innerEvent)
|
||||
if (persistOwn) persistDecryptedMessage(nostrGroupId, innerEvent.toJson())
|
||||
return TextMessageBundle(outbound = outbound, innerEvent = innerEvent)
|
||||
}
|
||||
|
||||
/** The inner kind:5 deletion rumor alone. See [buildTextRumor]. */
|
||||
suspend fun buildDeletionRumor(targetEvents: List<Event>): DeletionRequestEvent {
|
||||
require(targetEvents.isNotEmpty()) { "buildDeletionRumor: targetEvents must not be empty" }
|
||||
return RumorAssembler.assembleRumor(signer.pubKey, DeletionRequestEvent.build(targetEvents))
|
||||
}
|
||||
|
||||
/**
|
||||
* A single invitee for [addMemberInvites]: whose KeyPackage is consumed, the bare
|
||||
* KeyPackage bytes as published, and the id of the event that carried them
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.marmot
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||
import com.vitorpamplona.quartz.nip09Deletions.DeletionRequestEvent
|
||||
import com.vitorpamplona.quartz.nip25Reactions.ReactionEvent
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* The inner rumors the app sends for reactions and deletions in a Marmot group.
|
||||
* Both used to leave the group as NIP-17 gift wraps to the target's author; they
|
||||
* are now plain MIP-03 inner events, so their shape is what peers validate.
|
||||
*/
|
||||
class MarmotInnerRumorBuildersTest {
|
||||
private val signer = NostrSignerInternal(KeyPair())
|
||||
private val manager = MarmotManager(signer, SnapshotStateStore())
|
||||
|
||||
private val target =
|
||||
Event(
|
||||
id = "b".repeat(64),
|
||||
pubKey = "c".repeat(64),
|
||||
createdAt = 1_790_000_000,
|
||||
kind = 9,
|
||||
tags = emptyArray(),
|
||||
content = "react to me",
|
||||
sig = "",
|
||||
)
|
||||
|
||||
@Test
|
||||
fun aReactionNamesItsTargetFirstAndIsAnUnsignedRumor() =
|
||||
runBlocking<Unit> {
|
||||
val rumor = manager.buildReactionRumor(target, "🎉")
|
||||
assertEquals(ReactionEvent.KIND, rumor.kind)
|
||||
assertEquals("🎉", rumor.content)
|
||||
assertEquals(signer.pubKey, rumor.pubKey)
|
||||
assertTrue(rumor.sig.isEmpty(), "MIP-03 inner events are unsigned rumors")
|
||||
// MDK attaches a reaction to the FIRST e tag.
|
||||
assertEquals(target.id, rumor.tags.first { it[0] == "e" }[1])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aCustomEmojiReactionCarriesItsImage() =
|
||||
runBlocking<Unit> {
|
||||
val rumor = manager.buildReactionRumor(target, ":soapbox:https://example.com/soapbox.png")
|
||||
assertEquals(":soapbox:", rumor.content)
|
||||
val emoji = rumor.tags.first { it[0] == "emoji" }
|
||||
assertEquals(listOf("emoji", "soapbox", "https://example.com/soapbox.png"), emoji.take(3))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aDeletionTargetsEachRetractedEvent() =
|
||||
runBlocking<Unit> {
|
||||
val rumor = manager.buildDeletionRumor(listOf(target))
|
||||
assertEquals(DeletionRequestEvent.KIND, rumor.kind)
|
||||
assertEquals(signer.pubKey, rumor.pubKey)
|
||||
assertTrue(rumor.sig.isEmpty())
|
||||
assertEquals(listOf(target.id), rumor.tags.filter { it[0] == "e" }.map { it[1] })
|
||||
}
|
||||
}
|
||||
+68
@@ -20,7 +20,9 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.commons.marmot
|
||||
|
||||
import com.vitorpamplona.quartz.marmot.GroupEventResult
|
||||
import com.vitorpamplona.quartz.marmot.mip01Groups.MarmotGroupData
|
||||
import com.vitorpamplona.quartz.marmot.mip03GroupMessages.GroupEvent
|
||||
import com.vitorpamplona.quartz.marmot.protocolCore.GroupLifecycleState
|
||||
import com.vitorpamplona.quartz.marmot.protocolCore.LocalOutboundGate
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
@@ -439,6 +441,72 @@ class MarmotPublishBeforeApplyTest {
|
||||
assertEquals(listOf(relay), fx.manager.groupRelays(fx.groupId))
|
||||
}
|
||||
|
||||
/**
|
||||
* The relay echo of our own unconfirmed commit is the confirmation that
|
||||
* never arrived as an OK.
|
||||
*
|
||||
* Reproduced against White Noise on a slow (Tor) link: the admin-grant
|
||||
* publish timed out, so the commit stayed an unresolved obligation and the
|
||||
* group stayed at its old epoch. The relay HAD stored it, the peer applied
|
||||
* it, and when the relay echoed it back our inbound pipeline processed it as
|
||||
* someone else's commit. Its sender is our own leaf, and a committer does not
|
||||
* encrypt the path secret to itself, so it failed with "UpdatePath at common
|
||||
* ancestor carries no ciphertext for us" and the group forked: the peer at
|
||||
* epoch n+1, us still at n, every later message undecryptable.
|
||||
*/
|
||||
@Test
|
||||
fun theRelayEchoOfAnUnconfirmedCommitConfirmsIt() =
|
||||
runBlocking<Unit> {
|
||||
val fx = foundedFixture(accepts = false)
|
||||
val epochBefore =
|
||||
fx.manager.groupManager
|
||||
.getGroup(fx.groupId)!!
|
||||
.epoch
|
||||
|
||||
fx.manager.updateGroupMetadata(
|
||||
fx.groupId,
|
||||
MarmotGroupData(nostrGroupId = fx.groupId, name = "renamed", adminPubkeys = listOf(fx.manager.signer.pubKey)),
|
||||
listOf(relay),
|
||||
)
|
||||
assertEquals(GroupLifecycleState.PENDING_PUBLISH, fx.manager.lifecycle(fx.groupId))
|
||||
|
||||
// What the relay sends back: the same signed kind:445, byte for byte.
|
||||
val echo =
|
||||
Event.fromJson(
|
||||
fx.publisher.published
|
||||
.single()
|
||||
.toJson(),
|
||||
) as GroupEvent
|
||||
val result = fx.manager.processGroupEvent(echo)
|
||||
|
||||
assertTrue(result !is GroupEventResult.Error, "our own commit's echo must not be processed as a foreign commit: $result")
|
||||
assertEquals(
|
||||
epochBefore + 1,
|
||||
fx.manager.groupManager
|
||||
.getGroup(fx.groupId)!!
|
||||
.epoch,
|
||||
"the echo proves a relay took the commit, so it becomes canonical",
|
||||
)
|
||||
assertEquals(GroupLifecycleState.STABLE, fx.manager.lifecycle(fx.groupId))
|
||||
|
||||
// A second echo (another relay, or a retry) is just a duplicate.
|
||||
val again =
|
||||
fx.manager.processGroupEvent(
|
||||
Event.fromJson(
|
||||
fx.publisher.published
|
||||
.single()
|
||||
.toJson(),
|
||||
) as GroupEvent,
|
||||
)
|
||||
assertTrue(again !is GroupEventResult.Error, "a repeated echo must stay harmless: $again")
|
||||
assertEquals(
|
||||
epochBefore + 1,
|
||||
fx.manager.groupManager
|
||||
.getGroup(fx.groupId)!!
|
||||
.epoch,
|
||||
)
|
||||
}
|
||||
|
||||
private class InMemoryStateStore : com.vitorpamplona.quartz.marmot.groups.MlsGroupStateStore {
|
||||
private val states = mutableMapOf<String, ByteArray>()
|
||||
private val retained = mutableMapOf<String, List<ByteArray>>()
|
||||
|
||||
@@ -227,7 +227,6 @@
|
||||
<string name="relays">Relays</string>
|
||||
<string name="website">الموقع</string>
|
||||
<string name="lightning_address">Lightning عنوان</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">نسخ معرف Nsec (كلمة المرور الخاصة بك) إلى الحافظة للنسخ الاحتياطي</string>
|
||||
<string name="send_a_direct_message">إرسال رسالة مباشرة</string>
|
||||
<string name="edits_the_user_s_metadata">القيام بتحرير metadata للمستخدم</string>
|
||||
<string name="unblock">رفع الحظر</string>
|
||||
@@ -282,9 +281,6 @@
|
||||
<string name="mark_all_known_as_read">ضع علامة على جميع الرسائل/الاشعارات المعروفة كمقروء</string>
|
||||
<string name="mark_all_new_as_read">تعيين الجديد كمقروء</string>
|
||||
<string name="mark_all_as_read">تعيين الكل كمقروء</string>
|
||||
<string name="account_backup_tips2_md">## النصائح الرئيسية للنسخ الاحتياطي والسلامة \n\n- يتم تأمين حسابك بمفتاح سري. المفتاح السري هو سلسلة عشوائية طويلة تبدأ بـ **nsec1**. أي شخص لديه مفتاحك السري يمكنه نشر المحتوى باستخدام هويتك. \n\n- لا تقم بوضع مفتاحك السري في أي موقع أو برنامج لا تثق به. \n- مطوري Amethyst لن يطلبوا منك **أبدا** المفتاح السري الخاص بك. \n- حافظ على نسخة احتياطية آمنة لمفتاحك السري لاسترداد الحساب. نوصي باستخدام برنامج لادارة كلمات المرور.</string>
|
||||
<string name="account_backup_tips3_md">للحصول على أمان إضافي، يمكنك تشفير مفتاحك الخاص بكلمة مرور. يبدأ هذا المفتاح المشفر بـ **ncryptsec1** ولا يمكن استخدامه دون كلمة المرور الخاصة بك. \n\nإذا فقدت كلمة المرور، لن تتمكن من استرداد مفتاحك الخاص.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">تشفير و نسخ المفتاح الخاص</string>
|
||||
<string name="badge_award_image_for">صورة شارة مكافئة ل %1$s</string>
|
||||
<string name="badge_award_image">"صورة منح الشارة</string>
|
||||
<string name="new_badge_award_notif">لقد حصلت على شارة جائزة جديدة</string>
|
||||
@@ -2039,7 +2035,6 @@
|
||||
<string name="copied_note_text_to_clipboard">تم نسخ نص الملاحظة/المنشور إلى الحافظة</string>
|
||||
<string name="copied_to_clipboard">تم النسخ إلى الحافظة</string>
|
||||
<string name="copied_user_id_to_clipboard">تم نسخ عنوان @npub المؤلف إلى الحافظة</string>
|
||||
<string name="copy_my_secret_key">إنسخ مفتاحي السري</string>
|
||||
<string name="copy_to_clipboard">نسخ إلى الحافظة</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">تعذّر إنشاء LNUrl من عنوان Lightning "%1$s". تحقق من إعداد المستخدم</string>
|
||||
<string name="could_not_check_downloaded_file">تعذّر التحقق من الملف المنزّل بعد الرفع: %1$s</string>
|
||||
@@ -2930,10 +2925,8 @@
|
||||
<string name="share_hls_video">رفع HLS</string>
|
||||
<string name="share_or_save">مشاركة أو حفظ</string>
|
||||
<string name="shorts">مقاطع قصيرة</string>
|
||||
<string name="show_encrypted_private_key_qr_code">إظهار رمز QR المفتاح الخاص المشفر</string>
|
||||
<string name="show_messages_in_notifications_setting_description">تضمين الرسائل المباشرة والجماعية في تبويب الإشعارات. أوقف التشغيل للاحتفاظ بالرسائل في تبويب الرسائل فقط.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">إظهار الرسائل</string>
|
||||
<string name="show_private_key_qr_code">إظهار رمز QR المفتاح الخاص</string>
|
||||
<string name="sign_request_rejected2">تم رفض طلب التوقيع</string>
|
||||
<string name="sign_request_rejected_description">تأكد من أن تطبيق الموقِّع قد أذن بهذه المعاملة</string>
|
||||
<string name="signer_illegal_state_exception_description">أعاد الموقِّع الخارجي بيانات غير متوقعة للطلب. قد يكون هناك خطأ في Amethyst أو في تطبيق الموقِّع.</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays"> রিলেগুলি</string>
|
||||
<string name="website">ওয়েবসাইট</string>
|
||||
<string name="lightning_address">বিজলি-ঠিকানা</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">ব্যাকআপের জন্য আপনার Nsec আইডি (তথা পাসওয়ার্ড) ক্লিপবোর্ডে কপি করে</string>
|
||||
<string name="send_a_direct_message">একটি সরাসরি-বার্তা পাঠান</string>
|
||||
<string name="edits_the_user_s_metadata">ব্যবহারকারীর মেটাডেটা সম্পাদনা করে</string>
|
||||
<string name="unblock">আনব্লক করুন</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">পরিচিত সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন</string>
|
||||
<string name="mark_all_new_as_read">নতুন সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন</string>
|
||||
<string name="mark_all_as_read">সবগুলোকে পঠিত হিসেবে চিহ্নিত করুন</string>
|
||||
<string name="account_backup_tips2_md">## মূল ব্যাকআপ এবং নিরাপত্তা টিপস \n\n আপনার অ্যাকাউন্ট একটি গোপন কী দ্বারা সুরক্ষিত। মূলটি হল অক্ষরগুলির একটি দীর্ঘ ক্রম যা শুরু হয় **nsec1**. যে কেউ এই গোপন কী অ্যাক্সেস করতে পারে পোস্ট এবং আপনার পরিচয় পরিবর্তন করতে পারেন. \n\n- আপনি বিশ্বাস করেন না এমন কোনো ওয়েবসাইট বা সফ্টওয়্যারে আপনার গোপন কী **করবেন না**. \n- অ্যামেথিস্ট ডেভেলপাররা **কখনই** আপনার গোপন কী চাইবে না. \n- **করুন** অ্যাকাউন্ট পুনরুদ্ধারের জন্য আপনার গোপন কীটির একটি নিরাপদ ব্যাকআপ রাখুন৷. আমরা একটি পাসওয়ার্ড ম্যানেজার ব্যবহার করার পরামর্শ দিই।.</string>
|
||||
<string name="account_backup_tips3_md">অতিরিক্ত নিরাপত্তার জন্য, আপনি একটি পাসওয়ার্ড দিয়ে আপনার কী এনক্রিপ্ট করতে পারেন. এই কী দিয়ে শুরু হয় **ncryptsec1** এবং আপনার পাসওয়ার্ড ছাড়া ব্যবহার করা যাবে না।. \n\n আপনি যদি আপনার পাসওয়ার্ড হারিয়ে ফেলেন, আপনি আপনার কী পুনরুদ্ধার করতে পারবেন না।.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">এনক্রিপ্ট এবং আমার গোপন কী অনুলিপি</string>
|
||||
<string name="badge_award_image_for">%1$s -এর জন্য ব্যাজ পুরষ্কারের ছবি</string>
|
||||
<string name="badge_award_image">"ব্যাজ পুরস্কার চিত্র</string>
|
||||
<string name="new_badge_award_notif">আপনি একটি নতুন ব্যাজ পুরষ্কার পেয়েছেন</string>
|
||||
@@ -2005,7 +2001,6 @@
|
||||
<string name="copied_note_text_to_clipboard">নোটের রচনাটি ক্লিপবোর্ডে কপি করা হয়েছে</string>
|
||||
<string name="copied_to_clipboard">ক্লিপবোর্ডে কপি হয়েছে</string>
|
||||
<string name="copied_user_id_to_clipboard">রচয়িতার @npub ক্লিপবোর্ডে কপি করুন</string>
|
||||
<string name="copy_my_secret_key">আমার ব্যক্তিগত চাবিটি কপি করুন</string>
|
||||
<string name="copy_to_clipboard">ক্লিপবোর্ডে কপি করুন</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning Address "%1$s" থেকে LNUrl তৈরি করা যায়নি। ব্যবহারকারীর সেটআপ পরীক্ষা করুন</string>
|
||||
<string name="could_not_check_downloaded_file">আপলোডের পরে ডাউনলোড করা ফাইল পরীক্ষা করা যায়নি: %1$s</string>
|
||||
@@ -2811,10 +2806,8 @@
|
||||
<string name="share_hls_video">HLS আপলোড</string>
|
||||
<string name="share_or_save">শেয়ার বা সেভ করুন</string>
|
||||
<string name="shorts">শর্টস</string>
|
||||
<string name="show_encrypted_private_key_qr_code">এনক্রিপ্টেড প্রাইভেট কী QR কোড দেখান</string>
|
||||
<string name="show_messages_in_notifications_setting_description">বিজ্ঞপ্তি ট্যাবে সরাসরি ও গ্রুপ বার্তা অন্তর্ভুক্ত করুন। বার্তাগুলো শুধুমাত্র বার্তা ট্যাবে রাখতে বন্ধ করুন।</string>
|
||||
<string name="show_messages_in_notifications_setting_title">বার্তা দেখান</string>
|
||||
<string name="show_private_key_qr_code">প্রাইভেট কী QR কোড দেখান</string>
|
||||
<string name="sign_request_rejected2">সাইন অনুরোধ প্রত্যাখ্যাত</string>
|
||||
<string name="sign_request_rejected_description">নিশ্চিত করুন যে সাইনার অ্যাপ্লিকেশনটি এই লেনদেন অনুমোদন করেছে</string>
|
||||
<string name="signer_illegal_state_exception_description">এক্সটার্নাল সাইনার অনুরোধের জন্য একটি অপরিচিত পেলোড ফেরত দিয়েছে। Amethyst বা সাইনারে একটি বাগ থাকতে পারে।</string>
|
||||
|
||||
@@ -561,7 +561,6 @@
|
||||
<string name="relays"> Přeposílání</string>
|
||||
<string name="website">Webová stránka</string>
|
||||
<string name="lightning_address">Lightning adresa</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Zkopíruje Nsec ID (vaše heslo) do schránky pro zálohování</string>
|
||||
<string name="send_a_direct_message">Poslat přímou zprávu</string>
|
||||
<string name="edits_the_user_s_metadata">Upravit uživatelova metadata</string>
|
||||
<string name="unblock">Odblokovat</string>
|
||||
@@ -670,14 +669,11 @@
|
||||
<string name="mark_all_known_as_read">Označit všechny známé jako přečtené</string>
|
||||
<string name="mark_all_new_as_read">Označit všechny nové jako přečtené</string>
|
||||
<string name="mark_all_as_read">Označit všechny jako přečtené</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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íč.</string>
|
||||
<string name="backup_keys_nudge_title">Zálohujte si klíče</string>
|
||||
<string name="backup_keys_nudge_body">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čí.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Zálohovat nyní</string>
|
||||
<string name="backup_keys_nudge_already_saved">Uložil jsem si je</string>
|
||||
<string name="backup_keys_nudge_dismiss">Zavřít</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Zašifrovat a zkopírovat můj tajný klíč</string>
|
||||
<string name="badge_award_image_for">Obrázek ocenění od %1$s</string>
|
||||
<string name="badge_award_image">Obrázek ocenění</string>
|
||||
<string name="new_badge_award_notif">Obdrželi jste nové ocenění</string>
|
||||
@@ -3653,7 +3649,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Text poznámky zkopírován do schránky</string>
|
||||
<string name="copied_to_clipboard">Zkopírováno do schránky</string>
|
||||
<string name="copied_user_id_to_clipboard">Uživatelovo ID (@npub) zkopírováno do schránky</string>
|
||||
<string name="copy_my_secret_key">Zkopírovat můj tajný klíč</string>
|
||||
<string name="copy_to_clipboard">Kopírovat do schránky</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Nepodařilo se sestavit LNUrl z Lightning adresy "%1$s". Zkontrolujte nastavení uživatele</string>
|
||||
<string name="could_not_check_downloaded_file">Nelze zkontrolovat stažený soubor po nahrání: %1$s</string>
|
||||
@@ -5256,10 +5251,8 @@
|
||||
<string name="share_hls_video">HLS nahrávání</string>
|
||||
<string name="share_or_save">Sdílet nebo Uložit</string>
|
||||
<string name="shorts">Krátká videa</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Zobrazit šifrovaný QR kód soukromého klíče</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Zahrnout přímé a skupinové zprávy na kartě Oznámení. Vypněte, aby zprávy zůstaly pouze na kartě Zprávy.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Zobrazit zprávy</string>
|
||||
<string name="show_private_key_qr_code">Zobrazit QR kód privátního klíče</string>
|
||||
<string name="sign_request_rejected2">Požadavek na podpis byl zamítnut</string>
|
||||
<string name="sign_request_rejected_description">Ujistěte se, že podepisující aplikace autorizovala tuto transakci</string>
|
||||
<string name="signer_illegal_state_exception_description">Externí podepisovatel vrátil data, která jsou pro daný požadavek neobvyklá. Může se jednat o chybu v Amethystu nebo v podepisovateli.</string>
|
||||
|
||||
@@ -545,7 +545,6 @@
|
||||
<string name="relays"> Relays</string>
|
||||
<string name="website">Website</string>
|
||||
<string name="lightning_address">Lightning-Adresse</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopiert die Nsec-ID (Ihr Passwort) zur Sicherung in die Zwischenablage</string>
|
||||
<string name="send_a_direct_message">Sende eine Direktnachricht</string>
|
||||
<string name="edits_the_user_s_metadata">Bearbeitet die Benutzermetadaten</string>
|
||||
<string name="unblock">Entsperren</string>
|
||||
@@ -654,14 +653,11 @@
|
||||
<string name="mark_all_known_as_read">Alle Kontakte als gelesen markieren</string>
|
||||
<string name="mark_all_new_as_read">Alle Unbekannten als gelesen markieren</string>
|
||||
<string name="mark_all_as_read">Alle als gelesen markieren</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="backup_keys_nudge_title">Sichere deine Schlüssel</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Jetzt sichern</string>
|
||||
<string name="backup_keys_nudge_already_saved">Habe ich gespeichert</string>
|
||||
<string name="backup_keys_nudge_dismiss">Schließen</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Meinen privaten Schlüssel verschlüsseln und kopieren</string>
|
||||
<string name="badge_award_image_for">Auszeichnungsbild für %1$s</string>
|
||||
<string name="badge_award_image">Auszeichnungsbild</string>
|
||||
<string name="new_badge_award_notif">Du hast eine neue Auszeichnung erhalten</string>
|
||||
@@ -3577,7 +3573,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Notiztext in die Zwischenablage kopiert</string>
|
||||
<string name="copied_to_clipboard">In die Zwischenablage kopiert</string>
|
||||
<string name="copied_user_id_to_clipboard">Autor-ID in die Zwischenablage kopiert</string>
|
||||
<string name="copy_my_secret_key">Meinen geheimen Schlüssel kopieren</string>
|
||||
<string name="copy_to_clipboard">In Zwischenablage kopieren</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Konnte keine LNUrl aus der Lightning-Adresse "%1$s" zusammenstellen. Überprüfe die Konfiguration des Benutzers</string>
|
||||
<string name="could_not_check_downloaded_file">Die heruntergeladene Datei konnte nach dem Hochladen nicht überprüft werden: %1$s</string>
|
||||
@@ -5042,10 +5037,8 @@
|
||||
<string name="share_hls_video">HLS-Upload</string>
|
||||
<string name="share_or_save">Teilen oder Speichern</string>
|
||||
<string name="shorts">Kurzvideos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">QR-Code für verschlüsselten privaten Schlüssel anzeigen</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Direkt- und Gruppennachrichten im Benachrichtigungs-Tab anzeigen. Deaktivieren, um Nachrichten nur im Nachrichten-Tab zu behalten.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Nachrichten anzeigen</string>
|
||||
<string name="show_private_key_qr_code">Privaten QR-Code anzeigen</string>
|
||||
<string name="sign_request_rejected2">Signaturanfrage abgelehnt</string>
|
||||
<string name="sign_request_rejected_description">Stell sicher, dass die Signer-App diese Transaktion autorisiert hat</string>
|
||||
<string name="signer_illegal_state_exception_description">Externer Signer hat Daten zurückgegeben, die für die Anfrage ungewöhnlich sind. Es könnte ein Fehler in Amethyst oder im Signer vorliegen.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays"> Relais</string>
|
||||
<string name="website">Webseite</string>
|
||||
<string name="lightning_address">Lightning-Adresse</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopiert die Nsec-ID (Ihr Passwort) zur Sicherung in die Zwischenablage</string>
|
||||
<string name="send_a_direct_message">Sende eine Direktnachricht</string>
|
||||
<string name="edits_the_user_s_metadata">Bearbeitet die Benutzermetadaten</string>
|
||||
<string name="unblock">Entsperren</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Alle als bekannt markieren</string>
|
||||
<string name="mark_all_new_as_read">Alle als neu markieren</string>
|
||||
<string name="mark_all_as_read">Alle als gelesen markieren</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Verschlüsseln und kopieren Sie meinen geheimen Schlüssel</string>
|
||||
<string name="badge_award_image_for">Auszeichnungsbild für %1$s</string>
|
||||
<string name="badge_award_image">Auszeichnungsbild</string>
|
||||
<string name="new_badge_award_notif">Sie haben eine neue Auszeichnung erhalten</string>
|
||||
@@ -2047,7 +2043,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Notiztext in die Zwischenablage kopiert</string>
|
||||
<string name="copied_to_clipboard">In die Zwischenablage kopiert</string>
|
||||
<string name="copied_user_id_to_clipboard">Autor-ID in die Zwischenablage kopiert</string>
|
||||
<string name="copy_my_secret_key">Meinen geheimen Schlüssel kopieren</string>
|
||||
<string name="copy_to_clipboard">In Zwischenablage kopieren</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Konnte keine LNUrl aus der Lightning-Adresse "%1$s" zusammenstellen. Überprüfen Sie die Konfiguration des Benutzers</string>
|
||||
<string name="could_not_check_downloaded_file">Die heruntergeladene Datei konnte nach dem Hochladen nicht überprüft werden: %1$s</string>
|
||||
@@ -2896,10 +2891,8 @@
|
||||
<string name="share_hls_video">HLS-Upload</string>
|
||||
<string name="share_or_save">Teilen oder Speichern</string>
|
||||
<string name="shorts">Kurzvideos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">QR-Code für verschlüsselten privaten Schlüssel anzeigen</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Direkt- und Gruppennachrichten im Benachrichtigungs-Tab anzeigen. Deaktivieren, um Nachrichten nur im Nachrichten-Tab zu behalten.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Nachrichten anzeigen</string>
|
||||
<string name="show_private_key_qr_code">Privaten QR-Code anzeigen</string>
|
||||
<string name="sign_request_rejected2">Signaturanfrage abgelehnt</string>
|
||||
<string name="sign_request_rejected_description">Stellen Sie sicher, dass die Unterzeichner-Anwendung diese Transaktion autorisiert hat</string>
|
||||
<string name="signer_illegal_state_exception_description">Externer Signierer hat Daten zurückgegeben, die für die Anfrage ungewöhnlich sind. Es könnte ein Fehler in Amethyst oder im Signierer vorliegen.</string>
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
<string name="relays"> Διαμοιραστές</string>
|
||||
<string name="website">Ιστοσελίδα</string>
|
||||
<string name="lightning_address">Διεύθυνση Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Αντιγράφει το "Μυστικό Κλειδί" σας (Nsec ID ή αλλιώς ο μυστικός κωδικός πρόσβασής σας) στο πρόχειρο για δημιουργία αντιγράφου ασφαλείας</string>
|
||||
<string name="send_a_direct_message">Αποστολή Άμεσου Μηνύματος</string>
|
||||
<string name="edits_the_user_s_metadata">Επεξεργασία των Μεταδεδομένων του Χρήστη</string>
|
||||
<string name="unblock">Άρση Αποκλεισμού</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">Σήμανση όλων των γνωστοποιήσεων ως αναγνωσμένων</string>
|
||||
<string name="mark_all_new_as_read">Σήμανση όλων ως αναγνωσμένων</string>
|
||||
<string name="mark_all_as_read">Σήμανση όλων ως αναγνωσμένα</string>
|
||||
<string name="account_backup_tips2_md">## Συμβουλές ασφαλείας και δημιουργίας αντιγράφων ασφαλείας κλειδιού \n\nΟ λογαριασμός σου ασφαλίζεται με ένα μυστικό κλειδί. Το κλειδί είναι μια μακρά ακολουθία χαρακτήρων που ξεκινά με **nsec1**. Όποιος έχει πρόσβαση σε αυτό το μυστικό κλειδί μπορεί να δημοσιεύει και να αλλάζει την ταυτότητά σου. \n\n- **Μην** βάζεις το μυστικό σου κλειδί σε κανέναν ιστότοπο ή λογισμικό που δεν εμπιστεύεσαι. \n- Οι προγραμματιστές του Amethyst **δεν** θα ζητήσουν ποτέ το μυστικό σου κλειδί. \n- **Διατήρησε** ένα ασφαλές αντίγραφο ασφαλείας του μυστικού σου κλειδιού για ανάκτηση λογαριασμού. Συνιστούμε τη χρήση διαχειριστή κωδικών πρόσβασης.</string>
|
||||
<string name="account_backup_tips3_md">Για πρόσθετη ασφάλεια, μπορείς να κρυπτογραφήσεις το κλειδί σου με κωδικό πρόσβασης. Αυτό το κλειδί ξεκινά με **ncryptsec1** και δεν μπορεί να χρησιμοποιηθεί χωρίς τον κωδικό σου. \n\nΑν χάσεις τον κωδικό σου, δεν θα μπορείς να ανακτήσεις το κλειδί σου.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Κρυπτογράφηση και αντιγραφή του μυστικού μου κλειδιού</string>
|
||||
<string name="badge_award_image_for">Σήμα βράβευσης για %1$s</string>
|
||||
<string name="badge_award_image">"Εικόνα βραβείου παρασήμου</string>
|
||||
<string name="new_badge_award_notif">Λάβατε ένα νέο Σήμα Βράβευσης</string>
|
||||
@@ -1990,7 +1986,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Το κείμενο της δημοσίευσης αποθηκεύτηκε στο πρόχειρο</string>
|
||||
<string name="copied_to_clipboard">Αντιγράφηκε στο πρόχειρο</string>
|
||||
<string name="copied_user_id_to_clipboard">Το "Δημόσιο Κλειδί" του συντάκτη της δημοσίευσης αποθηκεύτηκε στο πρόχειρο</string>
|
||||
<string name="copy_my_secret_key">Αντιγραφή του "Μυστικού Κλειδιού" μου</string>
|
||||
<string name="copy_to_clipboard">Αντιγραφή στο πρόχειρο</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Δεν ήταν δυνατή η δημιουργία του LNUrl από τη διεύθυνση Lightning "%1$s". Ελέγξτε ρυθμίσεις χρήστη</string>
|
||||
<string name="could_not_check_downloaded_file">Δεν ήταν δυνατός ο έλεγχος του ληφθέντος αρχείου μετά το ανέβασμα: %1$s</string>
|
||||
@@ -2759,10 +2754,8 @@
|
||||
<string name="share_as_image_url">Κοινοποίηση ως URL εικόνας</string>
|
||||
<string name="share_hls_video">Μεταφόρτωση HLS</string>
|
||||
<string name="share_or_save">Κοινοποίηση ή αποθήκευση</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Εμφάνιση QR code κρυπτογραφημένου ιδιωτικού κλειδιού</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Συμπερίληψη άμεσων και ομαδικών μηνυμάτων στην καρτέλα ειδοποιήσεων. Απενεργοποιήστε για να διατηρείτε τα μηνύματα μόνο στην καρτέλα μηνυμάτων.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Εμφάνιση μηνυμάτων</string>
|
||||
<string name="show_private_key_qr_code">Εμφάνιση QR code ιδιωτικού κλειδιού</string>
|
||||
<string name="sign_request_rejected2">Αίτημα υπογραφής απορρίφθηκε</string>
|
||||
<string name="sign_request_rejected_description">Βεβαιωθείτε ότι η εφαρμογή υπογραφής έχει εξουσιοδοτήσει αυτή τη συναλλαγή</string>
|
||||
<string name="signer_illegal_state_exception_description">Ο εξωτερικός signer επέστρεψε ένα payload που είναι ασυνήθιστο για το αίτημα. Ενδέχεται να υπάρχει σφάλμα στο Amethyst ή στον signer.</string>
|
||||
|
||||
@@ -218,7 +218,6 @@
|
||||
<string name="relays"> Plusendiloj</string>
|
||||
<string name="website">Retejo</string>
|
||||
<string name="lightning_address">Lightning-Adreso</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopii la Nsec ID (vian pasvorton) al la tondujo por sekurkopio</string>
|
||||
<string name="send_a_direct_message">Sendi rektan mesaĝon</string>
|
||||
<string name="edits_the_user_s_metadata">Redakti metadatumojn de uzanto</string>
|
||||
<string name="unblock">Malbloki</string>
|
||||
@@ -273,9 +272,6 @@
|
||||
<string name="mark_all_known_as_read">Marki ĉiujn Konatajn legitaj</string>
|
||||
<string name="mark_all_new_as_read">Marki ĉiujn Novajn legitaj</string>
|
||||
<string name="mark_all_as_read">Marki ĉiujn legitajn</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Ĉifri kaj kopii mian seketan ŝlosilon</string>
|
||||
<string name="badge_award_image_for">Ŝildeto-premia bildo por %1$s</string>
|
||||
<string name="badge_award_image">"Insigna premibildeto</string>
|
||||
<string name="new_badge_award_notif">Vi ricevis novan ŝildeto-premion</string>
|
||||
@@ -2014,7 +2010,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Kopiita tekston de noto al tondujo</string>
|
||||
<string name="copied_to_clipboard">Kopiita al poŝujo</string>
|
||||
<string name="copied_user_id_to_clipboard">Kopiita @npub de aŭtoro al tondujo</string>
|
||||
<string name="copy_my_secret_key">Kopii mian sekretan ŝlosilon</string>
|
||||
<string name="copy_to_clipboard">Kopii al poŝujo</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Ne eblis kunmeti LNUrl el Lightning-Adreso "%1$s". Kontrolu la agordon de la uzanto</string>
|
||||
<string name="could_not_check_downloaded_file">Ne eblis kontroli la elŝutitan dosieron post alŝuto: %1$s</string>
|
||||
@@ -2813,10 +2808,8 @@
|
||||
<string name="share_hls_video">HLS Alŝuto</string>
|
||||
<string name="share_or_save">Kunhavigi aŭ Konservi</string>
|
||||
<string name="shorts">Mallongaj videoj</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Montri ĉifritan privatan ŝlosilon QR-kode</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inkluzivi rektajn kaj grupajn mesaĝojn en la Sciiga langeto. Malŝaltu por konservi mesaĝojn nur en la Mesaĝa langeto.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Montri Mesaĝojn</string>
|
||||
<string name="show_private_key_qr_code">Montri privatan ŝlosilon QR-kode</string>
|
||||
<string name="sign_request_rejected2">Subskrib-peto rifuzita</string>
|
||||
<string name="sign_request_rejected_description">Certigu ke la subskribista aplikaĵo aŭtoris ĉi tiun transakcion</string>
|
||||
<string name="signer_illegal_state_exception_description">La ekstera subskribanto resendis utilan ŝarĝon kiu estas stranga por la peto. Povas ekzisti eraro en Amethyst aŭ en la Subskribanto.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays"> Plusendiloj</string>
|
||||
<string name="website">Retejo</string>
|
||||
<string name="lightning_address">Lightning-Adreso</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopii la Nsec ID (vian pasvorton) al la tondujo por sekurkopio</string>
|
||||
<string name="send_a_direct_message">Sendi rektan mesaĝon</string>
|
||||
<string name="edits_the_user_s_metadata">Redakti metadatumojn de uzanto</string>
|
||||
<string name="unblock">Malbloki</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Marki ĉiujn Konatajn legitaj</string>
|
||||
<string name="mark_all_new_as_read">Marki ĉiujn Novajn legitaj</string>
|
||||
<string name="mark_all_as_read">Marki ĉiujn legitajn</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Ĉifri kaj kopii mian seketan ŝlosilon</string>
|
||||
<string name="badge_award_image_for">Ŝildeto-premia bildo por %1$s</string>
|
||||
<string name="badge_award_image">"Insigna premibildeto</string>
|
||||
<string name="new_badge_award_notif">Vi ricevis novan ŝildeto-premion</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Kopiita tekston de noto al tondujo</string>
|
||||
<string name="copied_to_clipboard">Kopiita al poŝujo</string>
|
||||
<string name="copied_user_id_to_clipboard">Kopiita @npub de aŭtoro al tondujo</string>
|
||||
<string name="copy_my_secret_key">Kopii mian sekretan ŝlosilon</string>
|
||||
<string name="copy_to_clipboard">Kopii al poŝujo</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Ne eblis kunmeti LNUrl el Lightning-Adreso "%1$s". Kontrolu la agordon de la uzanto</string>
|
||||
<string name="could_not_check_downloaded_file">Ne eblis kontroli la elŝutitan dosieron post alŝuto: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">HLS Alŝuto</string>
|
||||
<string name="share_or_save">Kunhavigi aŭ Konservi</string>
|
||||
<string name="shorts">Mallongaj videoj</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Montri ĉifritan privatan ŝlosilon QR-kode</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inkluzivi rektajn kaj grupajn mesaĝojn en la Sciiga langeto. Malŝaltu por konservi mesaĝojn nur en la Mesaĝa langeto.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Montri Mesaĝojn</string>
|
||||
<string name="show_private_key_qr_code">Montri privatan ŝlosilon QR-kode</string>
|
||||
<string name="sign_request_rejected2">Subskrib-peto rifuzita</string>
|
||||
<string name="sign_request_rejected_description">Certigu ke la subskribista aplikaĵo aŭtoris ĉi tiun transakcion</string>
|
||||
<string name="signer_illegal_state_exception_description">La ekstera subskribanto resendis utilan ŝarĝon kiu estas stranga por la peto. Povas ekzisti eraro en Amethyst aŭ en la Subskribanto.</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays"> Retransmisores</string>
|
||||
<string name="website">Sitio web</string>
|
||||
<string name="lightning_address">Dirección Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad</string>
|
||||
<string name="send_a_direct_message">Enviar un mensaje directo</string>
|
||||
<string name="edits_the_user_s_metadata">Edita los metadatos del usuario</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -272,9 +271,6 @@
|
||||
<string name="mark_all_known_as_read">Marcar los conocidos como leídos</string>
|
||||
<string name="mark_all_new_as_read">Marcar los nuevos como leídos</string>
|
||||
<string name="mark_all_as_read">Marcar todos como leídos</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Cifrar y copiar mi clave secreta</string>
|
||||
<string name="badge_award_image_for">Imagen del Badge para %1$s</string>
|
||||
<string name="badge_award_image">"Imagen de premio de insignia</string>
|
||||
<string name="new_badge_award_notif">Has recibido un nuevo Badge</string>
|
||||
@@ -2011,7 +2007,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto de nota copiado al portapapeles</string>
|
||||
<string name="copied_to_clipboard">Copiado al portapapeles</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub del autor copiado al portapapeles</string>
|
||||
<string name="copy_my_secret_key">Copiar mi clave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar al portapapeles</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario.</string>
|
||||
<string name="could_not_check_downloaded_file">No se pudo comprobar el archivo descargado después de cargar: %1$s</string>
|
||||
@@ -2826,10 +2821,8 @@
|
||||
<string name="share_hls_video">Subida HLS</string>
|
||||
<string name="share_or_save">Compartir o guardar</string>
|
||||
<string name="shorts">Cortos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar código QR de clave privada cifrada</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensajes</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de clave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitud de firma rechazada</string>
|
||||
<string name="sign_request_rejected_description">Asegúrate de que la aplicación firmante haya autorizado esta transacción.</string>
|
||||
<string name="signer_illegal_state_exception_description">El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante.</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays"> Relés</string>
|
||||
<string name="website">Sitio web</string>
|
||||
<string name="lightning_address">Dirección de Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad</string>
|
||||
<string name="send_a_direct_message">Enviar un mensaje directo</string>
|
||||
<string name="edits_the_user_s_metadata">Edita los metadatos del usuario</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -272,9 +271,6 @@
|
||||
<string name="mark_all_known_as_read">Marcar todos los conocidos como leídos</string>
|
||||
<string name="mark_all_new_as_read">Marcar todos los nuevos como leídos</string>
|
||||
<string name="mark_all_as_read">Marcar todos como leídos</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Cifrar y copiar mi clave secreta</string>
|
||||
<string name="badge_award_image_for">Imagen de premio de insignia por %1$s</string>
|
||||
<string name="badge_award_image">"Imagen de premio de insignia</string>
|
||||
<string name="new_badge_award_notif">Recibiste un nuevo premio de insignia</string>
|
||||
@@ -2010,7 +2006,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto de la nota copiado al portapapeles</string>
|
||||
<string name="copied_to_clipboard">Copiado al portapapeles</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub del autor copiado al portapapeles</string>
|
||||
<string name="copy_my_secret_key">Copiar mi clave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar al portapapeles</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario.</string>
|
||||
<string name="could_not_check_downloaded_file">No se pudo comprobar el archivo descargado después de subir: %1$s</string>
|
||||
@@ -2819,10 +2814,8 @@
|
||||
<string name="share_hls_video">Subida HLS</string>
|
||||
<string name="share_or_save">Compartir o guardar</string>
|
||||
<string name="shorts">Cortos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar código QR de clave privada cifrada</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensajes</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de clave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitud de firma rechazada</string>
|
||||
<string name="sign_request_rejected_description">Asegúrate de que la aplicación firmante haya autorizado esta transacción.</string>
|
||||
<string name="signer_illegal_state_exception_description">El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante.</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays"> Relés</string>
|
||||
<string name="website">Sitio web</string>
|
||||
<string name="lightning_address">Dirección de Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copia el ID Nsec (tu contraseña) en el portapapeles para hacer una copia de seguridad</string>
|
||||
<string name="send_a_direct_message">Enviar un mensaje directo</string>
|
||||
<string name="edits_the_user_s_metadata">Edita los metadatos del usuario</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -272,9 +271,6 @@
|
||||
<string name="mark_all_known_as_read">Marcar todos los conocidos como leídos</string>
|
||||
<string name="mark_all_new_as_read">Marcar todos los nuevos como leídos</string>
|
||||
<string name="mark_all_as_read">Marcar todos como leídos</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Cifrar y copiar mi clave secreta</string>
|
||||
<string name="badge_award_image_for">Imagen de premio de insignia por %1$s</string>
|
||||
<string name="badge_award_image">"Imagen de premio de insignia</string>
|
||||
<string name="new_badge_award_notif">Recibiste un nuevo premio de insignia</string>
|
||||
@@ -2010,7 +2006,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto de la nota copiado al portapapeles</string>
|
||||
<string name="copied_to_clipboard">Copiado al portapapeles</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub del autor copiado al portapapeles</string>
|
||||
<string name="copy_my_secret_key">Copiar mi clave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar al portapapeles</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario.</string>
|
||||
<string name="could_not_check_downloaded_file">No se pudo comprobar el archivo descargado después de subir: %1$s</string>
|
||||
@@ -2819,10 +2814,8 @@
|
||||
<string name="share_hls_video">Subida HLS</string>
|
||||
<string name="share_or_save">Compartir o guardar</string>
|
||||
<string name="shorts">Cortos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar código QR de clave privada cifrada</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensajes</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de clave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitud de firma rechazada</string>
|
||||
<string name="sign_request_rejected_description">Asegúrate de que la aplicación firmante haya autorizado esta transacción.</string>
|
||||
<string name="signer_illegal_state_exception_description">El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays"> Retransmisores</string>
|
||||
<string name="website">Sitio web</string>
|
||||
<string name="lightning_address">Dirección Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copia la ID de Nsec (su contraseña) en el portapapeles para hacer una copia de seguridad</string>
|
||||
<string name="send_a_direct_message">Enviar un mensaje directo</string>
|
||||
<string name="edits_the_user_s_metadata">Edita los metadatos del usuario</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -259,7 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Marcar los conocidos como leídos</string>
|
||||
<string name="mark_all_new_as_read">Marcar los nuevos como leídos</string>
|
||||
<string name="mark_all_as_read">Marcar todos como leídos</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Cifrar y copiar mi clave secreta</string>
|
||||
<string name="badge_award_image_for">Imagen del Badge para %1$s</string>
|
||||
<string name="badge_award_image">"Imagen de premio de insignia</string>
|
||||
<string name="new_badge_award_notif">Has recibido un nuevo Badge</string>
|
||||
@@ -1800,8 +1798,6 @@
|
||||
<string name="ots_explorer_api_label">URL base de la API del explorador</string>
|
||||
<string name="dvm_pay_invoice_from_dvm">Pagar factura del DVM</string>
|
||||
<string name="dvm_pay_amount_to_dvm">Pagar %1$s sats al DVM</string>
|
||||
<string xmlns:ns0="http://schemas.android.com/tools" name="account_backup_tips2_md" ns0:ignore="Typos">## 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.</string>
|
||||
<string xmlns:ns0="http://schemas.android.com/tools" name="account_backup_tips3_md" ns0:ignore="Typos">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.</string>
|
||||
<string name="use_direct_url">Usar URL directa</string>
|
||||
<string name="nsite_title">nSite: %1$s</string>
|
||||
<string name="napplet_card_title">nApplet: %1$s</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto de nota copiado al portapapeles</string>
|
||||
<string name="copied_to_clipboard">Copiado al portapapeles</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub del autor copiado al portapapeles</string>
|
||||
<string name="copy_my_secret_key">Copiar mi clave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar al portapapeles</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">No se pudo ensamblar la LNUrl desde la dirección de Lightning "%1$s". Comprueba la configuración del usuario.</string>
|
||||
<string name="could_not_check_downloaded_file">No se pudo comprobar el archivo descargado después de cargar: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">Subida HLS</string>
|
||||
<string name="share_or_save">Compartir o guardar</string>
|
||||
<string name="shorts">Cortos</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar código QR de clave privada cifrada</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Incluye mensajes directos y de grupo en la pestaña de Notificaciones. Desactívalo para mantener los mensajes solo en la pestaña de Mensajes.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensajes</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de clave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitud de firma rechazada</string>
|
||||
<string name="sign_request_rejected_description">Asegúrate de que la aplicación firmante haya autorizado esta transacción.</string>
|
||||
<string name="signer_illegal_state_exception_description">El firmante externo devolvió una carga útil que no concuerda con la solicitud. Es posible que haya un error, ya sea en Amethyst o en el firmante.</string>
|
||||
|
||||
@@ -219,7 +219,6 @@
|
||||
<string name="relays">رله ها</string>
|
||||
<string name="website">وبسایت</string>
|
||||
<string name="lightning_address">آدرس لایتنینگ</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">شناسه کلید خصوصی (پسوردتان) را در کلیپبورد کپی می کند(</string>
|
||||
<string name="send_a_direct_message">ارسال پیام مستقیم</string>
|
||||
<string name="edits_the_user_s_metadata">متادیتای کاربر را ویرایش می کند</string>
|
||||
<string name="unblock">از بلاک درآوردن</string>
|
||||
@@ -274,9 +273,6 @@
|
||||
<string name="mark_all_known_as_read">همه شناس ها خوانده شده کن</string>
|
||||
<string name="mark_all_new_as_read">همه جدیدها را خوانده شده کن</string>
|
||||
<string name="mark_all_as_read">همه را خوانده شده کن</string>
|
||||
<string name="account_backup_tips2_md">نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم.</string>
|
||||
<string name="account_backup_tips3_md">برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">رمزنگاری و کپی کلید من</string>
|
||||
<string name="badge_award_image_for">تصویر مدال پاداش برای %1$s</string>
|
||||
<string name="badge_award_image">تصویر جایزه نشان</string>
|
||||
<string name="new_badge_award_notif">یک مدال پاداش دریافت کردید</string>
|
||||
@@ -2015,7 +2011,6 @@
|
||||
<string name="copied_note_text_to_clipboard">یادداشت در کلیپبورد کپی شد</string>
|
||||
<string name="copied_to_clipboard">در کلیپبورد کپی شد</string>
|
||||
<string name="copied_user_id_to_clipboard">@npubنویسنده در کلیپبورد کپی شد</string>
|
||||
<string name="copy_my_secret_key">کلید خصوصیم را کپی کن</string>
|
||||
<string name="copy_to_clipboard">کپی به کلیپبورد</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید.</string>
|
||||
<string name="could_not_check_downloaded_file">فایل بارگیری شده پس از بارگذاری بررسی نشد: %1$s</string>
|
||||
@@ -2820,10 +2815,8 @@
|
||||
<string name="share_hls_video">آپلود HLS</string>
|
||||
<string name="share_or_save">اشتراک گذاری یا ذخیرهسازی</string>
|
||||
<string name="shorts">ویدیوهای کوتاه</string>
|
||||
<string name="show_encrypted_private_key_qr_code">نمایش کد QR کلید خصوصی رمزنگاری شده</string>
|
||||
<string name="show_messages_in_notifications_setting_description">پیامهای مستقیم و گروهی را در تب اعلانها نمایش دهید. غیرفعال کنید تا پیامها فقط در تب پیامها باشند.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">نمایش پیامها</string>
|
||||
<string name="show_private_key_qr_code">نمایش کد QR کلید خصوصی</string>
|
||||
<string name="sign_request_rejected2">درخواست امضا رد شد</string>
|
||||
<string name="sign_request_rejected_description">مطمئن شوید که اپ امضا کننده این تراکنش را تایید کرده است</string>
|
||||
<string name="signer_illegal_state_exception_description">signer خارجی یک پاسخ عجیب برای درخواست بازگرداند. ممکن است باگی در Amethyst یا در signer وجود داشته باشد.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays">رله ها</string>
|
||||
<string name="website">وبسایت</string>
|
||||
<string name="lightning_address">آدرس لایتنینگ</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">شناسه کلید خصوصی (پسوردتان) را در کلیپبورد کپی می کند(</string>
|
||||
<string name="send_a_direct_message">ارسال پیام مستقیم</string>
|
||||
<string name="edits_the_user_s_metadata">متادیتای کاربر را ویرایش می کند</string>
|
||||
<string name="unblock">از بلاک درآوردن</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">همه شناس ها خوانده شده کن</string>
|
||||
<string name="mark_all_new_as_read">همه جدیدها را خوانده شده کن</string>
|
||||
<string name="mark_all_as_read">همه را خوانده شده کن</string>
|
||||
<string name="account_backup_tips2_md">نکات ایمنی و ذخیره کلید حساب کاربری شما با یک کلید خصوصی محافظت می شود. این کلید دنباله ای بلند از کاراکترها است که با **nsec1** آغاز می گردد. هر کس به این کلید خصوصی دسترسی داشته باشد می تواند بجای شما یادداشت پست کرده یا هویت شما را تغییر دهد. هرگز کلید خصوصی خود را در هیچ وبسایت با نرم افزاری که به آن اطمینان ندارید **وارد نکنید**. سازندگان امتیست **هرگز** کلیدتان را از شما نمی خواهند. یک پشتیبان یدکی مخفی از کلید خود به منظور بازیابی **نگه دارید**. ما استفاده از نرم افزار مدیریت پسورد را توصیه می کنیم.</string>
|
||||
<string name="account_backup_tips3_md">برای ایمنی بیشتر، می توانید کلید خود را با یک رمزعبور رمزنگاری کنید. این نوع کلید با **ncryptsec1** آغاز می شود و نمی تواند بدون رمز عبور شما استفاده شود. اگر پسوردتان را گم کنید، نخواهید توانست کلیدتان را بازیابی کنید.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">رمزنگاری و کپی کلید من</string>
|
||||
<string name="badge_award_image_for">تصویر مدال پاداش برای %1$s</string>
|
||||
<string name="badge_award_image">تصویر جایزه نشان</string>
|
||||
<string name="new_badge_award_notif">یک مدال پاداش دریافت کردید</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">یادداشت در کلیپبورد کپی شد</string>
|
||||
<string name="copied_to_clipboard">در کلیپبورد کپی شد</string>
|
||||
<string name="copied_user_id_to_clipboard">@npubنویسنده در کلیپبورد کپی شد</string>
|
||||
<string name="copy_my_secret_key">کلید خصوصیم را کپی کن</string>
|
||||
<string name="copy_to_clipboard">کپی به کلیپبورد</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">LNUrl از آدرس لایتنینگ "%1$s" بدست نیامد. تنظیمات کاربر را بررسی کنید.</string>
|
||||
<string name="could_not_check_downloaded_file">فایل بارگیری شده پس از بارگذاری بررسی نشد: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">آپلود HLS</string>
|
||||
<string name="share_or_save">اشتراک گذاری یا ذخیرهسازی</string>
|
||||
<string name="shorts">ویدیوهای کوتاه</string>
|
||||
<string name="show_encrypted_private_key_qr_code">نمایش کد QR کلید خصوصی رمزنگاری شده</string>
|
||||
<string name="show_messages_in_notifications_setting_description">پیامهای مستقیم و گروهی را در تب اعلانها نمایش دهید. غیرفعال کنید تا پیامها فقط در تب پیامها باشند.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">نمایش پیامها</string>
|
||||
<string name="show_private_key_qr_code">نمایش کد QR کلید خصوصی</string>
|
||||
<string name="sign_request_rejected2">درخواست امضا رد شد</string>
|
||||
<string name="sign_request_rejected_description">مطمئن شوید که اپ امضا کننده این تراکنش را تایید کرده است</string>
|
||||
<string name="signer_illegal_state_exception_description">signer خارجی یک پاسخ عجیب برای درخواست بازگرداند. ممکن است باگی در Amethyst یا در signer وجود داشته باشد.</string>
|
||||
|
||||
@@ -213,7 +213,6 @@
|
||||
<string name="relays"> Releet</string>
|
||||
<string name="website">Verkkosivusto</string>
|
||||
<string name="lightning_address">Lightning-osoite</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopioi Nsec-tunniste (salasanasi) leikepöydälle varmuuskopiointia varten</string>
|
||||
<string name="send_a_direct_message">Lähetä suora viesti</string>
|
||||
<string name="edits_the_user_s_metadata">Muokkaa käyttäjän metatietoja</string>
|
||||
<string name="unblock">Poista esto</string>
|
||||
@@ -268,9 +267,6 @@
|
||||
<string name="mark_all_known_as_read">Merkitse kaikki Tunnetut luetuiksi</string>
|
||||
<string name="mark_all_new_as_read">Merkitse kaikki Uudet luetuiksi</string>
|
||||
<string name="mark_all_as_read">Merkitse kaikki luetuiksi</string>
|
||||
<string name="account_backup_tips2_md">## 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öä.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Salaa ja kopioi salainen avaimeni</string>
|
||||
<string name="badge_award_image_for">Merkki kohteelle %1$s</string>
|
||||
<string name="badge_award_image">"Merkkipalkinnon kuva</string>
|
||||
<string name="new_badge_award_notif">Olet saanut uuden merkin</string>
|
||||
@@ -1995,7 +1991,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Viestin teksti kopioitu leikepöydälle</string>
|
||||
<string name="copied_to_clipboard">Kopioitu leikepöydälle</string>
|
||||
<string name="copied_user_id_to_clipboard">Käyttäjän @npub kopioitu leikepöydälle</string>
|
||||
<string name="copy_my_secret_key">Kopioi salainen avain</string>
|
||||
<string name="copy_to_clipboard">Kopioi leikepöydälle</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Ei voitu koota LNUrlia Lightning-osoitteesta "%1$s". Tarkista käyttäjän asetukset</string>
|
||||
<string name="could_not_check_downloaded_file">Ladatun tiedoston tarkistus epäonnistui latauksen jälkeen: %1$s</string>
|
||||
@@ -2790,10 +2785,8 @@
|
||||
<string name="share_hls_video">HLS-lataus</string>
|
||||
<string name="share_or_save">Jaa tai tallenna</string>
|
||||
<string name="shorts">Lyhytvideot</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Näytä salatun yksityisen avaimen QR-koodi</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Sisällytä suorat viestit ja ryhmäviestit Ilmoitukset-välilehdelle. Poista käytöstä, jos haluat pitää viestit vain Viestit-välilehdellä.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Näytä viestit</string>
|
||||
<string name="show_private_key_qr_code">Näytä yksityisen avaimen QR-koodi</string>
|
||||
<string name="sign_request_rejected2">Allekirjoituspyyntö hylätty</string>
|
||||
<string name="sign_request_rejected_description">Varmista, että allekirjoittajasovellus on valtuuttanut tämän tapahtuman</string>
|
||||
<string name="signer_illegal_state_exception_description">Ulkoinen allekirjoittaja palautti pyyntöön nähden odottamattoman tietopaketin. Kyseessä voi olla vika Amethystissä tai allekirjoittajassa.</string>
|
||||
|
||||
@@ -211,7 +211,6 @@
|
||||
<string name="relays"> Relais</string>
|
||||
<string name="website">Site Web</string>
|
||||
<string name="lightning_address">Adresse Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder</string>
|
||||
<string name="send_a_direct_message">Envoyer un message direct</string>
|
||||
<string name="edits_the_user_s_metadata">Modifie les métadonnées de l'utilisateur</string>
|
||||
<string name="unblock">Débloquer</string>
|
||||
@@ -266,9 +265,6 @@
|
||||
<string name="mark_all_known_as_read">Marquer tous les Connus comme lu</string>
|
||||
<string name="mark_all_new_as_read">Marquer tous les Nouveaux comme lu</string>
|
||||
<string name="mark_all_as_read">Tout marquer comme lu</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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é.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Chiffrer et copier ma clé secrète</string>
|
||||
<string name="badge_award_image_for">Image de badge pour %1$s</string>
|
||||
<string name="badge_award_image">Image du badge de récompense</string>
|
||||
<string name="new_badge_award_notif">Vous avez reçu un nouveau Badge</string>
|
||||
@@ -1949,7 +1945,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Copie du contenu de la note dans le presse-papiers</string>
|
||||
<string name="copied_to_clipboard">Copié dans le presse-papiers</string>
|
||||
<string name="copied_user_id_to_clipboard">Copie du @npub utilisateur dans le presse-papiers</string>
|
||||
<string name="copy_my_secret_key">Copier ma clé secrète</string>
|
||||
<string name="copy_to_clipboard">Copier dans le presse-papiers</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur</string>
|
||||
<string name="could_not_check_downloaded_file">Impossible de vérifier le fichier téléchargé après le téléversement : %1$s</string>
|
||||
@@ -2717,10 +2712,8 @@
|
||||
<string name="share_as_image_url">Partager en tant qu'URL de l'image</string>
|
||||
<string name="share_hls_video">Mise en ligne HLS</string>
|
||||
<string name="share_or_save">Partager ou Enregistrer</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Afficher le QR code de la clé privée chiffrée</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Voir les messages</string>
|
||||
<string name="show_private_key_qr_code">Afficher le QR code de la clé privée</string>
|
||||
<string name="sign_request_rejected2">Requête de signature rejetée</string>
|
||||
<string name="sign_request_rejected_description">Assurez-vous que l'application signataire a autorisé cette transaction</string>
|
||||
<string name="signer_illegal_state_exception_description">Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire.</string>
|
||||
|
||||
@@ -213,7 +213,6 @@
|
||||
<string name="relays"> Relais</string>
|
||||
<string name="website">Site Web</string>
|
||||
<string name="lightning_address">Adresse Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder</string>
|
||||
<string name="send_a_direct_message">Envoyer un message direct</string>
|
||||
<string name="edits_the_user_s_metadata">Modifie les métadonnées de l'utilisateur</string>
|
||||
<string name="unblock">Débloquer</string>
|
||||
@@ -268,9 +267,6 @@
|
||||
<string name="mark_all_known_as_read">Marquer tous les Connus comme lu</string>
|
||||
<string name="mark_all_new_as_read">Marquer tous les Nouveaux comme lu</string>
|
||||
<string name="mark_all_as_read">Tout marquer comme lu</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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é.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Chiffrer et copier ma clé secrète</string>
|
||||
<string name="badge_award_image_for">Image de badge pour %1$s</string>
|
||||
<string name="badge_award_image">Image du badge de récompense</string>
|
||||
<string name="new_badge_award_notif">Vous avez reçu un nouveau Badge</string>
|
||||
@@ -2138,7 +2134,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Copie du contenu de la note dans le presse-papiers</string>
|
||||
<string name="copied_to_clipboard">Copié dans le presse-papiers</string>
|
||||
<string name="copied_user_id_to_clipboard">Copie du @npub utilisateur dans le presse-papiers</string>
|
||||
<string name="copy_my_secret_key">Copier ma clé secrète</string>
|
||||
<string name="copy_to_clipboard">Copier dans le presse-papiers</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur</string>
|
||||
<string name="could_not_check_downloaded_file">Impossible de vérifier le fichier téléchargé après le téléversement : %1$s</string>
|
||||
@@ -3003,10 +2998,8 @@
|
||||
<string name="share_hls_video">Mise en ligne HLS</string>
|
||||
<string name="share_or_save">Partager ou Enregistrer</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Afficher le QR code de la clé privée chiffrée</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Voir les messages</string>
|
||||
<string name="show_private_key_qr_code">Afficher le QR code de la clé privée</string>
|
||||
<string name="sign_request_rejected2">Requête de signature rejetée</string>
|
||||
<string name="sign_request_rejected_description">Assurez-vous que l'application signataire a autorisé cette transaction</string>
|
||||
<string name="signer_illegal_state_exception_description">Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays"> Relais</string>
|
||||
<string name="website">Site Web</string>
|
||||
<string name="lightning_address">Adresse Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copie l'ID Nsec (votre mot de passe) dans le presse-papiers pour le sauvegarder</string>
|
||||
<string name="send_a_direct_message">Envoyer un message direct</string>
|
||||
<string name="edits_the_user_s_metadata">Modifie les métadonnées de l'utilisateur</string>
|
||||
<string name="unblock">Débloquer</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Marquer tous les Connus comme lu</string>
|
||||
<string name="mark_all_new_as_read">Marquer tous les Nouveaux comme lu</string>
|
||||
<string name="mark_all_as_read">Tout marquer comme lu</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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é.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Chiffrer et copier ma clé secrète</string>
|
||||
<string name="badge_award_image_for">Image de badge pour %1$s</string>
|
||||
<string name="badge_award_image">Image du badge de récompense</string>
|
||||
<string name="new_badge_award_notif">Vous avez reçu un nouveau Badge</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Copie du contenu de la note dans le presse-papiers</string>
|
||||
<string name="copied_to_clipboard">Copié dans le presse-papiers</string>
|
||||
<string name="copied_user_id_to_clipboard">Copie du @npub utilisateur dans le presse-papiers</string>
|
||||
<string name="copy_my_secret_key">Copier ma clé secrète</string>
|
||||
<string name="copy_to_clipboard">Copier dans le presse-papiers</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Impossible d'assembler LNUrl à partir de l'adresse Lightning "%1$s". Vérifiez la configuration de l'utilisateur</string>
|
||||
<string name="could_not_check_downloaded_file">Impossible de vérifier le fichier téléchargé après le téléversement : %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">Mise en ligne HLS</string>
|
||||
<string name="share_or_save">Partager ou Enregistrer</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Afficher le QR code de la clé privée chiffrée</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inclure les messages directs et de groupe dans l'onglet Notifications. Désactivez pour conserver les messages uniquement dans l'onglet Messages.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Voir les messages</string>
|
||||
<string name="show_private_key_qr_code">Afficher le QR code de la clé privée</string>
|
||||
<string name="sign_request_rejected2">Requête de signature rejetée</string>
|
||||
<string name="sign_request_rejected_description">Assurez-vous que l'application signataire a autorisé cette transaction</string>
|
||||
<string name="signer_illegal_state_exception_description">Le signataire externe a renvoyé des données qui sont étranges pour la requête. Il peut y avoir un bug sur Amethyst ou le signataire.</string>
|
||||
|
||||
@@ -545,7 +545,6 @@
|
||||
<string name="relays"> पुनःप्रसारक</string>
|
||||
<string name="website">जालस्थान</string>
|
||||
<string name="lightning_address">लैटनिंग पता</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">एनसेक॰ सूचक (आपका गुप्त पारणशब्द) की अनुकृति करता है टाँकाफलक में सुरक्षित रखने के लिए</string>
|
||||
<string name="send_a_direct_message">सीधा संदेश भेजें</string>
|
||||
<string name="edits_the_user_s_metadata">उपयोगकर्ता के उपतथ्य का सम्पादन करता है</string>
|
||||
<string name="unblock">बाधा हटाएँ</string>
|
||||
@@ -654,14 +653,24 @@
|
||||
<string name="mark_all_known_as_read">सब ज्ञात को पढ लिया चिह्नित करें</string>
|
||||
<string name="mark_all_new_as_read">सब नये को पढ लिया चिह्नित करें</string>
|
||||
<string name="mark_all_as_read">सब को पढ लिया चिह्नित करें</string>
|
||||
<string name="account_backup_tips2_md">## कुंचिका सुरक्षार्थ अनुकृति तथा सुरक्षा सुझाव \n\nआपकी लेखा एक गुप्त कुंचिका से सुरक्षित किया गया है। कुंचिका अक्षरों की एक लम्बी श्रृंखला है जो **nsec1** से आरम्भ होता है। जिस किसी के पास यह कुंचिका है वह पत्र प्रकाशित कर सकेगा तथा आपका परिचय परिवर्तित कर सकेगा। \n\n- आपकी गुप्त कुंचिका किसी भी जालस्थान अथवा क्रमक में **ना** डालें जिसपर आपका विश्वास ना हो। \n- अमेथिस्ट क्रमलेख विकासकर्ता आपकी गुप्त कुंचिका **कभी नहीं** पूछेंगे। \n- आपकी गुप्त कुंचिका की एक सुरक्षित अनुकृति **अवश्य** रखें अपनी लेखा पुनः प्राप्त करने के लिए। पारणशब्ध प्रबंधन क्रमक की पुनः प्रशंसा करते हैं।</string>
|
||||
<string name="account_backup_tips3_md">अधिक सुरक्षा के लिए आप अपनी कुंचिका का रहस्यीकरण कर सकते हैं एक पारणशब्द के साथ। यह कुंचिका आरम्भ होगी **ncryptsec1** से तथा पारणशब्द के बिना प्रयोग साध्य नहीं। \n\n यदि आप अपना पारणशब्द खो देते हैं, तो आप अपनी कुंचिका को पुनः प्राप्त नहीं कर सकते।</string>
|
||||
<string name="account_backup_headline">आपकी गुप्त कुंचिका आपका लेखा है</string>
|
||||
<string name="account_backup_tap_to_reveal">दबाएँ देखने के लिए</string>
|
||||
<string name="account_backup_write_down_hint">इसे इस क्रम मे लिख लें। बडे अथवा छोटे अक्षर दोनों कार्य करेंगे।</string>
|
||||
<string name="account_backup_qr_code">क्यूआर अक्षरराशि</string>
|
||||
<string name="account_backup_encrypted_title">पारणशब्द रक्षित अनुकृति</string>
|
||||
<string name="account_backup_encrypted_password">पारणशब्द</string>
|
||||
<string name="account_backup_encrypted_body">एक ncryptsec1… जो केवल आपके पारणशब्द से कार्य करता है।</string>
|
||||
<string name="account_backup_password_min_length">न्यूनतम %1$d अक्षर</string>
|
||||
<string name="account_backup_encrypted_repeat_password">पारणशब्द दोहराएँ</string>
|
||||
<string name="account_backup_encrypted_password_mismatch">पारणशब्दों में मेल नहीं</string>
|
||||
<string name="account_backup_encrypt">रहस्यीकरण कुंचिका</string>
|
||||
<string name="account_backup_encrypting">रहस्यीकरणमध्य…</string>
|
||||
<string name="account_backup_encrypt_again">एक पृथक पारणशब्द का उपयोग करें</string>
|
||||
<string name="backup_keys_nudge_title">अपने कुंचिकाओं को सुरक्षित रखें</string>
|
||||
<string name="backup_keys_nudge_body">आपकी गुप्त कुंचिका एकमात्र विधि है इस लेखा का अभिगमन करने के लिए। यदि आप इसे खो देते हैं तो इसे कभी भी पुनःप्राप्त नहीं कर सकते। इसे कहीं सुरक्षित रखें अभी इस समय।</string>
|
||||
<string name="backup_keys_nudge_backup_now">अभी इसी समय सुरक्षित अनुकृति बनाएँ</string>
|
||||
<string name="backup_keys_nudge_already_saved">उनको मैंने सुरक्षित कर लिया</string>
|
||||
<string name="backup_keys_nudge_dismiss">हटाएँ</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">मेरी गुप्त कुंचिका का रहस्यीकरण तथा अनुकृति करें</string>
|
||||
<string name="badge_award_image_for">पदक पुरस्कार चित्र %1$s के लिए</string>
|
||||
<string name="badge_award_image">"पदक पुरस्कार चित्र</string>
|
||||
<string name="new_badge_award_notif">आपको नया पदक पुरस्कार प्राप्त हुआ</string>
|
||||
@@ -3577,7 +3586,6 @@
|
||||
<string name="copied_note_text_to_clipboard">टीका लेख की अनुकृति की गई टाँकाफलक में</string>
|
||||
<string name="copied_to_clipboard">टाँकाफलक में अनुकृत</string>
|
||||
<string name="copied_user_id_to_clipboard">लेखक के @npub की अनुकृति की गई टाँकाफलक में</string>
|
||||
<string name="copy_my_secret_key">मेरी गुप्त कुंचिका की अनुकृति करें</string>
|
||||
<string name="copy_to_clipboard">टाँकाफलक में अनुकृति करें</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">लै॰जालपता नहीं बना पाए लै॰पता "%1$s" से। उपयोगकर्ता की स्थापना की जाँच करें</string>
|
||||
<string name="could_not_check_downloaded_file">आरोहण पश्चात अवरोहित अभिलेख की जाँच नहीं हो सकी : %1$s</string>
|
||||
@@ -5040,10 +5048,8 @@
|
||||
<string name="share_hls_video">एचएलएस॰ आरोहण</string>
|
||||
<string name="share_or_save">बाँटें अथवा अभिलेखन करें</string>
|
||||
<string name="shorts">लघु चलचित्र</string>
|
||||
<string name="show_encrypted_private_key_qr_code">रहस्यीकृत निजी कुंचिका क्यूआर॰ चित्र अक्षरराशि दिखाएँ</string>
|
||||
<string name="show_messages_in_notifications_setting_description">सूचनाएँ पृष्ठ पर सीधे तथा समूह सन्देशों को समाविष्ट करें। निष्क्रिय करें यदि सन्देशों को केवल सन्देश पृष्ठ में रखना चाहते हों तो।</string>
|
||||
<string name="show_messages_in_notifications_setting_title">सन्देशों को दिखाएँ</string>
|
||||
<string name="show_private_key_qr_code">निजी कुंचिका क्यूआर॰ चित्र अक्षरराशि दिखाएँ</string>
|
||||
<string name="sign_request_rejected2">हस्ताक्षर अनुरोध अस्वीकृत</string>
|
||||
<string name="sign_request_rejected_description">सुनिश्चित करें हस्ताक्षर क्रमक ने इस व्यापार को अनुमति दिया</string>
|
||||
<string name="signer_illegal_state_exception_description">बाहरी हस्ताक्षरकर्ता द्वारा दिया गया उत्तर विचित्र है अनुरोध के लिए। अमेथिस्ट अथवा हस्ताक्षरकर्ता में कुछ दोष हो सकता है।</string>
|
||||
@@ -5300,10 +5306,28 @@
|
||||
<string name="cordn_hub_section_service">समायोजक</string>
|
||||
<string name="cordn_hub_section_device">इस यन्त्र</string>
|
||||
<string name="cordn_hub_coordinators">समायोजक</string>
|
||||
<string name="cordn_hub_coordinators_desc">सेवासंगणक जो आपके समूहों को रखते हैं</string>
|
||||
<string name="cordn_hub_keypackages">कुंचिका पोटलियाँ</string>
|
||||
<string name="cordn_hub_keypackages_desc">जिससे लोग आपको एक समूह से जोड सकते हैं</string>
|
||||
<string name="cordn_hub_backup">सुरक्षित अनुकृति तथा पुनःस्थापन</string>
|
||||
<string name="cordn_hub_backup_desc">पारणवाक्याम्श द्वारा रहस्यीकृत एक अभिलेख जो आप रखते हैं</string>
|
||||
<string name="cordn_hub_migrate">अन्य संचारयन्त्र तक विस्थापन</string>
|
||||
<string name="cordn_migrate_title">अन्य संचारयन्त्र तक विस्थापन</string>
|
||||
<string name="cordn_migrate_export">हस्तान्तरण आरम्भ करें</string>
|
||||
<string name="cordn_migrate_exporting">प्रकाशनमध्य…</string>
|
||||
<string name="cordn_migrate_scan_this">नए संचारयन्त्र में इसे परखें</string>
|
||||
<string name="cordn_migrate_handed_off">इस यन्त्र ने अपने समूहों का हस्तान्तरण कर दिया</string>
|
||||
<string name="cordn_migrate_cancel">इस यन्त्र को आप पुनः ले जाएँ</string>
|
||||
<string name="cordn_migrate_receive">अन्य संचारयन्त्र से प्राप्त करें</string>
|
||||
<string name="cordn_migrate_scan">अक्षरराशि परखें</string>
|
||||
<string name="cordn_migrate_paste">अथवा चिपकाएँ</string>
|
||||
<string name="cordn_migrate_import">समूहों को यहाँ ले आएँ</string>
|
||||
<string name="cordn_migrate_importing">लाया जा रहा है…</string>
|
||||
<plurals name="cordn_migrate_done">
|
||||
<item quantity="one">%1$d समूह स्थानान्तरित</item>
|
||||
<item quantity="other">%1$d समूह स्थानान्तरित</item>
|
||||
</plurals>
|
||||
<string name="cordn_migrate_exposure_title">इस यन्त्र से क्या जाता है</string>
|
||||
<string name="sno_object_title">त्रिमा वस्तु</string>
|
||||
<string name="sno_object_details">%1$d अस्र। %2$d मुख</string>
|
||||
<string name="sno_object_unreadable">इस त्रिमा वस्तु का पठन असफल। नियम %1$s</string>
|
||||
@@ -5347,6 +5371,105 @@
|
||||
<item quantity="other">%1$d अष्टकों का अमुक जिसे यह ग्राहक पढता नहीं</item>
|
||||
</plurals>
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
<string name="browser_pill_close">आवृत</string>
|
||||
<string name="browser_pill_tile_copy">योजक अनुकृति</string>
|
||||
<string name="browser_pill_tile_find">ढूंढें</string>
|
||||
<string name="browser_pill_tile_text">लेख आकार</string>
|
||||
<string name="browser_pill_tile_desktop">लेखनपीठ संगणक</string>
|
||||
<string name="browser_pill_tile_home">मुख्यपृष्ठ पर जोडें</string>
|
||||
<string name="browser_pill_tile_other">अन्य जालवीक्षक</string>
|
||||
<string name="browser_pill_tile_full">पूर्ण पटल</string>
|
||||
<string name="browser_pill_edit_address">पता सम्पादन</string>
|
||||
<string name="browser_pill_back">पीछे</string>
|
||||
<string name="browser_pill_forward">आगे</string>
|
||||
<string name="browser_pill_reload">पुनःआवहन</string>
|
||||
<string name="browser_pill_stop">आवहन रोकें</string>
|
||||
<string name="browser_pill_favorite_add">इष्टसूची में जोडें</string>
|
||||
<string name="browser_pill_favorite_remove">इष्टसूची में से हटाएँ</string>
|
||||
<string name="browser_pill_share">बाँटें</string>
|
||||
<string name="browser_pill_copy">योजक अनुकृति</string>
|
||||
<string name="browser_pill_find">पृष्ठ में ढूँढें</string>
|
||||
<string name="browser_pill_text_size">लेख आकार</string>
|
||||
<string name="browser_pill_add_home">मुख्यपृष्ठ पर जोडें</string>
|
||||
<string name="browser_pill_desktop">लेखनपीठ संगणक जालस्थान</string>
|
||||
<string name="browser_pill_other_browser">जालवीक्षक मे खोलें</string>
|
||||
<string name="browser_pill_other_browser_named">%1$s में खोलें</string>
|
||||
<string name="browser_pill_full_screen">पूर्ण पटल</string>
|
||||
<string name="browser_pill_left_site">आपने %1$s छोडा</string>
|
||||
<string name="browser_pill_back_to_app">क्रमक तक लौट जाएँ</string>
|
||||
<string name="browser_pill_text_smaller">अल्पतर आकार लेख</string>
|
||||
<string name="browser_pill_text_larger">बृहत्तर आकार लेख</string>
|
||||
<string name="browser_pill_text_reset">पुनःस्थापन</string>
|
||||
<string name="browser_pill_text_value">%1$d प्रतिशत</string>
|
||||
<string name="browser_pill_privacy">गोपनीयता</string>
|
||||
<string name="browser_pill_tor_title">बहुरहस्यावृत संचार द्वारा</string>
|
||||
<string name="browser_pill_tor_on">यह जालस्थान आपका अंकीय जालपता नहीं देख सकता</string>
|
||||
<string name="browser_pill_tor_off">यह जालस्थान आपका अंकीय जालपता देख सकता है</string>
|
||||
<string name="browser_pill_site_settings">जालस्थान स्थापना विकल्प</string>
|
||||
<string name="browser_pill_site_settings_none">कुछ भी अनुमत नहीं अब तक</string>
|
||||
<string name="browser_pill_access">इसके लिए क्या अभिगम्य है</string>
|
||||
<string name="browser_pill_access_desc">आपके कुंचिकाएँ कभी भी अमेथिस्ट से बाहर नहीं जाते</string>
|
||||
<string name="browser_pill_access_none">कोई विशेष अभिगमन अनुमति नहीं</string>
|
||||
<string name="browser_pill_access_manage">अनुमतियाँ प्रबन्धन</string>
|
||||
<string name="browser_pill_access_nsite">नोस्टरस्थान। पृथककृत पर्यावरण</string>
|
||||
<string name="browser_pill_access_napplet">नोस्टरसंलग्नक्रमक। पृथककृत पर्यावरण</string>
|
||||
<string name="browser_pill_console">कोष्ठक</string>
|
||||
<string name="browser_pill_security_https">सुरक्षित संयोजन</string>
|
||||
<string name="browser_pill_security_http">असुरक्षित</string>
|
||||
<string name="browser_pill_security_tor">बहुरहस्यावृत संचार द्वारा</string>
|
||||
<string name="browser_pill_security_sandbox">पर्यावरण पृथककृत क्रमक</string>
|
||||
<string name="browser_pill_permission_camera">चित्रग्राहक</string>
|
||||
<string name="browser_pill_permission_microphone">ध्वनिग्राहक</string>
|
||||
<string name="browser_pill_permission_location">स्थान</string>
|
||||
<string name="browser_pill_decision_ask">पूछें</string>
|
||||
<string name="browser_pill_decision_allow">अनुमत</string>
|
||||
<string name="browser_pill_decision_block">बाधित</string>
|
||||
<string name="browser_pill_permission_state">%1$s %2$s</string>
|
||||
<string name="browser_pill_decision_allowed">अनुमत</string>
|
||||
<string name="browser_pill_decision_blocked">बाधित</string>
|
||||
<string name="browser_pill_address_hint">ढूँढें अथवा पता प्रविष्ट करें</string>
|
||||
<string name="browser_pill_go">जाएँ</string>
|
||||
<string name="browser_pill_clear">रिक्त</string>
|
||||
<string name="browser_pill_paste_go">चिपकाएँ तथा जाएँ</string>
|
||||
<string name="browser_pill_fill_in">इस पता का उपयोग करें</string>
|
||||
<string name="browser_pill_find_hint">पृष्ठ में ढूँढें</string>
|
||||
<string name="browser_pill_find_count">%2$d में से %1$d</string>
|
||||
<string name="browser_pill_find_none">कोई परिणाम नहीं</string>
|
||||
<string name="browser_pill_find_previous">पूर्व परिणाम</string>
|
||||
<string name="browser_pill_find_next">अगला परिणाम</string>
|
||||
<string name="browser_pill_find_close">पृष्ठ खोज आवृत करें</string>
|
||||
<string name="browser_pill_console_all">सभी</string>
|
||||
<string name="browser_pill_console_errors">अपक्रम</string>
|
||||
<string name="browser_pill_console_warnings">चेतावनियाँ</string>
|
||||
<string name="browser_pill_console_copy">अनुकृति</string>
|
||||
<string name="browser_pill_console_clear">रिक्त</string>
|
||||
<string name="browser_pill_console_empty">कुछ भी अभिलेखित नहीं अब तक</string>
|
||||
<string name="browser_pill_perm_title">यह जालस्थान इसका उपयोग करना चाहता है</string>
|
||||
<string name="browser_pill_perm_camera_desc">देखें आपका चित्रग्राहक क्या देख रहा है</string>
|
||||
<string name="browser_pill_perm_microphone_desc">सुनें आपका ध्वनिग्राहक क्या सुन रहा है</string>
|
||||
<string name="browser_pill_perm_location_desc">जानें आप कहाँ हैं स्थूलतः</string>
|
||||
<string name="browser_pill_perm_allow">अभ्यागमन कालान्तर अनुमत</string>
|
||||
<string name="browser_pill_perm_once">केवल इस बार</string>
|
||||
<string name="browser_pill_perm_deny">अनुमति ना दें</string>
|
||||
<string name="browser_pill_dialog_says">%1$s कहता है</string>
|
||||
<string name="browser_pill_dialog_generic">यह पृष्ठ कहता है</string>
|
||||
<string name="browser_pill_dialog_answer">आपका उत्तर</string>
|
||||
<string name="browser_pill_dialog_leave_title">क्या जालस्थान छोड दें।</string>
|
||||
<string name="browser_pill_dialog_leave">निर्गमन</string>
|
||||
<string name="browser_pill_ok">ठीक</string>
|
||||
<string name="browser_pill_cancel">निरस्त</string>
|
||||
<string name="browser_pill_info_connection">संयोजन</string>
|
||||
<string name="browser_pill_info_https">संयोजन रहस्यीकृत</string>
|
||||
<string name="browser_pill_info_http">संयोजन अरहस्यीकृत</string>
|
||||
<string name="browser_pill_info_tor">टोर पर बहुरहस्यावृत संचार द्वारा</string>
|
||||
<string name="browser_pill_info_open">खुला जाल</string>
|
||||
<string name="browser_pill_info_certificate">प्रमाणपत्र</string>
|
||||
<string name="browser_pill_info_certificate_desc">निर्गत %1$s को %2$s द्वारा। मान्य %3$s तक</string>
|
||||
<string name="browser_pill_info_permissions">अनुमतियाँ</string>
|
||||
<string name="browser_pill_info_site_data">सेवाप्रसंग अभिलेख तथा जालस्थान जानकारी</string>
|
||||
<string name="browser_pill_info_site_data_desc">प्रवेशांकन तथा आद्यताएँ जो इस जालस्थान ने अभिलेखित किया इस लेखा के लिए</string>
|
||||
<string name="browser_pill_info_clear">जालस्थान जानकारी रिक्त करें</string>
|
||||
<string name="browser_pill_info_clear_confirm">क्या इस जालस्थान से निर्गमनांकन करें तथा इसकी जानकारी मिटा दें।</string>
|
||||
<string name="backup_action_block_again">पुनःबाधित करें %1$s को</string>
|
||||
<string name="backup_action_keep_count">रखें %1$s</string>
|
||||
<string name="backup_action_rejoin">पुनःजुडें %1$s</string>
|
||||
@@ -5671,4 +5794,175 @@
|
||||
<string name="backup_type_trust_providers_explainer">सेवाएँ जिनपर आप विश्वास करते है आपके लिए लोगों का सत्यापन तथा श्रेणीकरण करने के लिए।</string>
|
||||
<string name="backup_type_trusted_relays">विश्वसनीय पुनःप्रसारक सूची</string>
|
||||
<string name="backup_type_trusted_relays_explainer">पुनःप्रसारक जिनपर आप पर्याप्त विश्वास करते हैं बिना पूछे उनसे संयोजन करने के लिए।</string>
|
||||
<string name="cordn_action_delete">मिटाएँ</string>
|
||||
<string name="cordn_action_edit">सम्पादन</string>
|
||||
<string name="cordn_action_editing">आपके सन्देश का सम्पादन</string>
|
||||
<string name="cordn_action_go_to_message">सन्देश पर जाएँ</string>
|
||||
<string name="cordn_action_pin">टाँकें</string>
|
||||
<string name="cordn_action_reply">उत्तर</string>
|
||||
<string name="cordn_action_unpin">टाँका हटाएँ</string>
|
||||
<string name="cordn_admin_action_failed">वह परिवर्तन असफल।</string>
|
||||
<string name="cordn_admin_not_a_member">%1$s इस समुह में नहीं है।</string>
|
||||
<string name="cordn_admin_someone">वह व्यक्ति</string>
|
||||
<string name="cordn_backup_contents_title">अभिलेख में क्या है</string>
|
||||
<string name="cordn_backup_export">निर्यात</string>
|
||||
<string name="cordn_backup_exported">अनुकृति सुरक्षित।</string>
|
||||
<string name="cordn_backup_failed">वह कार्य असफल था। पारणवाक्याम्श तथा अभिलेख की जाँच करें।</string>
|
||||
<string name="cordn_backup_passphrase">पारणवाक्याम्श</string>
|
||||
<string name="cordn_backup_restore">पुनःस्थापन</string>
|
||||
<string name="cordn_backup_restore_confirm_title">क्या इस यन्त्र के कोर्डन समूहों का प्रतिस्थापन करें।</string>
|
||||
<string name="cordn_backup_restore_title">पुनःस्थापन</string>
|
||||
<string name="cordn_backup_restored">पुनःस्थापित।</string>
|
||||
<string name="cordn_chat_empty_title">कोई सन्देश नहीं अब तक</string>
|
||||
<string name="cordn_chat_unread_divider">नए सन्देश</string>
|
||||
<string name="cordn_chat_yesterday">एक दिन पूर्व</string>
|
||||
<string name="cordn_composer_hint">सन्देश</string>
|
||||
<string name="cordn_coordinators_add_action">जोडें</string>
|
||||
<string name="cordn_coordinators_add_failed">उस समायोजक को खोलने में असफल।</string>
|
||||
<string name="cordn_coordinators_copy_key">समायोजक के एनपुब॰ की अनुकृति</string>
|
||||
<string name="cordn_coordinators_discover_action">समायोजकों के लिए ढूँढें</string>
|
||||
<string name="cordn_coordinators_discover_add">जोडें</string>
|
||||
<string name="cordn_coordinators_discover_failed">घषणाओं को पढने में असफल</string>
|
||||
<string name="cordn_coordinators_discover_none">आपके पुनःप्रसारकों में कोई भी घषणा नहीं कर रहा।</string>
|
||||
<string name="cordn_coordinators_discover_seen">घोषित %1$s पूर्व</string>
|
||||
<string name="cordn_coordinators_discover_seen_on">पूर्व घोषित %1$s</string>
|
||||
<string name="cordn_coordinators_health_ok">उत्तर दे रहा है।</string>
|
||||
<string name="cordn_coordinators_health_retrying">एक आह्वान असफल। पुनःप्रयासमध्य।</string>
|
||||
<string name="cordn_coordinators_health_unknown">उससे कुछ पूछा नहीं गया अब तक।</string>
|
||||
<string name="cordn_coordinators_identify">पूछें कि कौन हैं</string>
|
||||
<string name="cordn_coordinators_key">समायोजक कुंचिका</string>
|
||||
<string name="cordn_coordinators_label">उसके लिए एक नाम। (आपका। विककल्पात्मक)</string>
|
||||
<string name="cordn_coordinators_more">अधिक क्रियाएँ</string>
|
||||
<string name="cordn_coordinators_none">कोई समायोजक नहीं अब तक।</string>
|
||||
<string name="cordn_coordinators_purge">मिटाएँ</string>
|
||||
<string name="cordn_coordinators_purge_title">क्या इस समायोजक को मिटा दें।</string>
|
||||
<string name="cordn_coordinators_relays">%1$s</string>
|
||||
<string name="cordn_coordinators_relays_label">उत्तर सक्रिय</string>
|
||||
<string name="cordn_coordinators_relays_more">%1$s स %2$d अधिक</string>
|
||||
<string name="cordn_coordinators_remove">हटाएँ</string>
|
||||
<string name="cordn_coordinators_rename">पुनःनामकरण</string>
|
||||
<string name="cordn_coordinators_server">कहता है कि यह है। %1$s</string>
|
||||
<string name="cordn_coordinators_server_silent">उत्तर दिया। पर कुछ भी नामित नहीं।</string>
|
||||
<string name="cordn_coordinators_show_all">सब कुछ दिखाएँ %1$d</string>
|
||||
<string name="cordn_coordinators_show_fewer">अल्पतर संख्या दिखाएँ</string>
|
||||
<string name="cordn_create_action">समूह बनाएँ</string>
|
||||
<plurals name="cordn_create_action_invite">
|
||||
<item quantity="one">बनाएँ तथा %1$d व्यक्ति को आमन्त्रण दें</item>
|
||||
<item quantity="other">बनाएँ तथा %1$d व्यक्तियों को आमन्त्रण दें</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_add_member">किसी को जोडें</string>
|
||||
<string name="cordn_create_admin">प्रशासक</string>
|
||||
<string name="cordn_create_admin_only_me">केवल मैं इस समूह का प्रबन्धक</string>
|
||||
<string name="cordn_create_coordinator">समायोजक</string>
|
||||
<string name="cordn_create_coordinator_change">परिवर्तन</string>
|
||||
<string name="cordn_create_coordinator_discover">समायोजक ढूँढें</string>
|
||||
<string name="cordn_create_coordinator_hide">हो गया</string>
|
||||
<string name="cordn_create_coordinator_new">एक अन्य समायोजक</string>
|
||||
<string name="cordn_create_coordinator_pubkey">समायोजक ख्याप्य कुंचिका। षोडशांक अथवा एनपुब॰</string>
|
||||
<string name="cordn_create_coordinator_relays">पुनःप्रसारक जिन पर यह उत्तर देता है। एक प्रति पंक्ति</string>
|
||||
<string name="cordn_create_description">विवरण (विकल्पात्मक)</string>
|
||||
<string name="cordn_create_egalitarian">सभी जोड सकते हैं तथा हटा सकते हैं</string>
|
||||
<string name="cordn_create_failed">समूह बनाने में असफल।</string>
|
||||
<string name="cordn_create_name">समूह नाम</string>
|
||||
<string name="cordn_create_no_coordinator">कोई समायोजक चयनित नहीं</string>
|
||||
<string name="cordn_create_outcome_failed">समायोजक ने आमन्त्रण अस्वीकार किया</string>
|
||||
<string name="cordn_create_outcome_link">योजक भेजें</string>
|
||||
<string name="cordn_create_outcome_open">चर्चा खोलें</string>
|
||||
<string name="cordn_create_outcome_skipped">कोई कुंचिका नहीं यहाँ। इसलिए कोई स्वागत सन्देश छोडा नहीं जा सका</string>
|
||||
<string name="cordn_create_outcome_title">समूह है</string>
|
||||
<string name="cordn_create_outcome_waiting">उनकी प्रतीक्षा में</string>
|
||||
<string name="cordn_create_people_done">हो गया</string>
|
||||
<string name="cordn_create_people_none">कोई नहीं अब तक। दबाएँ लोगों को जोडने के लिए</string>
|
||||
<plurals name="cordn_create_reach_count">
|
||||
<item quantity="one">अभिगम्य %1$d समायोजक पर</item>
|
||||
<item quantity="other">अभिगम्य %1$d समायोजकों पर</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_reach_none">कोई कुंचिका नहीं आपके द्वारा उपयुक्त किसी समायोजक के पास</string>
|
||||
<string name="cordn_create_reach_unknown">अब तक जाँच नहीं की</string>
|
||||
<string name="cordn_create_step_admins">कौन जोड सकता है तथा हटा सकता है</string>
|
||||
<string name="cordn_create_step_name">नामकरण</string>
|
||||
<string name="cordn_create_step_people">कौन इसमें हैं</string>
|
||||
<string name="cordn_create_step_where">कहाँ उसका आवास</string>
|
||||
<string name="cordn_create_title">नया कोर्डन समूह</string>
|
||||
<string name="cordn_create_you">आप। सर्वदा प्रशासक</string>
|
||||
<string name="cordn_delete_confirm_title">सन्देश लौटाएँ</string>
|
||||
<string name="cordn_delivery_accepted">समायोजक द्वारा स्वीकृत</string>
|
||||
<string name="cordn_exposure_close">समझ गया</string>
|
||||
<string name="cordn_exposure_open">यह समायोजक क्या देख सकता है</string>
|
||||
<string name="cordn_group_info">समूह जानकारी</string>
|
||||
<plurals name="cordn_groups_count">
|
||||
<item quantity="one">%1$d समूह</item>
|
||||
<item quantity="other">%1$d समूह</item>
|
||||
</plurals>
|
||||
<string name="cordn_groups_manage">समायोजक</string>
|
||||
<string name="cordn_groups_none">कोई कोर्डन समूह नहीं अब तक</string>
|
||||
<string name="cordn_groups_start">एक का आरम्भ करें</string>
|
||||
<string name="cordn_info_add_member">किसी को जोडें</string>
|
||||
<string name="cordn_info_add_member_none">उस नाम से कोई प्राप्त नहीं।</string>
|
||||
<string name="cordn_info_add_member_placeholder">नाम अथवा एनपुब॰ अथवा नाम@जालक्षेत्र</string>
|
||||
<string name="cordn_info_admin_badge">प्रशासक</string>
|
||||
<string name="cordn_info_coordinator">समायोजक</string>
|
||||
<string name="cordn_info_coordinator_key">समायोजक कुंचिका</string>
|
||||
<string name="cordn_info_coordinator_nprofile">समायोजक योजक</string>
|
||||
<string name="cordn_info_copy_nprofile">समायोजक एनप्रोफैल॰ की अनुकृति</string>
|
||||
<string name="cordn_info_edit_details">विवरण सम्पादन</string>
|
||||
<string name="cordn_info_epoch">युग</string>
|
||||
<string name="cordn_info_gid">समूह परिचायक</string>
|
||||
<string name="cordn_info_has_key_package">इस समायोजक पर जोडा जा सकता है</string>
|
||||
<string name="cordn_info_members">सदस्य</string>
|
||||
<string name="cordn_info_remove_confirm_title">क्या समूह से हटाएँ।</string>
|
||||
<string name="cordn_info_remove_member">हटाएँ</string>
|
||||
<string name="cordn_info_save">अभिलेखन</string>
|
||||
<string name="cordn_info_technical">तन्त्रज्ञानात्मक विवरण</string>
|
||||
<string name="cordn_invitations_accept">जुडें</string>
|
||||
<string name="cordn_invitations_decline">अस्वीकार</string>
|
||||
<string name="cordn_invitations_load_failed">आमन्त्रणों को पढने में असफल।</string>
|
||||
<string name="cordn_invitations_members_more">स %1$d अधिक</string>
|
||||
<string name="cordn_invitations_none">कोई आमन्त्रण प्रतीक्षा नहीं कर रहा।</string>
|
||||
<string name="cordn_invitations_refresh">पुनःजाचें</string>
|
||||
<string name="cordn_invitations_skipped">एक आमन्त्रण छोडा गया एक अन्य यन्त्र के लिए</string>
|
||||
<string name="cordn_invitations_title">कोर्डन आमन्त्रण</string>
|
||||
<string name="cordn_invitations_unreachable">%1$s ने उत्तर नहीं दिया</string>
|
||||
<string name="cordn_invitations_via">%1$s द्वारा</string>
|
||||
<string name="cordn_keypackages_failed">कुंचिका पोटलियाँ पढने में असफल।</string>
|
||||
<string name="cordn_keypackages_publish">एक का प्रकाशन</string>
|
||||
<string name="cordn_keypackages_publish_last_resort">अन्तिम उपाय का प्रकाशन</string>
|
||||
<string name="cordn_keypackages_withdraw_all">सब लौटा लें</string>
|
||||
<string name="cordn_keypackages_withdraw_orphans">उनको लौटा लें</string>
|
||||
<string name="cordn_link_request">इस समूह से जुडने का अनुरोध करें</string>
|
||||
<string name="cordn_link_request_failed">जुडने का अनुरोध असफल।</string>
|
||||
<string name="cordn_link_scan">परखें</string>
|
||||
<string name="cordn_media_download_failed">उस अभिलेख को खोलने में असफल।</string>
|
||||
<string name="cordn_media_unreadable">वह अभिलेख पठनशक्य नहीं।</string>
|
||||
<string name="cordn_media_upload_failed">उस अभिलेख को भेजने में असफल।</string>
|
||||
<plurals name="cordn_member_count">
|
||||
<item quantity="one">%1$d सदस्य</item>
|
||||
<item quantity="other">%1$d सदस्य</item>
|
||||
</plurals>
|
||||
<string name="cordn_message_deleted">सन्देश मिटाया गया</string>
|
||||
<string name="cordn_message_details_coordinator">समायोजक</string>
|
||||
<string name="cordn_message_details_cursor">धावक</string>
|
||||
<string name="cordn_message_details_sent_at">भेजा गया</string>
|
||||
<string name="cordn_message_details_title">सन्देश विवरण</string>
|
||||
<string name="cordn_message_edited">सम्पादित</string>
|
||||
<string name="cordn_pinned_by">टाँका गया %1$s द्वारा</string>
|
||||
<string name="cordn_pinned_next">अगला टाँका गया सन्देश</string>
|
||||
<string name="cordn_pinned_previous">पिछला टाँका गया सन्देश</string>
|
||||
<string name="cordn_pinned_show_all">सभी टाँके गए सन्देशों को दिखाएँ</string>
|
||||
<string name="cordn_pinned_title">टाँके गए सन्देश</string>
|
||||
<string name="cordn_reactions_title">प्रतिक्रियाएँ</string>
|
||||
<string name="cordn_requests_accept">जोडें</string>
|
||||
<string name="cordn_requests_check">अनुरोधों के लिए जाँचें</string>
|
||||
<string name="cordn_requests_decline">हटाएँ</string>
|
||||
<string name="cordn_requests_failed">अनुरोधों को पढने में असफल।</string>
|
||||
<string name="cordn_requests_none">जुडने की प्रतीक्षा में कोई नहीं।</string>
|
||||
<string name="cordn_requests_title">जुडने के अनुरोध</string>
|
||||
<string name="cordn_send">भेजें</string>
|
||||
<string name="cordn_send_failed">भेजने में असफल।</string>
|
||||
<string name="cordn_share_copied">अनुकृत</string>
|
||||
<string name="cordn_share_copy">योजक अनुकृति</string>
|
||||
<string name="cordn_share_title">इस समूह को बाँटें</string>
|
||||
<string name="cordn_voice_play">ध्वनि टीका चलाएँ</string>
|
||||
<string name="cordn_voice_record">ध्वनि टीका का अभिलेखन करें</string>
|
||||
<string name="cordn_voice_stop">रोकें तथा भेजें</string>
|
||||
</resources>
|
||||
|
||||
@@ -545,7 +545,6 @@
|
||||
<string name="relays"> Átjátszó</string>
|
||||
<string name="website">Weboldal</string>
|
||||
<string name="lightning_address">Lightning-cím</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Az Nsec azonosítót (az Ön „jelszavát”) a vágólapra másolja biztonsági mentés céljából</string>
|
||||
<string name="send_a_direct_message">Közvetlen üzenet küldése</string>
|
||||
<string name="edits_the_user_s_metadata">Felhasználó metaadatainak szerkesztése</string>
|
||||
<string name="unblock">Letiltás megszüntetése</string>
|
||||
@@ -654,14 +653,11 @@
|
||||
<string name="mark_all_known_as_read">Az összes ismert megjelölése olvasottként</string>
|
||||
<string name="mark_all_new_as_read">Az összes új üzenet megjelölése olvasottként</string>
|
||||
<string name="mark_all_as_read">Összes megjelölése olvasottként</string>
|
||||
<string name="account_backup_tips2_md">## 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ókja helyrehozása érdekében, a titkos kulcsáról **mindig** készítsen biztonsági másolatot. Javasoljuk egy jelszókezelő használatát.</string>
|
||||
<string name="account_backup_tips3_md">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 helyrehozni a kulcsát.</string>
|
||||
<string name="backup_keys_nudge_title">Biztonsági mentés készítése a kulcsokról</string>
|
||||
<string name="backup_keys_nudge_body">A titkos kulcs megadása az egyetlen módja a fiók elérésének. Ha elveszíti, akkor soha nem tudja helyrehozni. Mentse el biztonságos helyre most.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Biztonsági mentés most</string>
|
||||
<string name="backup_keys_nudge_already_saved">Elmentettem a kulcsokat</string>
|
||||
<string name="backup_keys_nudge_dismiss">Eltüntetés</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Saját titkos kulcs titkosítása és másolása</string>
|
||||
<string name="badge_award_image_for">Kitűző %1$s számára</string>
|
||||
<string name="badge_award_image">Kitűző képe</string>
|
||||
<string name="new_badge_award_notif">Ön egy új kitűzőt kapott</string>
|
||||
@@ -3577,7 +3573,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Bejegyzés szövege a vágólapra másolva</string>
|
||||
<string name="copied_to_clipboard">Vágólapra másolva</string>
|
||||
<string name="copied_user_id_to_clipboard">A szerző @npub-ja a vágólapra másolva</string>
|
||||
<string name="copy_my_secret_key">Saját titkos kulcs másolása</string>
|
||||
<string name="copy_to_clipboard">Másolás a vágólapra</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Nem sikerült az LN-webcímet a(z) „%1$s” Lightning-címről összeállítani. Ellenőrizze a felhasználó beállításait</string>
|
||||
<string name="could_not_check_downloaded_file">Nem lehetett ellenőrizni a letöltött fájlt a feltöltés után: %1$s</string>
|
||||
@@ -5040,10 +5035,8 @@
|
||||
<string name="share_hls_video">HLS-feltöltés</string>
|
||||
<string name="share_or_save">Megosztás vagy mentés</string>
|
||||
<string name="shorts">Rövidek</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Jelszóval védett privát kulcs megjelenítése QR-kódként</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Közvetlen és csoportos üzenetek megjelenítése az Értesítések lapon. Kapcsolja ki, ha az üzeneteket csak az Üzenetek lapon szeretné látni.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Üzenetek megjelenítése</string>
|
||||
<string name="show_private_key_qr_code">Privát kulcs megjelenítése QR-kódként</string>
|
||||
<string name="sign_request_rejected2">Aláírási kérés elutasítva</string>
|
||||
<string name="sign_request_rejected_description">Győződjön meg arról, hogy ezt a tranzakciót az aláíró-alkalmazás hitelesítette-e</string>
|
||||
<string name="signer_illegal_state_exception_description">A külső aláíró a kéréstől eltérő, szokatlan választ küldött. Lehet, hogy hiba lépett fel az Amethystben vagy az aláíró alkalmazásban.</string>
|
||||
|
||||
@@ -211,7 +211,6 @@
|
||||
<string name="relays"> Relai</string>
|
||||
<string name="website">Situs web</string>
|
||||
<string name="lightning_address">Alamat Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Salin ID Nsec (kata sandi Anda) ke papan klip untuk cadangan</string>
|
||||
<string name="send_a_direct_message">Kirim Pesan Langsung</string>
|
||||
<string name="edits_the_user_s_metadata">Ubah metadata pengguna</string>
|
||||
<string name="unblock">Buka blokir</string>
|
||||
@@ -266,9 +265,6 @@
|
||||
<string name="mark_all_known_as_read">Tandai semua yang dikenal sebagai telah dibaca</string>
|
||||
<string name="mark_all_new_as_read">Tandai semua yang baru sebagai telah dibaca</string>
|
||||
<string name="mark_all_as_read">Tandai semua sebagai telah dibaca</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Enkripsi dan salin kunci rahasia saya</string>
|
||||
<string name="badge_award_image_for">Gambar penghargaan lencana untuk %1$s</string>
|
||||
<string name="badge_award_image">"Gambar penghargaan lencana</string>
|
||||
<string name="new_badge_award_notif">Anda menerima penghargaan lencana baru</string>
|
||||
@@ -1972,7 +1968,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Teks disalin ke papan klip</string>
|
||||
<string name="copied_to_clipboard">Disalin ke clipboard</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub pemilik telah disalin ke papan klip</string>
|
||||
<string name="copy_my_secret_key">Salin kunci rahasia saya</string>
|
||||
<string name="copy_to_clipboard">Salin ke clipboard</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Tidak dapat merakit LNUrl dari Alamat Lightning "%1$s". Periksa pengaturan pengguna</string>
|
||||
<string name="could_not_check_downloaded_file">Tidak dapat memeriksa file yang diunduh setelah diunggah: %1$s</string>
|
||||
@@ -2721,10 +2716,8 @@
|
||||
<string name="share_as_image_url">Bagikan sebagai URL Gambar</string>
|
||||
<string name="share_hls_video">Unggah HLS</string>
|
||||
<string name="share_or_save">Bagikan atau Simpan</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Tampilkan kode QR kunci privat terenkripsi</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Sertakan pesan langsung dan grup pada tab Notifikasi. Matikan untuk menyimpan pesan hanya di tab Pesan.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Tampilkan Pesan</string>
|
||||
<string name="show_private_key_qr_code">Tampilkan kode QR kunci privat</string>
|
||||
<string name="sign_request_rejected2">Permintaan tanda tangan ditolak</string>
|
||||
<string name="sign_request_rejected_description">Pastikan aplikasi penandatangan telah mengizinkan transaksi ini</string>
|
||||
<string name="signer_illegal_state_exception_description">Penanda tangan eksternal mengembalikan payload yang tidak sesuai dengan permintaan. Mungkin ada bug di Amethyst atau di penanda tangan.</string>
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
<string name="relays"> Relai</string>
|
||||
<string name="website">Situs Web</string>
|
||||
<string name="lightning_address">Alamat Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Salin Nsec ID (kata sandi anda) ke papan klip sebagai cadangan</string>
|
||||
<string name="send_a_direct_message">Kirim Pesan Langsung</string>
|
||||
<string name="edits_the_user_s_metadata">Ubah Metadata Pengguna</string>
|
||||
<string name="unblock">Batalkan blokir</string>
|
||||
@@ -257,9 +256,6 @@
|
||||
<string name="mark_all_known_as_read">Tandai semua yg dikenal telah dibaca</string>
|
||||
<string name="mark_all_new_as_read">Tandai pesan baru telah dibaca</string>
|
||||
<string name="mark_all_as_read">Tandai semua telah dibaca</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Enkripsi dan salin kunci rahasia saya</string>
|
||||
<string name="badge_award_image_for">Gambar penghargaan lencana untuk %1$s</string>
|
||||
<string name="badge_award_image">"Gambar penghargaan lencana</string>
|
||||
<string name="new_badge_award_notif">Anda Menerima Penghargaan Lencana baru</string>
|
||||
@@ -2028,7 +2024,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Teks catatan disalin ke papan klip</string>
|
||||
<string name="copied_to_clipboard">Disalin ke clipboard</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub Penulis disalin ke papan klip</string>
|
||||
<string name="copy_my_secret_key">Salin kunci rahasia saya</string>
|
||||
<string name="copy_to_clipboard">Salin ke clipboard</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Tidak dapat merakit LNUrl dari Alamat Lightning "%1$s". Periksa pengaturan pengguna</string>
|
||||
<string name="could_not_check_downloaded_file">Tidak dapat memeriksa file yang diunduh setelah diunggah: %1$s</string>
|
||||
@@ -2827,10 +2822,8 @@
|
||||
<string name="share_hls_video">Unggah HLS</string>
|
||||
<string name="share_or_save">Bagikan atau Simpan</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Tampilkan kode QR kunci privat terenkripsi</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Sertakan pesan langsung dan grup pada tab Notifikasi. Matikan untuk menyimpan pesan hanya di tab Pesan.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Tampilkan Pesan</string>
|
||||
<string name="show_private_key_qr_code">Tampilkan kode QR kunci privat</string>
|
||||
<string name="sign_request_rejected2">Permintaan tanda tangan ditolak</string>
|
||||
<string name="sign_request_rejected_description">Pastikan aplikasi penandatangan telah mengizinkan transaksi ini</string>
|
||||
<string name="signer_illegal_state_exception_description">Penanda tangan eksternal mengembalikan payload yang tidak sesuai dengan permintaan. Mungkin ada bug di Amethyst atau di penanda tangan.</string>
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
<string name="relays"> Relè</string>
|
||||
<string name="website">Sito web</string>
|
||||
<string name="lightning_address">Indirizzo Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copia l'ID Nsec (la password) negli appunti per il backup</string>
|
||||
<string name="send_a_direct_message">Invia un messaggio diretto</string>
|
||||
<string name="edits_the_user_s_metadata">Modifica i metadati dell'utente</string>
|
||||
<string name="unblock">Sblocca</string>
|
||||
@@ -266,9 +265,6 @@
|
||||
<string name="mark_all_known_as_read">Segna tutti i conosciuti come letti</string>
|
||||
<string name="mark_all_new_as_read">Segna tutti i nuovi come letti</string>
|
||||
<string name="mark_all_as_read">Segna tutti come letti</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Cifra e copia la mia chiave segreta</string>
|
||||
<string name="badge_award_image_for">Immagine premio badge per %1$s</string>
|
||||
<string name="badge_award_image">"Immagine del premio badge</string>
|
||||
<string name="new_badge_award_notif">Hai ricevuto un nuovo premio Badge</string>
|
||||
@@ -1969,7 +1965,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Testo della nota copiato negli appunti</string>
|
||||
<string name="copied_to_clipboard">Copiato negli appunti</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub dell'autore copiata negli appunti</string>
|
||||
<string name="copy_my_secret_key">Copia la mia chiave segreta</string>
|
||||
<string name="copy_to_clipboard">Copia negli appunti</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Impossibile assemblare LNUrl dall'indirizzo Lightning "%1$s". Controlla la configurazione dell'utente</string>
|
||||
<string name="could_not_check_downloaded_file">Impossibile verificare il file scaricato dopo il caricamento: %1$s</string>
|
||||
@@ -2754,10 +2749,8 @@
|
||||
<string name="share_as_image_url">Condividi come URL immagine</string>
|
||||
<string name="share_hls_video">Caricamento HLS</string>
|
||||
<string name="share_or_save">Condividi o salva</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostra QR code della chiave privata cifrata</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Includi messaggi diretti e di gruppo nella scheda Notifiche. Disattiva per tenere i messaggi solo nella scheda Messaggi.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostra messaggi</string>
|
||||
<string name="show_private_key_qr_code">Mostra QR code della chiave privata</string>
|
||||
<string name="sign_request_rejected2">Richiesta di firma rifiutata</string>
|
||||
<string name="sign_request_rejected_description">Assicurati che l'applicazione signer abbia autorizzato questa transazione</string>
|
||||
<string name="signer_illegal_state_exception_description">Il firmatario esterno ha restituito un payload inatteso per la richiesta. Potrebbe esserci un bug in Amethyst o nell'app firmatario.</string>
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
<string name="relays"> リレー</string>
|
||||
<string name="website">ウェブサイト</string>
|
||||
<string name="lightning_address">Lightningアドレス</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">バックアップ用に nsec ID (パスワード) をクリップボードにコピー</string>
|
||||
<string name="send_a_direct_message">ダイレクトメッセージを送信</string>
|
||||
<string name="edits_the_user_s_metadata">ユーザのメタデータを編集</string>
|
||||
<string name="unblock">ブロック解除</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">すべての「知り合い」を既読にする</string>
|
||||
<string name="mark_all_new_as_read">すべての「新規リクエスト」を既読にする</string>
|
||||
<string name="mark_all_as_read">すべて既読にする</string>
|
||||
<string name="account_backup_tips2_md">## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。</string>
|
||||
<string name="account_backup_tips3_md">さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">秘密鍵を暗号化してコピー</string>
|
||||
<string name="badge_award_image_for">%1$sのバッジ授与画像</string>
|
||||
<string name="badge_award_image">バッジ授与の画像</string>
|
||||
<string name="new_badge_award_notif">新しいバッジが授与されました</string>
|
||||
@@ -1999,7 +1995,6 @@
|
||||
<string name="copied_note_text_to_clipboard">テキストがクリップボードにコピーされました</string>
|
||||
<string name="copied_to_clipboard">クリップボードにコピーしました</string>
|
||||
<string name="copied_user_id_to_clipboard">@npubをクリップボードにコピーしました</string>
|
||||
<string name="copy_my_secret_key">秘密鍵をコピー</string>
|
||||
<string name="copy_to_clipboard">クリップボードにコピー</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning アドレス「%1$s」から LNUrl を組み立てられませんでした。ユーザーの設定を確認してください</string>
|
||||
<string name="could_not_check_downloaded_file">アップロード後にダウンロードしたファイルを確認できませんでした:%1$s</string>
|
||||
@@ -2774,10 +2769,8 @@
|
||||
<string name="share_hls_video">HLS アップロード</string>
|
||||
<string name="share_or_save">共有または保存</string>
|
||||
<string name="shorts">ショート</string>
|
||||
<string name="show_encrypted_private_key_qr_code">暗号化された秘密鍵の QR コードを表示</string>
|
||||
<string name="show_messages_in_notifications_setting_description">通知タブにダイレクト・グループメッセージを含めます。オフにするとメッセージはメッセージタブのみに表示されます。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">メッセージを表示</string>
|
||||
<string name="show_private_key_qr_code">秘密鍵の QR コードを表示</string>
|
||||
<string name="sign_request_rejected2">署名リクエストが拒否されました</string>
|
||||
<string name="sign_request_rejected_description">署名アプリがこのトランザクションを承認していることを確認してください</string>
|
||||
<string name="signer_illegal_state_exception_description">外部署名アプリがリクエストに対して予期しないペイロードを返しました。Amethyst または署名アプリにバグがある可能性があります。</string>
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
<string name="relays"> リレー</string>
|
||||
<string name="website">ウェブサイト</string>
|
||||
<string name="lightning_address">Lightningアドレス</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">バックアップ用に nsec ID (パスワード) をクリップボードにコピー</string>
|
||||
<string name="send_a_direct_message">ダイレクトメッセージを送信</string>
|
||||
<string name="edits_the_user_s_metadata">ユーザのメタデータを編集</string>
|
||||
<string name="unblock">ブロック解除</string>
|
||||
@@ -257,9 +256,6 @@
|
||||
<string name="mark_all_known_as_read">すべての「知り合い」を既読にする</string>
|
||||
<string name="mark_all_new_as_read">すべての「新規リクエスト」を既読にする</string>
|
||||
<string name="mark_all_as_read">すべて既読にする</string>
|
||||
<string name="account_backup_tips2_md">## 鍵のバックアップとセキュリティのヒント \n\nアカウントは秘密鍵によって保護されています。この鍵は **nsec1** で始まる長い文字列です。この秘密鍵にアクセスできる人は誰でも、あなたの名前でポストしたり、プロフィールを変更したりできます。 \n\n- 信頼していないウェブサイトやアプリに秘密鍵を **入力しないでください**。 \n- Amethyst の開発者が秘密鍵を **求めることは絶対にありません**。 \n- アカウントの復元のために、秘密鍵の安全なバックアップを **必ず** 保管してください。パスワードマネージャーの使用をお勧めします。</string>
|
||||
<string name="account_backup_tips3_md">さらにセキュリティを高めるために、鍵をパスワードで暗号化することができます。この鍵は **ncryptsec1** で始まり、パスワードなしでは使用できません。 \n\nパスワードを忘れると、鍵を復元できなくなります。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">秘密鍵を暗号化してコピー</string>
|
||||
<string name="badge_award_image_for">%1$sのバッジ授与画像</string>
|
||||
<string name="badge_award_image">バッジ授与の画像</string>
|
||||
<string name="new_badge_award_notif">新しいバッジが授与されました</string>
|
||||
@@ -2028,7 +2024,6 @@
|
||||
<string name="copied_note_text_to_clipboard">テキストがクリップボードにコピーされました</string>
|
||||
<string name="copied_to_clipboard">クリップボードにコピーしました</string>
|
||||
<string name="copied_user_id_to_clipboard">@npubをクリップボードにコピーしました</string>
|
||||
<string name="copy_my_secret_key">秘密鍵をコピー</string>
|
||||
<string name="copy_to_clipboard">クリップボードにコピー</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning アドレス「%1$s」から LNUrl を組み立てられませんでした。ユーザーの設定を確認してください</string>
|
||||
<string name="could_not_check_downloaded_file">アップロード後にダウンロードしたファイルを確認できませんでした:%1$s</string>
|
||||
@@ -2827,10 +2822,8 @@
|
||||
<string name="share_hls_video">HLS アップロード</string>
|
||||
<string name="share_or_save">共有または保存</string>
|
||||
<string name="shorts">ショート</string>
|
||||
<string name="show_encrypted_private_key_qr_code">暗号化された秘密鍵の QR コードを表示</string>
|
||||
<string name="show_messages_in_notifications_setting_description">通知タブにダイレクト・グループメッセージを含めます。オフにするとメッセージはメッセージタブのみに表示されます。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">メッセージを表示</string>
|
||||
<string name="show_private_key_qr_code">秘密鍵の QR コードを表示</string>
|
||||
<string name="sign_request_rejected2">署名リクエストが拒否されました</string>
|
||||
<string name="sign_request_rejected_description">署名アプリがこのトランザクションを承認していることを確認してください</string>
|
||||
<string name="signer_illegal_state_exception_description">外部署名アプリがリクエストに対して予期しないペイロードを返しました。Amethyst または署名アプリにバグがある可能性があります。</string>
|
||||
|
||||
@@ -211,7 +211,6 @@
|
||||
<string name="relays"> relay</string>
|
||||
<string name="website">웹사이트</string>
|
||||
<string name="lightning_address">Lightning 주소</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Nsec ID(비밀번호)를 백업을 위해 클립보드에 복사합니다</string>
|
||||
<string name="send_a_direct_message">다이렉트 메시지 보내기</string>
|
||||
<string name="edits_the_user_s_metadata">사용자 메타데이터 편집</string>
|
||||
<string name="unblock">차단 해제</string>
|
||||
@@ -266,9 +265,6 @@
|
||||
<string name="mark_all_known_as_read">알려진 항목 모두 읽음 표시</string>
|
||||
<string name="mark_all_new_as_read">새 항목 모두 읽음 표시</string>
|
||||
<string name="mark_all_as_read">모두 읽음 표시</string>
|
||||
<string name="account_backup_tips2_md">## 키 백업 및 보안 팁 \n\n계정은 비밀 키로 보호됩니다. 키는 **nsec1**로 시작하는 긴 문자열입니다. 이 비밀 키에 접근할 수 있는 누구든 게시물 작성 및 신원 변경이 가능합니다. \n\n- 신뢰하지 않는 웹사이트나 소프트웨어에 비밀 키를 **입력하지** 마세요. \n- Amethyst 개발자는 **절대** 비밀 키를 요청하지 않습니다. \n- 계정 복구를 위해 비밀 키를 안전하게 백업해 **두세요**. 비밀번호 관리자 사용을 권장합니다.</string>
|
||||
<string name="account_backup_tips3_md">추가 보안을 위해 비밀번호로 키를 암호화할 수 있습니다. 이 키는 **ncryptsec1**로 시작하며 비밀번호 없이는 사용할 수 없습니다. \n\n비밀번호를 분실하면 키를 복구할 수 없습니다.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">내 비밀 키 암호화 및 복사</string>
|
||||
<string name="badge_award_image_for">%1$s의 배지 수상 이미지</string>
|
||||
<string name="badge_award_image">"배지 수상 이미지</string>
|
||||
<string name="new_badge_award_notif">새 배지를 수여받았습니다</string>
|
||||
@@ -1988,7 +1984,6 @@
|
||||
<string name="copied_note_text_to_clipboard">노트 텍스트가 클립보드에 복사되었습니다</string>
|
||||
<string name="copied_to_clipboard">클립보드에 복사됨</string>
|
||||
<string name="copied_user_id_to_clipboard">작성자의 @npub가 클립보드에 복사되었습니다</string>
|
||||
<string name="copy_my_secret_key">내 비밀 키 복사</string>
|
||||
<string name="copy_to_clipboard">클립보드에 복사</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning 주소 "%1$s"에서 LNUrl을 구성할 수 없습니다. 사용자 설정을 확인하세요</string>
|
||||
<string name="could_not_check_downloaded_file">업로드 후 다운로드된 파일을 확인할 수 없습니다: %1$s</string>
|
||||
@@ -2759,10 +2754,8 @@
|
||||
<string name="share_as_image_url">이미지 URL로 공유</string>
|
||||
<string name="share_hls_video">HLS 업로드</string>
|
||||
<string name="share_or_save">공유 또는 저장</string>
|
||||
<string name="show_encrypted_private_key_qr_code">암호화된 개인 키 QR 코드 표시</string>
|
||||
<string name="show_messages_in_notifications_setting_description">알림 탭에 다이렉트 및 그룹 메시지를 포함합니다. 메시지를 메시지 탭에만 표시하려면 끄세요.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">메시지 표시</string>
|
||||
<string name="show_private_key_qr_code">개인 키 QR 코드 표시</string>
|
||||
<string name="sign_request_rejected2">서명 요청이 거부됨</string>
|
||||
<string name="sign_request_rejected_description">서명 앱이 이 트랜잭션을 승인했는지 확인하세요</string>
|
||||
<string name="signer_illegal_state_exception_description">외부 서명 앱이 요청과 맞지 않는 응답을 반환했습니다. Amethyst 또는 서명 앱에 버그가 있을 수 있습니다.</string>
|
||||
|
||||
@@ -220,7 +220,6 @@
|
||||
<string name="relays"> Relay</string>
|
||||
<string name="website">Vietne</string>
|
||||
<string name="lightning_address">Lightning adrese</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopē Nsec ID (jūsu paroli) starpliktuvē dublēšanai</string>
|
||||
<string name="send_a_direct_message">Sūtīt tiešo ziņojumu</string>
|
||||
<string name="edits_the_user_s_metadata">Rediģē lietotāja metadatus</string>
|
||||
<string name="unblock">Atbloķēt</string>
|
||||
@@ -277,11 +276,8 @@
|
||||
<string name="mark_all_known_as_read">Atzīmēt visu zināmo kā lasītu</string>
|
||||
<string name="mark_all_new_as_read">Atzīmēt visu jauno kā lasītu</string>
|
||||
<string name="mark_all_as_read">Atzīmēt visu kā lasītu</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_already_saved">Esiet tās saglabājuši</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Šifrēt un kopēt manu slepeno atslēgu</string>
|
||||
<string name="badge_award_image_for">Žetona piešķiršanas attēls par %1$s</string>
|
||||
<string name="badge_award_image">"Žetona piešķiršanas attēls</string>
|
||||
<string name="new_badge_award_notif">Jūs saņēmāt jaunu žetonu</string>
|
||||
@@ -2020,7 +2016,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Piezīmes teksts nokopēts starpliktuvē</string>
|
||||
<string name="copied_to_clipboard">Nokopēts starpliktuvē</string>
|
||||
<string name="copied_user_id_to_clipboard">Autora @npub nokopēts starpliktuvē</string>
|
||||
<string name="copy_my_secret_key">Kopēt manu slepeno atslēgu</string>
|
||||
<string name="copy_to_clipboard">Kopēt starpliktuvē</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Nevarēja izveidot LNUrl no Lightning adreses "%1$s". Pārbaudiet lietotāja iestatījumus</string>
|
||||
<string name="could_not_check_downloaded_file">Nevarēja pārbaudīt lejupielādēto failu pēc augšupielādes: %1$s</string>
|
||||
@@ -2842,10 +2837,8 @@
|
||||
<string name="share_hls_video">HLS augšupielāde</string>
|
||||
<string name="share_or_save">Kopīgot vai saglabāt</string>
|
||||
<string name="shorts">Šorti</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Rādīt šifrētās privātās atslēgas QR kodu</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Iekļaut tiešās un grupas ziņas paziņojumu cilnē. Izslēdziet, lai ziņas tiktu rādītas tikai ziņojumu cilnē.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Rādīt ziņas</string>
|
||||
<string name="show_private_key_qr_code">Rādīt privātās atslēgas QR kodu</string>
|
||||
<string name="sign_request_rejected2">Parakstīšanas pieprasījums noraidīts</string>
|
||||
<string name="sign_request_rejected_description">Pārliecinieties, ka parakstītāja lietotne ir autorizējusi šo darījumu</string>
|
||||
<string name="signer_illegal_state_exception_description">Ārējais parakstītājs atgrieza neparastu atbildi uz pieprasījumu. Iespējams, ir kļūda Amethyst vai parakstītājā.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays">Relays</string>
|
||||
<string name="website">Website</string>
|
||||
<string name="lightning_address">Lightning-adres</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopieert je privésleutel (nsec) naar het klembord voor back-up</string>
|
||||
<string name="send_a_direct_message">Stuur privébericht</string>
|
||||
<string name="edits_the_user_s_metadata">Bewerkt gebruikers-metadata</string>
|
||||
<string name="unblock">Deblokkeren</string>
|
||||
@@ -259,7 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Alle bekende markeren als gelezen</string>
|
||||
<string name="mark_all_new_as_read">Alle nieuwe markeren als gelezen</string>
|
||||
<string name="mark_all_as_read">Alles markeren als gelezen</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Versleutel en kopieer mijn privésleutel</string>
|
||||
<string name="badge_award_image_for">Badge-awardafbeelding voor %1$s</string>
|
||||
<string name="badge_award_image">Badge-awardafbeelding</string>
|
||||
<string name="new_badge_award_notif">Je hebt een nieuwe badge-award ontvangen</string>
|
||||
@@ -1800,8 +1798,6 @@
|
||||
<string name="ots_explorer_api_label">Explorer API-basis-URL</string>
|
||||
<string name="dvm_pay_invoice_from_dvm">Factuur betalen van de DVM</string>
|
||||
<string name="dvm_pay_amount_to_dvm">%1$s sats betalen aan de DVM</string>
|
||||
<string xmlns:ns0="http://schemas.android.com/tools" name="account_backup_tips2_md" ns0:ignore="Typos">## Sleutelback-up en veiligheidstips\n\nJe account wordt beveiligd door een privésleutel (begint met **nsec1**). Iedereen met deze sleutel kan namens jou posten.\n\n- Voer je privésleutel **nooit** in op een website of app die je niet volledig vertrouwt.\n- Amethyst-ontwikkelaars zullen **nooit** om je privésleutel vragen.\n- Maak een veilige back-up van je privésleutel (bijvoorbeeld in een wachtwoordmanager).</string>
|
||||
<string xmlns:ns0="http://schemas.android.com/tools" name="account_backup_tips3_md" ns0:ignore="Typos">Voor extra veiligheid kun je je sleutel versleutelen met een wachtwoord. Deze versleutelde sleutel begint met **ncryptsec1** en kan alleen met je wachtwoord worden gebruikt.\n\nAls je het wachtwoord vergeet, kun je de sleutel niet meer herstellen.</string>
|
||||
<string name="use_direct_url">Directe URL gebruiken</string>
|
||||
<string name="nsite_title">Statische website: %1$s</string>
|
||||
<string name="nsite_root_site">Root-site</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Note-tekst gekopieerd naar klembord</string>
|
||||
<string name="copied_to_clipboard">Gekopieerd naar klembord</string>
|
||||
<string xmlns:ns0="http://schemas.android.com/tools" name="copied_user_id_to_clipboard" ns0:ignore="Typos">Gebruikers-ID (@npub…) gekopieerd naar klembord</string>
|
||||
<string name="copy_my_secret_key">Mijn privésleutel kopiëren</string>
|
||||
<string name="copy_to_clipboard">Kopiëren naar klembord</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Kon LNURL niet samenstellen vanuit Lightning-adres "%1$s". Controleer de instellingen van de gebruiker.</string>
|
||||
<string name="could_not_check_downloaded_file">Kon gedownload bestand niet controleren na upload: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">HLS-upload</string>
|
||||
<string name="share_or_save">Delen of opslaan</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Toon versleutelde QR-code van privésleutel</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Berichten tonen</string>
|
||||
<string name="show_private_key_qr_code">Toon QR-code van privésleutel</string>
|
||||
<string name="sign_request_rejected2">Ondertekenverzoek afgewezen</string>
|
||||
<string name="sign_request_rejected_description">Zorg dat de signer-app dit verzoek heeft goedgekeurd.</string>
|
||||
<string name="signer_illegal_state_exception_description">Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer.</string>
|
||||
|
||||
@@ -338,7 +338,6 @@
|
||||
<string name="number_reports">%1$s rapportages</string>
|
||||
<string name="relays">Relays</string>
|
||||
<string name="lightning_address">Lightning-adres</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopieert je privésleutel (nsec) naar het klembord voor back-up</string>
|
||||
<string name="send_a_direct_message">Stuur privébericht</string>
|
||||
<string name="edits_the_user_s_metadata">Bewerkt gebruikers-metadata</string>
|
||||
<string name="unblock">Deblokkeren</string>
|
||||
@@ -444,14 +443,11 @@
|
||||
<string name="mark_all_known_as_read">Alle bekende markeren als gelezen</string>
|
||||
<string name="mark_all_new_as_read">Alle nieuwe markeren als gelezen</string>
|
||||
<string name="mark_all_as_read">Alles markeren als gelezen</string>
|
||||
<string name="account_backup_tips2_md">## Sleutelback-up en veiligheidstips\n\nJe account wordt beveiligd door een privésleutel (begint met **nsec1**). Iedereen met deze sleutel kan namens jou posten.\n\n- Voer je privésleutel **nooit** in op een website of app die je niet volledig vertrouwt.\n- Amethyst-ontwikkelaars zullen **nooit** om je privésleutel vragen.\n- Maak een veilige back-up van je privésleutel (bijvoorbeeld in een wachtwoordmanager).</string>
|
||||
<string name="account_backup_tips3_md">Voor extra veiligheid kun je je sleutel versleutelen met een wachtwoord. Deze versleutelde sleutel begint met **ncryptsec1** en kan alleen met je wachtwoord worden gebruikt.\n\nAls je het wachtwoord vergeet, kun je de sleutel niet meer herstellen.</string>
|
||||
<string name="backup_keys_nudge_title">Maak een back-up van je sleutels</string>
|
||||
<string name="backup_keys_nudge_body">Je geheime sleutel is de enige manier om bij dit account te komen. Raak je hem kwijt, dan is hij nooit meer te herstellen. Sla hem nu op een veilige plek op.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Nu back-uppen</string>
|
||||
<string name="backup_keys_nudge_already_saved">Ik heb ze opgeslagen</string>
|
||||
<string name="backup_keys_nudge_dismiss">Sluiten</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Versleutel en kopieer mijn privésleutel</string>
|
||||
<string name="badge_award_image_for">Badge-awardafbeelding voor %1$s</string>
|
||||
<string name="badge_award_image">Badge-awardafbeelding</string>
|
||||
<string name="new_badge_award_notif">Je hebt een nieuwe badge-award ontvangen</string>
|
||||
@@ -3081,7 +3077,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Note-tekst gekopieerd naar klembord</string>
|
||||
<string name="copied_to_clipboard">Gekopieerd naar klembord</string>
|
||||
<string name="copied_user_id_to_clipboard">Gebruikers-ID (@npub…) gekopieerd naar klembord</string>
|
||||
<string name="copy_my_secret_key">Mijn privésleutel kopiëren</string>
|
||||
<string name="copy_to_clipboard">Kopiëren naar klembord</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Kon LNURL niet samenstellen vanuit Lightning-adres "%1$s". Controleer de instellingen van de gebruiker.</string>
|
||||
<string name="could_not_check_downloaded_file">Kon gedownload bestand niet controleren na upload: %1$s</string>
|
||||
@@ -4473,10 +4468,8 @@
|
||||
<string name="share_hls_video">HLS-upload</string>
|
||||
<string name="share_or_save">Delen of opslaan</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Toon versleutelde QR-code van privésleutel</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Berichten tonen</string>
|
||||
<string name="show_private_key_qr_code">Toon QR-code van privésleutel</string>
|
||||
<string name="sign_request_rejected2">Ondertekenverzoek afgewezen</string>
|
||||
<string name="sign_request_rejected_description">Zorg dat de signer-app dit verzoek heeft goedgekeurd.</string>
|
||||
<string name="signer_illegal_state_exception_description">Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays">Relays</string>
|
||||
<string name="website">Website</string>
|
||||
<string name="lightning_address">Lightning Adress</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopieert het NSEC ID (uw wachtwoord) naar klembord voor back-up.</string>
|
||||
<string name="send_a_direct_message">Stuur een privébericht</string>
|
||||
<string name="edits_the_user_s_metadata">Bewerkt de metadata van de gebruiker</string>
|
||||
<string name="unblock">Deblokkeren</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Bekende markeren als gelezen</string>
|
||||
<string name="mark_all_new_as_read">Nieuwe markeren als gelezen</string>
|
||||
<string name="mark_all_as_read">Alles markeren als gelezen</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Versleutel en kopieer mijn geheime sleutel</string>
|
||||
<string name="badge_award_image_for">Badge award afbeelding voor %1$s</string>
|
||||
<string name="badge_award_image">Badge-awardafbeelding</string>
|
||||
<string name="new_badge_award_notif">Je hebt een nieuwe Badge award ontvangen</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Note tekst gekopieerd naar klembord</string>
|
||||
<string name="copied_to_clipboard">Gekopieerd naar klembord</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub auteur gekopieerd naar klembord</string>
|
||||
<string name="copy_my_secret_key">Kopieer mijn privésleutel</string>
|
||||
<string name="copy_to_clipboard">Kopiëren naar klembord</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Kon LNUrl niet samenbrengen van Lightning Adress "%1$s". Controleer de instellingen van de gebruiker</string>
|
||||
<string name="could_not_check_downloaded_file">Kan het gedownloade bestand niet controleren na upload: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">HLS-upload</string>
|
||||
<string name="share_or_save">Delen of opslaan</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Toon versleutelde QR-code van privésleutel</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Directe berichten en groepsberichten opnemen in het tabblad Meldingen. Uitschakelen om berichten alleen in het tabblad Berichten te houden.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Berichten tonen</string>
|
||||
<string name="show_private_key_qr_code">Toon QR-code van privésleutel</string>
|
||||
<string name="sign_request_rejected2">Ondertekenverzoek afgewezen</string>
|
||||
<string name="sign_request_rejected_description">Zorg ervoor dat de teken-app deze transactie heeft geautoriseerd</string>
|
||||
<string name="signer_illegal_state_exception_description">Externe signer heeft een onjuiste payload geretourneerd voor dit verzoek. Er kan een bug zitten in Amethyst of in de signer.</string>
|
||||
|
||||
@@ -561,7 +561,6 @@
|
||||
<string name="relays"> Transmitery</string>
|
||||
<string name="website">Strona www</string>
|
||||
<string name="lightning_address">Lightning Adres</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopiuje Nsec ID (hasło) do schowka w celu wykonania kopii zapasowej</string>
|
||||
<string name="send_a_direct_message">Wyślij bezpośrednią wiadomość</string>
|
||||
<string name="edits_the_user_s_metadata">Edytowanie metadanych użytkowników</string>
|
||||
<string name="unblock">Odblokuj</string>
|
||||
@@ -670,14 +669,29 @@
|
||||
<string name="mark_all_known_as_read">Zaznacz wszystkie popularne jako przeczytane</string>
|
||||
<string name="mark_all_new_as_read">Zaznacz wszystkie nowe jako przeczytane</string>
|
||||
<string name="mark_all_as_read">Zaznacz wszystkie jako przeczytane</string>
|
||||
<string name="account_backup_tips2_md">## 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ł.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="account_backup_headline">Twój tajny klucz to Twoje konto</string>
|
||||
<string name="account_backup_intro">Każdy, kto go posiada, może publikować posty pod twoim imieniem. Jeśli go zgubisz, nikt nie będzie w stanie go odzyskać, nawet Amethyst.</string>
|
||||
<string name="account_backup_tap_to_reveal">Kliknij, aby przejrzeć</string>
|
||||
<string name="account_backup_write_down_hint">Zapisz to w tej kolejności. Można używać zarówno wielkich, jak i małych liter.</string>
|
||||
<string name="account_backup_qr_code">Kod QR</string>
|
||||
<string name="account_backup_encrypted_title">Kopia chroniona hasłem</string>
|
||||
<string name="account_backup_encrypted_password">Hasło</string>
|
||||
<string name="account_backup_encrypted_body">Ncryptsec1… który działa tylko z twoim hasłem.</string>
|
||||
<string name="account_backup_password_min_length">Co najmniej %1$d znaków</string>
|
||||
<string name="account_backup_encrypted_repeat_password">Powtórz hasło</string>
|
||||
<string name="account_backup_encrypted_password_mismatch">Hasła nie są identyczne</string>
|
||||
<string name="account_backup_encrypt">Zaszyfruj klucz</string>
|
||||
<string name="account_backup_encrypting">Szyfrowanie…</string>
|
||||
<string name="account_backup_encrypted_saved_hint">Można je bezpiecznie przechowywać w menedżerze haseł lub notatkach w chmurze: nie da się ich otworzyć bez hasła, a zapomnianego hasła nie da się odzyskać.</string>
|
||||
<string name="account_backup_encrypt_again">Użyj innego hasła</string>
|
||||
<string name="account_backup_tip_storage">Schowaj ten zapis w miejscu, które znasz tylko ty, albo zapisz klucz w menedżerze haseł.</string>
|
||||
<string name="account_backup_tip_trust">Nigdy nie wpisuj swojego klucza na stronach internetowych ani w aplikacjach, do których nie masz zaufania.</string>
|
||||
<string name="account_backup_tip_developers">Programiści serwisu Amethyst nigdy nie poproszą Cię o podanie klucza.</string>
|
||||
<string name="backup_keys_nudge_title">Kopia zapasowa kluczy</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Utwórz kopię zapasową</string>
|
||||
<string name="backup_keys_nudge_already_saved">Zapisałem(am)</string>
|
||||
<string name="backup_keys_nudge_dismiss">Ignoruj</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Zaszyfruj i skopiuj mój tajny klucz</string>
|
||||
<string name="badge_award_image_for">Wizerunek odznaki dla %1$s</string>
|
||||
<string name="badge_award_image">Wizerunek odznaki</string>
|
||||
<string name="new_badge_award_notif">Otrzymałeś nową odznakę</string>
|
||||
@@ -2696,6 +2710,18 @@
|
||||
<string name="nickname_private">Widoczne tylko dla Ciebie</string>
|
||||
<string name="cast_to_device_dialog_title">Zrzuć do…</string>
|
||||
<string name="cast_searching_for_devices">Wyszukiwanie urządzeń w sieci Wi-Fi…</string>
|
||||
<string name="cast_local_network_permission_title">Wymagane uprawnienia</string>
|
||||
<string name="cast_local_network_permission_message">Aplikacja Amethyst potrzebuje dostępu do sieci lokalnej, aby wykryć urządzenia obsługujące funkcję Cast w Twojej sieci Wi-Fi. Włącz tę opcję w ustawieniach aplikacji.</string>
|
||||
<string name="cast_local_network_permission_open_settings">Otwórz ustawienia</string>
|
||||
<string name="cast_error_unsupported_media">%1$s nie może odtworzyć tego formatu wideo</string>
|
||||
<string name="cast_error_playback_failed">%1$s nie mógł odtworzyć tego filmu</string>
|
||||
<string name="cast_error_receiver_not_responding">%1$s przestał odpowiadać. Ponowne uruchomienie urządzenia zwykle naprawia.</string>
|
||||
<string name="cast_error_connect_failed">Nie można połączyć się z %1$s. Ponowne uruchomienie urządzenia zwykle je naprawia.</string>
|
||||
<string name="cast_error_load_failed">Nie można załadować tego filmu na %1$s</string>
|
||||
<string name="cast_error_play_services_unavailable">Udostępnianie wymaga usług Google Play, które nie są dostępne na tym urządzeniu</string>
|
||||
<string name="cast_error_unsupported_media_detail">%1$s nie może odtworzyć formatu tego wideo (%2$s)</string>
|
||||
<string name="cast_error_playback_failed_detail">%1$s nie mógł odtworzyć tego wideo (%2$s)</string>
|
||||
<string name="cast_error_receiver_not_responding_detail">%1$s nigdy nie rozpoczął odtwarzania tego wideo (%2$s). Może nie obsługiwać tego formatu, lub ponowne uruchomienie urządzenia może pomóc.</string>
|
||||
<string name="hls_pick_video_primary">Wybierz wideo</string>
|
||||
<string name="hls_pick_video_helper">Twoje wideo zostanie przekodowane do różnych rozdzielczości, dzięki czemu widzowie będą mogli cieszyć się płynnym odtwarzaniem niezależnie od szybkości połączenia.</string>
|
||||
<string name="hls_change_video">Zmień</string>
|
||||
@@ -3653,7 +3679,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Skopiowano tekst wpisu do schowka</string>
|
||||
<string name="copied_to_clipboard">Skopiowano do schowka</string>
|
||||
<string name="copied_user_id_to_clipboard">Skopiowano @npub autora do schowka</string>
|
||||
<string name="copy_my_secret_key">Kopiuj mój tajny klucz</string>
|
||||
<string name="copy_to_clipboard">Kopiuj do schowka</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Nie można stworzyć LNUrl z Adresu "%1$s". Sprawdź konfigurację użytkownika</string>
|
||||
<string name="could_not_check_downloaded_file">Nie można sprawdzić pobranego pliku po wgraniu: %1$s</string>
|
||||
@@ -5256,10 +5281,8 @@
|
||||
<string name="share_hls_video">Wgraj HLS</string>
|
||||
<string name="share_or_save">Udostępnij lub zapisz</string>
|
||||
<string name="shorts">Filmiki</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Pokaż zaszyfrowany kod QR klucza prywatnego</string>
|
||||
<string name="show_messages_in_notifications_setting_description">W zakładce „Powiadomienia” znajdują się zarówno wiadomości bezpośrednie, jak i grupowe. Wyłącz tę opcję, aby wiadomości były wyświetlane wyłącznie w zakładce „Wiadomości”.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Pokaż wiadomości</string>
|
||||
<string name="show_private_key_qr_code">Pokaż kod QR klucza prywatnego</string>
|
||||
<string name="sign_request_rejected2">Prośba o zalogowanie została odrzucona</string>
|
||||
<string name="sign_request_rejected_description">Upewnij się, że aplikacja logującego autoryzuje tę operację</string>
|
||||
<string name="signer_illegal_state_exception_description">Sygnatariusz zewnętrzny zwrócił dane, które są niezgodne z żądaniem. Być może wystąpił błąd w Amethyst lub w samym sygnatariuszu.</string>
|
||||
@@ -5483,6 +5506,12 @@
|
||||
<string name="cordn_health_unknown">Jeszcze się nie skontaktowano</string>
|
||||
<string name="cordn_health_ok">Odpowiedź</string>
|
||||
<string name="cordn_health_down">Brak odpowiedzi</string>
|
||||
<plurals name="cordn_health_failures">
|
||||
<item quantity="one">%1$d nieudana próba z rzędu</item>
|
||||
<item quantity="few">%1$d nieudanych prób z rzędu</item>
|
||||
<item quantity="many">%1$d nieudanych prób z rzędu</item>
|
||||
<item quantity="other">%1$d nieudane próby z rzędu</item>
|
||||
</plurals>
|
||||
<string name="cordn_link_explainer">Wklej link „cordn1…” udostępniony przez inną osobę, aby sprawdzić, który koordynator prowadzi tę grupę oraz jakie informacje o tobie uzyskałby ten operator, gdybyś do niej dołączył.</string>
|
||||
<string name="cordn_link_field">cordn1…</string>
|
||||
<string name="cordn_link_inspect">Zbadaj</string>
|
||||
@@ -5571,6 +5600,12 @@
|
||||
<string name="cordn_migrate_import">Przynieś grupy tutaj</string>
|
||||
<string name="cordn_migrate_importing">Pobieranie…</string>
|
||||
<string name="cordn_migrate_replaces_warning">Powyższe dane zastępują wszelkie grupy „cordn” już istniejące w tym telefonie. Nie można ich połączyć.</string>
|
||||
<plurals name="cordn_migrate_done">
|
||||
<item quantity="one">%1$d grupa przeniesiona</item>
|
||||
<item quantity="few">%1$d grup przeniesionych</item>
|
||||
<item quantity="many">%1$d grup przeniesiono</item>
|
||||
<item quantity="other">%1$d grupy przeniesione</item>
|
||||
</plurals>
|
||||
<string name="cordn_migrate_no_groups">Na tym urządzeniu nie ma żadnych grup cordn, które można by przenieść.</string>
|
||||
<string name="cordn_migrate_no_server">Najpierw skonfiguruj serwer multimediów — zaszyfrowane dokumenty muszą gdzieś się znaleźć, dopóki drugi telefon je pobierze.</string>
|
||||
<string name="cordn_migrate_exposure_title">Co opuszcza to urządzenie</string>
|
||||
@@ -6126,6 +6161,10 @@
|
||||
<string name="cordn_action_pin">Przypnij</string>
|
||||
<string name="cordn_action_reply">Odpowiedz</string>
|
||||
<string name="cordn_action_unpin">Odepnij</string>
|
||||
<string name="cordn_admin_action_failed">Ta zmiana nie mogła zostać wprowadzona.</string>
|
||||
<string name="cordn_admin_coordinator_silent">Koordynator nie odpowiedział, więc nic się nie zmieniło. Spróbuj ponownie za chwilę.</string>
|
||||
<string name="cordn_admin_no_key_package">%1$s nie opublikował jeszcze pakietu kluczy na tym koordynatorze, więc nie można go jeszcze dodać. Poproś go, aby najpierw uruchomił program cordn na tym koordynatorze.</string>
|
||||
<string name="cordn_admin_no_self_remove">Nie można samodzielnie usunąć się z grupy cordn.</string>
|
||||
<string name="cordn_backup_restore_confirm_title">Czy zamienić grupy cordn tego urządzenia?</string>
|
||||
<string name="cordn_backup_restore_title">Przywróć</string>
|
||||
<string name="cordn_backup_restored">Przywrócono.</string>
|
||||
|
||||
@@ -545,7 +545,6 @@
|
||||
<string name="relays"> Relés</string>
|
||||
<string name="website">Site</string>
|
||||
<string name="lightning_address">Endereço Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copiar a chave Nsec (sua senha) para backup</string>
|
||||
<string name="send_a_direct_message">Enviar uma mensagem direta</string>
|
||||
<string name="edits_the_user_s_metadata">Muda os dados do usuário</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -654,14 +653,11 @@
|
||||
<string name="mark_all_known_as_read">Marcar todos conhecidos como lidos</string>
|
||||
<string name="mark_all_new_as_read">Marcar todas novas solicitações como lidas</string>
|
||||
<string name="mark_all_as_read">Marcar todas como lidas</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="backup_keys_nudge_title">Faça backup das suas chaves</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Fazer backup agora</string>
|
||||
<string name="backup_keys_nudge_already_saved">Já salvei</string>
|
||||
<string name="backup_keys_nudge_dismiss">Dispensar</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Criptografar e copiar minha chave secreta</string>
|
||||
<string name="badge_award_image_for">Imagem da medalha para %1$s</string>
|
||||
<string name="badge_award_image">Imagem do prêmio</string>
|
||||
<string name="new_badge_award_notif">Você recebeu uma nova medalha</string>
|
||||
@@ -3577,7 +3573,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto copiado</string>
|
||||
<string name="copied_to_clipboard">Copiado para a área de transferência</string>
|
||||
<string name="copied_user_id_to_clipboard">Copiado @npub do autor</string>
|
||||
<string name="copy_my_secret_key">Copiar minha chave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar para a Área de Transferência</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Não foi possível montar o LNUrl a partir do Endereço Lightning "%1$s". Verifique a configuração do usuário</string>
|
||||
<string name="could_not_check_downloaded_file">Não foi possível verificar o arquivo baixado após o upload: %1$s</string>
|
||||
@@ -5040,10 +5035,8 @@
|
||||
<string name="share_hls_video">Upload HLS</string>
|
||||
<string name="share_or_save">Compartilhar ou Salvar</string>
|
||||
<string name="shorts">Curtas</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar o código QR da chave privada criptografado</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inclui mensagens diretas e de grupo na aba Notificações. Desative para manter as mensagens apenas na aba Mensagens.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensagens</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de chave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitação de assinatura rejeitada</string>
|
||||
<string name="sign_request_rejected_description">Certifique-se de que a aplicação assinante autorizou esta transação</string>
|
||||
<string name="signer_illegal_state_exception_description">O assinador externo retornou dados estranhos para a solicitação. Pode haver um bug no Amethyst ou no assinador.</string>
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
<string name="relays"> Relés</string>
|
||||
<string name="website">Site</string>
|
||||
<string name="lightning_address">Endereço Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copiar a chave Nsec (sua senha) para backup</string>
|
||||
<string name="send_a_direct_message">Enviar uma mensagem direta</string>
|
||||
<string name="edits_the_user_s_metadata">Muda os dados do usuário</string>
|
||||
<string name="unblock">Desbloquear</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">Marcar todos conhecidos como lidos</string>
|
||||
<string name="mark_all_new_as_read">Marcar todas novas solicitações como lidas</string>
|
||||
<string name="mark_all_as_read">Marcar todas como lidas</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Criptografar e copiar minha chave secreta</string>
|
||||
<string name="badge_award_image_for">Imagem da medalha para %1$s</string>
|
||||
<string name="badge_award_image">Imagem do prêmio</string>
|
||||
<string name="new_badge_award_notif">Você recebeu uma nova medalha</string>
|
||||
@@ -1988,7 +1984,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Texto copiado</string>
|
||||
<string name="copied_to_clipboard">Copiado para a área de transferência</string>
|
||||
<string name="copied_user_id_to_clipboard">Copiado @npub do autor</string>
|
||||
<string name="copy_my_secret_key">Copiar minha chave secreta</string>
|
||||
<string name="copy_to_clipboard">Copiar para a Área de Transferência</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Não foi possível montar o LNUrl a partir do Endereço Lightning "%1$s". Verifique a configuração do usuário</string>
|
||||
<string name="could_not_check_downloaded_file">Não foi possível verificar o arquivo baixado após o upload: %1$s</string>
|
||||
@@ -2775,10 +2770,8 @@
|
||||
<string name="share_hls_video">Upload HLS</string>
|
||||
<string name="share_or_save">Compartilhar ou Salvar</string>
|
||||
<string name="shorts">Curtas</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Mostrar o código QR da chave privada criptografado</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inclui mensagens diretas e de grupo na aba Notificações. Desative para manter as mensagens apenas na aba Mensagens.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mostrar mensagens</string>
|
||||
<string name="show_private_key_qr_code">Mostrar código QR de chave privada</string>
|
||||
<string name="sign_request_rejected2">Solicitação de assinatura rejeitada</string>
|
||||
<string name="sign_request_rejected_description">Certifique-se de que a aplicação assinante autorizou esta transação</string>
|
||||
<string name="signer_illegal_state_exception_description">O assinador externo retornou dados estranhos para a solicitação. Pode haver um bug no Amethyst ou no assinador.</string>
|
||||
|
||||
@@ -219,7 +219,6 @@
|
||||
<string name="relays"> Релеев</string>
|
||||
<string name="website">Сайт</string>
|
||||
<string name="lightning_address">Lightning адрес</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Копирует Nsec ID (ваш пароль) для резервного копирования</string>
|
||||
<string name="send_a_direct_message">Отправить сообщение</string>
|
||||
<string name="edits_the_user_s_metadata">Редактирует метаданные пользователя</string>
|
||||
<string name="unblock">Разблокировать</string>
|
||||
@@ -274,9 +273,6 @@
|
||||
<string name="mark_all_known_as_read">Отметить все известные прочитанными</string>
|
||||
<string name="mark_all_new_as_read">Отметить все новые прочитанными</string>
|
||||
<string name="mark_all_as_read">Отметить всё прочитанным</string>
|
||||
<string name="account_backup_tips2_md">## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей.</string>
|
||||
<string name="account_backup_tips3_md">Для дополнительной безопасности вы можете зашифровать ваш ключ с помощью пароля. Этот ключ начинается с **ncryptsec1** и не может быть использован без пароля. \n\nЕсли вы потеряете свой пароль, вы не сможете восстановить ваш ключ.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Зашифровать и копировать мой секретный ключ</string>
|
||||
<string name="badge_award_image_for">Картинка значка-награды %1$s</string>
|
||||
<string name="badge_award_image">Изображение награды за значок</string>
|
||||
<string name="new_badge_award_notif">Вы получили в награду новый значок</string>
|
||||
@@ -2029,7 +2025,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Копировать текст</string>
|
||||
<string name="copied_to_clipboard">Скопировано в буфер обмена</string>
|
||||
<string name="copied_user_id_to_clipboard">ID (npub) автора скопирован</string>
|
||||
<string name="copy_my_secret_key">Скопировать мой приватный ключ</string>
|
||||
<string name="copy_to_clipboard">Копировать в буфер обмена</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя</string>
|
||||
<string name="could_not_check_downloaded_file">Не удалось проверить загруженный файл после выгрузки: %1$s</string>
|
||||
@@ -2858,10 +2853,8 @@
|
||||
<string name="share_as_image_url">Поделиться URL изображения</string>
|
||||
<string name="share_hls_video">Загрузка HLS</string>
|
||||
<string name="share_or_save">Поделиться или сохранить</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Показать зашифрованный QR-код приватного ключа</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения».</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Показывать сообщения</string>
|
||||
<string name="show_private_key_qr_code">Показать QR-код приватного ключа</string>
|
||||
<string name="sign_request_rejected2">Запрос на подпись отклонён</string>
|
||||
<string name="sign_request_rejected_description">Убедитесь, что приложение подписи авторизовало эту транзакцию</string>
|
||||
<string name="signer_illegal_state_exception_description">Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи.</string>
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
<string name="reports">Жалобы</string>
|
||||
<string name="number_reports">%1$s жалоб</string>
|
||||
<string name="website">Веб-сайт</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Копирует Nsec ID (ваш пароль) в буфер обмена для резервного копирования</string>
|
||||
<string name="send_a_direct_message">Отправить личное сообщение</string>
|
||||
<string name="edits_the_user_s_metadata">Редактирует метаданные пользователя</string>
|
||||
<string name="unblock">Разблокировать</string>
|
||||
@@ -267,9 +266,6 @@
|
||||
<string name="mark_all_known_as_read">Отметить все известные как прочитанные</string>
|
||||
<string name="mark_all_new_as_read">Отметить все новые как прочитанные</string>
|
||||
<string name="mark_all_as_read">Отметить все как прочитанные</string>
|
||||
<string name="account_backup_tips2_md">## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей.</string>
|
||||
<string name="account_backup_tips3_md">Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ключ.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Зашифровать и скопировать мой секретный ключ</string>
|
||||
<string name="badge_award_image_for">Изображение награды для %1$s</string>
|
||||
<string name="badge_award_image">Изображение награды за значок</string>
|
||||
<string name="new_badge_award_notif">Вы получили новую награду</string>
|
||||
@@ -2015,7 +2011,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Текст записи скопирован в буфер обмена</string>
|
||||
<string name="copied_to_clipboard">Скопировано в буфер обмена</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub автора скопирован в буфер обмена</string>
|
||||
<string name="copy_my_secret_key">Скопировать мой секретный ключ</string>
|
||||
<string name="copy_to_clipboard">Скопировать в буфер обмена</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя</string>
|
||||
<string name="could_not_check_downloaded_file">Не удалось проверить загруженный файл после выгрузки: %1$s</string>
|
||||
@@ -2840,10 +2835,8 @@
|
||||
<string name="share_as_image_url">Поделиться URL изображения</string>
|
||||
<string name="share_hls_video">Загрузка HLS</string>
|
||||
<string name="share_or_save">Поделиться или сохранить</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Показать QR-код зашифрованного приватного ключа</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения».</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Показывать сообщения</string>
|
||||
<string name="show_private_key_qr_code">Показать QR-код приватного ключа</string>
|
||||
<string name="sign_request_rejected2">Запрос на подпись отклонён</string>
|
||||
<string name="sign_request_rejected_description">Убедитесь, что приложение подписи авторизовало эту транзакцию</string>
|
||||
<string name="signer_illegal_state_exception_description">Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи.</string>
|
||||
|
||||
@@ -208,7 +208,6 @@
|
||||
<string name="relays"> Релеев</string>
|
||||
<string name="website">Сайт</string>
|
||||
<string name="lightning_address">Lightning адрес</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Копирует Nsec ID (ваш пароль) для резервного копирования</string>
|
||||
<string name="send_a_direct_message">Отправить сообщение</string>
|
||||
<string name="edits_the_user_s_metadata">Редактирует метаданные пользователя</string>
|
||||
<string name="unblock">Разблокировать</string>
|
||||
@@ -263,9 +262,6 @@
|
||||
<string name="mark_all_known_as_read">Отметить все известные прочитанными</string>
|
||||
<string name="mark_all_new_as_read">Отметить все новые прочитанными</string>
|
||||
<string name="mark_all_as_read">Отметить всё прочитанным</string>
|
||||
<string name="account_backup_tips2_md">## Советы по резервному копированию и безопасности ключей \n\nВаш аккаунт защищён секретным ключом. Ключ — это длинная последовательность символов, начинающаяся с **nsec1**. Любой, кто получит доступ к этому секретному ключу, сможет публиковать записи и менять вашу личность. \n\n- **Не** вводите свой секретный ключ на сайтах или в приложениях, которым не доверяете. \n- Разработчики Amethyst **никогда** не будут запрашивать ваш секретный ключ. \n- **Обязательно** сохраните надёжную резервную копию секретного ключа для восстановления аккаунта. Рекомендуем использовать менеджер паролей.</string>
|
||||
<string name="account_backup_tips3_md">Для дополнительной безопасности вы можете зашифровать ваш ключ паролем. Этот ключ начинается с **ncryptsec1** и не может быть использован без вашего пароля. \n\nЕсли вы потеряете пароль, вы не сможете восстановить ваш ключ.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Зашифровать и скопировать секретный ключ</string>
|
||||
<string name="badge_award_image_for">Картинка значка-награды %1$s</string>
|
||||
<string name="badge_award_image">Изображение награды за значок</string>
|
||||
<string name="new_badge_award_notif">Вы получили в награду новый значок</string>
|
||||
@@ -2058,7 +2054,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Копировать текст</string>
|
||||
<string name="copied_to_clipboard">Скопировано в буфер обмена</string>
|
||||
<string name="copied_user_id_to_clipboard">ID (npub) автора скопирован</string>
|
||||
<string name="copy_my_secret_key">Скопировать мой приватный ключ</string>
|
||||
<string name="copy_to_clipboard">Копировать в буфер обмена</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Не удалось собрать LNUrl из Lightning Address «%1$s». Проверьте настройки пользователя</string>
|
||||
<string name="could_not_check_downloaded_file">Не удалось проверить загруженный файл после выгрузки: %1$s</string>
|
||||
@@ -2935,10 +2930,8 @@
|
||||
<string name="share_hls_video">Загрузка HLS</string>
|
||||
<string name="share_or_save">Поделиться или сохранить</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Показать QR-код зашифрованного приватного ключа</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Включить личные и групповые сообщения во вкладку «Уведомления». Отключите, чтобы сообщения отображались только во вкладке «Сообщения».</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Показывать сообщения</string>
|
||||
<string name="show_private_key_qr_code">Показать QR-код приватного ключа</string>
|
||||
<string name="sign_request_rejected2">Запрос на подпись отклонён</string>
|
||||
<string name="sign_request_rejected_description">Убедитесь, что приложение подписи авторизовало эту транзакцию</string>
|
||||
<string name="signer_illegal_state_exception_description">Внешний подписант вернул неожиданный ответ на запрос. Возможно, ошибка в Amethyst или в приложении подписи.</string>
|
||||
|
||||
@@ -363,7 +363,6 @@
|
||||
<string name="relays"> Releji</string>
|
||||
<string name="website">Spletna stran</string>
|
||||
<string name="lightning_address">Lightning naslov</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopira Nsec ID (tvoje geslo) v odložišče za varnostno kopiranje</string>
|
||||
<string name="send_a_direct_message">Pošlji direktno sporočilo</string>
|
||||
<string name="edits_the_user_s_metadata">Uredi uporabnikove metapodatke</string>
|
||||
<string name="unblock">Deblokiraj</string>
|
||||
@@ -472,14 +471,11 @@
|
||||
<string name="mark_all_known_as_read">Označi vse znane kot prebrane</string>
|
||||
<string name="mark_all_new_as_read">Označi vse nove kot prebrane</string>
|
||||
<string name="mark_all_as_read">Označi vse kot prebrane</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="backup_keys_nudge_title">Varno shrani ključe</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Varno shrani zdaj</string>
|
||||
<string name="backup_keys_nudge_already_saved">shranjeno</string>
|
||||
<string name="backup_keys_nudge_dismiss">Opusti</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Šifriraj in kopiraj moj privatni ključ</string>
|
||||
<string name="badge_award_image_for">Slika nagradne značke za %1$s</string>
|
||||
<string name="badge_award_image">"Slika nagradne značke</string>
|
||||
<string name="new_badge_award_notif">Prejel/a si novo nagradno značko</string>
|
||||
@@ -3316,7 +3312,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Tekst zapiska kopiran v odložišče</string>
|
||||
<string name="copied_to_clipboard">Kopirano v odložišče</string>
|
||||
<string name="copied_user_id_to_clipboard">Avtorjev @npub kopiran v odložišče</string>
|
||||
<string name="copy_my_secret_key">Kopiraj moj privatni ključ</string>
|
||||
<string name="copy_to_clipboard">Kopiraj v odložišče</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Ni bilo mogoče sestaviti LNUrl iz "lightning" naslova '%1$s'. Preverite uporabnikove nastavitve</string>
|
||||
<string name="could_not_check_downloaded_file">Ni bilo mogoče preveriti prenesene datoteke po nalaganju: %1$s</string>
|
||||
@@ -4844,10 +4839,8 @@
|
||||
<string name="share_hls_video">Naloži HLS</string>
|
||||
<string name="share_or_save">Deli ali shrani</string>
|
||||
<string name="shorts">Kratki posnetki</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Pokaži QR kodo šifriranega zasebnega ključa</string>
|
||||
<string name="show_messages_in_notifications_setting_description">V zavihek Obvestila vključite neposredna in skupinska sporočila. Izklopite, če želite sporočila ohraniti samo v zavihku Sporočila.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Prikaži sporočilo</string>
|
||||
<string name="show_private_key_qr_code">Pokaži QR kodo zasebnega ključa</string>
|
||||
<string name="sign_request_rejected2">Zahteva za vpis zavrnjena</string>
|
||||
<string name="sign_request_rejected_description">Prepričajte se, da je aplikacija za podpisovanje odobrila to transakcijo</string>
|
||||
<string name="signer_illegal_state_exception_description">Zunanji podpisnik je vrnil neobičajen odgovor. Morda gre za napako v aplikaciji Amethyst ali v podpisniku.</string>
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
<string name="relays"> Relay-ovi</string>
|
||||
<string name="website">Veb stranica</string>
|
||||
<string name="lightning_address">Lightning adresa</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopira Nsec ID (vaša lozinka) u međuspremnik radi rezervne kopije</string>
|
||||
<string name="send_a_direct_message">Pošalji direktnu poruku</string>
|
||||
<string name="edits_the_user_s_metadata">Izmeni metapodatke korisnika</string>
|
||||
<string name="unblock">Odblokiraj</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">Označi sve poznate kao pročitano</string>
|
||||
<string name="mark_all_new_as_read">Označi sve novo kao pročitano</string>
|
||||
<string name="mark_all_as_read">Označi sve kao pročitano</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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č.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Šifruj i kopiraj moj tajni ključ</string>
|
||||
<string name="badge_award_image_for">Slika značke za %1$s</string>
|
||||
<string name="badge_award_image">"Slika značke</string>
|
||||
<string name="new_badge_award_notif">Dobili ste novu značku</string>
|
||||
@@ -1997,7 +1993,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Tekst beleške kopiran u clipboard</string>
|
||||
<string name="copied_to_clipboard">Kopirano u privremenu memoriju</string>
|
||||
<string name="copied_user_id_to_clipboard">@npub autora kopiran u clipboard</string>
|
||||
<string name="copy_my_secret_key">Kopiraj moj tajni ključ</string>
|
||||
<string name="copy_to_clipboard">Kopiraj u privremenu memoriju</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Nije moguće sastaviti LNUrl iz Lightning adrese "%1$s". Proverite podešavanja korisnika</string>
|
||||
<string name="could_not_check_downloaded_file">Preuzeta datoteka se ne može proveriti nakon otpremanja: %1$s</string>
|
||||
@@ -2820,10 +2815,8 @@
|
||||
<string name="share_hls_video">HLS otpremanje</string>
|
||||
<string name="share_or_save">Podeli ili sačuvaj</string>
|
||||
<string name="shorts">Kratki snimci</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Prikaži QR kod šifrovanog privatnog ključa</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Uključi direktne i grupne poruke na kartici Obaveštenja. Isključite da poruke budu samo na kartici Poruke.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Prikaži poruke</string>
|
||||
<string name="show_private_key_qr_code">Prikaži QR kod privatnog ključa</string>
|
||||
<string name="sign_request_rejected2">Zahtev za potpisivanje odbijen</string>
|
||||
<string name="sign_request_rejected_description">Proverite da li je aplikacija za potpisivanje odobrila ovu transakciju</string>
|
||||
<string name="signer_illegal_state_exception_description">Spoljni potpisnik je vratio podatke koji su neočekivani za zahtev. Možda postoji greška u Amethyst-u ili aplikaciji za potpisivanje.</string>
|
||||
|
||||
@@ -545,7 +545,6 @@
|
||||
<string name="relays"> Reläer</string>
|
||||
<string name="website">Websida</string>
|
||||
<string name="lightning_address">Lightning Adress</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Kopierar Nsec ID (ditt lösenord) till urklipp för säkerhetskopiering</string>
|
||||
<string name="send_a_direct_message">Skicka ett direkt meddelande</string>
|
||||
<string name="edits_the_user_s_metadata">Redigerar användarens metadata</string>
|
||||
<string name="unblock">Sluta blockera</string>
|
||||
@@ -654,14 +653,11 @@
|
||||
<string name="mark_all_known_as_read">Markera alla kända som lästa</string>
|
||||
<string name="mark_all_new_as_read">Markera alla nya som lästa</string>
|
||||
<string name="mark_all_as_read">Markera allt som läst</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="backup_keys_nudge_title">Säkerhetskopiera dina nycklar</string>
|
||||
<string name="backup_keys_nudge_body">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.</string>
|
||||
<string name="backup_keys_nudge_backup_now">Säkerhetskopiera nu</string>
|
||||
<string name="backup_keys_nudge_already_saved">Jag har sparat dem</string>
|
||||
<string name="backup_keys_nudge_dismiss">Avfärda</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Kryptera och kopiera min hemliga nyckel</string>
|
||||
<string name="badge_award_image_for">Tilldelad Badge för %1$s</string>
|
||||
<string name="badge_award_image">Bild på utmärkelse</string>
|
||||
<string name="new_badge_award_notif">Du har blivit tilldelad en ny Badge</string>
|
||||
@@ -3577,7 +3573,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Kopierade anteckningstext till urklipp</string>
|
||||
<string name="copied_to_clipboard">Kopierat till urklipp</string>
|
||||
<string name="copied_user_id_to_clipboard">Kopierade författarens @npub till urklipp</string>
|
||||
<string name="copy_my_secret_key">Kopiera min hemliga nyckel</string>
|
||||
<string name="copy_to_clipboard">Kopiera till Urklipp</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Kunde inte montera LNUrl från Lightning Address "%1$s". Kontrollera användarens konfiguration</string>
|
||||
<string name="could_not_check_downloaded_file">Kunde inte kontrollera nedladdad fil efter uppladdning: %1$s</string>
|
||||
@@ -5040,10 +5035,8 @@
|
||||
<string name="share_hls_video">HLS-uppladdning</string>
|
||||
<string name="share_or_save">Dela eller Spara</string>
|
||||
<string name="shorts">Kortfilmer</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Visa QR-kod för krypterad privat nyckel</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Inkludera direktmeddelanden och gruppmeddelanden på fliken Aviseringar. Stäng av för att hålla meddelanden enbart på fliken Meddelanden.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Visa meddelanden</string>
|
||||
<string name="show_private_key_qr_code">Visa QR-kod för privat nyckel</string>
|
||||
<string name="sign_request_rejected2">Signeringsförfrågan avvisad</string>
|
||||
<string name="sign_request_rejected_description">Kontrollera att signeringsprogrammet har godkänt denna transaktion</string>
|
||||
<string name="signer_illegal_state_exception_description">Extern signatär returnerade data som är ovanliga för begäran. Det kan finnas en bugg i antingen Amethyst eller signatären.</string>
|
||||
|
||||
@@ -213,7 +213,6 @@
|
||||
<string name="number_reports">%1$s Ripoti</string>
|
||||
<string name="website">Tovuti</string>
|
||||
<string name="lightning_address">Anwani ya Umeme</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Hunakili Kitambulisho cha Nsec (nywila yako) kwenye ubao wa kunakili kwa ajili ya nakala rudufu</string>
|
||||
<string name="send_a_direct_message">Tuma Ujumbe wa Moja kwa Moja</string>
|
||||
<string name="edits_the_user_s_metadata">Huhariri Metadata ya Mtumiaji</string>
|
||||
<string name="unblock">Fungua</string>
|
||||
@@ -268,9 +267,6 @@
|
||||
<string name="mark_all_known_as_read">Funga kama Zimejulikana</string>
|
||||
<string name="mark_all_new_as_read">Funga kama Mpya</string>
|
||||
<string name="mark_all_as_read">Funga kama Zimejulikana</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Simba na nakili ufunguo wangu wa siri</string>
|
||||
<string name="badge_award_image_for">Picha ya tuzo ya alama kwa %1$s</string>
|
||||
<string name="badge_award_image">"Picha ya tuzo ya beji</string>
|
||||
<string name="new_badge_award_notif">Umepokea Tuzo Mpya ya Alama</string>
|
||||
@@ -1999,7 +1995,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Maudhui ya dokezo yamenakiliwa kwenye ubao wa kunakili</string>
|
||||
<string name="copied_to_clipboard">Imenakiliwa kwenye ubao wa kunakili</string>
|
||||
<string name="copied_user_id_to_clipboard">Imesakinishwa @npub ya mwandishi kwa ubao wa kunakili</string>
|
||||
<string name="copy_my_secret_key">Nakili Ufunguo Wangu wa Siri</string>
|
||||
<string name="copy_to_clipboard">Nakili kwenye ubao wa kunakili</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Haikuweza kuunda LNUrl kutoka kwa Anwani ya Lightning "%1$s". Angalia mpangilio wa mtumiaji</string>
|
||||
<string name="could_not_check_downloaded_file">Haikuweza kukagua faili lililопakuliwa baada ya kupakia: %1$s</string>
|
||||
@@ -2795,10 +2790,8 @@
|
||||
<string name="share_hls_video">Pakia HLS</string>
|
||||
<string name="share_or_save">Shiriki au Hifadhi</string>
|
||||
<string name="shorts">Mafupi</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Onyesha msimbo wa QR wa ufunguo wa siri uliofichwa</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Jumuisha ujumbe wa moja kwa moja na wa kikundi kwenye kichupo cha Arifa. Zima ili kuweka ujumbe kwenye kichupo cha Ujumbe pekee.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Onyesha Ujumbe</string>
|
||||
<string name="show_private_key_qr_code">Onyesha msimbo wa QR wa ufunguo wa siri</string>
|
||||
<string name="sign_request_rejected2">Ombi la kusaini limekataliwa</string>
|
||||
<string name="sign_request_rejected_description">Hakikisha programu ya kusaini imeidhinisha muamala huu</string>
|
||||
<string name="signer_illegal_state_exception_description">Msimamizi wa nje alirejesha data ya ajabu kwa ombi hili. Huenda kuna hitilafu katika Amethyst au Msimamizi.</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays"> ரிலேகள்</string>
|
||||
<string name="website">இணையதளம்</string>
|
||||
<string name="lightning_address">லைட்னிங் முகவரி</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Nsec IDயை (உங்கள் கடவுச்சொல்) காப்புப்பிரதிக்காக கிளிப்போர்டுக்கு நகலெடுக்கிறது</string>
|
||||
<string name="send_a_direct_message">நேரடிச் செய்தியை அனுப்பு</string>
|
||||
<string name="edits_the_user_s_metadata">பயனரின் தகவலை திருத்துகிறது</string>
|
||||
<string name="unblock">தடையை நீக்கு</string>
|
||||
@@ -272,9 +271,6 @@
|
||||
<string name="mark_all_known_as_read">தெரிந்தவற்றைப் படித்ததாகக் குறி</string>
|
||||
<string name="mark_all_new_as_read">புதியனவற்றைப் படித்ததாகக் குறி</string>
|
||||
<string name="mark_all_as_read">அனைத்தையும் படித்ததாகக் குறி</string>
|
||||
<string name="account_backup_tips2_md">## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம்.</string>
|
||||
<string name="account_backup_tips3_md">கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும்</string>
|
||||
<string name="badge_award_image_for">%1$s க்கான பேட்ஜ் விருது படம்</string>
|
||||
<string name="badge_award_image">"பேட்ஜ் விருது படம்</string>
|
||||
<string name="new_badge_award_notif">நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள்</string>
|
||||
@@ -1999,7 +1995,6 @@
|
||||
<string name="copied_note_text_to_clipboard">குறிப்பு கிளிப்போர்டுக்கு நகலெடுக்கப் பட்டது</string>
|
||||
<string name="copied_to_clipboard">கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது</string>
|
||||
<string name="copied_user_id_to_clipboard">கிளிப்போர்டுக்கு எழுத்தாளரின் @npub நகலெடுக்கப் பட்டது</string>
|
||||
<string name="copy_my_secret_key">எனது ரகசிய சாவியை நகலெடுக்கவும்</string>
|
||||
<string name="copy_to_clipboard">கிளிப்போர்டுக்கு நகலெடு</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning முகவரி "%1$s" இலிருந்து LNUrl ஐ உருவாக்க முடியவில்லை. பயனரின் அமைப்பை சரிபார்க்கவும்</string>
|
||||
<string name="could_not_check_downloaded_file">பதிவேற்றத்திற்குப் பிறகு பதிவிறக்கிய கோப்பை சரிபார்க்க முடியவில்லை: %1$s</string>
|
||||
@@ -2784,10 +2779,8 @@
|
||||
<string name="share_hls_video">HLS பதிவேற்றம்</string>
|
||||
<string name="share_or_save">பகிர் அல்லது சேமி</string>
|
||||
<string name="shorts">குறுவீடியோக்கள்</string>
|
||||
<string name="show_encrypted_private_key_qr_code">மறைகுறியாக்கப்பட்ட தனிப்பட்ட விசை QR குறியீட்டை காட்டு</string>
|
||||
<string name="show_messages_in_notifications_setting_description">அறிவிப்பு தாவலில் நேரடி மற்றும் குழு செய்திகளை சேர்க்கவும். செய்திகளை செய்திகள் தாவலில் மட்டும் வைக்க அணைக்கவும்.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">செய்திகளை காட்டு</string>
|
||||
<string name="show_private_key_qr_code">தனிப்பட்ட விசை QR குறியீட்டை காட்டு</string>
|
||||
<string name="sign_request_rejected2">கையொப்பமிடல் கோரிக்கை நிராகரிக்கப்பட்டது</string>
|
||||
<string name="sign_request_rejected_description">கையொப்பமிடல் செயலி இந்த பரிவர்த்தனையை அங்கீகரித்திருக்கிறதா என சரிபார்க்கவும்</string>
|
||||
<string name="signer_illegal_state_exception_description">வெளிப்புற கையெழுத்திட்டவர் கோரிக்கைக்கு அசாதாரணமான தரவை திரும்ப அனுப்பியது. Amethyst அல்லது கையெழுத்திட்டவரில் ஒரு பிழை இருக்கலாம்.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays"> ரிலேகள்</string>
|
||||
<string name="website">இணையதளம்</string>
|
||||
<string name="lightning_address">லைட்னிங் முகவரி</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Nsec IDயை (உங்கள் கடவுச்சொல்) காப்புப்பிரதிக்காக கிளிப்போர்டுக்கு நகலெடுக்கிறது</string>
|
||||
<string name="send_a_direct_message">நேரடிச் செய்தியை அனுப்பு</string>
|
||||
<string name="edits_the_user_s_metadata">பயனரின் தகவலை திருத்துகிறது</string>
|
||||
<string name="unblock">தடையை நீக்கு</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">தெரிந்தவற்றைப் படித்ததாகக் குறி</string>
|
||||
<string name="mark_all_new_as_read">புதியனவற்றைப் படித்ததாகக் குறி</string>
|
||||
<string name="mark_all_as_read">அனைத்தையும் படித்ததாகக் குறி</string>
|
||||
<string name="account_backup_tips2_md">## திறவுகோல் காப்புப்பிரதி மற்றும் பாதுகாப்பு குறிப்புகள் \n\nஉங்கள் கணக்கு ஒரு இரகசிய திறவுகோலால் பாதுகாக்கப்படுகிறது. இந்த திறவுகோல் **nsec1** என்று தொடங்கும் நீண்ட எழுத்துத் தொடராகும். இந்த இரகசிய திறவுகோலை யாராவது பெற்றால் அவர்கள் உங்கள் அடையாளத்தை பயன்படுத்தி இடுகையிடலாம் மற்றும் மாற்றலாம். \n\n- உங்கள் இரகசிய திறவுகோலை நீங்கள் நம்பாத எந்த வலைத்தளத்திலும் அல்லது மென்பொருளிலும் வைக்க **வேண்டாம்**. \n- Amethyst டெவலப்பர்கள் உங்கள் இரகசிய திறவுகோலை **ஒருபோதும்** கேட்கமாட்டார்கள். \n- கணக்கு மீட்டெடுப்புக்காக உங்கள் இரகசிய திறவுகோலை பாதுகாப்பாக காப்புப்பிரதி எடுங்கள். கடவுச்சொல் மேலாளரை பயன்படுத்த பரிந்துரைக்கிறோம்.</string>
|
||||
<string name="account_backup_tips3_md">கூடுதல் பாதுகாப்புக்காக, உங்கள் திறவுகோலை கடவுச்சொல்லால் குறியாக்கலாம். இந்த திறவுகோல் **ncryptsec1** என்று தொடங்கும் மற்றும் உங்கள் கடவுச்சொல்லின்றி பயன்படுத்த முடியாது. \n\nகடவுச்சொல்லை மறந்தால், உங்கள் திறவுகோலை மீட்டெடுக்க முடியாது.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">என் இரகசிய விசையை மறைகுறியாக்கி நகல் எடுக்கவும்</string>
|
||||
<string name="badge_award_image_for">%1$s க்கான பேட்ஜ் விருது படம்</string>
|
||||
<string name="badge_award_image">"பேட்ஜ் விருது படம்</string>
|
||||
<string name="new_badge_award_notif">நீங்கள் ஒரு புதிய பேட்ஜ் விருதைப் பெற்றீர்கள்</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">குறிப்பு கிளிப்போர்டுக்கு நகலெடுக்கப் பட்டது</string>
|
||||
<string name="copied_to_clipboard">கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது</string>
|
||||
<string name="copied_user_id_to_clipboard">கிளிப்போர்டுக்கு எழுத்தாளரின் @npub நகலெடுக்கப் பட்டது</string>
|
||||
<string name="copy_my_secret_key">எனது ரகசிய சாவியை நகலெடுக்கவும்</string>
|
||||
<string name="copy_to_clipboard">கிளிப்போர்டுக்கு நகலெடு</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning முகவரி "%1$s" இலிருந்து LNUrl ஐ உருவாக்க முடியவில்லை. பயனரின் அமைப்பை சரிபார்க்கவும்</string>
|
||||
<string name="could_not_check_downloaded_file">பதிவேற்றத்திற்குப் பிறகு பதிவிறக்கிய கோப்பை சரிபார்க்க முடியவில்லை: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">HLS பதிவேற்றம்</string>
|
||||
<string name="share_or_save">பகிர் அல்லது சேமி</string>
|
||||
<string name="shorts">குறுவீடியோக்கள்</string>
|
||||
<string name="show_encrypted_private_key_qr_code">மறைகுறியாக்கப்பட்ட தனிப்பட்ட விசை QR குறியீட்டை காட்டு</string>
|
||||
<string name="show_messages_in_notifications_setting_description">அறிவிப்பு தாவலில் நேரடி மற்றும் குழு செய்திகளை சேர்க்கவும். செய்திகளை செய்திகள் தாவலில் மட்டும் வைக்க அணைக்கவும்.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">செய்திகளை காட்டு</string>
|
||||
<string name="show_private_key_qr_code">தனிப்பட்ட விசை QR குறியீட்டை காட்டு</string>
|
||||
<string name="sign_request_rejected2">கையொப்பமிடல் கோரிக்கை நிராகரிக்கப்பட்டது</string>
|
||||
<string name="sign_request_rejected_description">கையொப்பமிடல் செயலி இந்த பரிவர்த்தனையை அங்கீகரித்திருக்கிறதா என சரிபார்க்கவும்</string>
|
||||
<string name="signer_illegal_state_exception_description">வெளிப்புற கையெழுத்திட்டவர் கோரிக்கைக்கு அசாதாரணமான தரவை திரும்ப அனுப்பியது. Amethyst அல்லது கையெழுத்திட்டவரில் ஒரு பிழை இருக்கலாம்.</string>
|
||||
|
||||
@@ -215,7 +215,6 @@
|
||||
<string name="relays"> รีเลย์</string>
|
||||
<string name="website">เว็บไซต์</string>
|
||||
<string name="lightning_address">ไม่ได้ตั้งค่า Lightning Address</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">คัดลอก Nsec ID (รหัสผ่านของคุณ) ลงคลิปบอร์ดเพื่อสำรองข้อมูล</string>
|
||||
<string name="send_a_direct_message">ส่งข้อความส่วนตัว</string>
|
||||
<string name="edits_the_user_s_metadata">แก้ไข the User's Metadata</string>
|
||||
<string name="unblock">เลิกบล๊อก</string>
|
||||
@@ -269,9 +268,6 @@
|
||||
<string name="mark_all_known_as_read">ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด</string>
|
||||
<string name="mark_all_new_as_read">ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่</string>
|
||||
<string name="mark_all_as_read">ทพเครื่องหมายว่าอ่านแล้วทั้งหมด</string>
|
||||
<string name="account_backup_tips2_md">## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน</string>
|
||||
<string name="account_backup_tips3_md">สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน</string>
|
||||
<string name="badge_award_image_for">ภาพเหรียญตราสําหรับ %1$s</string>
|
||||
<string name="badge_award_image">"รูปภาพรางวัลป้าย</string>
|
||||
<string name="new_badge_award_notif">คุณได้รับเหรียญตราใหม่</string>
|
||||
@@ -1972,7 +1968,6 @@
|
||||
<string name="copied_note_text_to_clipboard">คัดลอกข่้อความในโน้ตลงคลิปบอร์ด</string>
|
||||
<string name="copied_to_clipboard">คัดลอกไปยังคลิปบอร์ดแล้ว</string>
|
||||
<string name="copied_user_id_to_clipboard">คัดลอก @npub ของผู้เขียนลงคลิปบอร์ด</string>
|
||||
<string name="copy_my_secret_key">คัดลอก secret key ของฉัน</string>
|
||||
<string name="copy_to_clipboard">คัดลอก</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">ไม่สามารถสร้าง LNUrl จากที่อยู่ Lightning ได้ "%1$s" โปรดตรวจสอบการตั้งค่า</string>
|
||||
<string name="could_not_check_downloaded_file">ไม่สามารถตรวจสอบไฟล์ที่ดาวน์โหลดหลังจากอัปโหลด: %1$s</string>
|
||||
@@ -2624,10 +2619,8 @@
|
||||
<string name="share_as_image_url">แชร์เป็น URL รูปภาพ</string>
|
||||
<string name="share_hls_video">อัปโหลด HLS</string>
|
||||
<string name="share_or_save">แชร์ หรือเก็บไว้</string>
|
||||
<string name="show_encrypted_private_key_qr_code">แสดง QR code คีย์ส่วนตัวแบบเข้ารหัส</string>
|
||||
<string name="show_messages_in_notifications_setting_description">รวมข้อความส่วนตัวและกลุ่มในแท็บการแจ้งเตือน ปิดเพื่อเก็บข้อความไว้เฉพาะในแท็บข้อความ</string>
|
||||
<string name="show_messages_in_notifications_setting_title">แสดงข้อความ</string>
|
||||
<string name="show_private_key_qr_code">แสดง QR code คีย์ส่วนตัว</string>
|
||||
<string name="sign_request_rejected2">คำขอลงชื่อถูกปฏิเสธ</string>
|
||||
<string name="sign_request_rejected_description">โปรดตรวจสอบให้แน่ใจว่าแอพเข้ารหัส หรือ Signer ได้อนุญาติทำรายการนี้</string>
|
||||
<string name="signer_illegal_state_exception_description">ผู้ลงนามภายนอกส่งคืนข้อมูลที่ผิดปกติสำหรับคำขอนี้ อาจมีข้อผิดพลาดใน Amethyst หรือแอปผู้ลงนาม</string>
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
<string name="relays"> รีเลย์</string>
|
||||
<string name="website">เว็บไซต์</string>
|
||||
<string name="lightning_address">ไม่ได้ตั้งค่า Lightning Address</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">คัดลอก Nsec ID (รหัสผ่านของคุณ) ลงคลิปบอร์ดเพื่อสำรองข้อมูล</string>
|
||||
<string name="send_a_direct_message">ส่งข้อความส่วนตัว</string>
|
||||
<string name="edits_the_user_s_metadata">แก้ไข the User's Metadata</string>
|
||||
<string name="unblock">เลิกบล๊อก</string>
|
||||
@@ -257,9 +256,6 @@
|
||||
<string name="mark_all_known_as_read">ทำเครื่องหมายอ่านแล้วในแชทที่รู้จักทั้งหมด</string>
|
||||
<string name="mark_all_new_as_read">ทำเครื่องหมายว่าอ่านแล้วทั้งหมดสำหรับข้อความใหม่</string>
|
||||
<string name="mark_all_as_read">ทพเครื่องหมายว่าอ่านแล้วทั้งหมด</string>
|
||||
<string name="account_backup_tips2_md">## เคล็ดลับการสำรองข้อมูลและความปลอดภัยที่สำคัญ \n\nบัญชีของคุณได้รับการรักษาความปลอดภัยด้วยคีย์ลับ คีย์เป็นรหัสชุดตัวอักษรยาวขึ้นต้นด้วย **nsec1** ใครก็ตามที่สามารถเข้าถึงรหัสชุดนี้ได้ จะสามารถโพสต์และเปลี่ยนแปลงข้อมูลประจำตัวของคุณได้ \n\n- **ห้าม** ใส่รหัสชุดนี้ในเว็บไซต์หรือซอฟต์แวร์ที่คุณไม่ไว้ใจ \n- ทีมพัฒนา Amethyst **จะไม่มีวัน** ขอรหัสชุดนี้ของคุณ \n- **ควร** สำรองข้อมูลรหัสชุดนี้ไว้เพื่อกู้คืนบัญชีของคุณ เราแนะนำให้ใช้โปรแกรมจัดการรหัสผ่าน</string>
|
||||
<string name="account_backup_tips3_md">สำหรับการรักษาความปลอดภัยเพิ่มเติม คุณสามารถเข้ารหัสคีย์ของคุณด้วยรหัสผ่าน คีย์นี้ขึ้นต้นด้วย **ncryptsec1** และไม่สามารถใช้งานได้หากไม่มีรหัสผ่านของคุณ \n\n**แต่** หากคุณสูญหายรหัสผ่าน คุณจะไม่สามารถกู้คืนคีย์ของคุณได้</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">เข้ารหัสและคัดลอกคีย์ความปลอดภัยของฉัน</string>
|
||||
<string name="badge_award_image_for">ภาพเหรียญตราสําหรับ %1$s</string>
|
||||
<string name="badge_award_image">"รูปภาพรางวัลป้าย</string>
|
||||
<string name="new_badge_award_notif">คุณได้รับเหรียญตราใหม่</string>
|
||||
@@ -2028,7 +2024,6 @@
|
||||
<string name="copied_note_text_to_clipboard">คัดลอกข่้อความในโน้ตลงคลิปบอร์ด</string>
|
||||
<string name="copied_to_clipboard">คัดลอกไปยังคลิปบอร์ดแล้ว</string>
|
||||
<string name="copied_user_id_to_clipboard">คัดลอก @npub ของผู้เขียนลงคลิปบอร์ด</string>
|
||||
<string name="copy_my_secret_key">คัดลอก secret key ของฉัน</string>
|
||||
<string name="copy_to_clipboard">คัดลอก</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">ไม่สามารถสร้าง LNUrl จากที่อยู่ Lightning ได้ "%1$s" โปรดตรวจสอบการตั้งค่า</string>
|
||||
<string name="could_not_check_downloaded_file">ไม่สามารถตรวจสอบไฟล์ที่ดาวน์โหลดหลังจากอัปโหลด: %1$s</string>
|
||||
@@ -2827,10 +2822,8 @@
|
||||
<string name="share_hls_video">อัปโหลด HLS</string>
|
||||
<string name="share_or_save">แชร์ หรือเก็บไว้</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">แสดง QR code คีย์ส่วนตัวแบบเข้ารหัส</string>
|
||||
<string name="show_messages_in_notifications_setting_description">รวมข้อความส่วนตัวและกลุ่มในแท็บการแจ้งเตือน ปิดเพื่อเก็บข้อความไว้เฉพาะในแท็บข้อความ</string>
|
||||
<string name="show_messages_in_notifications_setting_title">แสดงข้อความ</string>
|
||||
<string name="show_private_key_qr_code">แสดง QR code คีย์ส่วนตัว</string>
|
||||
<string name="sign_request_rejected2">คำขอลงชื่อถูกปฏิเสธ</string>
|
||||
<string name="sign_request_rejected_description">โปรดตรวจสอบให้แน่ใจว่าแอพเข้ารหัส หรือ Signer ได้อนุญาติทำรายการนี้</string>
|
||||
<string name="signer_illegal_state_exception_description">ผู้ลงนามภายนอกส่งคืนข้อมูลที่ผิดปกติสำหรับคำขอนี้ อาจมีข้อผิดพลาดใน Amethyst หรือแอปผู้ลงนาม</string>
|
||||
|
||||
@@ -217,7 +217,6 @@
|
||||
<string name="relays">Relaylar</string>
|
||||
<string name="website">Web Sitesi</string>
|
||||
<string name="lightning_address">Lİghtning Adresi</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Yedekleme için Nsec ID'yi (sizin şifreniz) panoya kopyalar</string>
|
||||
<string name="send_a_direct_message">Direkt Mesaj Gönder</string>
|
||||
<string name="edits_the_user_s_metadata">Kullanıcının Üstverisini Düzenler</string>
|
||||
<string name="unblock">Engelleme</string>
|
||||
@@ -272,9 +271,6 @@
|
||||
<string name="mark_all_known_as_read">Tüm bilinenleri okundu olarak işaretle</string>
|
||||
<string name="mark_all_new_as_read">Tüm yenileri okundu olarak işaretle</string>
|
||||
<string name="mark_all_as_read">Tümünü okundu olarak işaretle</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Gizli anahtarımı şifrele ve kopyala</string>
|
||||
<string name="badge_award_image_for">%1$s için rozet ödülü görseli</string>
|
||||
<string name="badge_award_image">"Rozet ödülü görseli</string>
|
||||
<string name="new_badge_award_notif">Yeni bir Rozet Ödülü aldınız</string>
|
||||
@@ -2007,7 +2003,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Not metni panoya kopyalandı</string>
|
||||
<string name="copied_to_clipboard">Panoya kopyalandı</string>
|
||||
<string name="copied_user_id_to_clipboard">Yazarın @npub'ı panoya kopyalandı</string>
|
||||
<string name="copy_my_secret_key">Gizli anahtarımı kopyala</string>
|
||||
<string name="copy_to_clipboard">Panoya kopyala</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">"%1$s" Lightning Adresinden LNUrl oluşturulamadı. Kullanıcının kurulumunu kontrol edin</string>
|
||||
<string name="could_not_check_downloaded_file">Yükleme sonrası indirilen dosya kontrol edilemedi: %1$s</string>
|
||||
@@ -2789,10 +2784,8 @@
|
||||
<string name="share_hls_video">HLS Yükle</string>
|
||||
<string name="share_or_save">Paylaş veya Kaydet</string>
|
||||
<string name="shorts">Kısa videolar</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Şifreli özel anahtar QR kodunu göster</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Bildirim sekmesine doğrudan ve grup mesajlarını dahil et. Mesajları yalnızca Mesajlar sekmesinde tutmak için kapatın.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mesajları Göster</string>
|
||||
<string name="show_private_key_qr_code">Özel anahtar QR kodunu göster</string>
|
||||
<string name="sign_request_rejected2">İmza isteği reddedildi</string>
|
||||
<string name="sign_request_rejected_description">İmzalayıcı uygulamanın bu işlemi yetkilendirdiğinden emin olun</string>
|
||||
<string name="signer_illegal_state_exception_description">Harici imzalayıcı, istek için beklenmedik bir yük döndürdü. Amethyst veya İmzalayıcıda bir hata olabilir.</string>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<string name="relays">Relaylar</string>
|
||||
<string name="website">Web Sitesi</string>
|
||||
<string name="lightning_address">Lİghtning Adresi</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Yedekleme için Nsec ID'yi (sizin şifreniz) panoya kopyalar</string>
|
||||
<string name="send_a_direct_message">Direkt Mesaj Gönder</string>
|
||||
<string name="edits_the_user_s_metadata">Kullanıcının Üstverisini Düzenler</string>
|
||||
<string name="unblock">Engelleme</string>
|
||||
@@ -259,9 +258,6 @@
|
||||
<string name="mark_all_known_as_read">Tüm bilinenleri okundu olarak işaretle</string>
|
||||
<string name="mark_all_new_as_read">Tüm yenileri okundu olarak işaretle</string>
|
||||
<string name="mark_all_as_read">Tümünü okundu olarak işaretle</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Gizli anahtarımı şifrele ve kopyala</string>
|
||||
<string name="badge_award_image_for">%1$s için rozet ödülü görseli</string>
|
||||
<string name="badge_award_image">"Rozet ödülü görseli</string>
|
||||
<string name="new_badge_award_notif">Yeni bir Rozet Ödülü aldınız</string>
|
||||
@@ -2038,7 +2034,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Not metni panoya kopyalandı</string>
|
||||
<string name="copied_to_clipboard">Panoya kopyalandı</string>
|
||||
<string name="copied_user_id_to_clipboard">Yazarın @npub'ı panoya kopyalandı</string>
|
||||
<string name="copy_my_secret_key">Gizli anahtarımı kopyala</string>
|
||||
<string name="copy_to_clipboard">Panoya kopyala</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">"%1$s" Lightning Adresinden LNUrl oluşturulamadı. Kullanıcının kurulumunu kontrol edin</string>
|
||||
<string name="could_not_check_downloaded_file">Yükleme sonrası indirilen dosya kontrol edilemedi: %1$s</string>
|
||||
@@ -2863,10 +2858,8 @@
|
||||
<string name="share_hls_video">HLS Yükle</string>
|
||||
<string name="share_or_save">Paylaş veya Kaydet</string>
|
||||
<string name="shorts">Kısa videolar</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Şifreli özel anahtar QR kodunu göster</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Bildirim sekmesine doğrudan ve grup mesajlarını dahil et. Mesajları yalnızca Mesajlar sekmesinde tutmak için kapatın.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Mesajları Göster</string>
|
||||
<string name="show_private_key_qr_code">Özel anahtar QR kodunu göster</string>
|
||||
<string name="sign_request_rejected2">İmza isteği reddedildi</string>
|
||||
<string name="sign_request_rejected_description">İmzalayıcı uygulamanın bu işlemi yetkilendirdiğinden emin olun</string>
|
||||
<string name="signer_illegal_state_exception_description">Harici imzalayıcı, istek için beklenmedik bir yük döndürdü. Amethyst veya İmzalayıcıda bir hata olabilir.</string>
|
||||
|
||||
@@ -218,7 +218,6 @@
|
||||
<string name="relays"> Релеїв</string>
|
||||
<string name="website">Сайт</string>
|
||||
<string name="lightning_address">Lightning адреса</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Копіює Nsec ID (ваш пароль) для резервного копіювання</string>
|
||||
<string name="send_a_direct_message">Відправити повідомлення</string>
|
||||
<string name="edits_the_user_s_metadata">Редагує метадані користувача</string>
|
||||
<string name="unblock">Розблокувати</string>
|
||||
@@ -273,9 +272,6 @@
|
||||
<string name="mark_all_known_as_read">Позначити всі відомі прочитаними</string>
|
||||
<string name="mark_all_new_as_read">Позначити всі нові прочитаними</string>
|
||||
<string name="mark_all_as_read">Позначити все прочитаним</string>
|
||||
<string name="account_backup_tips2_md">## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів.</string>
|
||||
<string name="account_backup_tips3_md">Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Зашифрувати та скопіювати мій секретний ключ</string>
|
||||
<string name="badge_award_image_for">Картинка значка-нагороди %1$s</string>
|
||||
<string name="badge_award_image">"Зображення нагороди значком</string>
|
||||
<string name="new_badge_award_notif">Ви отримали в нагороду новий значок</string>
|
||||
@@ -2020,7 +2016,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Скопіювати текст</string>
|
||||
<string name="copied_to_clipboard">Скопійовано до буфера обміну</string>
|
||||
<string name="copied_user_id_to_clipboard">ID (npub) автора скопійовано</string>
|
||||
<string name="copy_my_secret_key">Скопіювати мій приватний ключ</string>
|
||||
<string name="copy_to_clipboard">Скопіювати в буфер</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Не вдалося скласти LNUrl з Lightning адреси «%1$s». Перевірте налаштування користувача</string>
|
||||
<string name="could_not_check_downloaded_file">Не вдалося перевірити завантажений файл після вивантаження: %1$s</string>
|
||||
@@ -2845,10 +2840,8 @@
|
||||
<string name="share_as_image">Поділитися як зображення</string>
|
||||
<string name="share_as_image_url">Поділитися як URL зображення</string>
|
||||
<string name="share_or_save">Поділитися або зберегти</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Показати QR-код зашифрованого приватного ключа</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Включати особисті та групові повідомлення на вкладку «Сповіщення». Вимкніть, щоб залишити повідомлення лише на вкладці «Повідомлення».</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Показувати повідомлення</string>
|
||||
<string name="show_private_key_qr_code">Показати QR-код приватного ключа</string>
|
||||
<string name="sign_request_rejected2">Запит на підписання відхилено</string>
|
||||
<string name="sign_request_rejected_description">Переконайтеся, що застосунок-підписант авторизував цю транзакцію</string>
|
||||
<string name="signer_illegal_state_exception_description">Зовнішній підписувач повернув дані, що не відповідають запиту. Можливо, є помилка в Amethyst або підписувачі.</string>
|
||||
|
||||
@@ -208,7 +208,6 @@
|
||||
<string name="relays"> Релеїв</string>
|
||||
<string name="website">Сайт</string>
|
||||
<string name="lightning_address">Lightning адреса</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Копіює Nsec ID (ваш пароль) для резервного копіювання</string>
|
||||
<string name="send_a_direct_message">Відправити повідомлення</string>
|
||||
<string name="edits_the_user_s_metadata">Редагує метадані користувача</string>
|
||||
<string name="unblock">Розблокувати</string>
|
||||
@@ -263,9 +262,6 @@
|
||||
<string name="mark_all_known_as_read">Позначити всі відомі прочитаними</string>
|
||||
<string name="mark_all_new_as_read">Позначити всі нові прочитаними</string>
|
||||
<string name="mark_all_as_read">Позначити все прочитаним</string>
|
||||
<string name="account_backup_tips2_md">## Поради щодо резервного копіювання та безпеки ключа \n\nВаш обліковий запис захищений секретним ключем. Ключ — це довга послідовність символів, що починається з **nsec1**. Будь-хто, хто має доступ до цього секретного ключа, може публікувати та змінювати вашу особу. \n\n- **Не** вводьте свій секретний ключ на жодному сайті чи в програмі, якій ви не довіряєте. \n- Розробники Amethyst **ніколи** не запитуватимуть ваш секретний ключ. \n- **Зробіть** надійне резервне копіювання секретного ключа для відновлення облікового запису. Рекомендуємо використовувати менеджер паролів.</string>
|
||||
<string name="account_backup_tips3_md">Для додаткової безпеки ви можете зашифрувати ключ паролем. Цей ключ починається з **ncryptsec1** і не може бути використаний без вашого пароля. \n\nЯкщо ви забудете пароль, ви не зможете відновити ключ.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Зашифрувати та скопіювати мій секретний ключ</string>
|
||||
<string name="badge_award_image_for">Картинка значка-нагороди %1$s</string>
|
||||
<string name="badge_award_image">"Зображення нагороди значком</string>
|
||||
<string name="new_badge_award_notif">Ви отримали в нагороду новий значок</string>
|
||||
@@ -2058,7 +2054,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Скопіювати текст</string>
|
||||
<string name="copied_to_clipboard">Скопійовано до буфера обміну</string>
|
||||
<string name="copied_user_id_to_clipboard">ID (npub) автора скопійовано</string>
|
||||
<string name="copy_my_secret_key">Скопіювати мій приватний ключ</string>
|
||||
<string name="copy_to_clipboard">Скопіювати в буфер</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Не вдалося скласти LNUrl з Lightning адреси «%1$s». Перевірте налаштування користувача</string>
|
||||
<string name="could_not_check_downloaded_file">Не вдалося перевірити завантажений файл після вивантаження: %1$s</string>
|
||||
@@ -2935,10 +2930,8 @@
|
||||
<string name="share_hls_video">HLS Upload</string>
|
||||
<string name="share_or_save">Поділитися або зберегти</string>
|
||||
<string name="shorts">Shorts</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Показати QR-код зашифрованого приватного ключа</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Включати особисті та групові повідомлення на вкладку «Сповіщення». Вимкніть, щоб залишити повідомлення лише на вкладці «Повідомлення».</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Показувати повідомлення</string>
|
||||
<string name="show_private_key_qr_code">Показати QR-код приватного ключа</string>
|
||||
<string name="sign_request_rejected2">Запит на підписання відхилено</string>
|
||||
<string name="sign_request_rejected_description">Переконайтеся, що застосунок-підписант авторизував цю транзакцію</string>
|
||||
<string name="signer_illegal_state_exception_description">Зовнішній підписувач повернув дані, що не відповідають запиту. Можливо, є помилка в Amethyst або підписувачі.</string>
|
||||
|
||||
@@ -218,7 +218,6 @@
|
||||
<string name="relays"> Relay lar</string>
|
||||
<string name="website">Veb-sayt</string>
|
||||
<string name="lightning_address">Lightning manzili</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Nsec ID (parolingiz) nusxasini zaxiralash uchun buferga nusxalaydi</string>
|
||||
<string name="send_a_direct_message">To'g'ridan-to'g'ri xabar yuborish</string>
|
||||
<string name="edits_the_user_s_metadata">Foydalanuvchi metama'lumotlarini tahrirlaydi</string>
|
||||
<string name="unblock">Blokdan chiqarish</string>
|
||||
@@ -273,9 +272,6 @@
|
||||
<string name="mark_all_known_as_read">Barcha ma'lumlarni o'qilgan deb belgilash</string>
|
||||
<string name="mark_all_new_as_read">Barcha yangilarni o'qilgan deb belgilash</string>
|
||||
<string name="mark_all_as_read">Barchasini o'qilgan deb belgilash</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Maxfiy kalitni shifrlash va nusxalash</string>
|
||||
<string name="badge_award_image_for">%1$s uchun nishon mukofoti rasmi</string>
|
||||
<string name="badge_award_image">"Nishon mukofoti rasmi</string>
|
||||
<string name="new_badge_award_notif">Siz yangi nishon mukofoti oldingiz</string>
|
||||
@@ -1995,7 +1991,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Eslatma matni buferga nusxalandi</string>
|
||||
<string name="copied_to_clipboard">Buferga nusxalandi</string>
|
||||
<string name="copied_user_id_to_clipboard">Muallifning @npub manzili buferga nusxalandi</string>
|
||||
<string name="copy_my_secret_key">Mening maxfiy kalitimni nusxalash</string>
|
||||
<string name="copy_to_clipboard">Buferga nusxalash</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Lightning manzilidan LNUrl yig'ib bo'lmadi "%1$s". Foydalanuvchi sozlamasini tekshiring</string>
|
||||
<string name="could_not_check_downloaded_file">Yuklashdan keyin yuklab olingan faylni tekshirib bo'lmadi: %1$s</string>
|
||||
@@ -2798,10 +2793,8 @@
|
||||
<string name="share_hls_video">HLS yuklash</string>
|
||||
<string name="share_or_save">Ulashish yoki saqlash</string>
|
||||
<string name="shorts">Shortslar</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Shifrlangan shaxsiy kalit QR kodini ko'rsatish</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Bildirishnoma yorlig'iga to'g'ridan-to'g'ri va guruh xabarlarini kiriting. Xabarlarni faqat Xabarlar yorlig'ida saqlash uchun o'chiring.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Xabarlarni Ko'rsatish</string>
|
||||
<string name="show_private_key_qr_code">Shaxsiy kalit QR kodini ko'rsatish</string>
|
||||
<string name="sign_request_rejected2">Imzo so'rovi rad etildi</string>
|
||||
<string name="sign_request_rejected_description">Imzolash ilovasi ushbu tranzaksiyaga ruxsat berganligini tekshiring</string>
|
||||
<string name="signer_illegal_state_exception_description">Tashqi imzolash dasturi so'rov uchun g'alati javob qaytardi. Amethyst yoki imzolash dasturida xato bo'lishi mumkin.</string>
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
<string name="relays"> Relay</string>
|
||||
<string name="website">Trang web</string>
|
||||
<string name="lightning_address">Địa chỉ Lightning</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Sao chép Nsec ID (mật khẩu của bạn) vào clipboard để sao lưu</string>
|
||||
<string name="send_a_direct_message">Gửi tin nhắn trực tiếp</string>
|
||||
<string name="edits_the_user_s_metadata">Chỉnh sửa siêu dữ liệu người dùng</string>
|
||||
<string name="unblock">Bỏ chặn</string>
|
||||
@@ -267,9 +266,6 @@
|
||||
<string name="mark_all_known_as_read">Đánh dấu tất cả đã biết là đã đọc</string>
|
||||
<string name="mark_all_new_as_read">Đánh dấu tất cả mới là đã đọc</string>
|
||||
<string name="mark_all_as_read">Đánh dấu tất cả là đã đọc</string>
|
||||
<string name="account_backup_tips2_md">## 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.</string>
|
||||
<string name="account_backup_tips3_md">Để 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.</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">Mã hóa và sao chép khóa bí mật của tôi</string>
|
||||
<string name="badge_award_image_for">Hình ảnh huy hiệu được trao cho %1$s</string>
|
||||
<string name="badge_award_image">"Hình ảnh huy hiệu được trao</string>
|
||||
<string name="new_badge_award_notif">Bạn đã nhận được huy hiệu mới</string>
|
||||
@@ -1983,7 +1979,6 @@
|
||||
<string name="copied_note_text_to_clipboard">Đã sao chép nội dung ghi chú vào clipboard</string>
|
||||
<string name="copied_to_clipboard">Đã sao chép vào clipboard</string>
|
||||
<string name="copied_user_id_to_clipboard">Đã sao chép @npub của tác giả vào clipboard</string>
|
||||
<string name="copy_my_secret_key">Sao chép khóa bí mật của tôi</string>
|
||||
<string name="copy_to_clipboard">Sao chép vào clipboard</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">Không thể tạo LNUrl từ Địa chỉ Lightning "%1$s". Hãy kiểm tra cài đặt của người dùng</string>
|
||||
<string name="could_not_check_downloaded_file">Không thể kiểm tra tệp đã tải xuống sau khi tải lên: %1$s</string>
|
||||
@@ -2746,10 +2741,8 @@
|
||||
<string name="share_as_image_url">Chia sẻ dưới dạng URL hình ảnh</string>
|
||||
<string name="share_hls_video">Tải lên HLS</string>
|
||||
<string name="share_or_save">Chia sẻ hoặc Lưu</string>
|
||||
<string name="show_encrypted_private_key_qr_code">Hiển thị mã QR khóa riêng tư đã mã hóa</string>
|
||||
<string name="show_messages_in_notifications_setting_description">Bao gồm tin nhắn trực tiếp và nhóm trên tab Thông báo. Tắt để chỉ giữ tin nhắn trong tab Tin nhắn.</string>
|
||||
<string name="show_messages_in_notifications_setting_title">Hiển thị tin nhắn</string>
|
||||
<string name="show_private_key_qr_code">Hiển thị mã QR khóa riêng tư</string>
|
||||
<string name="sign_request_rejected2">Yêu cầu ký bị từ chối</string>
|
||||
<string name="sign_request_rejected_description">Hãy đảm bảo ứng dụng ký đã cho phép giao dịch này</string>
|
||||
<string name="signer_illegal_state_exception_description">Trình ký bên ngoài trả về dữ liệu không hợp lệ cho yêu cầu. Có thể có lỗi trong Amethyst hoặc trong trình ký.</string>
|
||||
|
||||
@@ -303,7 +303,6 @@
|
||||
<string name="relays">中继</string>
|
||||
<string name="website">网站</string>
|
||||
<string name="lightning_address">闪电地址</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">复制 Nsec ID(您的私人密钥)到剪贴板以备备份</string>
|
||||
<string name="send_a_direct_message">发送直接消息</string>
|
||||
<string name="edits_the_user_s_metadata">编辑用户元数据</string>
|
||||
<string name="unblock">不隐藏</string>
|
||||
@@ -389,9 +388,6 @@
|
||||
<string name="mark_all_known_as_read">将所有已知内容标记为已读</string>
|
||||
<string name="mark_all_new_as_read">将所有新内容标记为已读</string>
|
||||
<string name="mark_all_as_read">将所有内容标记为已读</string>
|
||||
<string name="account_backup_tips2_md">## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。</string>
|
||||
<string name="account_backup_tips3_md">为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">加密并复制我的密钥。</string>
|
||||
<string name="badge_award_image_for">颁发给 %1$s 的徽章图片</string>
|
||||
<string name="badge_award_image">"徽章图片</string>
|
||||
<string name="new_badge_award_notif">你收到了新的徽章奖励</string>
|
||||
@@ -2623,7 +2619,6 @@
|
||||
<string name="copied_note_text_to_clipboard">文本已复制到剪贴板</string>
|
||||
<string name="copied_to_clipboard">已复制到剪贴板</string>
|
||||
<string name="copied_user_id_to_clipboard">已复制作者公钥 ID 到剪贴板</string>
|
||||
<string name="copy_my_secret_key">复制我的私人密钥</string>
|
||||
<string name="copy_to_clipboard">复制到剪贴板</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">无法从闪电地址集合LNURL"%1$s"。请检查用户设置</string>
|
||||
<string name="could_not_check_downloaded_file">无法检查经过上传后再下载的文件:%1$s</string>
|
||||
@@ -3754,10 +3749,8 @@
|
||||
<string name="share_hls_video">HLS 上传</string>
|
||||
<string name="share_or_save">分享或保存</string>
|
||||
<string name="shorts">短视频</string>
|
||||
<string name="show_encrypted_private_key_qr_code">显示加密私钥二维码</string>
|
||||
<string name="show_messages_in_notifications_setting_description">在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">显示消息</string>
|
||||
<string name="show_private_key_qr_code">显示私钥二维码</string>
|
||||
<string name="sign_request_rejected2">签名请求已被拒绝</string>
|
||||
<string name="sign_request_rejected_description">请确保签名应用程序已授权此交易</string>
|
||||
<string name="signer_illegal_state_exception_description">外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。</string>
|
||||
|
||||
@@ -221,7 +221,6 @@
|
||||
<string name="relays">中繼</string>
|
||||
<string name="website">網站</string>
|
||||
<string name="lightning_address">閃電地址</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">複製 Nsec ID(您的私人密鑰)到剪貼板以備備份</string>
|
||||
<string name="send_a_direct_message">發送直接消息</string>
|
||||
<string name="edits_the_user_s_metadata">編輯用户元數據</string>
|
||||
<string name="unblock">不隱藏</string>
|
||||
@@ -276,9 +275,6 @@
|
||||
<string name="mark_all_known_as_read">將所有已知內容標記為已讀</string>
|
||||
<string name="mark_all_new_as_read">將所有新內容標記為已讀</string>
|
||||
<string name="mark_all_as_read">將所有內容標記為已讀</string>
|
||||
<string name="account_backup_tips2_md">## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。</string>
|
||||
<string name="account_backup_tips3_md">为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">加密并复制我的密钥。</string>
|
||||
<string name="badge_award_image_for">頒發給 %1$s 的徽章圖片</string>
|
||||
<string name="badge_award_image">"徽章图片</string>
|
||||
<string name="new_badge_award_notif">您收到了新的徽章獎勵</string>
|
||||
@@ -2020,7 +2016,6 @@
|
||||
<string name="copied_note_text_to_clipboard">文本已複製到剪貼板</string>
|
||||
<string name="copied_to_clipboard">已复制到剪贴板</string>
|
||||
<string name="copied_user_id_to_clipboard">複製作者的 @npub 到剪貼板</string>
|
||||
<string name="copy_my_secret_key">複製我的私人密鑰</string>
|
||||
<string name="copy_to_clipboard">复制到剪贴板</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">无法从闪电地址集合LNURL"%1$s"。请检查用户设置</string>
|
||||
<string name="could_not_check_downloaded_file">无法检查经过上传后再下载的文件:%1$s</string>
|
||||
@@ -2807,10 +2802,8 @@
|
||||
<string name="share_hls_video">HLS 上传</string>
|
||||
<string name="share_or_save">分享或保存</string>
|
||||
<string name="shorts">短视频</string>
|
||||
<string name="show_encrypted_private_key_qr_code">显示加密私钥二维码</string>
|
||||
<string name="show_messages_in_notifications_setting_description">在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">显示消息</string>
|
||||
<string name="show_private_key_qr_code">显示私钥二维码</string>
|
||||
<string name="sign_request_rejected2">签名请求已被拒绝</string>
|
||||
<string name="sign_request_rejected_description">请确保签名应用程序已授权此交易</string>
|
||||
<string name="signer_illegal_state_exception_description">外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。</string>
|
||||
|
||||
@@ -221,7 +221,6 @@
|
||||
<string name="relays">中继</string>
|
||||
<string name="website">网站</string>
|
||||
<string name="lightning_address">闪电地址</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">复制 Nsec ID(您的私人密钥)到剪贴板以备备份</string>
|
||||
<string name="send_a_direct_message">发送直接消息</string>
|
||||
<string name="edits_the_user_s_metadata">编辑用户元数据</string>
|
||||
<string name="unblock">不隐藏</string>
|
||||
@@ -276,9 +275,6 @@
|
||||
<string name="mark_all_known_as_read">将所有已知内容标记为已读</string>
|
||||
<string name="mark_all_new_as_read">将所有新内容标记为已读</string>
|
||||
<string name="mark_all_as_read">将所有内容标记为已读</string>
|
||||
<string name="account_backup_tips2_md">## 备份与安全提示 \n\n你的帐户由一个私钥保护。私钥是以**nsec1**开头的随机字符串。任何拥有你的私钥的人都可以使用你的身份发布内容。 \n\n- **不要**将你的私钥添加到任何你不信任的网站或软件,亦不要在网上公开。 \n- Amethyst 开发人员**永远不会**要求你提供私钥。 \n- **请**保留你的私钥的安全备份,以备帐户恢复。我们建议使用密码管理器。</string>
|
||||
<string name="account_backup_tips3_md">为了额外的安全性,你可以用密码加密你的密钥。 此密钥以 **ncryptsec1** 开头,没有密码就不能使用。 \n\n如果你丢失密码, 你将无法恢复你的密钥。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">加密并复制我的密钥。</string>
|
||||
<string name="badge_award_image_for">颁发给 %1$s 的徽章图片</string>
|
||||
<string name="badge_award_image">"徽章图片</string>
|
||||
<string name="new_badge_award_notif">你收到了新的徽章奖励</string>
|
||||
@@ -2020,7 +2016,6 @@
|
||||
<string name="copied_note_text_to_clipboard">文本已复制到剪贴板</string>
|
||||
<string name="copied_to_clipboard">已复制到剪贴板</string>
|
||||
<string name="copied_user_id_to_clipboard">已复制作者公钥 ID 到剪贴板</string>
|
||||
<string name="copy_my_secret_key">复制我的私人密钥</string>
|
||||
<string name="copy_to_clipboard">复制到剪贴板</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">无法从闪电地址集合LNURL"%1$s"。请检查用户设置</string>
|
||||
<string name="could_not_check_downloaded_file">无法检查经过上传后再下载的文件:%1$s</string>
|
||||
@@ -2807,10 +2802,8 @@
|
||||
<string name="share_hls_video">HLS 上传</string>
|
||||
<string name="share_or_save">分享或保存</string>
|
||||
<string name="shorts">短视频</string>
|
||||
<string name="show_encrypted_private_key_qr_code">显示加密私钥二维码</string>
|
||||
<string name="show_messages_in_notifications_setting_description">在通知选项卡上包含私信和群消息。如关闭只在消息选项卡中保留消息。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">显示消息</string>
|
||||
<string name="show_private_key_qr_code">显示私钥二维码</string>
|
||||
<string name="sign_request_rejected2">签名请求已被拒绝</string>
|
||||
<string name="sign_request_rejected_description">请确保签名应用程序已授权此交易</string>
|
||||
<string name="signer_illegal_state_exception_description">外部签名器对该请求返回了不正常的载荷。这可能是 Amethyst 或签名器上的错误。</string>
|
||||
|
||||
@@ -216,7 +216,6 @@
|
||||
<string name="relays">中繼</string>
|
||||
<string name="website">網站</string>
|
||||
<string name="lightning_address">閃電地址</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">複製 NSec (私人密鑰)到剪貼板以備備份</string>
|
||||
<string name="send_a_direct_message">發送直接消息</string>
|
||||
<string name="edits_the_user_s_metadata">編輯用户元數據</string>
|
||||
<string name="unblock">不隱藏</string>
|
||||
@@ -271,9 +270,6 @@
|
||||
<string name="mark_all_known_as_read">將所有已知內容標記為已讀</string>
|
||||
<string name="mark_all_new_as_read">將所有新內容標記為已讀</string>
|
||||
<string name="mark_all_as_read">將所有內容標記為已讀</string>
|
||||
<string name="account_backup_tips2_md">## 備份與安全提示 \n\n你的帳戶由一個私鑰保護。私鑰是以 **nsec1** 開頭的隨機字符串。任何擁有你的私鑰的人都可以使用你的身份發佈內容。 \n\n- **不要**將你的私鑰添加到任何你不信任的網站或軟件,亦不要在網上公開。 \n- Amethyst 開發人員**永遠不會**要求你提供私鑰。 \n- **請**保留你的私鑰的安全備份,以備帳戶恢復。我們建議使用密碼管理器。</string>
|
||||
<string name="account_backup_tips3_md">爲了額外的安全性,你可以用密碼加密你的密鑰。此密鑰以 **ncryptsec1** 開頭,沒有密碼就不能使用。 \n\n如果你丟失密碼,你將無法恢復你的密鑰。</string>
|
||||
<string name="encrypt_and_copy_my_secret_key">加密並複製我的密鑰</string>
|
||||
<string name="badge_award_image_for">頒發給 %1$s 的徽章圖片</string>
|
||||
<string name="badge_award_image">"徽章獎勵圖片</string>
|
||||
<string name="new_badge_award_notif">您收到了新的徽章獎勵</string>
|
||||
@@ -2005,7 +2001,6 @@
|
||||
<string name="copied_note_text_to_clipboard">文本已複製到剪貼板</string>
|
||||
<string name="copied_to_clipboard">已複製到剪貼簿</string>
|
||||
<string name="copied_user_id_to_clipboard">複製作者的 @npub 到剪貼板</string>
|
||||
<string name="copy_my_secret_key">複製我的私人密鑰</string>
|
||||
<string name="copy_to_clipboard">複製至剪貼簿</string>
|
||||
<string name="could_not_assemble_lnurl_from_lightning_address_check_the_user_s_setup">無法從閃電地址集合 LNURL “%1$s”。請檢查用戶設置</string>
|
||||
<string name="could_not_check_downloaded_file">上傳後無法檢查已下載的檔案:%1$s</string>
|
||||
@@ -2779,10 +2774,8 @@
|
||||
<string name="share_hls_video">HLS 上傳</string>
|
||||
<string name="share_or_save">分享或保存</string>
|
||||
<string name="shorts">短片</string>
|
||||
<string name="show_encrypted_private_key_qr_code">顯示加密私鑰 QR 碼</string>
|
||||
<string name="show_messages_in_notifications_setting_description">在通知分頁中包含私訊及群組訊息。關閉後,訊息將只出現在訊息分頁中。</string>
|
||||
<string name="show_messages_in_notifications_setting_title">顯示訊息</string>
|
||||
<string name="show_private_key_qr_code">顯示私鑰 QR 碼</string>
|
||||
<string name="sign_request_rejected2">簽名請求已被拒絕</string>
|
||||
<string name="sign_request_rejected_description">請確保簽名應用程式已授權此交易</string>
|
||||
<string name="signer_illegal_state_exception_description">外部簽署器回傳了與請求不符的酬載。Amethyst 或簽署器可能存在錯誤。</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user