mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
Merge remote-tracking branch 'origin/main' into claude/hopeful-volta-2aphad
# Conflicts: # commonsUI/src/commonMain/composeResources/values-hu-rHU/strings.xml
This commit is contained in:
@@ -140,7 +140,7 @@ Separator legend: **NL** = `joinToString("\n")`, **SP** = `joinToString(" ")`.
|
||||
| 39000 | GroupMetadataEvent | nip29RelayGroups/metadata | `listOfNotNull(name(), about())` NL |
|
||||
| 39089 | StarterPackEvent | nip51Lists/starterPack | `listOfNotNull(title(), description())` NL |
|
||||
| 39092 | MediaStarterPackEvent | nip51Lists/mediaStarterPack | `listOfNotNull(title(), description())` NL |
|
||||
| 39307 | TextTrackEvent | nip71Video/textTrack | `content` (the WebVTT cue text) |
|
||||
| 39307 | TextTrackEvent | nip71Video/textTrack | `WebVttText.cueText(content)` NL — each cue's payload lines with tags removed and character references decoded; no header, timings, cue settings, ids, `NOTE`/`STYLE`/`REGION` blocks. Content with no `-->` timing line is not a caption file and is indexed as written |
|
||||
| 39701 | WebBookmarkEvent | nipB0WebBookmarks | `listOfNotNull(title(), description())` NL |
|
||||
| 39998 | AddressableListHeaderEvent | experimental/decentralizedLists/header | same as 9998 |
|
||||
| 39999 | AddressableListItemEvent | experimental/decentralizedLists/item | same as 9998 |
|
||||
|
||||
@@ -22,9 +22,13 @@ package com.vitorpamplona.amethyst.service.playback
|
||||
|
||||
/**
|
||||
* Shared logcat tag for the playback diagnostic trace (source routing, player lifecycle, error
|
||||
* recovery, HLS liveness learning). Emitted with `Log.d`, so it appears only in a debug build
|
||||
* (`Log.minLevel = DEBUG`) and is silent in benchmark/release (`ERROR`). To capture a playback
|
||||
* investigation, install a debug build and run:
|
||||
* recovery, HLS liveness learning).
|
||||
*
|
||||
* Emitted with `Log.d`, which fires only while `Log.minLevel <= DEBUG`. No shipped variant is
|
||||
* there by default: [com.vitorpamplona.amethyst.Amethyst.DEFAULT_LOG_LEVEL] gives debug AND
|
||||
* benchmark builds `INFO` (the `benchmark` build type counts as `isDebug`) and release `WARN`, so
|
||||
* this trace is silent everywhere until `Amethyst.VERBOSE_LOGS` is flipped to true. To capture a
|
||||
* playback investigation, set that flag, install a debug build and run:
|
||||
*
|
||||
* ```
|
||||
* adb logcat -s PlaybackDiag
|
||||
|
||||
+5
-3
@@ -148,9 +148,11 @@ const val VIDEO_QUALITY_TAG = "VideoQuality"
|
||||
* Traces which rendition adaptive selection landed on, against the full ladder the manifest
|
||||
* offered.
|
||||
*
|
||||
* The listener is registered only when the trace can actually be emitted — debug builds set
|
||||
* `Log.minLevel = DEBUG` while benchmark/release set `ERROR` (see [PLAYBACK_DIAG_TAG]) — so the
|
||||
* release path keeps the "no listener per player" property that dropping the old selector bought.
|
||||
* The listener is registered only when the trace can actually be emitted. `Log.minLevel` is above
|
||||
* `DEBUG` in every variant by default — `INFO` for debug and benchmark builds, `WARN` for release
|
||||
* (see [PLAYBACK_DIAG_TAG]) — so this costs nothing until `Amethyst.VERBOSE_LOGS` is turned on,
|
||||
* and every build keeps the "no listener per player" property that dropping the old selector
|
||||
* bought.
|
||||
*/
|
||||
@Composable
|
||||
fun LogVideoQualitySelection(player: Player) {
|
||||
|
||||
+17
-2
@@ -27,9 +27,11 @@ import androidx.media3.exoplayer.audio.TeeAudioProcessor
|
||||
import com.vitorpamplona.amethyst.commons.audio.AudioWindow
|
||||
import com.vitorpamplona.amethyst.commons.audio.Fft
|
||||
import com.vitorpamplona.amethyst.commons.audio.Spectrum
|
||||
import com.vitorpamplona.amethyst.commons.audio.SpectrumTrail
|
||||
import com.vitorpamplona.amethyst.commons.audio.normalizeToPeakInPlace
|
||||
import com.vitorpamplona.amethyst.commons.audio.toLogBins
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import java.nio.ByteBuffer
|
||||
@@ -65,6 +67,10 @@ class SpectrumAudioBufferSink(
|
||||
private var channels = 1
|
||||
private var encoding = C.ENCODING_PCM_16BIT
|
||||
|
||||
// Audio time one fft frame covers: fftSize samples per channel at the stream's sample rate.
|
||||
// Zero until the first flush reports a rate, which leaves the frame unpaced rather than wrong.
|
||||
private var frameDurationNanos = 0L
|
||||
|
||||
@kotlin.OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun flush(
|
||||
sampleRateHz: Int,
|
||||
@@ -73,6 +79,7 @@ class SpectrumAudioBufferSink(
|
||||
) {
|
||||
this.channels = channelCount.coerceAtLeast(1)
|
||||
this.encoding = encoding
|
||||
this.frameDurationNanos = if (sampleRateHz > 0) fftSize * 1_000_000_000L / sampleRateHz else 0L
|
||||
filled = 0
|
||||
output?.resetReplayCache()
|
||||
}
|
||||
@@ -98,7 +105,7 @@ class SpectrumAudioBufferSink(
|
||||
// Skip the DC bin (index 0): toLogBins ignores it, so letting a DC/offset component be the
|
||||
// peak would scale every audible bin toward zero and wash the spectrum out.
|
||||
mags.normalizeToPeakInPlace(fromIndex = 1)
|
||||
output?.tryEmit(Spectrum(mags.toLogBins(binCount)))
|
||||
output?.tryEmit(Spectrum(mags.toLogBins(binCount), frameDurationNanos))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +174,15 @@ object PcmTapRegistry {
|
||||
if (!fedByLiveSink && !stillCollected) iter.remove()
|
||||
}
|
||||
}
|
||||
MutableSharedFlow(replay = 1, extraBufferCapacity = 1)
|
||||
// Frames arrive in clusters (see SpectrumTrail) emitted within a few ms on the audio
|
||||
// thread, while the collector sits on the main dispatcher and cannot run in between;
|
||||
// a 2-slot buffer kept ~2 frames of each cluster and dropped the rest. Hold as much as
|
||||
// the visualizer's own backlog, which is the real lag bound, dropping the stalest.
|
||||
MutableSharedFlow(
|
||||
replay = 1,
|
||||
extraBufferCapacity = SpectrumTrail.MAX_BACKLOG_FRAMES,
|
||||
onBufferOverflow = BufferOverflow.DROP_OLDEST,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_cancel
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_damaged
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_destination
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_dropped
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_dropped_many
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_empty
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_measuring
|
||||
import com.vitorpamplona.amethyst.commons.resources.cyberspace_bag_no_hint
|
||||
@@ -80,6 +79,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.pluralStringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
/**
|
||||
@@ -242,7 +242,7 @@ private fun Contents(
|
||||
null -> Footnote(stringResource(Res.string.cyberspace_bag_damaged))
|
||||
|
||||
is CyberspaceBagContents.Opaque ->
|
||||
Footnote(asText(contents.bytes) ?: stringResource(Res.string.cyberspace_bag_opaque, contents.bytes.size))
|
||||
Footnote(asText(contents.bytes) ?: pluralStringResource(Res.plurals.cyberspace_bag_opaque, contents.bytes.size, contents.bytes.size))
|
||||
|
||||
is CyberspaceBagContents.Items -> {
|
||||
if (contents.items.isEmpty() && contents.dropped == 0) {
|
||||
@@ -256,13 +256,7 @@ private fun Contents(
|
||||
// still worth saying that something was thrown away.
|
||||
if (contents.dropped > 0) {
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Footnote(
|
||||
if (contents.dropped == 1) {
|
||||
stringResource(Res.string.cyberspace_bag_dropped, contents.dropped)
|
||||
} else {
|
||||
stringResource(Res.string.cyberspace_bag_dropped_many, contents.dropped)
|
||||
},
|
||||
)
|
||||
Footnote(pluralStringResource(Res.plurals.cyberspace_bag_dropped, contents.dropped, contents.dropped))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,9 +316,10 @@ private fun Footnote(text: String) {
|
||||
private fun outOfReach(estimateMillis: Long): String {
|
||||
val minutes = estimateMillis / 60_000L
|
||||
return if (minutes >= MINUTES_PER_HOUR) {
|
||||
stringResource(Res.string.cyberspace_bag_too_slow_hours, (minutes / MINUTES_PER_HOUR).toInt())
|
||||
val hours = (minutes / MINUTES_PER_HOUR).toInt()
|
||||
pluralStringResource(Res.plurals.cyberspace_bag_too_slow_hours, hours, hours)
|
||||
} else {
|
||||
stringResource(Res.string.cyberspace_bag_too_slow_minutes, minutes.toInt())
|
||||
pluralStringResource(Res.plurals.cyberspace_bag_too_slow_minutes, minutes.toInt(), minutes.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -144,6 +144,7 @@ import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
|
||||
import com.vitorpamplona.amethyst.ui.note.elements.BannerImage
|
||||
import com.vitorpamplona.amethyst.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.relayGroup.LoadRelayGroupChannel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.LoadUser
|
||||
@@ -420,7 +421,7 @@ private fun PeopleSearch(
|
||||
singleLine = true,
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
leadingIcon = { Icon(symbol = MaterialSymbols.Search, contentDescription = null) },
|
||||
placeholder = { Text(stringRes(Res.string.backup_review_search_people, count.toString())) },
|
||||
placeholder = { Text(pluralStringRes(Res.plurals.backup_review_search_people, count, count.toString())) },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -754,7 +754,7 @@ private fun LazyListScope.trustProviderItems(
|
||||
Icon(symbol = MaterialSymbols.Group, contentDescription = null, tint = tones.changed)
|
||||
}
|
||||
Column {
|
||||
Text(stringRes(Res.string.backup_review_services_changed, affected.toString(), services.size.toString()), fontSize = 24.sp, lineHeight = 28.sp, fontWeight = FontWeight.Bold)
|
||||
Text(pluralStringResource(Res.plurals.backup_review_services_changed, services.size, affected.toString(), services.size.toString()), fontSize = 24.sp, lineHeight = 28.sp, fontWeight = FontWeight.Bold)
|
||||
Text(stringRes(Res.string.backup_review_services_changed_explainer), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.placeholderText)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -387,7 +387,7 @@ fun CordnCreateGroupScreen(
|
||||
if (draft.showStale) {
|
||||
stringRes(Res.string.cordn_coordinators_hide_older)
|
||||
} else {
|
||||
stringRes(Res.string.cordn_coordinators_show_older, stale.size)
|
||||
pluralStringRes(Res.plurals.cordn_coordinators_show_older, stale.size, stale.size)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -462,7 +462,7 @@ fun CordnCreateGroupScreen(
|
||||
// different answers and only one of them is final.
|
||||
// Reporting the first for the second sends someone
|
||||
// off to paste a pubkey by hand over a timeout.
|
||||
stringRes(Res.string.cordn_coordinators_discover_unheard, result.unreachable.size)
|
||||
pluralStringRes(Res.plurals.cordn_coordinators_discover_unheard, result.unreachable.size, result.unreachable.size)
|
||||
},
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
@@ -927,7 +927,7 @@ private fun CoordinatorSummary(
|
||||
text =
|
||||
when {
|
||||
coverage == null || !coverage.answered -> stringRes(Res.string.cordn_create_coverage_unknown)
|
||||
reached == rosterSize -> stringRes(Res.string.cordn_create_coverage_all, rosterSize)
|
||||
reached == rosterSize -> pluralStringRes(Res.plurals.cordn_create_coverage_all, rosterSize, rosterSize)
|
||||
else -> stringRes(Res.string.cordn_create_coverage_partial, reached ?: 0, rosterSize)
|
||||
},
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
|
||||
+2
-1
@@ -45,6 +45,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_caches
|
||||
import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_progress
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -119,7 +120,7 @@ fun GeocacheHuntRow(
|
||||
Text(
|
||||
text =
|
||||
stringRes(Res.string.geocache_hunt_progress, doneCount, caches.size) +
|
||||
" · " + stringRes(Res.string.geocache_hunt_caches, caches.size),
|
||||
" · " + pluralStringRes(Res.plurals.geocache_hunt_caches, caches.size, caches.size),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
+3
-1
@@ -56,6 +56,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_already_on
|
||||
import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_caches
|
||||
import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_new
|
||||
import com.vitorpamplona.amethyst.commons.resources.geocache_hunt_none_yet
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Address
|
||||
@@ -178,7 +179,8 @@ fun GeocacheAddToHuntSheet(
|
||||
if (already) {
|
||||
stringRes(Res.string.geocache_hunt_already_on)
|
||||
} else {
|
||||
stringRes(Res.string.geocache_hunt_caches, hunt.geocaches().size)
|
||||
val cacheCount = hunt.geocaches().size
|
||||
pluralStringRes(Res.plurals.geocache_hunt_caches, cacheCount, cacheCount)
|
||||
},
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ import com.vitorpamplona.amethyst.commons.resources.geocache_caches_here
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.note.rememberGeocachePalette
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.dal.GeocachesHereFeedViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.geocaches.datasource.GeocachesFilterAssemblerSubscription
|
||||
@@ -121,7 +121,7 @@ private fun GeocachesHereCount(
|
||||
tint = palette.live,
|
||||
)
|
||||
Text(
|
||||
text = stringRes(Res.string.geocache_caches_here, count),
|
||||
text = pluralStringRes(Res.plurals.geocache_caches_here, count, count),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
|
||||
+2
-1
@@ -63,6 +63,7 @@ import com.vitorpamplona.amethyst.commons.resources.qr_scanner_sequence_progress
|
||||
import com.vitorpamplona.amethyst.commons.resources.qr_scanner_torch_off
|
||||
import com.vitorpamplona.amethyst.commons.resources.qr_scanner_torch_on
|
||||
import com.vitorpamplona.amethyst.commons.resources.qr_scanner_zoom_reset
|
||||
import com.vitorpamplona.amethyst.commons.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.commons.ui.stringRes
|
||||
import kotlin.math.max
|
||||
|
||||
@@ -255,7 +256,7 @@ private fun HintStack(
|
||||
val message =
|
||||
when {
|
||||
state.notice != null -> state.notice
|
||||
progress != null -> stringRes(Res.string.qr_scanner_sequence_progress, progress.first, progress.second)
|
||||
progress != null -> pluralStringRes(Res.plurals.qr_scanner_sequence_progress, progress.second, progress.first, progress.second)
|
||||
state.candidates.size > 1 -> stringRes(Res.string.qr_scanner_pick_one)
|
||||
state.isDark && !state.torchOn -> stringRes(Res.string.qr_scanner_dark_hint)
|
||||
else -> null
|
||||
|
||||
+3
-2
@@ -114,6 +114,7 @@ import com.vitorpamplona.amethyst.commons.ui.note.timeAgoNoDot
|
||||
import com.vitorpamplona.amethyst.commons.ui.theme.DividerThickness
|
||||
import com.vitorpamplona.amethyst.model.cordn.CordnRuntime
|
||||
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||
import com.vitorpamplona.amethyst.ui.pluralStringRes
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.cordnGroup.CopyableKeyRow
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsSection
|
||||
@@ -444,7 +445,7 @@ private fun HealthLine(state: CoordinatorHealth.State) {
|
||||
val text =
|
||||
when {
|
||||
state.isUnknown -> stringRes(Res.string.cordn_coordinators_health_unknown)
|
||||
state.isDown -> stringRes(Res.string.cordn_coordinators_health_down, state.consecutiveFailures)
|
||||
state.isDown -> pluralStringRes(Res.plurals.cordn_coordinators_health_down, state.consecutiveFailures, state.consecutiveFailures)
|
||||
state.consecutiveFailures > 0 -> stringRes(Res.string.cordn_coordinators_health_retrying)
|
||||
else -> stringRes(Res.string.cordn_coordinators_health_ok)
|
||||
}
|
||||
@@ -535,7 +536,7 @@ private fun DiscoverCoordinators(
|
||||
} else {
|
||||
// "Nobody is announcing" and "we were not told" are
|
||||
// different answers and only one of them is final.
|
||||
stringRes(Res.string.cordn_coordinators_discover_unheard, found.unreachable.size)
|
||||
pluralStringRes(Res.plurals.cordn_coordinators_discover_unheard, found.unreachable.size, found.unreachable.size)
|
||||
},
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
|
||||
+2
-1
@@ -80,6 +80,7 @@ import com.vitorpamplona.amethyst.commons.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.commons.ui.navigation.topbars.TopBarWithBackButton
|
||||
import com.vitorpamplona.amethyst.model.cordn.AndroidCordnBlobStore
|
||||
import com.vitorpamplona.amethyst.model.cordn.CordnRuntime
|
||||
import com.vitorpamplona.amethyst.ui.pluralStringRes
|
||||
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
|
||||
@@ -351,7 +352,7 @@ private fun ReceiveSide(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
||||
done?.let { Text(stringRes(Res.string.cordn_migrate_done, it), style = MaterialTheme.typography.bodyMedium) }
|
||||
done?.let { Text(pluralStringRes(Res.plurals.cordn_migrate_done, it, it), style = MaterialTheme.typography.bodyMedium) }
|
||||
error?.let { Text(it, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error) }
|
||||
|
||||
Button(
|
||||
|
||||
@@ -192,6 +192,9 @@
|
||||
<string name="share_target_as_picture">Nový obrázek</string>
|
||||
<string name="share_target_as_short_video">Nové krátké video</string>
|
||||
<string name="share_target_as_video">Nové video</string>
|
||||
<string name="share_target_scan_qr">Skenovat QR kód</string>
|
||||
<string name="shortcut_scan_qr_short">Skenovat QR</string>
|
||||
<string name="shortcut_scan_qr_long">Naskenovat QR kód</string>
|
||||
<string name="new_highlight_passage_label">Zvýrazněný text</string>
|
||||
<!-- Label for the mixed media feed: pictures + every NIP-71 video kind + NIP-94 files.
|
||||
Distinct from the "shorts" string, which labels the vertical/short-video-only feed. -->
|
||||
@@ -311,6 +314,7 @@
|
||||
<item quantity="other">Těžení proof of work… (%1$d příspěvků ve frontě)</item>
|
||||
</plurals>
|
||||
<string name="pow_mining_title">Těžení proof of work</string>
|
||||
<string name="pow_notification_sending">Odesílání na relé…</string>
|
||||
<string name="pow_notification_cancel_all">Zrušit</string>
|
||||
<string name="pow_time_left">≈ %1$s zbývá</string>
|
||||
<string name="pow_time_left_soon">každou chvíli</string>
|
||||
|
||||
@@ -180,6 +180,9 @@
|
||||
<string name="share_target_as_picture">Neues Bild</string>
|
||||
<string name="share_target_as_short_video">Neuer Kurzfilm</string>
|
||||
<string name="share_target_as_video">Neues Video</string>
|
||||
<string name="share_target_scan_qr">QR-Code scannen</string>
|
||||
<string name="shortcut_scan_qr_short">QR scannen</string>
|
||||
<string name="shortcut_scan_qr_long">Einen QR-Code scannen</string>
|
||||
<string name="new_highlight_passage_label">Hervorgehobener Text</string>
|
||||
<!-- Label for the mixed media feed: pictures + every NIP-71 video kind + NIP-94 files.
|
||||
Distinct from the "shorts" string, which labels the vertical/short-video-only feed. -->
|
||||
@@ -291,6 +294,7 @@
|
||||
<item quantity="other">Arbeitsnachweis wird geschürft… (%1$d Beiträge in der Warteschlange)</item>
|
||||
</plurals>
|
||||
<string name="pow_mining_title">Arbeitsnachweis wird geschürft</string>
|
||||
<string name="pow_notification_sending">Wird an Relays gesendet…</string>
|
||||
<string name="pow_notification_cancel_all">Abbrechen</string>
|
||||
<string name="pow_time_left">≈ %1$s verbleibend</string>
|
||||
<string name="pow_time_left_soon">jeden Moment</string>
|
||||
|
||||
@@ -180,6 +180,9 @@
|
||||
<string name="share_target_as_picture">Nova Foto</string>
|
||||
<string name="share_target_as_short_video">Novo Vídeo Curto</string>
|
||||
<string name="share_target_as_video">Novo Vídeo</string>
|
||||
<string name="share_target_scan_qr">Escanear código QR</string>
|
||||
<string name="shortcut_scan_qr_short">Ler QR</string>
|
||||
<string name="shortcut_scan_qr_long">Escanear um código QR</string>
|
||||
<string name="new_highlight_passage_label">Texto destacado</string>
|
||||
<!-- Label for the mixed media feed: pictures + every NIP-71 video kind + NIP-94 files.
|
||||
Distinct from the "shorts" string, which labels the vertical/short-video-only feed. -->
|
||||
@@ -291,6 +294,7 @@
|
||||
<item quantity="other">Minerando prova de trabalho… (%1$d publicações na fila)</item>
|
||||
</plurals>
|
||||
<string name="pow_mining_title">Minerando prova de trabalho</string>
|
||||
<string name="pow_notification_sending">Enviando para relays…</string>
|
||||
<string name="pow_notification_cancel_all">Cancelar</string>
|
||||
<string name="pow_time_left">≈ %1$s restante</string>
|
||||
<string name="pow_time_left_soon">a qualquer momento</string>
|
||||
|
||||
@@ -180,6 +180,9 @@
|
||||
<string name="share_target_as_picture">Ny bild</string>
|
||||
<string name="share_target_as_short_video">Ny kortfilm</string>
|
||||
<string name="share_target_as_video">Ny video</string>
|
||||
<string name="share_target_scan_qr">Skanna QR-kod</string>
|
||||
<string name="shortcut_scan_qr_short">Skanna QR</string>
|
||||
<string name="shortcut_scan_qr_long">Skanna en QR-kod</string>
|
||||
<string name="new_highlight_passage_label">Markerad text</string>
|
||||
<!-- Label for the mixed media feed: pictures + every NIP-71 video kind + NIP-94 files.
|
||||
Distinct from the "shorts" string, which labels the vertical/short-video-only feed. -->
|
||||
@@ -291,6 +294,7 @@
|
||||
<item quantity="other">Minar bevis på arbete… (%1$d inlägg i kön)</item>
|
||||
</plurals>
|
||||
<string name="pow_mining_title">Minar bevis på arbete</string>
|
||||
<string name="pow_notification_sending">Skickar till reläer…</string>
|
||||
<string name="pow_notification_cancel_all">Avbryt</string>
|
||||
<string name="pow_time_left">≈ %1$s kvar</string>
|
||||
<string name="pow_time_left_soon">när som helst nu</string>
|
||||
|
||||
+63
@@ -24,7 +24,11 @@ import androidx.annotation.OptIn
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.vitorpamplona.amethyst.commons.audio.Spectrum
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
@@ -33,6 +37,7 @@ import java.nio.ByteOrder
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.sin
|
||||
|
||||
@kotlin.OptIn(ExperimentalCoroutinesApi::class)
|
||||
@OptIn(UnstableApi::class)
|
||||
class SpectrumAudioBufferSinkTest {
|
||||
private val fftSize = 64
|
||||
@@ -136,4 +141,62 @@ class SpectrumAudioBufferSinkTest {
|
||||
|
||||
assertTrue("non-16-bit PCM must not emit a spectrum", out.replayCache.isEmpty())
|
||||
}
|
||||
|
||||
// Pacing draws each frame for the audio time it covers, so the sink has to say how long that is.
|
||||
// It is fftSize samples PER CHANNEL: a stereo stream must not report half (or double) the time.
|
||||
@Test
|
||||
fun eachFrameCarriesTheAudioTimeItCovers() {
|
||||
val sink = SpectrumAudioBufferSink(fftSize = fftSize, binCount = binCount)
|
||||
val out = MutableSharedFlow<Spectrum>(replay = 1, extraBufferCapacity = 1)
|
||||
sink.output = out
|
||||
sink.flush(48000, 1, C.ENCODING_PCM_16BIT)
|
||||
sink.handleBuffer(monoPcm(sineShorts(k = 2, n = fftSize)))
|
||||
|
||||
assertEquals(fftSize * 1_000_000_000L / 48000, out.replayCache.last().durationNanos)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stereoFramesCoverTheSameTimeAsMono() {
|
||||
val sink = SpectrumAudioBufferSink(fftSize = fftSize, binCount = binCount)
|
||||
val out = MutableSharedFlow<Spectrum>(replay = 1, extraBufferCapacity = 1)
|
||||
sink.output = out
|
||||
sink.flush(44100, 2, C.ENCODING_PCM_16BIT)
|
||||
val tone = sineShorts(k = 2, n = fftSize)
|
||||
sink.handleBuffer(interleavedStereoPcm(tone, tone))
|
||||
|
||||
assertEquals(fftSize * 1_000_000_000L / 44100, out.replayCache.last().durationNanos)
|
||||
}
|
||||
|
||||
/**
|
||||
* The audio thread emits a cluster of fft frames within a few ms, with no suspension point in
|
||||
* between, while the UI collector sits on the main dispatcher and cannot interleave. Anything the
|
||||
* registry's flow cannot hold at that instant is dropped; a 2-slot buffer kept 2 of every cluster.
|
||||
*/
|
||||
private fun deliveredFromOneCluster(framesInCluster: Int): Int {
|
||||
var count = -1
|
||||
runTest {
|
||||
val mediaId = "test://cluster-$framesInCluster"
|
||||
val sink = SpectrumAudioBufferSink(fftSize = fftSize, binCount = binCount)
|
||||
PcmTapRegistry.bind(mediaId, sink)
|
||||
sink.flush(48000, 1, C.ENCODING_PCM_16BIT)
|
||||
|
||||
val received = mutableListOf<Spectrum>()
|
||||
val collector = launch { PcmTapRegistry.spectrumFor(mediaId).collect { received.add(it) } }
|
||||
advanceUntilIdle() // let the collector subscribe
|
||||
|
||||
sink.handleBuffer(monoPcm(sineShorts(k = 2, n = fftSize * framesInCluster)))
|
||||
|
||||
advanceUntilIdle() // only now does the UI collector get to run
|
||||
collector.cancel()
|
||||
PcmTapRegistry.bind(null, sink)
|
||||
count = received.size
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
@Test
|
||||
fun everyFrameOfAClusterReachesTheVisualizer() {
|
||||
assertEquals("cluster of 8", 8, deliveredFromOneCluster(8))
|
||||
assertEquals("cluster of 20", 20, deliveredFromOneCluster(20))
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -26,9 +26,16 @@ import kotlin.math.exp
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.log10
|
||||
|
||||
/** One frame of frequency-domain magnitudes, ordered low→high Hz and normalized 0f..1f. */
|
||||
/**
|
||||
* One frame of frequency-domain magnitudes, ordered low→high Hz and normalized 0f..1f.
|
||||
*
|
||||
* [durationNanos] is how much audio the frame describes (fft size / sample rate), which is how long
|
||||
* it should stay on screen. Zero — the default — means the producer is not pacing to audio (the
|
||||
* synthetic preview emits one per display frame), so the frame is shown as soon as it arrives.
|
||||
*/
|
||||
class Spectrum(
|
||||
val bins: FloatArray,
|
||||
val durationNanos: Long = 0L,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.audio
|
||||
|
||||
/**
|
||||
* The per-displayed-frame step of the spectrum visualizer: queue incoming frames, release each as
|
||||
* its audio time comes due, apply the decay trail against what is already on screen, and return a
|
||||
* fresh array to draw.
|
||||
*
|
||||
* Why pacing is needed at all: the audio pipeline fills its output buffer in chunks, so frames reach
|
||||
* the UI in clusters — ~15 frames roughly every 330 ms, measured on a Pixel 9a. Drawn on arrival a
|
||||
* cluster collapses into one frame; released one per display refresh it plays out in ~110 ms at
|
||||
* 120 Hz and then freezes (161 stalls averaging 211 ms over 52.8 s). Each frame instead stays up for
|
||||
* the [Spectrum.durationNanos] of audio it describes, so a cluster spreads across the gap to the
|
||||
* next. Time lost while starved is not owed back: after a gap, frames resume from the current frame
|
||||
* time rather than being dumped at once to catch up.
|
||||
*
|
||||
* The backlog is capped at [capacity], evicting the stalest frame, so faster-than-real-time playback
|
||||
* or a stalled UI cannot leave the picture drifting ever further behind the sound.
|
||||
*
|
||||
* The decay gives each bin an instant attack and a gradual release, so bars snap up to a transient
|
||||
* and fall back smoothly instead of flickering.
|
||||
*
|
||||
* This lives here, rather than inline in the Compose collector, so the pacing, starvation and decay
|
||||
* rules are unit-testable without a Compose harness; the composable is left as plumbing.
|
||||
*
|
||||
* Not thread-safe by design: both ends run on the UI dispatcher.
|
||||
*/
|
||||
class SpectrumTrail(
|
||||
private val decay: Float,
|
||||
private val capacity: Int = MAX_BACKLOG_FRAMES,
|
||||
) {
|
||||
private val queue = ArrayDeque<Spectrum>(capacity)
|
||||
private var drawn = FloatArray(0)
|
||||
|
||||
// When the frame at the head of the queue may be drawn, in the caller's frame-clock nanos.
|
||||
private var dueNanos = Long.MIN_VALUE
|
||||
private var starved = true
|
||||
|
||||
/** Queues a freshly decoded frame, evicting the stalest if the backlog is at [capacity]. */
|
||||
fun offer(frame: Spectrum) {
|
||||
while (queue.size >= capacity) queue.removeFirst()
|
||||
queue.addLast(frame)
|
||||
}
|
||||
|
||||
/** True when nothing is queued, so the caller can stop polling until the next [offer]. */
|
||||
fun isEmpty(): Boolean = queue.isEmpty()
|
||||
|
||||
/**
|
||||
* The array to draw at [frameTimeNanos], or null when nothing new is due and the current one
|
||||
* should persist.
|
||||
*
|
||||
* A fresh array each time is intentional: `mutableStateOf` compares by reference, so a new
|
||||
* instance is what signals Compose to redraw. Do NOT switch to in-place mutation.
|
||||
*/
|
||||
fun nextOrNull(frameTimeNanos: Long): FloatArray? {
|
||||
if (queue.isEmpty()) {
|
||||
starved = true
|
||||
return null
|
||||
}
|
||||
if (starved) {
|
||||
// Resume from now, but never earlier than the last drawn frame's audio time runs out.
|
||||
dueNanos = maxOf(dueNanos, frameTimeNanos)
|
||||
starved = false
|
||||
}
|
||||
|
||||
var result: FloatArray? = null
|
||||
while (dueNanos <= frameTimeNanos) {
|
||||
val frame = queue.removeFirstOrNull() ?: break
|
||||
result = decayedFrom(frame)
|
||||
dueNanos += frame.durationNanos
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun decayedFrom(frame: Spectrum): FloatArray {
|
||||
val prev = drawn
|
||||
val next =
|
||||
FloatArray(frame.bins.size) { i ->
|
||||
val prior = if (i < prev.size) prev[i] * decay else 0f
|
||||
if (frame.bins[i] > prior) frame.bins[i] else prior
|
||||
}
|
||||
drawn = next
|
||||
return next
|
||||
}
|
||||
|
||||
companion object {
|
||||
// A cluster is ~15 frames, so 24 (~0.5 s of audio) never trims ordinary playback, while
|
||||
// bounding how far the picture can lag the sound (e.g. at 2x playback speed).
|
||||
const val MAX_BACKLOG_FRAMES = 24
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.audio
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNotSame
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/** Pacing, starvation, backlog and decay rules of [SpectrumTrail]; see its KDoc for why each exists. */
|
||||
class SpectrumTrailTest {
|
||||
private val ms = 1_000_000L
|
||||
|
||||
private fun frame(
|
||||
value: Float,
|
||||
durationMs: Long = 20,
|
||||
) = Spectrum(floatArrayOf(value), durationNanos = durationMs * ms)
|
||||
|
||||
@Test
|
||||
fun yieldsNothingWhenStarvedSoTheDrawnFrameIsHeld() {
|
||||
val trail = SpectrumTrail(decay = 0.5f)
|
||||
assertNull(trail.nextOrNull(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theFirstFrameIsDrawnOnArrivalWithNothingToDecayFrom() {
|
||||
val trail = SpectrumTrail(decay = 0.5f)
|
||||
trail.offer(frame(1f))
|
||||
|
||||
assertContentEquals(floatArrayOf(1f), trail.nextOrNull(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aClusterIsSpreadOverTheAudioTimeItCoversNotTheScreenRefresh() {
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
trail.offer(frame(1f))
|
||||
trail.offer(frame(2f))
|
||||
trail.offer(frame(3f))
|
||||
|
||||
// 120 Hz refreshes (~8 ms) must not drain a frame that covers 20 ms of audio.
|
||||
assertContentEquals(floatArrayOf(1f), trail.nextOrNull(0))
|
||||
assertNull(trail.nextOrNull(8 * ms))
|
||||
assertNull(trail.nextOrNull(16 * ms))
|
||||
assertContentEquals(floatArrayOf(2f), trail.nextOrNull(20 * ms))
|
||||
assertNull(trail.nextOrNull(33 * ms))
|
||||
assertContentEquals(floatArrayOf(3f), trail.nextOrNull(40 * ms))
|
||||
assertNull(trail.nextOrNull(48 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun afterStarvingTheNextClusterStartsWhenItArrivesInsteadOfBeingDumpedToCatchUp() {
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
trail.offer(frame(1f))
|
||||
assertContentEquals(floatArrayOf(1f), trail.nextOrNull(0))
|
||||
assertNull(trail.nextOrNull(100 * ms)) // starved for a while
|
||||
|
||||
trail.offer(frame(2f))
|
||||
trail.offer(frame(3f))
|
||||
|
||||
// The idle time is not owed: frame 2 shows now and frame 3 a full frame later.
|
||||
assertContentEquals(floatArrayOf(2f), trail.nextOrNull(300 * ms))
|
||||
assertNull(trail.nextOrNull(308 * ms))
|
||||
assertContentEquals(floatArrayOf(3f), trail.nextOrNull(320 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aFrameArrivingBeforeThePreviousOneElapsedStillWaitsItsTurn() {
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
trail.offer(frame(1f))
|
||||
assertContentEquals(floatArrayOf(1f), trail.nextOrNull(0))
|
||||
assertNull(trail.nextOrNull(8 * ms)) // queue momentarily empty
|
||||
|
||||
trail.offer(frame(2f))
|
||||
|
||||
assertNull(trail.nextOrNull(16 * ms)) // frame 1 still covers until 20 ms
|
||||
assertContentEquals(floatArrayOf(2f), trail.nextOrNull(24 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aSlowFrameClockJumpsToTheLatestDueFrame() {
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
trail.offer(frame(1f))
|
||||
trail.offer(frame(2f))
|
||||
trail.offer(frame(3f))
|
||||
|
||||
assertContentEquals(floatArrayOf(1f), trail.nextOrNull(0))
|
||||
// A janky 45 ms frame: frames 2 (due 20) and 3 (due 40) are both due; show the newest.
|
||||
assertContentEquals(floatArrayOf(3f), trail.nextOrNull(45 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aFrameWithNoDurationIsShownOnArrival() {
|
||||
// Producers that do not declare a duration (the synthetic preview emits one per display
|
||||
// frame) keep the old behaviour: whatever is queued is current.
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
trail.offer(Spectrum(floatArrayOf(1f)))
|
||||
trail.offer(Spectrum(floatArrayOf(2f)))
|
||||
|
||||
assertContentEquals(floatArrayOf(2f), trail.nextOrNull(0))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aBacklogIsCappedByDroppingTheStalestFrame() {
|
||||
// Faster-than-real-time playback (2x speed) produces frames faster than they come due;
|
||||
// the cap bounds how far the picture can lag the sound.
|
||||
val trail = SpectrumTrail(decay = 0f, capacity = 2)
|
||||
trail.offer(frame(1f))
|
||||
trail.offer(frame(2f))
|
||||
trail.offer(frame(3f)) // evicts frame 1
|
||||
|
||||
assertContentEquals(floatArrayOf(2f), trail.nextOrNull(0))
|
||||
assertContentEquals(floatArrayOf(3f), trail.nextOrNull(20 * ms))
|
||||
assertNull(trail.nextOrNull(40 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aRisingBinTakesItsNewValueImmediately() {
|
||||
val trail = SpectrumTrail(decay = 0.5f)
|
||||
trail.offer(frame(0.2f))
|
||||
trail.nextOrNull(0)
|
||||
trail.offer(frame(0.9f))
|
||||
|
||||
assertContentEquals(floatArrayOf(0.9f), trail.nextOrNull(20 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aFallingBinDecaysFromWhatWasDrawnRatherThanSnapping() {
|
||||
val trail = SpectrumTrail(decay = 0.5f)
|
||||
trail.offer(frame(1f))
|
||||
trail.nextOrNull(0)
|
||||
trail.offer(frame(0f))
|
||||
|
||||
assertContentEquals(floatArrayOf(0.5f), trail.nextOrNull(20 * ms))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun eachDrawGetsAFreshArraySoComposeSeesTheChange() {
|
||||
val trail = SpectrumTrail(decay = 0.5f)
|
||||
trail.offer(frame(1f))
|
||||
trail.offer(frame(1f))
|
||||
|
||||
val first = trail.nextOrNull(0)
|
||||
val second = trail.nextOrNull(20 * ms)
|
||||
|
||||
// mutableStateOf compares by reference; reusing one array would never trigger a redraw.
|
||||
assertNotSame(first, second)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reportsEmptyOnlyOnceEveryQueuedFrameIsReleasedSoTheCallerKnowsWhenToPark() {
|
||||
val trail = SpectrumTrail(decay = 0f)
|
||||
assertTrue(trail.isEmpty())
|
||||
|
||||
trail.offer(frame(1f))
|
||||
trail.offer(frame(2f))
|
||||
assertFalse(trail.isEmpty())
|
||||
|
||||
trail.nextOrNull(0)
|
||||
assertFalse(trail.isEmpty()) // frame 2 is queued but not yet due
|
||||
trail.nextOrNull(20 * ms)
|
||||
assertTrue(trail.isEmpty())
|
||||
}
|
||||
}
|
||||
@@ -3074,4 +3074,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2949,4 +2949,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2897,4 +2897,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -34,4 +34,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2953,4 +2953,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2969,4 +2969,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2962,4 +2962,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2962,4 +2962,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2963,4 +2963,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2929,4 +2929,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2853,4 +2853,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -3146,4 +3146,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -206,7 +206,10 @@
|
||||
<string name="geocache_hunt_new">नई खोज…</string>
|
||||
<string name="geocache_hunt_none_yet">आपने कोई खोज नहीं की अब तक।</string>
|
||||
<string name="geocache_hunt_already_on">पहले से इस खोज में लगे</string>
|
||||
<string name="geocache_caches_here">%1$d कोष यहाँ</string>
|
||||
<plurals name="geocache_caches_here">
|
||||
<item quantity="one">%1$d कोष यहाँ</item>
|
||||
<item quantity="other">%1$d कोष यहाँ</item>
|
||||
</plurals>
|
||||
<string name="geocache_photo_remove">इस चित्र को हटाएँ</string>
|
||||
<string name="geocache_archived_notice">इस कोष को संगृहीत कर दिया गया। यह अब खेल में नहीं है।</string>
|
||||
<string name="geocache_ftf_won_by">सर्वप्रथम खोज का कथन %1$s द्वारा</string>
|
||||
@@ -265,7 +268,6 @@
|
||||
<string name="geocache_map_recenter">मुझ पर मध्यीकरण</string>
|
||||
<string name="geocache_map_long_press">मानचित्र पर दीर्घ दबाएँ वहाँ एक कोष छिपाने के लिए</string>
|
||||
<string name="geocache_map_open">खोलें</string>
|
||||
<string name="geocache_map_pin_count">%1$d कोष</string>
|
||||
<string name="geocache_new_section_where">कहाँ</string>
|
||||
<string name="geocache_new_section_what">क्या</string>
|
||||
<string name="geocache_new_section_extras">अतिरिक्त</string>
|
||||
@@ -293,7 +295,10 @@
|
||||
<string name="geocache_new_needs_location">कोष कहाँ छिपाया जाए चयन करें।</string>
|
||||
<string name="geocache_hunt_progress">%2$d में से %1$d प्राप्त</string>
|
||||
<string name="geocache_hunt_start">खोज आरम्भ करें</string>
|
||||
<string name="geocache_hunt_caches">%1$d कोष</string>
|
||||
<plurals name="geocache_hunt_caches">
|
||||
<item quantity="one">%1$d कोष</item>
|
||||
<item quantity="other">%1$d कोष</item>
|
||||
</plurals>
|
||||
<string name="geocache_hunt_title">शीर्षक</string>
|
||||
<string name="geocache_hunt_description">विवरण</string>
|
||||
<string name="geocache_hunt_banner">ध्वज चित्र</string>
|
||||
@@ -342,7 +347,10 @@
|
||||
<string name="qr_scanner_no_code_in_image">उस चित्र में से कोई क्यूआर॰ चित्र अक्षरराशि प्राप्त नहीं</string>
|
||||
<string name="qr_scanner_clipboard_empty">टाँकाफलक में कुछ भी नहीं परखने के लिए</string>
|
||||
<string name="qr_scanner_pick_one">अक्षरराशि का चयन करें</string>
|
||||
<string name="qr_scanner_sequence_progress">%2$s में से %1$s भाग प्राप्त। आगे बढें</string>
|
||||
<plurals name="qr_scanner_sequence_progress">
|
||||
<item quantity="one">%2$s में से %1$s भाग प्राप्त। आगे बढें</item>
|
||||
<item quantity="other">%2$s में से %1$s भाग प्राप्त। आगे बढें</item>
|
||||
</plurals>
|
||||
<string name="qr_scanner_zoom_reset">विस्तारण पुनःस्थापना</string>
|
||||
<string name="qr_scanner_unsupported_title">अमेथिस्ट इस अक्षरराशि को नहीं खोल सकता</string>
|
||||
<string name="qr_scanner_unsupported_secret">इस अक्षरराशि में एक निजी कुंचिका अथवा जोडनेवाला रहस्य है। इसलिए इसकी विषयवस्तु यहाँ दिखाया नहीं जाता। अनुकूल पटल का उपयोग करें।</string>
|
||||
@@ -1850,7 +1858,7 @@
|
||||
<string name="media_compression_quality_medium">मध्यम</string>
|
||||
<string name="media_compression_quality_high">उच्च</string>
|
||||
<string name="media_compression_quality_uncompressed">असंकुचित</string>
|
||||
<string name="metadata_strip_failed_body">यह अभिलेख प्रारूप परितथ्य हटाने का अवलम्बन नहीं करता। निजी जानकारी जैसे स्थान तथा यन्त्र विवरण समाविष्ट हो सकते हैं। क्या तो भी आरोहण करें।</string>
|
||||
<string name="metadata_strip_failed_body">यह अभिलेख प्रारूप उपतथ्य हटाने का अवलम्बन नहीं करता। निजी जानकारी जैसे स्थान तथा यन्त्र विवरण समाविष्ट हो सकते हैं। क्या तो भी आरोहण करें।</string>
|
||||
<string name="metadata_strip_failed_upload">तो भी आरोहण करें</string>
|
||||
<string name="edit_draft">पाण्डुलिपि सम्पादन</string>
|
||||
<string name="login_with_qr_code">क्यूआर॰ चित्र अक्षरराशि के साथ प्रवेशांकन करें</string>
|
||||
@@ -2877,6 +2885,7 @@
|
||||
<string name="community_rules_violation_wot_gate_failed">आप इस समुदाय के विश्वासजाल आवश्यकताओं को पार नहीं कर सके।</string>
|
||||
<string name="community_rules_violation_stale_rules">समुदाय का नवीनतम नियम अभिलेख पुराना होने के कारण अस्वीकृत।</string>
|
||||
<string name="marmot_groups_title">मार्मोट॰ समूह</string>
|
||||
<string name="cordn_groups_title">कोर्डन समूह</string>
|
||||
<string name="marmot_create_group">समूह बनाएँ</string>
|
||||
<string name="marmot_create_group_title">मार्मोट॰ समूह बनाएँ</string>
|
||||
<string name="marmot_create_group_footer">एक नया एमएलएस॰ समूह बनेगा। आप सदस्य जोड सकते हैं तत्पश्चात।</string>
|
||||
@@ -3236,7 +3245,7 @@
|
||||
<string name="automatically_show_url_preview_description">जालपता के पूर्वीक्षण दिखाएँ</string>
|
||||
<string name="autoplay_videos">स्वतःचालन चलचित्र</string>
|
||||
<string name="autoplay_videos_description">स्वतः चालू करें चलचित्रों को जब पटल पर दिखाई दें</string>
|
||||
<string name="avif_metadata_strip_failed">एविफ॰ से परितथ्य नहीं मिटा सके : %1$s</string>
|
||||
<string name="avif_metadata_strip_failed">एविफ॰ से उपतथ्य नहीं मिटा सके। %1$s</string>
|
||||
<string name="award_badge">पदक पुरस्कार</string>
|
||||
<string name="back">पीछे चलें</string>
|
||||
<string name="backup_keys">कुंचिकाएँ सुरक्षित रखें</string>
|
||||
@@ -4106,8 +4115,8 @@
|
||||
<string name="messages_cant_upload_title">आरोहण असफल</string>
|
||||
<string name="messages_new_message_subject">विषय</string>
|
||||
<string name="messages_settings">सन्देश</string>
|
||||
<string name="metadata_strip_failed_title">परितथ्य हटाने में असफल</string>
|
||||
<string name="metadata_strip_failed_upload_cancelled">श्रव्यदृश्याभिलेख से निजी परितथ्य हटाने में असफल। आरोहण निरस्त।</string>
|
||||
<string name="metadata_strip_failed_title">उपतथ्य हटाने में असफल</string>
|
||||
<string name="metadata_strip_failed_upload_cancelled">श्रव्यदृश्याभिलेख से निजी उपतथ्य हटाने में असफल। आरोहण निरस्त।</string>
|
||||
<string name="migrate_bookmarks_success">स्मर्त्तव्यचिह्न सफलतापूर्वक स्थानान्तरित किए गए</string>
|
||||
<string name="missing_lud16">लैटनिंग स्थापना अनुपलब्ध</string>
|
||||
<string name="more_options">अधिक विकल्प</string>
|
||||
@@ -5041,8 +5050,8 @@
|
||||
<string name="spamming_users">कचरालेख प्रेषक</string>
|
||||
<string name="split_notifications_setting_description">दो सूचना पृष्ठसूचक दिखाएँ। अनुचरित (लोग जिनका आप अनुचरण करते हैं) तथा सभी। अपठित संकेतक चमकता है केवल आपके द्वारा अनुचरित लोगों के गतिविधियों के लिए।</string>
|
||||
<string name="split_notifications_setting_title">सूचनाएँ विभाजित करें अनुचरित के अनुसार</string>
|
||||
<string name="strip_metadata_description">निजी परितथ्य हटाने का प्रयास करता है आलम्बित श्रव्यदृश्याभिलेखों से आरोहण पूर्व</string>
|
||||
<string name="strip_metadata_label">निजी परितथ्य हटाएँ</string>
|
||||
<string name="strip_metadata_description">निजी उपतथ्य हटाने का प्रयास करता है आलम्बित श्रव्यदृश्याभिलेखों से आरोहण पूर्व</string>
|
||||
<string name="strip_metadata_label">निजी उपतथ्य हटाएँ</string>
|
||||
<string name="suggest_workouts_setting_description">सम्पन्न व्यायाम पढता है स्वास्थ्य संयोजन से (सामसंग स्वास्थ्य तथा गूगिल फिट तथा फिटबिट तथा गार्मिन इत्यादि) तथा पत्र के रूप में बाँटने का सुझाव देता है। अनुमति अनुरोध केवल संयोजन करने पर।</string>
|
||||
<string name="suggest_workouts_setting_title">व्यायामों का सुझाव बाँटनें के लिए</string>
|
||||
<string name="system">यन्त्रव्यवस्था</string>
|
||||
@@ -5217,9 +5226,36 @@
|
||||
<!-- cordn: groups delivered by an MCP coordinator rather than by relays.
|
||||
The exposure strings state what the coordinator operator learns; see
|
||||
spec/00.md §8 and quartz/plans/2026-09-17-cordn-interop.md. -->
|
||||
<string name="cordn_badge_coordinator">समायोजक समूह</string>
|
||||
<string name="cordn_badge_coordinator_desc">समायोजक द्वारा भेजा गया। पुनःप्रसारकों द्वारा नहीं</string>
|
||||
<string name="cordn_exposure_title">यह समायोजक क्या देख सकता है</string>
|
||||
<string name="cordn_exposure_dimension_content">सन्देश विषयवस्तु</string>
|
||||
<string name="cordn_exposure_dimension_membership">समूह में कौन हैं</string>
|
||||
<string name="cordn_exposure_dimension_messaging">कौन क्या भेजता है</string>
|
||||
<string name="cordn_exposure_level_none">पठन असाध्य</string>
|
||||
<string name="cordn_exposure_level_pseudonymous">एक अस्थायी कुंचिका द्वारा</string>
|
||||
<string name="cordn_exposure_level_identified">आपकी वास्तविक लेखा से सम्बद्ध</string>
|
||||
<string name="cordn_exposure_details">विवरण</string>
|
||||
<string name="cordn_exposure_coordinator">समायोजक %1$s</string>
|
||||
<string name="cordn_health_unknown">सम्पर्क अब तक किया नहीं</string>
|
||||
<string name="cordn_health_ok">प्रतिवचनमध्य</string>
|
||||
<string name="cordn_health_down">कोई प्रतिवचन नहीं</string>
|
||||
<string name="cordn_link_field">cordn1…</string>
|
||||
<string name="cordn_link_inspect">निरीक्षण</string>
|
||||
<string name="cordn_link_paste">चिपकाएँ</string>
|
||||
<string name="cordn_link_clear">रिक्त</string>
|
||||
<string name="cordn_link_invalid">वह एक कोर्डन समूह योजक नहीं। %1$s</string>
|
||||
<string name="cordn_link_group_id">समूह परिचायक</string>
|
||||
<string name="cordn_link_coordinator">समायोजक</string>
|
||||
<string name="cordn_link_relays">अभिगम्य इनके द्वारा</string>
|
||||
<!-- cordn entries in the settings catalog and the Messages chat-type
|
||||
list. Here rather than in amethyst/res because both screens read
|
||||
them through Res. -->
|
||||
<string name="cordn_link_title">कोर्डन समूह योजक</string>
|
||||
<string name="cordn_link_search_keywords">कोर्डन समायोजक समूह योजक आमन्त्रण एमएलएस॰ चर्चा उपतथ्य गोपनीयता अनावरण</string>
|
||||
<string name="cordn_coordinators_title">कोर्डन समायोजक</string>
|
||||
<string name="cordn_coordinators_search_keywords">कोर्डन समायोजक जोडें हटाएँ मिटाएँ स्वास्थ्य सेवासंगणक एमएलएस॰ चर्चा अनुक्रमण</string>
|
||||
<string name="cordn_keypackages_title">कोर्डन कुंचिका पोटलियाँ</string>
|
||||
<!-- cordn strings on screens main migrated to Res: the shared inbox row
|
||||
and the new-conversation picker. -->
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
@@ -5246,16 +5282,28 @@
|
||||
<string name="cyberspace_bag_cancel">रोकें</string>
|
||||
<string name="cyberspace_bag_measuring">खोज का मूल्यांकन इस यन्त्र पर…</string>
|
||||
<string name="cyberspace_bag_progress">खोज सम्पन्न %2$s में से %1$s क्षेत्रों में</string>
|
||||
<string name="cyberspace_bag_too_slow_minutes">अप्राप्य। लगभग %1$d मिनुट का खोज इस यन्त्र पर</string>
|
||||
<string name="cyberspace_bag_too_slow_hours">अप्राप्य। लगभग %1$d घण्टों का खोज इस यन्त्र पर</string>
|
||||
<plurals name="cyberspace_bag_too_slow_minutes">
|
||||
<item quantity="one">अप्राप्य। लगभग %1$d मिनुट का खोज इस यन्त्र पर</item>
|
||||
<item quantity="other">अप्राप्य। लगभग %1$d मिनुट का खोज इस यन्त्र पर</item>
|
||||
</plurals>
|
||||
<plurals name="cyberspace_bag_too_slow_hours">
|
||||
<item quantity="one">अप्राप्य। लगभग %1$d घण्टों का खोज इस यन्त्र पर</item>
|
||||
<item quantity="other">अप्राप्य। लगभग %1$d घण्टों का खोज इस यन्त्र पर</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_not_found">सहायक संकेत में नामित पेटिका में नहीं</string>
|
||||
<string name="cyberspace_bag_damaged">क्षेत्र प्राप्त। पर विषयवस्तु पढने में असफल</string>
|
||||
<string name="cyberspace_bag_dropped">%1$d वस्तु जो यहाँ छिपाया गया था उसके हस्ताक्षर से मेल नहीं तथा परित्यक्त</string>
|
||||
<string name="cyberspace_bag_dropped_many">%1$d वस्तु जो यहाँ छिपाए गए थे उनके हस्ताक्षरों से मेल नहीं तथा परित्यक्त</string>
|
||||
<plurals name="cyberspace_bag_dropped">
|
||||
<item quantity="one">%1$d वस्तु जो यहाँ छिपाया गया था उसके हस्ताक्षर से मेल नहीं तथा परित्यक्त</item>
|
||||
<item quantity="other">%1$d वस्तु जो यहाँ छिपाए गए थे उनके हस्ताक्षरों से मेल नहीं तथा परित्यक्त</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_empty">खोला। पर भीतर कुछ नहीं था</string>
|
||||
<string name="cyberspace_bag_unsigned">हस्ताक्षररहित। इसलिए यह कर्ता केवल एक कथन है</string>
|
||||
<string name="cyberspace_bag_unknown_kind">प्रकार %1$d का वस्तु। जिसे यह ग्राहक चित्रित नहीं करता</string>
|
||||
<string name="cyberspace_bag_opaque">%1$d अष्टकों का अमुक जिसे यह ग्राहक पढता नहीं</string>
|
||||
<plurals name="cyberspace_bag_opaque">
|
||||
<item quantity="one">%1$d अष्टकों का अमुक जिसे यह ग्राहक पढता नहीं</item>
|
||||
<item quantity="other">%1$d अष्टकों का अमुक जिसे यह ग्राहक पढता नहीं</item>
|
||||
</plurals>
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
<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>
|
||||
@@ -5493,13 +5541,19 @@
|
||||
<string name="backup_review_renamed">पुनःनामकृत</string>
|
||||
<string name="backup_review_renamed_tag">पुनःनामकृत</string>
|
||||
<string name="backup_review_saved">इस यन्त्र पर</string>
|
||||
<string name="backup_review_search_people">%1$s लोग खोजें</string>
|
||||
<plurals name="backup_review_search_people">
|
||||
<item quantity="one">%1$s लोग खोजें</item>
|
||||
<item quantity="other">%1$s लोग खोजें</item>
|
||||
</plurals>
|
||||
<string name="backup_review_searching_tag">खोज मध्य</string>
|
||||
<string name="backup_review_service">सेवा</string>
|
||||
<string name="backup_review_service_followers">अनुचर</string>
|
||||
<string name="backup_review_service_rank">श्रेणी</string>
|
||||
<string name="backup_review_service_topics">विषयसूची</string>
|
||||
<string name="backup_review_services_changed">%2$s में से %1$s सेवाएँ परिवर्तित</string>
|
||||
<plurals name="backup_review_services_changed">
|
||||
<item quantity="one">%2$s में से %1$s सेवाएँ परिवर्तित</item>
|
||||
<item quantity="other">%2$s में से %1$s सेवाएँ परिवर्तित</item>
|
||||
</plurals>
|
||||
<string name="backup_review_services_changed_explainer">वे अब अन्य व्यक्ति से आते है। अथवा किसी से नहीं</string>
|
||||
<string name="backup_review_still_blocked">अभी भी बाधित</string>
|
||||
<string name="backup_review_storing_tag">अभिलेखन मध्य</string>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<string name="login_hide_key">Kulcs elrejtése</string>
|
||||
<!-- New Key Warning -->
|
||||
<string name="new_key_warning_title">FONTOS: Mentse el a kulcsait!</string>
|
||||
<string name="new_key_warning_message">A titkos kulcs (nsec) olyan, mint egy jelszó, amelyet SOHA nem lehet visszaállítani vagy helyreállítani. Ez az EGYETLEN módja a fiókhoz való hozzáférésnek, és aki birtokolja, az örökre irányítja ezt a fiókot. Ha elveszíti, a fiókja végleg elvész. Soha ne adja tovább és tárolja egy jelszókezelőben.</string>
|
||||
<string name="new_key_warning_message">A titkos kulcs (nsec) olyan, mint egy jelszó, amelyet SOHA nem lehet visszaállítani vagy helyrehozni. Ez az EGYETLEN módja a fiókhoz való hozzáférésnek, és aki birtokolja, az örökre irányítja ezt a fiókot. Ha elveszíti, a fiókja végleg elvész. Soha ne adja tovább és tárolja egy jelszókezelőben.</string>
|
||||
<string name="new_key_public_label">Nyilvános kulcs (megosztható):</string>
|
||||
<string name="new_key_secret_label">Titkos kulcs (SOHA ne ossza meg!):</string>
|
||||
<string name="new_key_continue_button">Elmentettem a kulcsaimat, folytatás</string>
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="new_key_step_intro_nsec">A titkos kulcs (nsec) egy jelszó, amelyet SOHA nem lehet visszaállítani. Ez az egyetlen alkalom, amikor megjelenik — mentse el most, különben örökre elveszíti a hozzáférését ehhez a fiókhoz.</string>
|
||||
<string name="new_key_keys_title">Saját kulcsok</string>
|
||||
<string name="new_key_confirm_title">Még valami</string>
|
||||
<string name="new_key_confirm_recap">Tárolja a titkos kulcsát egy jelszókezelőben. Ha elveszíti, akkor senki sem tudja helyreállítani Önnek.</string>
|
||||
<string name="new_key_confirm_recap">Tárolja a titkos kulcsát egy jelszókezelőben. Ha elveszíti, akkor senki sem tudja helyrehozni Önnek.</string>
|
||||
<string name="new_key_readonly_info">Ez csak egy olvasásra jogosult fiók. Nem jött létre titkos kulcs, így nincs miről biztonsági mentést készíteni.</string>
|
||||
<!-- Key Backup (Desktop settings) -->
|
||||
<string name="backup_keys_title">Kulcsok biztonsági mentése</string>
|
||||
@@ -42,7 +42,7 @@
|
||||
<string name="backup_keys_show_qr">QR-kód megjelenítése</string>
|
||||
<string name="backup_keys_hide_qr">QR-kód elrejtése</string>
|
||||
<string name="backup_keys_secret_label">Titkos kulcs (nsec)</string>
|
||||
<string name="backup_keys_secret_warning">A titkos kulcs egy jelszó, amelyet SOHA nem lehet visszaállítani vagy helyreállítani. Aki ismeri, az örökre irányíthatja ezt a fiókot. Soha ne adja meg senkinek és tárolja egy biztonságos jelszókezelőben.</string>
|
||||
<string name="backup_keys_secret_warning">A titkos kulcs egy jelszó, amelyet SOHA nem lehet visszaállítani vagy helyrehozni. Aki ismeri, az örökre irányíthatja ezt a fiókot. Soha ne adja meg senkinek és tárolja egy biztonságos jelszókezelőben.</string>
|
||||
<string name="backup_keys_secret_hidden">A titkos kulcs rejtve van</string>
|
||||
<string name="backup_keys_reveal">Titkos kulcs megjelenítése</string>
|
||||
<string name="backup_keys_hide">Titkos kulcs elrejtése</string>
|
||||
@@ -206,7 +206,10 @@
|
||||
<string name="geocache_hunt_new">Új vadászat…</string>
|
||||
<string name="geocache_hunt_none_yet">Még nem hozott létre vadászatot.</string>
|
||||
<string name="geocache_hunt_already_on">Már szerepel ebben a vadászatban</string>
|
||||
<string name="geocache_caches_here">%1$d láda van itt</string>
|
||||
<plurals name="geocache_caches_here">
|
||||
<item quantity="one">%1$d láda van itt</item>
|
||||
<item quantity="other">%1$d láda van itt</item>
|
||||
</plurals>
|
||||
<string name="geocache_photo_remove">Fénykép eltávolítása</string>
|
||||
<string name="geocache_archived_notice">Ezt a ládát archiválták. Már nem játszik.</string>
|
||||
<string name="geocache_ftf_won_by">Az első megtalálást %1$s szerezte meg</string>
|
||||
@@ -265,7 +268,6 @@
|
||||
<string name="geocache_map_recenter">Középre</string>
|
||||
<string name="geocache_map_long_press">Egy láda elrejtéséhez nyomja meg hossza a térképet</string>
|
||||
<string name="geocache_map_open">Megnyitás</string>
|
||||
<string name="geocache_map_pin_count">%1$d láda</string>
|
||||
<string name="geocache_new_section_where">Hol</string>
|
||||
<string name="geocache_new_section_what">Mi</string>
|
||||
<string name="geocache_new_section_extras">Extrák</string>
|
||||
@@ -293,7 +295,10 @@
|
||||
<string name="geocache_new_needs_location">Válassza ki, hogy hol van elrejtve a láda.</string>
|
||||
<string name="geocache_hunt_progress">%2$d / %1$d megtalálva</string>
|
||||
<string name="geocache_hunt_start">Vadászat indítása</string>
|
||||
<string name="geocache_hunt_caches">%1$d láda</string>
|
||||
<plurals name="geocache_hunt_caches">
|
||||
<item quantity="one">%1$d láda</item>
|
||||
<item quantity="other">%1$d láda</item>
|
||||
</plurals>
|
||||
<string name="geocache_hunt_title">Cím</string>
|
||||
<string name="geocache_hunt_description">Leírás</string>
|
||||
<string name="geocache_hunt_banner">Borítókép</string>
|
||||
@@ -342,7 +347,10 @@
|
||||
<string name="qr_scanner_no_code_in_image">Nem található QR-kód a képen</string>
|
||||
<string name="qr_scanner_clipboard_empty">A vágólapon nincs semmi a beolvasáshoz</string>
|
||||
<string name="qr_scanner_pick_one">Érintse meg a beolvasandó kódot</string>
|
||||
<string name="qr_scanner_sequence_progress">%1$s darabot sikerült beolvasni a(z) %2$s darab közül, folytatás</string>
|
||||
<plurals name="qr_scanner_sequence_progress">
|
||||
<item quantity="one">%1$s darabot sikerült beolvasni a(z) %2$s darab közül, folytatás</item>
|
||||
<item quantity="other">%1$s darabot sikerült beolvasni a(z) %2$s darab közül, folytatás</item>
|
||||
</plurals>
|
||||
<string name="qr_scanner_zoom_reset">Nagyítás visszaállítása</string>
|
||||
<string name="qr_scanner_unsupported_title">Az Amethyst nem tudja megnyitni ezt a kódot</string>
|
||||
<string name="qr_scanner_unsupported_secret">Ez a kód egy titkos kulcsot vagy párosítási titkot tartalmaz, ezért a tartalma itt nem jelenik meg. Használja azt a képernyőt, ahol meg kell adni.</string>
|
||||
@@ -646,7 +654,7 @@
|
||||
<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="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 visszaszerezni. Mentse el biztonságos helyre most.</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>
|
||||
@@ -1009,7 +1017,7 @@
|
||||
<string name="relay_auth_session_row_desc">Bejelentkezve maradás az Amethyst újraindításáig</string>
|
||||
<string name="relay_auth_forget_session">Bejelentkezés elfelejtése</string>
|
||||
<string name="relay_auth_session_forgotten_undo">Ha szükség lesz rá, a(z) %1$s ismét rákérdez.</string>
|
||||
<string name="relay_auth_session_undo_blocked">Nincs visszaállítva. A „Soha ne jelentkezzen be” be van kapcsolva, ezért az Amethyst nem fog bejelentkezni ide: %1$s.</string>
|
||||
<string name="relay_auth_session_undo_blocked">Nincs helyreállítva. A „Soha ne jelentkezzen be” be van kapcsolva, ezért az Amethyst nem fog bejelentkezni ide: %1$s.</string>
|
||||
<string name="relay_auth_blocked_section">Letiltva az Ön tiltólistája alapján</string>
|
||||
<string name="relay_auth_blocked_row_desc">Az Amethyst soha nem jelentkezik be a letiltott átjátszókra.</string>
|
||||
<string name="relay_auth_no_blocked">Semmi sincs letiltva. Az Ön által blokkolt átjátszókra soha nem fog bejelentkezni, függetlenül attól, hogy mit állít be itt.</string>
|
||||
@@ -1915,8 +1923,8 @@
|
||||
<string name="cashu_wizard_set_main">Beállítás fő pénztárcaként</string>
|
||||
<string name="cashu_wizard_recover_funds">Összegek átmentése a fő pénztárcába</string>
|
||||
<string name="cashu_wizard_recoverable">%1$s satoshi menthető át</string>
|
||||
<string name="cashu_wizard_recovered">Sikeres átvitel: %1$s satoshi</string>
|
||||
<string name="cashu_wizard_no_funds">Nincsenek átvihető összegek</string>
|
||||
<string name="cashu_wizard_recovered">Átmentve: %1$s satoshi</string>
|
||||
<string name="cashu_wizard_no_funds">Nincsenek átmenthető összegek</string>
|
||||
<string name="cashu_wizard_invalid">Nem sikerült beolvasni ezt a pénztárcát</string>
|
||||
<string name="cashu_wizard_set_main_first">Először állítsa be a fő pénztárcáját, majd mentse át az összegeket a régebbiekből.</string>
|
||||
<string name="cashu_wizard_adopting">Saját pénztárca beállítása…</string>
|
||||
@@ -1959,10 +1967,10 @@
|
||||
<string name="cashu_settings_delete_recommendation">Ajánlás törlése</string>
|
||||
<string name="cashu_settings_delete_confirm_title">Visszavonja az ajánlást?</string>
|
||||
<string name="cashu_settings_add_recommendation">Egy pénzverde ajánlása</string>
|
||||
<string name="cashu_settings_restore_title">Visszaállítás seed-ből</string>
|
||||
<string name="cashu_settings_restore_title">Helyrehozás seed-ből</string>
|
||||
<string name="cashu_settings_restore_subtitle">Minden korábbi titok újralevezetése, és minden mint megkérdezése, hogy visszaadja-e a még nyilvántartásban lévő vak aláírásokat. Hasznos eszközvesztés vagy egy megbízhatatlan átjátszó általi token-esemény törlése esetén.</string>
|
||||
<string name="cashu_settings_restore_running">Pénzverdék vizsgálata…</string>
|
||||
<string name="cashu_settings_restore_nothing_found">Nem található visszaállítható bizonyíték.</string>
|
||||
<string name="cashu_settings_restore_nothing_found">Nem található helyreállítható bizonyíték.</string>
|
||||
<string name="cashu_settings_stop_nutzaps">Nutzapok fogadásának leállítása</string>
|
||||
<string name="cashu_settings_stop_nutzaps_subtitle">Vonja vissza a kind:10019 eseményét, hogy mások ne küldhessenek Önnek több nutzapot. Az Ön pénztárcája és egyenlege változatlan marad.</string>
|
||||
<string name="cashu_settings_stop_nutzaps_confirm_title">Leállítja a nutzapok fogadását?</string>
|
||||
@@ -1970,18 +1978,18 @@
|
||||
<string name="cashu_settings_recreate_key">Nutzap-kulcs újraelőállítása</string>
|
||||
<string name="cashu_settings_recreate_key_subtitle">Egy teljesen új kulcs előállítása a nutzapok fogadásához. Ritkán van rá szükség - általában csak akkor, ha a jelenlegi kulcsa kiszivárgott. A régi kulcsára már elküldött, de még be nem váltott nutzapok elvesznek.</string>
|
||||
<string name="cashu_settings_recreate_key_confirm_title">Újraelőállítja a nutzap-kulcsot?</string>
|
||||
<string name="cashu_settings_recreate_key_confirm_body">Egy új P2PK kulcs kerül előállításra és közzétételre a kind:10019 és kind:17375 eseményeiben, megtartva a jelenlegi pénzverdéit. A küldők elkezdenek nutzapokat zárolni az új kulcshoz. A régi kulcsára már elküldött, de még be nem váltott nutzapok helyreállíthatatlanná válnak. Erre ritkán van szükség.</string>
|
||||
<string name="cashu_settings_recreate_key_confirm_body">Egy új P2PK kulcs kerül előállításra és közzétételre a kind:10019 és kind:17375 eseményeiben, megtartva a jelenlegi pénzverdéit. A küldők elkezdenek nutzapokat zárolni az új kulcshoz. A régi kulcsára már elküldött, de még be nem váltott nutzapok helyrehozhatatlanná válnak. Erre ritkán van szükség.</string>
|
||||
<string name="cashu_settings_recreate_key_action">Kulcs újraelőállítása</string>
|
||||
<string name="cashu_settings_import_key">Nutzap-kulcs importálása</string>
|
||||
<string name="cashu_settings_import_key_subtitle">Cserélje le a nutzap-kulcsát egy beillesztett kulcsra - például a pénztárca biztonsági mentésből történő visszaállításához. Ritkán van rá szükség. A régi kulcsához zárolt nutzapek a továbbiakban nem lesznek beválthatók.</string>
|
||||
<string name="cashu_settings_import_key_subtitle">Cserélje le a nutzap-kulcsát egy beillesztett kulcsra, például a pénztárca biztonsági mentésből történő helyreállításához. Ritkán van rá szükség. A régi kulcsához zárolt nutzapek a továbbiakban nem lesznek beválthatók.</string>
|
||||
<string name="cashu_settings_import_key_confirm_title">Importálja a nutzap-kulcsot?</string>
|
||||
<string name="cashu_settings_import_key_confirm_body">Illessze be a nutzapok fogadásához használandó P2PK privát kulcsot (hex). A kind:10019 és kind:17375 eseményei újra közzé lesznek téve ezzel a kulccsal, megtartva a jelenlegi pénzverdéit. A jelenlegi kulcsához zárolt nutzapok többé nem lesznek beválthatók, kivéve, ha a kulcs megegyezik. Erre ritkán van szükség.</string>
|
||||
<string name="cashu_settings_import_key_field">P2PK privát kulcs (hex)</string>
|
||||
<string name="cashu_settings_import_key_action">Kulcs importálása</string>
|
||||
<string name="cashu_settings_delete_wallet">Pénztárca törlése</string>
|
||||
<string name="cashu_settings_delete_wallet_subtitle">Távolítsa el a pénztárcát és állítsa le a nutzapokat. A fennmaradó egyenleg helyreállíthatatlanná válhat.</string>
|
||||
<string name="cashu_settings_delete_wallet_subtitle">Távolítsa el a pénztárcát és állítsa le a nutzapokat. A fennmaradó egyenleg helyrehozhatatlanná válhat.</string>
|
||||
<string name="cashu_settings_delete_wallet_confirm_title">Törli ezt a pénztárcát?</string>
|
||||
<string name="cashu_settings_delete_wallet_confirm_body">Ez a művelet a kind:17375 pénztárca és a kind:10019 nutzap-információ törlését kéri. Az ecash-igazolások nem törlődnek a pénzverdékből, de a pénztárca kulcsának eltűnésével a megmaradt egyenleg és a be nem váltott nutzapok helyreállíthatatlanná válhatnak. Győződjön meg arról, hogy először elköltötte vagy áthelyezte a pénzét. Ez a művelet nem vonható vissza.</string>
|
||||
<string name="cashu_settings_delete_wallet_confirm_body">Ez a művelet a kind:17375 pénztárca és a kind:10019 nutzap-információ törlését kéri. Az ecash-igazolások nem törlődnek a pénzverdékből, de a pénztárca kulcsának eltűnésével a megmaradt egyenleg és a be nem váltott nutzapok helyrehozhatatlanná válhatnak. Győződjön meg arról, hogy először elköltötte vagy áthelyezte a pénzét. Ez a művelet nem vonható vissza.</string>
|
||||
<string name="cashu_pay_invoice">Számla kifizetése</string>
|
||||
<string name="cashu_get_quote">Árajánlat kérése</string>
|
||||
<string name="cashu_getting_quote">Árajánlat kérése a pénzverdétől…</string>
|
||||
@@ -2147,7 +2155,7 @@
|
||||
<string name="bottom_bar_settings_expand">Beállítások megjelenítése</string>
|
||||
<string name="bottom_bar_settings_reorder_hint">Húzza a rendezéshez, koppintson az ✕ gombra az eltávolításhoz</string>
|
||||
<string name="bottom_bar_settings_remove">Eltávolítás</string>
|
||||
<string name="bottom_bar_settings_restore_default">Alapértelmezés visszaállítása</string>
|
||||
<string name="bottom_bar_settings_restore_default">Alapértelmezés helyreállítása</string>
|
||||
<string name="drawer_settings_title">Saját oldalsó menü</string>
|
||||
<string name="drawer_settings_description">Nyisson meg egy szakaszt, és kapcsolja ki azokat a sorokat, amelyeket soha nem használ. A beállítások mindig láthatók maradnak, így bármikor visszatérhet ide. A szakaszok sorrendje rögzített.</string>
|
||||
<string name="drawer_settings_sections">Szakaszok</string>
|
||||
@@ -2232,7 +2240,7 @@
|
||||
<string name="buzz_system_ttl_set">%1$s beállította, hogy az üzenetek %2$s után tűnjenek el</string>
|
||||
<string name="buzz_system_ttl_cleared">%1$s kikapcsolta az eltűnő üzeneteket</string>
|
||||
<string name="buzz_system_channel_archived">%1$s archiválta ezt a csatornát</string>
|
||||
<string name="buzz_system_channel_unarchived">%1$s visszaállította ezt a csatornát</string>
|
||||
<string name="buzz_system_channel_unarchived">%1$s helyreállította ezt a csatornát</string>
|
||||
<string name="buzz_system_channel_created">%1$s létrehozta ezt a csatornát</string>
|
||||
<string name="buzz_system_channel_deleted">%1$s törölte ezt a csatornát</string>
|
||||
<string name="buzz_system_message_deleted">%1$s törölt egy üzenetet</string>
|
||||
@@ -2877,6 +2885,7 @@
|
||||
<string name="community_rules_violation_wot_gate_failed">Ön nem felel meg a közösség bizalmi hálóra (Web-of-Trust) vonatkozó követelményeinek.</string>
|
||||
<string name="community_rules_violation_stale_rules">A legfrissebb közösségi szabálydokumentum elavultként el lett utasítva.</string>
|
||||
<string name="marmot_groups_title">Marmot csoportok</string>
|
||||
<string name="cordn_groups_title">Cordn csoportok</string>
|
||||
<string name="marmot_create_group">Csoport létrehozása</string>
|
||||
<string name="marmot_create_group_title">Marmot csoport létrehozása</string>
|
||||
<string name="marmot_create_group_footer">Egy új MLS-csoport jön létre. A tagokat később adhatja hozzá.</string>
|
||||
@@ -3408,7 +3417,7 @@
|
||||
</plurals>
|
||||
<string name="cashu_quote_confirm">Kifizetsz %1$s satot + legfeljebb %2$s sat díjat?</string>
|
||||
<string name="cashu_settings_delete_confirm_body">Törlési kérés közzététele a(z) %1$s pénzverdéről szóló kind:38000 ajánlásához. Azok az átjátszók, amelyek tiszteletben tartják a NIP-09-et, el fogják távolítani.</string>
|
||||
<string name="cashu_settings_restore_result">%1$s visszaállíttva %2$s bizonyítékon keresztül.</string>
|
||||
<string name="cashu_settings_restore_result">%1$s helyrehozva %2$s bizonyítékon keresztül.</string>
|
||||
<string name="cashu_successful_redemption">Cashu megkapva</string>
|
||||
<string name="cashu_successful_redemption_explainer">%1$s satoshi érkezett a pénztárcájába. (Költség: %2$s satoshi)</string>
|
||||
<string name="cashu_unsafe_mint_url">Nem biztonságos Cashu pénzverde-cím</string>
|
||||
@@ -3517,7 +3526,7 @@
|
||||
<string name="concord_invite_revoked_ok">Meghívási hivatkozás visszavonva.</string>
|
||||
<string name="concord_invite_title">Meghívóhivatkozás</string>
|
||||
<string name="concord_leave_community">Közösség elhagyása</string>
|
||||
<string name="concord_leave_message">Elhagyja a következőt: %1$s? Eltávolításra kerül ezen fiók listájáról, és leáll a szinkronizálása az Ön eszközein. A közösség nem kap értesítést, és Ön nem kerül le a tagok listájáról. Azok az üzenetek, amelyeket már nem tud visszafejteni, helyreállíthatatlanná válhatnak, és csak új meghívóval térhet vissza.</string>
|
||||
<string name="concord_leave_message">Elhagyja a következőt: %1$s? Eltávolításra kerül ezen fiók listájáról, és leáll a szinkronizálása az Ön eszközein. A közösség nem kap értesítést, és Ön nem kerül le a tagok listájáról. Azok az üzenetek, amelyeket már nem tud visszafejteni, helyrehozhatatlanná válhatnak, és csak új meghívóval térhet vissza.</string>
|
||||
<string name="concord_leave_owner_warning">Ön hozta létre ezt a közösséget. A kilépés nem törli, és nem is adja át másnak, de eldobja a listáján tárolt tulajdonosi kulcsot — a jövőben nem fogja tudni kezelni.</string>
|
||||
<string name="concord_leave_title">Elhagyja a közösséget?</string>
|
||||
<string name="concord_make_admin">Kinevezés adminisztrátornak</string>
|
||||
@@ -4237,7 +4246,7 @@
|
||||
<string name="napplets">nKisalkalmazások</string>
|
||||
<string name="nest_chat_send_failed_title">Nem sikerült elküldeni az üzenetet</string>
|
||||
<string name="nest_hush_local">Előadó elnémítása</string>
|
||||
<string name="nest_hush_local_restore">Ezen előadó visszaállítása</string>
|
||||
<string name="nest_hush_local_restore">Ezen előadó helyreállítása</string>
|
||||
<string name="nest_leave">Elhagyás</string>
|
||||
<string name="nest_leave_host_close_failed">Nem sikerült a szobát zártként megjelölni. Távozás ettől függetlenül — a szoba automatikusan bezár.</string>
|
||||
<plurals name="nest_listener_count">
|
||||
@@ -5217,14 +5226,120 @@
|
||||
<!-- cordn: groups delivered by an MCP coordinator rather than by relays.
|
||||
The exposure strings state what the coordinator operator learns; see
|
||||
spec/00.md §8 and quartz/plans/2026-09-17-cordn-interop.md. -->
|
||||
<string name="cordn_badge_coordinator">Koordinátor-csoport</string>
|
||||
<string name="cordn_badge_coordinator_desc">Koordinátor kézbesíti, nem az átjátszók</string>
|
||||
<string name="cordn_exposure_title">Mit lát ez a koordinátor</string>
|
||||
<string name="cordn_exposure_subtitle">A koordinátor egyetlen kiszolgáló, amely ennek a csoportnak minden üzenetét sorrendben továbbítja. Ez másfajta kompromisszum, mint az átjátszóké; érdemes utánaolvasnia, mielőtt úgy kezelné ezt, mint bármely más csevegést.</string>
|
||||
<string name="cordn_exposure_dimension_content">Üzenetek tartalma</string>
|
||||
<string name="cordn_exposure_dimension_membership">Ki van a csoportban</string>
|
||||
<string name="cordn_exposure_dimension_messaging">Ki mit küld</string>
|
||||
<string name="cordn_exposure_level_none">Olvashatatlan</string>
|
||||
<string name="cordn_exposure_level_pseudonymous">Eldobható kulcs alatt</string>
|
||||
<string name="cordn_exposure_level_identified">A valódi fiókjához van kötve</string>
|
||||
<string name="cordn_exposure_details">Részletek</string>
|
||||
<string name="cordn_exposure_coordinator">%1$s koordinátor</string>
|
||||
<string name="cordn_exposure_differs">Ez nem ugyanaz a kitettség, mint egy Marmot csoportnál, ahol egyetlen üzemeltető sem birtokolja a teljes beszélgetést.</string>
|
||||
<string name="cordn_note_membership">A csatlakozás mindkét végén valódi fiókokat nevez meg, így a koordinátor tudja, ki van ebben a csoportban.</string>
|
||||
<string name="cordn_note_linked">Egyetlen eldobható kulcs küld és kér le minden üzenetet az itteni csoportjához, így a koordinátor megállapíthatja, hogy mindegyik Ön.</string>
|
||||
<string name="cordn_note_history">Egyetlen üzemeltető birtokolja minden általa továbbított csoport teljes, sorrendbe rendezett előzményét.</string>
|
||||
<string name="cordn_note_publication">A közzétett kulcscsomag egy aláírt nyilvántartás arról, hogy ez a fiók koordinátort használ, és a koordinátor bárkinek átadhatja.</string>
|
||||
<string name="cordn_note_sizes">Az üzenetek nincsenek kitöltve, így a koordinátor mindegyiket látja, hogy milyen hosszúak.</string>
|
||||
<string name="cordn_note_encryption_bug">Ez a kliens nem titkosít a koordinátor felé. Ez egy hiba, jelentse minél hamarabb.</string>
|
||||
<string name="cordn_health_unknown">Még nem jött létra a kapcsolat</string>
|
||||
<string name="cordn_health_ok">Válaszol</string>
|
||||
<string name="cordn_health_down">Nem válaszol</string>
|
||||
<string name="cordn_link_explainer">Illesszen be egy Önnel megosztott cordn1… hivatkozást, hogy lássa, melyik koordinátor továbbítja azt a csoportot, és mit tudna meg az az üzemeltető Önről, ha csatlakozna.</string>
|
||||
<string name="cordn_link_field">cordn1…</string>
|
||||
<string name="cordn_link_inspect">Vizsgálat</string>
|
||||
<string name="cordn_link_paste">Beillesztés</string>
|
||||
<string name="cordn_link_clear">Törlés</string>
|
||||
<string name="cordn_link_invalid">Ez nem egy Cordn csoporthivatkozás: %1$s</string>
|
||||
<string name="cordn_link_group_id">Csoportazonosító</string>
|
||||
<string name="cordn_link_coordinator">Koordinátor</string>
|
||||
<string name="cordn_link_relays">Elérhető ezeken keresztül</string>
|
||||
<string name="cordn_link_no_coordinator">Ez a hivatkozás nem nevez meg koordinátort, így önmagában nem követhető. Kérdezze meg a küldőt, melyik koordinátor továbbítja a csoportot.</string>
|
||||
<string name="cordn_link_not_joinable">A hivatkozás vizsgálata nem csatlakozik semmihez, és a birtoklása nem tesz taggá.</string>
|
||||
<!-- cordn entries in the settings catalog and the Messages chat-type
|
||||
list. Here rather than in amethyst/res because both screens read
|
||||
them through Res. -->
|
||||
<string name="cordn_link_title">Cordn csoporthivatkozás</string>
|
||||
<string name="cordn_link_search_keywords">cordn koordinátor csoporthivatkozás meghívó mls csevegés metaadat adatvédelem kitettség</string>
|
||||
<string name="cordn_coordinators_title">Cordn koordinátorok</string>
|
||||
<string name="cordn_coordinators_search_keywords">cordn koordinátor hozzáadás eltávolítás tisztítás állapot kiszolgáló mls csevegés sorbarendezés</string>
|
||||
<string name="cordn_keypackages_title">Cordn kulcscsomagok</string>
|
||||
<string name="cordn_keypackages_search_keywords">cordn kulcscsomag közzététel meghívó végsőmegoldás koordinátor mls</string>
|
||||
<string name="cordn_backup_title">Cordn biztonsági mentés</string>
|
||||
<string name="cordn_backup_search_keywords">cordn biztonsági mentés helyreállítás exportálás importálás jelmondat csoportok helyrehozás</string>
|
||||
<string name="chat_type_cordn_title">Cordn csoportok</string>
|
||||
<string name="chat_type_cordn_desc">Végpontok között titkosított csoportok, amelyeket az Ön által választott koordinátor rendez, nem pedig átjátszók.</string>
|
||||
<!-- cordn strings on screens main migrated to Res: the shared inbox row
|
||||
and the new-conversation picker. -->
|
||||
<string name="cordn_group_untitled">%1$s csoport</string>
|
||||
<string name="cordn_group_no_messages_yet">Még nincsenek üzenetek</string>
|
||||
<string name="cordn_group_via_coordinator">Cordn csoport, továbbítja: %1$s</string>
|
||||
<string name="cordn_preview_deleted">Üzenet törölve</string>
|
||||
<string name="cordn_preview_voice_note">Hangfelvétel</string>
|
||||
<string name="cordn_preview_photo">Fénykép</string>
|
||||
<string name="cordn_preview_video">Videó</string>
|
||||
<string name="cordn_preview_file">Fájl</string>
|
||||
<string name="new_conversation_cordn_title">Cordn csoport</string>
|
||||
<string name="new_conversation_cordn_tagline">Titkosított csoportos csevegés, amelyet az Ön által választott koordinátor rendez.</string>
|
||||
<string name="new_conversation_cordn_chip">Koordinált</string>
|
||||
<string name="new_conversation_cordn_best">Azoknak a csapatoknak a legjobb, amelyek a beszélgetés egyetlen megbízható sorrendjét szeretnék.</string>
|
||||
<string name="new_conversation_cordn_cta">Cordn csoport létrehozása</string>
|
||||
<string name="new_conversation_cordn_pro_1">Végponttól végpontig titkosított MLS-sel – a koordinátor soha nem olvashat el egyetlen üzenetet sem.</string>
|
||||
<string name="new_conversation_cordn_pro_2">Egy mindenki által elfogadott sorrend, így az előzményeket egy hibás óra sem keverheti össze.</string>
|
||||
<string name="new_conversation_cordn_con_1">A koordinátor tudja, ki van a csoportban és mikor beszélnek, még ha nem is tudja elolvasni, mit mondanak.</string>
|
||||
<string name="cordn_invitations_entry">Meghívták egy cordn csoportba?</string>
|
||||
<string name="cordn_invitations_entry_action">Meghívók áttekintése</string>
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<string name="cordn_hub_title">Cordn</string>
|
||||
<string name="cordn_hub_explainer">Csoportok, amelyeket az Ön által választott koordinátor kézbesít, nem pedig átjátszók.</string>
|
||||
<string name="cordn_hub_link">Csoporthivatkozás vizsgálata</string>
|
||||
<string name="cordn_hub_link_desc">Nézze meg, mire mutat egy cordn1… hivatkozás, mielőtt bármit tenne</string>
|
||||
<string name="cordn_migrate_section_send">Átköltöztetés erről a telefonról</string>
|
||||
<string name="cordn_migrate_section_receive">Átköltöztetés egy másik telefonról</string>
|
||||
<string name="cordn_keypackages_section">Közzétett kulcscsomagok</string>
|
||||
<string name="cordn_link_section_input">A hivatkozás</string>
|
||||
<string name="cordn_coordinators_section_yours">Az Ön által használt koordinátorok</string>
|
||||
<string name="cordn_coordinators_section_discover">Bemutatkozottak</string>
|
||||
<string name="cordn_coordinators_section_manual">Hozzáadás kézzel</string>
|
||||
<string name="cordn_backup_section_passphrase">Jelmondat</string>
|
||||
<string name="cordn_backup_section_export">Biztonsági mentés készítése</string>
|
||||
<string name="cordn_backup_section_restore">Helyreállítás biztonsági mentésből</string>
|
||||
<string name="cordn_hub_section_service">A koordinátor</string>
|
||||
<string name="cordn_hub_section_device">Ez az eszköz</string>
|
||||
<string name="cordn_hub_coordinators">Koordinátorok</string>
|
||||
<string name="cordn_hub_coordinators_desc">A kiszolgálók, amelyek a csoportjait továbbítják</string>
|
||||
<string name="cordn_hub_keypackages">Kulcscsomagok</string>
|
||||
<string name="cordn_hub_keypackages_desc">Ez teszi lehetővé, hogy mások csoportokhoz adhassák Önt</string>
|
||||
<string name="cordn_hub_backup">Biztonsági mentés és helyreállítás</string>
|
||||
<string name="cordn_hub_backup_desc">Egy jelmondattal titkosított fájl, amelyet Ön őriz</string>
|
||||
<string name="cordn_hub_migrate">Átköltöztetés másik telefonra</string>
|
||||
<string name="cordn_hub_migrate_desc">Költöztesse át a csoportjait arra az eszközre, amelyre vált</string>
|
||||
<string name="cordn_migrate_title">Átköltöztetés egy másik eszközre</string>
|
||||
<string name="cordn_migrate_explainer">A cordn csoportjai ezen az eszközön élnek. Az átköltöztetéshez egyetlen kód kell: ez az eszköz közzéteszi őket, és a másik eszközön beolvashatja őket, majd ez az eszköz nem tárolja tovább.</string>
|
||||
<string name="cordn_migrate_sign_in_first">Először jelentkezzen be ugyanazzal a fiókkal a másik eszközön. Ez a csoportjait költözteti át, és nem a kulcsát.</string>
|
||||
<string name="cordn_migrate_export">Átköltöztetés indítása</string>
|
||||
<string name="cordn_migrate_exporting">Közzététel…</string>
|
||||
<string name="cordn_migrate_scan_this">Olvassa be ezt a másik eszközön</string>
|
||||
<string name="cordn_migrate_code_note">A kód csak egy mutató. Aki lefényképezi, semmit sem tud meg, amire mutat, az az Ön fiókjához van titkosítva.</string>
|
||||
<string name="cordn_migrate_handed_off">Ez az eszköz átköltöztette a csoportjait</string>
|
||||
<string name="cordn_migrate_handed_off_desc">Leállította az átköltöztetést, mert a két eszköz, amely ugyanabból a csoportból küld, mindenki számára tönkretenné az üzenetek fogadását. A csoportjai még mindig ezen az eszközön vannak, és semmi sem törlődött.</string>
|
||||
<string name="cordn_migrate_cancel">Eszköz visszavétele</string>
|
||||
<string name="cordn_migrate_cancel_desc">Ezt akkor használja, ha az átköltöztetés nem fejeződött be. Csak akkor tegye, ha a másik eszközön még nem kezdett el üzeneteket küldeni.</string>
|
||||
<string name="cordn_migrate_receive">Fogadás egy másik eszközről</string>
|
||||
<string name="cordn_migrate_scan">Kód beolvasása</string>
|
||||
<string name="cordn_migrate_paste">vagy illessze be</string>
|
||||
<string name="cordn_migrate_import">Csoportok átköltöztetése ide</string>
|
||||
<string name="cordn_migrate_importing">Lekérés…</string>
|
||||
<string name="cordn_migrate_replaces_warning">Ez lecseréli az eszközön már meglévő cordn csoportokat. Ezek nem olvaszthatók egybe.</string>
|
||||
<string name="cordn_migrate_no_groups">Nincsenek átköltöztethető cordn csoportok ezen az eszközön.</string>
|
||||
<string name="cordn_migrate_no_server">Először állítson be médiakiszolgálót, a titkosított dokumentumoknak valahol lenniük kell, amíg a másik telefon le nem kéri őket.</string>
|
||||
<string name="cordn_migrate_exposure_title">Mi hagyja el ezt az eszközt</string>
|
||||
<string name="cordn_migrate_exposure_body">A csoport állapota titkosítva van, és fel lesz töltve a médiakiszolgálójára, hogy a másik eszköz le tudja kérni. Az a kiszolgáló számára olvashatatlan, csak egy méretet és egy időpontot lát. Ha nem szeretne semmit hátrahagyni, utána törölje a blobokat.</string>
|
||||
<string name="sno_object_title">3D-objektum</string>
|
||||
<string name="sno_object_details">%1$d csúcs · %2$d lap</string>
|
||||
<string name="sno_object_unreadable">Ezt a 3D-objektumot nem sikerült beolvasni (%1$s szabály)</string>
|
||||
@@ -5246,28 +5361,146 @@
|
||||
<string name="cyberspace_bag_cancel">Leállítás</string>
|
||||
<string name="cyberspace_bag_measuring">A keresés árazása ezen az eszközön…</string>
|
||||
<string name="cyberspace_bag_progress">%2$s régióból %1$s átkutatva</string>
|
||||
<string name="cyberspace_bag_too_slow_minutes">Elérhetetlen: körülbelül %1$d perc keresés ezen az eszközön</string>
|
||||
<string name="cyberspace_bag_too_slow_hours">Elérhetetlen: körülbelül %1$d óra keresés ezen az eszközön</string>
|
||||
<plurals name="cyberspace_bag_too_slow_minutes">
|
||||
<item quantity="one">Elérhetetlen: körülbelül %1$d perc keresés ezen az eszközön</item>
|
||||
<item quantity="other">Elérhetetlen: körülbelül %1$d perc keresés ezen az eszközön</item>
|
||||
</plurals>
|
||||
<plurals name="cyberspace_bag_too_slow_hours">
|
||||
<item quantity="one">Elérhetetlen: körülbelül %1$d óra keresés ezen az eszközön</item>
|
||||
<item quantity="other">Elérhetetlen: körülbelül %1$d óra keresés ezen az eszközön</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_not_found">Nincs abban a dobozban, amelyet a nyom megnevezett</string>
|
||||
<string name="cyberspace_bag_damaged">A régió megvan, de a tartalmát nem sikerült beolvasni</string>
|
||||
<string name="cyberspace_bag_dropped">Az itt elrejtett %1$d elem nem egyezett az aláírásával, ezért el lett vetve</string>
|
||||
<string name="cyberspace_bag_dropped_many">Az itt elrejtett %1$d elem nem egyezett az aláírásával, ezért el lettek vetve</string>
|
||||
<plurals name="cyberspace_bag_dropped">
|
||||
<item quantity="one">Az itt elrejtett %1$d elem nem egyezett az aláírásával, ezért el lett vetve</item>
|
||||
<item quantity="other">Az itt elrejtett %1$d elem nem egyezett az aláírásával, ezért el lettek vetve</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_empty">Kinyitva, és nem volt benne semmi</string>
|
||||
<string name="cyberspace_bag_unsigned">Aláírás nélküli, így ez a szerző csak állítás</string>
|
||||
<string name="cyberspace_bag_unknown_kind">Egy %1$d típusú elem, amelyet ez a kliens nem jelenít meg</string>
|
||||
<string name="cyberspace_bag_opaque">%1$d bájt valamiből, amit ez a kliens nem olvas</string>
|
||||
<plurals name="cyberspace_bag_opaque">
|
||||
<item quantity="one">%1$d bájt valamiből, amit ez a kliens nem olvas</item>
|
||||
<item quantity="other">%1$d bájt valamiből, amit ez a kliens nem olvas</item>
|
||||
</plurals>
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
<string name="browser_pill_close">Bezárás</string>
|
||||
<string name="browser_pill_tile_copy">Hivatkozás másolása</string>
|
||||
<string name="browser_pill_tile_find">Keresés</string>
|
||||
<string name="browser_pill_tile_text">Szövegméret</string>
|
||||
<string name="browser_pill_tile_desktop">Asztali</string>
|
||||
<string name="browser_pill_tile_home">Hozzáadás a kezdőképernyőhöz</string>
|
||||
<string name="browser_pill_tile_other">Másik böngésző</string>
|
||||
<string name="browser_pill_tile_full">Teljes képernyő</string>
|
||||
<string name="browser_pill_edit_address">Cím szerkesztése</string>
|
||||
<string name="browser_pill_back">Vissza</string>
|
||||
<string name="browser_pill_forward">Előre</string>
|
||||
<string name="browser_pill_reload">Újratöltés</string>
|
||||
<string name="browser_pill_stop">Betöltés leállítása</string>
|
||||
<string name="browser_pill_favorite_add">Hozzáadás a kedvencekhez</string>
|
||||
<string name="browser_pill_favorite_remove">Eltávolítás a kedvencekből</string>
|
||||
<string name="browser_pill_share">Megosztás</string>
|
||||
<string name="browser_pill_copy">Hivatkozás másolása</string>
|
||||
<string name="browser_pill_find">Keresés az oldalon</string>
|
||||
<string name="browser_pill_text_size">Szövegméret</string>
|
||||
<string name="browser_pill_add_home">Hozzáadás a kezdőképernyőhöz</string>
|
||||
<string name="browser_pill_desktop">Asztali oldal</string>
|
||||
<string name="browser_pill_other_browser">Megnyitás böngészőben</string>
|
||||
<string name="browser_pill_other_browser_named">Megnyitás a(z) %1$s alkalmazásban</string>
|
||||
<string name="browser_pill_full_screen">Teljes képernyő</string>
|
||||
<string name="browser_pill_left_site">Elhagyta a(z) %1$s oldalt</string>
|
||||
<string name="browser_pill_back_to_app">Vissza az alkalmazásba</string>
|
||||
<string name="browser_pill_text_smaller">Kisebb szöveg</string>
|
||||
<string name="browser_pill_text_larger">Nagyobb szöveg</string>
|
||||
<string name="browser_pill_text_reset">Visszaállítás</string>
|
||||
<string name="browser_pill_text_value">%1$d%</string>
|
||||
<string name="browser_pill_privacy">Adatvédelem</string>
|
||||
<string name="browser_pill_tor_title">Onion-útválasztás</string>
|
||||
<string name="browser_pill_tor_on">Az oldal nem látja az Ön IP-címét</string>
|
||||
<string name="browser_pill_tor_off">Az oldal látja az Ön IP-címét</string>
|
||||
<string name="browser_pill_site_settings">Oldalbeállítások</string>
|
||||
<string name="browser_pill_site_settings_none">Még semmi sincs engedélyezve</string>
|
||||
<string name="browser_pill_access">Mihez férhet hozzá</string>
|
||||
<string name="browser_pill_access_desc">A kulcsai soha nem hagyják el az Amethystet</string>
|
||||
<string name="browser_pill_access_keys_desc">Minden aláírás, közzététel, feltöltés vagy fizetés az Ön jóváhagyását követeli meg</string>
|
||||
<string name="browser_pill_access_none">Nincs különleges hozzáférés</string>
|
||||
<string name="browser_pill_access_none_desc">Homokozóban fut, és nem tud cselekedni a fiókjában</string>
|
||||
<string name="browser_pill_access_manage">Engedélyek kezelése</string>
|
||||
<string name="browser_pill_access_nsite">nOldal · homokozóban</string>
|
||||
<string name="browser_pill_access_napplet">nKisalkalmazás · homokozóban</string>
|
||||
<string name="browser_pill_console">Konzol</string>
|
||||
<string name="browser_pill_security_https">Biztonságos kapcsolat</string>
|
||||
<string name="browser_pill_security_http">Nem biztonságos</string>
|
||||
<string name="browser_pill_security_tor">Onion-útvonalon</string>
|
||||
<string name="browser_pill_security_sandbox">Homokozóban futó alkalmazás</string>
|
||||
<string name="browser_pill_permission_camera">Kamera</string>
|
||||
<string name="browser_pill_permission_microphone">Mikrofon</string>
|
||||
<string name="browser_pill_permission_location">Helyzet</string>
|
||||
<string name="browser_pill_decision_ask">Rákérdezés</string>
|
||||
<string name="browser_pill_decision_allow">Engedélyezés</string>
|
||||
<string name="browser_pill_decision_block">Blokkolás</string>
|
||||
<string name="browser_pill_permission_state">%1$s %2$s</string>
|
||||
<string name="browser_pill_decision_allowed">engedélyezve</string>
|
||||
<string name="browser_pill_decision_blocked">blokkolva</string>
|
||||
<string name="browser_pill_address_hint">Keresés vagy cím megadása</string>
|
||||
<string name="browser_pill_go">Ugrás</string>
|
||||
<string name="browser_pill_clear">Törlés</string>
|
||||
<string name="browser_pill_paste_go">Beillesztés és ugrás</string>
|
||||
<string name="browser_pill_fill_in">Cím használata</string>
|
||||
<string name="browser_pill_find_hint">Keresés az oldalon</string>
|
||||
<string name="browser_pill_find_count">%1$d / %2$d</string>
|
||||
<string name="browser_pill_find_none">Nincs találat</string>
|
||||
<string name="browser_pill_find_previous">Előző találat</string>
|
||||
<string name="browser_pill_find_next">Következő találat</string>
|
||||
<string name="browser_pill_find_close">Keresés bezárása az oldalon</string>
|
||||
<string name="browser_pill_console_all">Összes</string>
|
||||
<string name="browser_pill_console_errors">Hibák</string>
|
||||
<string name="browser_pill_console_warnings">Figyelmeztetések</string>
|
||||
<string name="browser_pill_console_copy">Másolás</string>
|
||||
<string name="browser_pill_console_clear">Törlés</string>
|
||||
<string name="browser_pill_console_empty">Még semmi sincs naplózva</string>
|
||||
<string name="browser_pill_perm_title">Ez az oldal használni akarja</string>
|
||||
<string name="browser_pill_perm_camera_desc">Nézze meg, amit a kamerája lát</string>
|
||||
<string name="browser_pill_perm_microphone_desc">Hallgassa meg, amit a mikrofonja hall</string>
|
||||
<string name="browser_pill_perm_location_desc">Nagyjából tudja, hol van</string>
|
||||
<string name="browser_pill_perm_tor_note">A hívások Tor-on keresztül is felfedhetik az IP-címét.</string>
|
||||
<string name="browser_pill_perm_allow">Engedélyezés a látogatás idejére</string>
|
||||
<string name="browser_pill_perm_once">Csak most az egyszer</string>
|
||||
<string name="browser_pill_perm_deny">Ne engedélyezze</string>
|
||||
<string name="browser_pill_dialog_says">%1$s üzeni</string>
|
||||
<string name="browser_pill_dialog_generic">Ez az oldal üzeni</string>
|
||||
<string name="browser_pill_dialog_block">Oldal megakadályozása a még több párbeszédablak megjelenítésében</string>
|
||||
<string name="browser_pill_dialog_answer">Az Ön válasza</string>
|
||||
<string name="browser_pill_dialog_leave_title">Elhagyja az oldalt?</string>
|
||||
<string name="browser_pill_dialog_leave_message">Lehet, hogy a módosításai nem lettek mentve.</string>
|
||||
<string name="browser_pill_dialog_leave">Elhagyás</string>
|
||||
<string name="browser_pill_ok">OK</string>
|
||||
<string name="browser_pill_cancel">Mégse</string>
|
||||
<string name="browser_pill_info_connection">Kapcsolódás</string>
|
||||
<string name="browser_pill_info_https">A kapcsolat titkosított</string>
|
||||
<string name="browser_pill_info_https_desc">Az Ön által küldött információ útközben nem olvasható.</string>
|
||||
<string name="browser_pill_info_http">A kapcsolat nincs titkosítva</string>
|
||||
<string name="browser_pill_info_http_desc">Ne adjon meg jelszavakat vagy fizetési adatokat.</string>
|
||||
<string name="browser_pill_info_tor">Onion-útvonalon Tor-on keresztül</string>
|
||||
<string name="browser_pill_info_open">Nyílt web</string>
|
||||
<string name="browser_pill_info_certificate">Tanúsítvány</string>
|
||||
<string name="browser_pill_info_certificate_desc">%2$s állította ki %1$s részére · érvényes eddig: %3$s</string>
|
||||
<string name="browser_pill_info_permissions">Engedélyek</string>
|
||||
<string name="browser_pill_info_site_data">Sütik és oldaladatok</string>
|
||||
<string name="browser_pill_info_site_data_desc">Bejelentkezések és beállítások, amelyeket ez az oldal ehhez a fiókhoz mentett</string>
|
||||
<string name="browser_pill_info_clear">Oldaladatok törlése</string>
|
||||
<string name="browser_pill_info_clear_confirm">Kijelentkezik erről az oldalról és törli az adatait?</string>
|
||||
<string name="backup_action_block_again">%1$s újbóli letiltása</string>
|
||||
<string name="backup_action_keep_count">%1$s megtartása</string>
|
||||
<string name="backup_action_rejoin">Újbóli csatlakozás ehhez: %1$s</string>
|
||||
<string name="backup_action_remute">%1$s újbóli némítása</string>
|
||||
<string name="backup_action_restore_count">%1$s visszaállítása</string>
|
||||
<string name="backup_action_restore_feeds">Hírfolyamok visszaállítása</string>
|
||||
<string name="backup_action_restore_places">Helyek visszaállítása</string>
|
||||
<string name="backup_action_restore_profile">Profil visszaállítása</string>
|
||||
<string name="backup_action_restore_providers">Szolgáltatók visszaállítása</string>
|
||||
<string name="backup_action_restore_relays">Átjátszók visszaállítása</string>
|
||||
<string name="backup_action_restore_topics">Témák visszaállítása</string>
|
||||
<string name="backup_action_restore_wallet">Pénztárca visszaállítása</string>
|
||||
<string name="backup_action_restore_count">%1$s helyreállítása</string>
|
||||
<string name="backup_action_restore_feeds">Hírfolyamok helyreállítása</string>
|
||||
<string name="backup_action_restore_places">Helyek helyreállítása</string>
|
||||
<string name="backup_action_restore_profile">Profil helyreállítása</string>
|
||||
<string name="backup_action_restore_providers">Szolgáltatók helyreállítása</string>
|
||||
<string name="backup_action_restore_relays">Átjátszók helyreállítása</string>
|
||||
<string name="backup_action_restore_topics">Témák helyreállítása</string>
|
||||
<string name="backup_action_restore_wallet">Pénztárca helyreállítása</string>
|
||||
<string name="backup_card_accept">Elfogadás</string>
|
||||
<plurals name="backup_card_and_added">
|
||||
<item quantity="one">%1$s és %2$d hozzáadva</item>
|
||||
@@ -5401,7 +5634,7 @@
|
||||
<string name="backup_conflict_relay_read_write">olvasás és írás</string>
|
||||
<string name="backup_conflict_relay_write_only">csak írható</string>
|
||||
<string name="backup_conflict_removed">Eltávolítva (%1$s)</string>
|
||||
<string name="backup_conflict_restore_mine">Mentett verzió visszaállítása</string>
|
||||
<string name="backup_conflict_restore_mine">Mentett verzió helyreállítása</string>
|
||||
<string name="backup_conflict_title">Ön módosította a következőt: %1$s, egy másik alkalmazásban</string>
|
||||
<string name="backup_entry_algo_feed">Hírfolyamok</string>
|
||||
<string name="backup_entry_chat_room">Csevegőszobák</string>
|
||||
@@ -5493,13 +5726,19 @@
|
||||
<string name="backup_review_renamed">átnevezte</string>
|
||||
<string name="backup_review_renamed_tag">Átnevezve</string>
|
||||
<string name="backup_review_saved">Ezen az eszközön</string>
|
||||
<string name="backup_review_search_people">%1$s személy keresése</string>
|
||||
<plurals name="backup_review_search_people">
|
||||
<item quantity="one">%1$s személy keresése</item>
|
||||
<item quantity="other">%1$s személy keresése</item>
|
||||
</plurals>
|
||||
<string name="backup_review_searching_tag">Keresés</string>
|
||||
<string name="backup_review_service">Szolgáltatás</string>
|
||||
<string name="backup_review_service_followers">Követők</string>
|
||||
<string name="backup_review_service_rank">Rang</string>
|
||||
<string name="backup_review_service_topics">Témák</string>
|
||||
<string name="backup_review_services_changed">%2$s szolgáltatásból %1$s módosult</string>
|
||||
<plurals name="backup_review_services_changed">
|
||||
<item quantity="one">%2$s szolgáltatásból %1$s módosult</item>
|
||||
<item quantity="other">%2$s szolgáltatásból %1$s módosult</item>
|
||||
</plurals>
|
||||
<string name="backup_review_services_changed_explainer">Most már valaki mástól vagy senkitől sem származnak</string>
|
||||
<string name="backup_review_still_blocked">Továbbra is le van tiltva</string>
|
||||
<string name="backup_review_storing_tag">Tárolás</string>
|
||||
@@ -5574,4 +5813,252 @@
|
||||
<string name="backup_type_trust_providers_explainer">A szolgáltatások, amelyekben megbízik, hogy rangsorolják és ellenőrizzék Önnek az embereket.</string>
|
||||
<string name="backup_type_trusted_relays">megbízható átjátszólista</string>
|
||||
<string name="backup_type_trusted_relays_explainer">Átjátszók, amelyekhez kérdezés nélkül kapcsolódhat.</string>
|
||||
<string name="cordn_action_delete">Törlés</string>
|
||||
<string name="cordn_action_edit">Szerkesztés</string>
|
||||
<string name="cordn_action_editing">Üzenet szerkesztése</string>
|
||||
<string name="cordn_action_go_to_message">Ugrás az üzenetre</string>
|
||||
<string name="cordn_action_pin">Kitűzés</string>
|
||||
<string name="cordn_action_reply">Válasz</string>
|
||||
<string name="cordn_action_unpin">Kitűzés megszüntetése</string>
|
||||
<string name="cordn_admin_action_failed">Nem sikerült végrehajtani a módosítás.</string>
|
||||
<string name="cordn_admin_coordinator_silent">A koordinátor nem válaszolt, így semmi sem változott. Próbálja újra.</string>
|
||||
<string name="cordn_admin_no_key_package">%1$s nem tett közzé kulcscsomagot ehhez a koordinátorhoz, így még nem adható hozzá. Kérje meg, hogy először nyissa meg a cordnt ezen a koordinátoron.</string>
|
||||
<string name="cordn_admin_no_self_remove">Nem távolíthatja el saját magát egy cordn csoportból.</string>
|
||||
<string name="cordn_admin_no_welcome">%1$s számára nem sikerült utat biztosítani a csoportba, így a hozzáadása megszakadt.</string>
|
||||
<string name="cordn_admin_not_a_member">%1$s nincs ebben a csoportban.</string>
|
||||
<string name="cordn_admin_someone">Az a személy</string>
|
||||
<string name="cordn_admin_wrong_key_package">Ez a koordinátor egy máshoz tartozó kulcscsomagot szolgáltatott, így %1$s nem lett hozzáadva. Semmi sem változott.</string>
|
||||
<string name="cordn_backup_contents_body">A csoport titkosítási kulcsai, a kulcscsomagjai és azokban a csoportokban lévő minden üzenet. Aki megnyitja, elolvashatja a beszélgetéseket. A jelmondat az egyetlen dolog, ami védi, miután elhagyja az Amethystet.</string>
|
||||
<string name="cordn_backup_contents_title">Mi van a fájlban</string>
|
||||
<string name="cordn_backup_explainer">Az nsec nem tudja visszahozni a cordn csoportokat. Egy cordn csoport titkosítási állapotként él ezen az eszközön, és sorrendbe rendezett adatfolyamként egy koordinátoron, amely nem tudja elolvasni; ha biztonsági mentés nélkül elveszíti az eszközt, a csoport eltűnik, beleértve mindazt, ami már elhangzott benne.</string>
|
||||
<string name="cordn_backup_export">Exportálás</string>
|
||||
<string name="cordn_backup_exported">Biztonsági mentés kész.</string>
|
||||
<string name="cordn_backup_failed">Ez nem működött. Ellenőrizze a jelmondatot és a fájlt.</string>
|
||||
<string name="cordn_backup_passphrase">Jelmondat</string>
|
||||
<string name="cordn_backup_restore">Helyreállítás</string>
|
||||
<string name="cordn_backup_restore_body">A helyreállítás lecseréli az ezen az eszközön lévő cordn csoportokat a fájlban lévőkre. Ez egy olyan eszköznek szól, amely átvett egy másikat; nem arra való, hogy ugyanazokat a csoportokat egyszerre két eszközön használja.</string>
|
||||
<string name="cordn_backup_restore_confirm_body">Minden most ezen az eszközön lévő cordn csoport eltávolításra és a fájlban lévőkkel lesz helyettesítve.\n\nNe állítsa helyre egy második eszközre, amíg az elsőt még használja. Mindkettő ugyanazokat a csoportkulcsokat birtokolná, és miután mindkettő küldött egy üzenetet, a csoport mindenki számára végleg használhatatlanná válna.</string>
|
||||
<string name="cordn_backup_restore_confirm_title">Lecseréli az eszköz cordn csoportjait?</string>
|
||||
<string name="cordn_backup_restore_title">Helyreállítás</string>
|
||||
<string name="cordn_backup_restored">Helyreállítva.</string>
|
||||
<string name="cordn_chat_empty_description">Minden ide küldött üzenet titkosítva van ehhez a csoporthoz. A koordinátor továbbítja anélkül, hogy el tudná olvasni.</string>
|
||||
<string name="cordn_chat_empty_title">Még nincsenek üzenetek</string>
|
||||
<string name="cordn_chat_unread_divider">Új üzenetek</string>
|
||||
<string name="cordn_chat_yesterday">Tegnap</string>
|
||||
<string name="cordn_composer_hint">Üzenet</string>
|
||||
<string name="cordn_coordinators_add_action">Hozzáadás</string>
|
||||
<string name="cordn_coordinators_add_failed">Nem sikerült megnyitni azt a koordinátort.</string>
|
||||
<string name="cordn_coordinators_copy_key">A koordinátor npub-jának másolása</string>
|
||||
<string name="cordn_coordinators_discover_action">Koordinátorok keresése</string>
|
||||
<string name="cordn_coordinators_discover_add">Hozzáadás</string>
|
||||
<string name="cordn_coordinators_discover_explainer">Az átjátszói által már továbbított bejelentéseket olvassa. Egyetlen koordinátorral sem lép kapcsolatba, így egyik sem tudja meg, hogy Ön keresett.</string>
|
||||
<string name="cordn_coordinators_discover_failed">Nem sikerült beolvasni a bejelentéseket</string>
|
||||
<string name="cordn_coordinators_discover_none">Senki sem jelentkezik be az átjátszóin.</string>
|
||||
<string name="cordn_coordinators_discover_seen">Bejelentve ennyi ideje: %1$s</string>
|
||||
<string name="cordn_coordinators_discover_seen_on">Utoljára bejelentve: %1$s</string>
|
||||
<string name="cordn_coordinators_explainer">Egy koordinátor egy csoport üzeneteit rendezi sorba, és ez az egyetlen, ami ezt megteheti. Ha elvész, a sorrend is elvész, és egy második nem tükrözi az elsőt; így ezek névvel ellátott dolgok, amelyeket Ön választ, nem pedig felcserélhető átjátszók.</string>
|
||||
<string name="cordn_coordinators_health_ok">Válaszol.</string>
|
||||
<string name="cordn_coordinators_health_retrying">Egy hívás sikertelen volt; újrapróbálkozás.</string>
|
||||
<string name="cordn_coordinators_health_unknown">Még semmit sem kérdeztek tőle.</string>
|
||||
<string name="cordn_coordinators_hide_older">A bejelentést abbahagyók elrejtése</string>
|
||||
<string name="cordn_coordinators_identify">Kérdezze meg, ki az</string>
|
||||
<string name="cordn_coordinators_key">Koordinátorkulcs</string>
|
||||
<string name="cordn_coordinators_label">Egy név kell neki (az Öné, nem kötelező)</string>
|
||||
<string name="cordn_coordinators_label_note">Ez a név az Öné, és ezen az eszközön marad. Egy koordinátor nem tudja bizonyítani a nevét, ezért soha nem kérdeznek tőle ilyet.</string>
|
||||
<string name="cordn_coordinators_more">További műveletek</string>
|
||||
<string name="cordn_coordinators_none">Még nincsenek koordinátorok.</string>
|
||||
<string name="cordn_coordinators_purge">Tisztítás</string>
|
||||
<string name="cordn_coordinators_purge_body">Az eltávolítás megtartja a csoportokat ezen az eszközön, így a koordinátor újbóli hozzáadása visszahozza őket. A tisztítás törli őket: a csoportkulcsok, az olvasási pozíciók és a kulcscsomagjai mind eltűnnek, és ezekbe a csoportokba csak friss meghívással lehet újra belépni.\n\nA koordinátort nem értesítik, és megtartja mindazt, amije már volt.</string>
|
||||
<string name="cordn_coordinators_purge_title">Tisztítja ezt a koordinátort?</string>
|
||||
<string name="cordn_coordinators_relays">%1$s</string>
|
||||
<string name="cordn_coordinators_relays_label">Válaszol ezeken</string>
|
||||
<string name="cordn_coordinators_relays_more">%1$s és további %2$d</string>
|
||||
<string name="cordn_coordinators_remove">Eltávolítás</string>
|
||||
<string name="cordn_coordinators_rename">Átnevezés</string>
|
||||
<string name="cordn_coordinators_server">Azt mondja, ő: %1$s</string>
|
||||
<string name="cordn_coordinators_server_claim">Egy koordinátor neve és verziója az általa választott szöveg. Az egyetlen dolog, ami azonosítja, a nyilvános kulcsa.</string>
|
||||
<string name="cordn_coordinators_server_silent">Válaszolt, de semmit sem nevezett meg.</string>
|
||||
<string name="cordn_coordinators_show_all">Mind a(z) %1$d megjelenítése</string>
|
||||
<string name="cordn_coordinators_show_fewer">Kevesebb megjelenítése</string>
|
||||
<string name="cordn_coordinators_stale_note">Ezek több mint egy hónapja nem jelentkeztek be. A csoport létrehozása egy eltűnt koordinátoron sikertelen lesz.</string>
|
||||
<string name="cordn_create_action">Csoport létrehozása</string>
|
||||
<plurals name="cordn_create_action_invite">
|
||||
<item quantity="one">Létrehozás és %1$d személy meghívása</item>
|
||||
<item quantity="other">Létrehozás és %1$d személy meghívása</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_add_member">Valaki hozzáadása</string>
|
||||
<string name="cordn_create_admin">Adminisztrátor</string>
|
||||
<plurals name="cordn_create_admin_count">
|
||||
<item quantity="one">%1$d személy adhat hozzá és távolíthat el</item>
|
||||
<item quantity="other">%1$d személy adhat hozzá és távolíthat el</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_admin_only_me">Csak én kezelem ezt a csoportot</string>
|
||||
<string name="cordn_create_admin_only_me_on">Csak Ön hívhat meg, távolíthat el tagokat vagy változtathatja meg a csoport adatait. Ezt később átadhatja valaki másnak.</string>
|
||||
<string name="cordn_create_coordinator">Koordinátor</string>
|
||||
<string name="cordn_create_coordinator_change">Módosítás</string>
|
||||
<string name="cordn_create_coordinator_discover">Koordinátorok keresése</string>
|
||||
<string name="cordn_create_coordinator_hide">Kész</string>
|
||||
<string name="cordn_create_coordinator_new">Egy másik koordinátor</string>
|
||||
<string name="cordn_create_coordinator_pubkey">Koordinátor nyilvános kulcsa (hex vagy npub)</string>
|
||||
<string name="cordn_create_coordinator_relays">Átjátszók, amelyeken válaszol, soronként egy</string>
|
||||
<string name="cordn_create_coverage_partial">%2$d / %1$d embert érne el, a többi kimaradna</string>
|
||||
<string name="cordn_create_coverage_unknown">Nincs ellenőrizve; a rendszer rá fog kérdezni a kiválasztására</string>
|
||||
<string name="cordn_create_description">Leírás (nem kötelező)</string>
|
||||
<string name="cordn_create_egalitarian">Mindenki hozzáadhat és eltávolíthat</string>
|
||||
<string name="cordn_create_egalitarian_note">A csoport minden tagja meghívhat, eltávolíthat tagokat és megváltoztathatja a csoport adatait. Bármely tag később kinevezhet adminisztrátorokat, ami ezt megszünteti.</string>
|
||||
<string name="cordn_create_explainer">Egy cordn csoportot egy Ön által választott koordinátor rendez. A csoport létrehozása ezen az eszközön történik – a koordinátor csak akkor szerez tudomást a csoport létezéséről, amikor meghív valakit vagy üzenetet küld.</string>
|
||||
<string name="cordn_create_failed">Nem sikerült létrehozni a csoportot.</string>
|
||||
<string name="cordn_create_name">Csoportnév</string>
|
||||
<string name="cordn_create_no_coordinator">Nincs koordinátor kiválasztva</string>
|
||||
<string name="cordn_create_outcome_explainer">Minden meghívó egy Üdvözlés is, amelyet a koordinátoron hagynak, így egyenként sikertelenek lehetnek. Senkit sincs értesítve: az emberek legközelebb akkor látják, amikor megnyitják az alkalmazást.</string>
|
||||
<string name="cordn_create_outcome_failed">A koordinátor elutasította a meghívót</string>
|
||||
<string name="cordn_create_outcome_link">Hivatkozás küldése</string>
|
||||
<string name="cordn_create_outcome_no_welcome">Hozzáadva a csoporthoz, de a meghívó nem érte el, próbálja újra a csoport képernyőjéről</string>
|
||||
<string name="cordn_create_outcome_open">Csevegés megnyitása</string>
|
||||
<string name="cordn_create_outcome_skipped">Itt nincs kulcs, így nem lehetett Üdvözlést hagyni</string>
|
||||
<string name="cordn_create_outcome_title">A csoport létezik</string>
|
||||
<string name="cordn_create_outcome_waiting">Várakozás rájuk</string>
|
||||
<string name="cordn_create_people_done">Kész</string>
|
||||
<string name="cordn_create_people_empty">Még senki sincs hozzáadva. Egy csoport létrehozható üresen, és a meghívók később küldhetők, de ha most megnevezi az embereket, az mutatja meg, melyik koordinátor tudja elérni őket.</string>
|
||||
<string name="cordn_create_people_none">Még senki – koppintson az emberek hozzáadásához</string>
|
||||
<string name="cordn_create_people_note">Ha most megnevezi az embereket, akkor mondja meg, melyik koordinátor tudja őket elérni. Mindegyikük kap egy Üdvözlést azon a koordinátoron, amelyet legközelebb akkor választanak ki, amikor megnyitják az alkalmazást.</string>
|
||||
<plurals name="cordn_create_reach_count">
|
||||
<item quantity="one">Elérhető %1$d koordinátoron</item>
|
||||
<item quantity="other">Elérhető %1$d koordinátoron</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_reach_none">Nincs kulcs egyetlen Ön által használt koordinátoron sem</string>
|
||||
<string name="cordn_create_reach_unknown">Még nincs ellenőrizve</string>
|
||||
<string name="cordn_create_step_admins">Ki adhat hozzá és távolíthat el</string>
|
||||
<string name="cordn_create_step_name">Nevezze el</string>
|
||||
<string name="cordn_create_step_people">Ki van benne</string>
|
||||
<string name="cordn_create_step_where">Hol él</string>
|
||||
<string name="cordn_create_title">Új Cordn csoport</string>
|
||||
<plurals name="cordn_create_unreachable_count">
|
||||
<item quantity="one">%1$d személyt egyetlen Ön által használt koordinátor sem tud elérni</item>
|
||||
<item quantity="other">%1$d személyt egyetlen Ön által használt koordinátor sem tud elérni</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_you">Ön, mindig adminisztrátor</string>
|
||||
<string name="cordn_delete_confirm_body">A csoport minden tagja visszavontként fogja látni ezt az üzenetet, és az Amethyst nem fogja többé megjeleníteni a szövegét. A koordinátor továbbra is birtokolja a titkosított másolatot, amelyként elküldték, és aki már elolvasta, az már elolvasta.</string>
|
||||
<string name="cordn_delete_confirm_title">Üzenet visszavonása</string>
|
||||
<string name="cordn_delivery_accepted">A koordinátor elfogadta</string>
|
||||
<string name="cordn_exposure_close">Értem</string>
|
||||
<string name="cordn_exposure_open">Mit lát ez a koordinátor</string>
|
||||
<string name="cordn_group_info">Csoportadatok</string>
|
||||
<string name="cordn_group_unavailable">Ez a csoport nem érhető el. Lehet, hogy a koordinátorát eltávolították.</string>
|
||||
<string name="cordn_group_unavailable_detail">Adjon hozzá egy koordinátort a Beállításokban, hogy elkezdje használni a cordn csoportokat.</string>
|
||||
<plurals name="cordn_groups_count">
|
||||
<item quantity="one">%1$d csoport</item>
|
||||
<item quantity="other">%1$d csoport</item>
|
||||
</plurals>
|
||||
<string name="cordn_groups_down_note">Ezekből a csoportokból semmi sem érkezik. Az Amethyst folyamatosan újrapróbálkozik.</string>
|
||||
<string name="cordn_groups_manage">Koordinátorok</string>
|
||||
<string name="cordn_groups_none">Még nincsenek cordn csoportok</string>
|
||||
<string name="cordn_groups_none_detail">Egy cordn csoport egyetlen koordinátoron él, amely nyilvántartja a tagságát és továbbítja az üzeneteket, anélkül, hogy valaha is látná, mit írnak.</string>
|
||||
<string name="cordn_groups_start">Indítson egyet</string>
|
||||
<string name="cordn_info_add_member">Valaki hozzáadása</string>
|
||||
<string name="cordn_info_add_member_none">Senkit sem találtunk azon a néven.</string>
|
||||
<string name="cordn_info_add_member_note">Csak akkor adhatók hozzá, ha közzétettek egy kulcscsomagot ehhez a koordinátorhoz.</string>
|
||||
<string name="cordn_info_add_member_placeholder">Név, npub vagy nev@domain</string>
|
||||
<string name="cordn_info_admin_badge">Adminisztrátor</string>
|
||||
<plurals name="cordn_info_admins_kept">
|
||||
<item quantity="one">A csoport %1$d adminisztrátora marad, ahogy van.</item>
|
||||
<item quantity="other">A csoport %1$d adminisztrátora marad, ahogy van.</item>
|
||||
</plurals>
|
||||
<string name="cordn_info_coordinator">Koordinátor</string>
|
||||
<string name="cordn_info_coordinator_key">Koordinátorkulcs</string>
|
||||
<string name="cordn_info_coordinator_nprofile">Koordinátorhivatkozás</string>
|
||||
<string name="cordn_info_copy_nprofile">A koordinátor nprofile-jának másolása</string>
|
||||
<string name="cordn_info_edit_details">Adatok szerkesztése</string>
|
||||
<string name="cordn_info_egalitarian">Ennek a csoportnak nincsenek adminisztrátorai: mindenki hozzáadhat, eltávolíthat és átnevezhet, véglegesen.</string>
|
||||
<string name="cordn_info_epoch">Korszak</string>
|
||||
<string name="cordn_info_gid">Csoportazonosító</string>
|
||||
<string name="cordn_info_has_key_package">Hozzáadható ezen a koordinátoron</string>
|
||||
<string name="cordn_info_members">Tagok</string>
|
||||
<string name="cordn_info_remove_confirm_body">%1$s nem fog többé üzeneteket fogadni innen. Megtartja, amit már elolvasott, és ez nem vonható vissza – újra meg kellene hívni.</string>
|
||||
<string name="cordn_info_remove_confirm_title">Eltávolítja a csoportból?</string>
|
||||
<string name="cordn_info_remove_member">Eltávolítás</string>
|
||||
<string name="cordn_info_save">Mentés</string>
|
||||
<string name="cordn_info_technical">Technikai részletek</string>
|
||||
<string name="cordn_invitations_accept">Csatlakozás</string>
|
||||
<string name="cordn_invitations_decline">Elutasítás</string>
|
||||
<string name="cordn_invitations_decline_warning">Az elutasítás végleges. A visszakerüléshez újra meg kell hívni.</string>
|
||||
<string name="cordn_invitations_explainer">Akkor ellenőrzi, amikor megnyitja ezt a képernyőt, és máskor soha, ha megkérdez egy koordinátort, hogy meghívta-e valaki, az elárulja neki, hogy Ön itt van, ezért az Amethyst nem teszi ezt a háttérben.</string>
|
||||
<string name="cordn_invitations_load_failed">Nem sikerült beolvasni a meghívókat.</string>
|
||||
<plurals name="cordn_invitations_members">
|
||||
<item quantity="one">%1$d személy már tagja ennek a csoportnak</item>
|
||||
<item quantity="other">%1$d személy már tagja ennek a csoportnak</item>
|
||||
</plurals>
|
||||
<string name="cordn_invitations_members_more">+%1$d további</string>
|
||||
<string name="cordn_invitations_no_coordinators">Nincs nyitott koordinátora. A cordn meghívók egy koordinátoron keresztül érkeznek, így még nincs hol keresni.</string>
|
||||
<string name="cordn_invitations_none">Nincs várakozó meghívó.</string>
|
||||
<string name="cordn_invitations_refresh">Újraellenőrzés</string>
|
||||
<string name="cordn_invitations_skipped">Egy meghívó egy másik eszköznek maradt</string>
|
||||
<string name="cordn_invitations_title">Cordn meghívók</string>
|
||||
<string name="cordn_invitations_unreachable">%1$s nem válaszolt</string>
|
||||
<string name="cordn_invitations_via">%1$s által</string>
|
||||
<string name="cordn_keypackages_disclosure">A közzététel egy bejegyzést ír alá a saját fiókkulcsával. Az a koordinátor ezután tudja, hogy ez a fiók létezik és meghívható, véglegesen, függetlenül attól, hogy meghívja-e valaki.</string>
|
||||
<string name="cordn_keypackages_explainer">Mások csak úgy adhatják hozzá egy cordn csoporthoz, ha elvesznek egy kulcscsomagot, amelyet Ön közzétett annál a koordinátornál. A cordnnak nincs más helye, ahol tárolhatna egyet, így ha egy sincs közzétéve, senki sem tudja meghívni – és semmi sem mondja meg nekik, miért.</string>
|
||||
<string name="cordn_keypackages_failed">Nem sikerült beolvasni a kulcscsomagokat.</string>
|
||||
<string name="cordn_keypackages_last_resort_no">Nincsenek tartalékcsomagok. Amint az egyszer használatosak elfogynak, a meghívók sikertelenek lesznek.</string>
|
||||
<string name="cordn_keypackages_last_resort_yes">Egy végső megoldás csomag közzé van téve, így a meghívó akkor is elkészíthető, ha az egyszer használatosak elfogytak.</string>
|
||||
<plurals name="cordn_keypackages_orphans">
|
||||
<item quantity="one">%1$d csomag, amelyet ez az eszköz nem tud megnyitni</item>
|
||||
<item quantity="other">%1$d csomag, amelyet ez az eszköz nem tud megnyitni</item>
|
||||
</plurals>
|
||||
<string name="cordn_keypackages_orphans_body">A koordinátor odaadja ezeket bárkinek, aki meghívja Önt, de a privát fele nincs ezen az eszközön – egy másik telepítéshez tartozik. Ha az a telepítés eltűnt, egy ilyen használatával készült meghívó olyan welcome-ot hoz létre, amelyet soha senki sem tud megnyitni.</string>
|
||||
<string name="cordn_keypackages_publish">Egy közzététele</string>
|
||||
<string name="cordn_keypackages_publish_last_resort">Végső megoldás közzététele</string>
|
||||
<plurals name="cordn_keypackages_summary">
|
||||
<item quantity="one">%1$d egyszer használatos csomag elérhető.</item>
|
||||
<item quantity="other">%1$d egyszer használatos csomag elérhető.</item>
|
||||
</plurals>
|
||||
<string name="cordn_keypackages_topup_note">Miután itt közzétett, az Amethyst csendben pótolja a csomagokat, ahogy elfogynak. Az elsőt soha nem teszi közzé Ön helyett.</string>
|
||||
<string name="cordn_keypackages_withdraw_all">Összes visszavonása</string>
|
||||
<string name="cordn_keypackages_withdraw_orphans">Azok visszavonása</string>
|
||||
<string name="cordn_link_request">Csatlakozási kérelem ehhez a csoporthoz</string>
|
||||
<string name="cordn_link_request_disclosure">Ez közzétesz egy kulcscsomagot a saját fiókkulcsa alatt, és megmondja a koordinátornak, hogy be szeretne kerülni ebbe a csoportba – függetlenül attól, hogy válaszol-e valaki.</string>
|
||||
<string name="cordn_link_request_failed">Nem sikerült csatlakozási kérelmet küldeni.</string>
|
||||
<string name="cordn_link_request_sent">Elküldve. A csoport egyik tagjának hozzá kell adnia Önt; a meghívó a cordn meghívók alatt fog megjelenni.</string>
|
||||
<string name="cordn_link_scan">Beolvasás</string>
|
||||
<string name="cordn_media_download_failed">Nem sikerült megnyitni azt a fájlt.</string>
|
||||
<string name="cordn_media_no_server">Nincs médiakiszolgáló beállítva ehhez a fiókhoz, így nincs hová tenni a fájlt. Válasszon egyet a Beállításokban.</string>
|
||||
<string name="cordn_media_unreadable">Azt a fájlt nem sikerült beolvasni.</string>
|
||||
<string name="cordn_media_upload_failed">Nem sikerült elküldeni azt a fájlt.</string>
|
||||
<plurals name="cordn_member_count">
|
||||
<item quantity="one">%1$d tag</item>
|
||||
<item quantity="other">%1$d tag</item>
|
||||
</plurals>
|
||||
<string name="cordn_message_deleted">Üzenet törölve</string>
|
||||
<string name="cordn_message_details_coordinator">Koordinátor</string>
|
||||
<string name="cordn_message_details_cursor">Kurzor</string>
|
||||
<string name="cordn_message_details_sent_at">Elküldve</string>
|
||||
<string name="cordn_message_details_title">Üzenet részletei</string>
|
||||
<string name="cordn_message_edited">szerkesztve</string>
|
||||
<string name="cordn_pinned_by">%1$s rögzítette</string>
|
||||
<plurals name="cordn_pinned_count">
|
||||
<item quantity="one">%1$d rögzített üzenet ebben a csoportban</item>
|
||||
<item quantity="other">%1$d rögzített üzenet ebben a csoportban</item>
|
||||
</plurals>
|
||||
<string name="cordn_pinned_next">Következő rögzített üzenet</string>
|
||||
<string name="cordn_pinned_previous">Előző rögzített üzenet</string>
|
||||
<string name="cordn_pinned_show_all">Összes rögzített üzenet megjelenítése</string>
|
||||
<string name="cordn_pinned_title">Rögzített üzenetek</string>
|
||||
<string name="cordn_reactions_title">Reakciók</string>
|
||||
<string name="cordn_requests_accept">Hozzáadás</string>
|
||||
<string name="cordn_requests_admin_only">Csak az adminisztrátor fogadhat el. Egy adminisztrátorok nélküli csoportban ez mindenki.</string>
|
||||
<string name="cordn_requests_check">Kérelmek ellenőrzése</string>
|
||||
<string name="cordn_requests_decline">Elvetés</string>
|
||||
<string name="cordn_requests_failed">Nem sikerült beolvasni a kérelmeket.</string>
|
||||
<string name="cordn_requests_none">Senki sem vár a csatlakozásra.</string>
|
||||
<string name="cordn_requests_title">Csatlakozási kérelmek</string>
|
||||
<string name="cordn_send">Küldés</string>
|
||||
<string name="cordn_send_failed">Ez nem került elküldésre.</string>
|
||||
<string name="cordn_send_no_session">Ennek a csoportnak a koordinátora nincs nyitva, így még semmit sem lehet küldeni.</string>
|
||||
<string name="cordn_share_copied">Másolva</string>
|
||||
<string name="cordn_share_copy">Hivatkozás másolása</string>
|
||||
<string name="cordn_share_explainer">Bárki, aki rendelkezik ezzel a hivatkozással, kérheti a csatlakozást. Egy adminisztrátornak még mindig be kell engednie.</string>
|
||||
<string name="cordn_share_title">Csoport megosztása</string>
|
||||
<string name="cordn_voice_play">Hangfelvétel lejátszása</string>
|
||||
<string name="cordn_voice_record">Hangfelvétel készítése</string>
|
||||
<string name="cordn_voice_stop">Leállítás és küldés</string>
|
||||
</resources>
|
||||
|
||||
@@ -2855,4 +2855,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2893,4 +2893,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2913,4 +2913,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2897,4 +2897,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2981,4 +2981,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -4625,4 +4625,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -214,7 +214,12 @@
|
||||
<string name="geocache_hunt_new">Nowe polowanie…</string>
|
||||
<string name="geocache_hunt_none_yet">Nie dokonałeś jeszcze polowania.</string>
|
||||
<string name="geocache_hunt_already_on">Już podczas tego polowania</string>
|
||||
<string name="geocache_caches_here">%1$d skrzynek tutaj</string>
|
||||
<plurals name="geocache_caches_here">
|
||||
<item quantity="one">%1$d skrzynka tutaj</item>
|
||||
<item quantity="few">%1$d skrzynki tutaj</item>
|
||||
<item quantity="many">%1$d skrzynek tutaj</item>
|
||||
<item quantity="other">%1$d skrzynki tutaj</item>
|
||||
</plurals>
|
||||
<string name="geocache_photo_remove">Usuń to zdjęcie</string>
|
||||
<string name="geocache_archived_notice">Ta skrzynka została zarchiwizowana. Nie jest już w grze.</string>
|
||||
<string name="geocache_ftf_won_by">Pierwszy, który znalazł – zgłoszone przez %1$s</string>
|
||||
@@ -273,7 +278,6 @@
|
||||
<string name="geocache_map_recenter">Wyśrodkuj na mnie</string>
|
||||
<string name="geocache_map_long_press">Naciśnij i przytrzymaj mapę, aby ukryć skrzynkę</string>
|
||||
<string name="geocache_map_open">Otwórz</string>
|
||||
<string name="geocache_map_pin_count">%1$d skrzynek</string>
|
||||
<string name="geocache_new_section_where">Gdzie</string>
|
||||
<string name="geocache_new_section_what">Co</string>
|
||||
<string name="geocache_new_section_extras">Dodatki</string>
|
||||
@@ -301,7 +305,12 @@
|
||||
<string name="geocache_new_needs_location">Wybierz gdzie skrzynka jest ukryta.</string>
|
||||
<string name="geocache_hunt_progress">Znaleziono %1$d z %2$d</string>
|
||||
<string name="geocache_hunt_start">Rozpocznij polowanie</string>
|
||||
<string name="geocache_hunt_caches">%1$d skrzynek</string>
|
||||
<plurals name="geocache_hunt_caches">
|
||||
<item quantity="one">%1$d skrzynka</item>
|
||||
<item quantity="few">%1$d skrzynki</item>
|
||||
<item quantity="many">%1$d skrzynek</item>
|
||||
<item quantity="other">%1$d skrzynki</item>
|
||||
</plurals>
|
||||
<string name="geocache_hunt_title">Tytuł</string>
|
||||
<string name="geocache_hunt_description">Opis</string>
|
||||
<string name="geocache_hunt_banner">Obraz banera</string>
|
||||
@@ -352,7 +361,12 @@
|
||||
<string name="qr_scanner_no_code_in_image">Nie znaleziono kodu QR na tym obrazku</string>
|
||||
<string name="qr_scanner_clipboard_empty">Nic w schowku do skanowania</string>
|
||||
<string name="qr_scanner_pick_one">Wybierz żądany kod</string>
|
||||
<string name="qr_scanner_sequence_progress">Zdobyto %1$s z %2$s części — kontynuuj</string>
|
||||
<plurals name="qr_scanner_sequence_progress">
|
||||
<item quantity="one">Zdobyto %1$s z %2$s części — kontynuuj</item>
|
||||
<item quantity="few">Zdobyto %1$s z %2$s części — kontynuuj</item>
|
||||
<item quantity="many">Zdobyto %1$s z %2$s części — kontynuuj</item>
|
||||
<item quantity="other">Zdobyto %1$s z %2$s części — kontynuuj</item>
|
||||
</plurals>
|
||||
<string name="qr_scanner_zoom_reset">Zresetuj zoom</string>
|
||||
<string name="qr_scanner_unsupported_title">Ametyst nie może otworzyć tego kodu</string>
|
||||
<string name="qr_scanner_unsupported_secret">Ten kod zawiera klucz prywatny lub hasło parowania, dlatego jego treść nie jest tutaj wyświetlana. Należy skorzystać z odpowiedniego ekranu, na którym należy go wprowadzić.</string>
|
||||
@@ -2891,6 +2905,7 @@
|
||||
<string name="community_rules_violation_wot_gate_failed">Nie spełniasz wymogów dotyczących rankingu zaufania tej społeczności.</string>
|
||||
<string name="community_rules_violation_stale_rules">Najnowszy dokument zawierający zasady społeczności został odrzucony jako nieaktualny.</string>
|
||||
<string name="marmot_groups_title">Grupy Marmot</string>
|
||||
<string name="cordn_groups_title">Grupy Cordn</string>
|
||||
<string name="marmot_create_group">Utwórz Grupę</string>
|
||||
<string name="marmot_create_group_title">Utwórz Grupę Marmot</string>
|
||||
<string name="marmot_create_group_footer">Zostanie utworzona nowa grupa MLS. Następnie możesz dodać członków.</string>
|
||||
@@ -5439,14 +5454,120 @@
|
||||
<!-- cordn: groups delivered by an MCP coordinator rather than by relays.
|
||||
The exposure strings state what the coordinator operator learns; see
|
||||
spec/00.md §8 and quartz/plans/2026-09-17-cordn-interop.md. -->
|
||||
<string name="cordn_badge_coordinator">Grupa koordynatora</string>
|
||||
<string name="cordn_badge_coordinator_desc">Dostarczone przez koordynatora, nie przez transmitery</string>
|
||||
<string name="cordn_exposure_title">Co ten koordynator może zobaczyć</string>
|
||||
<string name="cordn_exposure_subtitle">Koordynator to serwer, który przekazuje wszystkie wiadomości w tej grupie w kolejności. Różni się to od działania transmiterów — warto o tym wiedzieć, zanim potraktujesz to, jak zwykły czat.</string>
|
||||
<string name="cordn_exposure_dimension_content">Treść wiadomości</string>
|
||||
<string name="cordn_exposure_dimension_membership">Kto jest w grupie</string>
|
||||
<string name="cordn_exposure_dimension_messaging">Kto co wysyła</string>
|
||||
<string name="cordn_exposure_level_none">Nieczytelne</string>
|
||||
<string name="cordn_exposure_level_pseudonymous">Z użyciem klucza jednorazowego</string>
|
||||
<string name="cordn_exposure_level_identified">Powiązane z Twoim prawdziwym kontem</string>
|
||||
<string name="cordn_exposure_details">Szczegóły</string>
|
||||
<string name="cordn_exposure_coordinator">Koordynator %1$s</string>
|
||||
<string name="cordn_exposure_differs">Nie jest to taka sama forma interakcji jak w grupie Marmot, gdzie żadna z osób prowadzących nie dominuje całej rozmowy.</string>
|
||||
<string name="cordn_note_membership">Łączy nazwy rzeczywistych kont po obu stronach, dzięki czemu koordynator wie, kto należy do tej grupy.</string>
|
||||
<string name="cordn_note_linked">Pojedynczy klucz jednorazowego użytku służy do wysyłania i pobierania danych dla każdej z grup, które tu masz, dzięki czemu koordynator może stwierdzić, że wszystkie one należą do ciebie.</string>
|
||||
<string name="cordn_note_history">Każdy operator przechowuje kompletną, uporządkowaną historię wszystkich grup, które obsługuje.</string>
|
||||
<string name="cordn_note_publication">Opublikowany przez Ciebie pakiet kluczy to podpisany zapis potwierdzający, że to konto korzysta z usługi cordn, a koordynator może go przekazać dowolnej osobie.</string>
|
||||
<string name="cordn_note_sizes">Komunikaty nie są uzupełniane, więc koordynator widzi, jak długi jest każdy z nich.</string>
|
||||
<string name="cordn_note_encryption_bug">Ten klient nie szyfruje danych przesyłanych do koordynatora. To błąd — prosimy o zgłoszenie tego.</string>
|
||||
<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>
|
||||
<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>
|
||||
<string name="cordn_link_paste">Wklej</string>
|
||||
<string name="cordn_link_clear">Wyczyść</string>
|
||||
<string name="cordn_link_invalid">To nie jest link do grupy Cordn: %1$s</string>
|
||||
<string name="cordn_link_group_id">ID grupy</string>
|
||||
<string name="cordn_link_coordinator">Koordynator</string>
|
||||
<string name="cordn_link_relays">Osiągalne przez</string>
|
||||
<string name="cordn_link_no_coordinator">W tym linku nie podano nazwiska koordynatora, więc nie można z niego skorzystać samodzielnie. Zapytaj osobę, która go przesłała, który koordynator prowadzi tę grupę.</string>
|
||||
<string name="cordn_link_not_joinable">Sprawdzenie linku nie powoduje dołączenia do niczego, a samo kliknięcie go nie czyni cię członkiem.</string>
|
||||
<!-- cordn entries in the settings catalog and the Messages chat-type
|
||||
list. Here rather than in amethyst/res because both screens read
|
||||
them through Res. -->
|
||||
<string name="cordn_link_title">Link do grupy Cordn</string>
|
||||
<string name="cordn_link_search_keywords">cordn koordynator grupa link zaproszenie mls czat metadane prywatność ujawnienie</string>
|
||||
<string name="cordn_coordinators_title">Koordynatorzy Cordn</string>
|
||||
<string name="cordn_coordinators_search_keywords">cordn koordynator dodawanie usuwanie czyszczenie stan serwera mls czat sortowanie</string>
|
||||
<string name="cordn_keypackages_title">Pakiety kluczy Cordn</string>
|
||||
<string name="cordn_keypackages_search_keywords">cordn klucz pakiet publikacja zaproszenie ostatni resort koordynator mls</string>
|
||||
<string name="cordn_backup_title">Kopia zapasowa Cordn</string>
|
||||
<string name="cordn_backup_search_keywords">cordn kopia zapasowa przywracanie eksport import hasło odzyskiwanie grup</string>
|
||||
<string name="chat_type_cordn_title">Grupy Cordn</string>
|
||||
<string name="chat_type_cordn_desc">Grupy z szyfrowaniem typu end-to-end, zarządzane przez wybranego przez Ciebie koordynatora, a nie przez transmitery.</string>
|
||||
<!-- cordn strings on screens main migrated to Res: the shared inbox row
|
||||
and the new-conversation picker. -->
|
||||
<string name="cordn_group_untitled">Grupa %1$s</string>
|
||||
<string name="cordn_group_no_messages_yet">Brak wiadomości</string>
|
||||
<string name="cordn_group_via_coordinator">Grupa Cordn, obsługiwana przez %1$s</string>
|
||||
<string name="cordn_preview_deleted">Wiadomość usunięta</string>
|
||||
<string name="cordn_preview_voice_note">Wiadomość głosowa</string>
|
||||
<string name="cordn_preview_photo">Zdjęcie</string>
|
||||
<string name="cordn_preview_video">Wideo</string>
|
||||
<string name="cordn_preview_file">Plik</string>
|
||||
<string name="new_conversation_cordn_title">Grupa Cordn</string>
|
||||
<string name="new_conversation_cordn_tagline">Szyfrowany czat grupowy zorganizowany przez wybranego przez Ciebie koordynatora.</string>
|
||||
<string name="new_conversation_cordn_chip">Skoordynowane</string>
|
||||
<string name="new_conversation_cordn_best">Najlepsze rozwiązanie dla zespołów, które chcą mieć jeden spójny porządek dyskusji.</string>
|
||||
<string name="new_conversation_cordn_cta">Utwórz grupę Cordn</string>
|
||||
<string name="new_conversation_cordn_pro_1">Szyfrowanie typu „end-to-end” z wykorzystaniem MLS — koordynator nigdy nie ma możliwości odczytania wiadomości.</string>
|
||||
<string name="new_conversation_cordn_pro_2">Jedno uzgodnione postanowienie dla wszystkich, aby historia nie mogła zostać zmieniona przez błędny zegar.</string>
|
||||
<string name="new_conversation_cordn_con_1">Koordynator wie, kto należy do grupy i kiedy ktoś zabiera głos, mimo że nie potrafi odczytać treści wypowiedzi.</string>
|
||||
<string name="cordn_invitations_entry">Zostałeś zaproszony do grupy „cordn”?</string>
|
||||
<string name="cordn_invitations_entry_action">Przejrzyj zaproszenia</string>
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<string name="cordn_hub_title">Cordn</string>
|
||||
<string name="cordn_hub_explainer">Grupy prowadzone przez wybranego przez Ciebie koordynatora, a nie przez transmitery.</string>
|
||||
<string name="cordn_hub_link">Sprawdź link do grupy</string>
|
||||
<string name="cordn_hub_link_desc">Zanim klikniesz w link typu „cordn1…”, sprawdź, dokąd prowadzi</string>
|
||||
<string name="cordn_migrate_section_send">Zmień ten telefon</string>
|
||||
<string name="cordn_migrate_section_receive">Przeniesienie danych z innego telefonu</string>
|
||||
<string name="cordn_keypackages_section">Opublikowane pakiety kluczy</string>
|
||||
<string name="cordn_link_section_input">Link</string>
|
||||
<string name="cordn_coordinators_section_yours">Koordynatorzy, z których korzystasz</string>
|
||||
<string name="cordn_coordinators_section_discover">Przedstawianie się</string>
|
||||
<string name="cordn_coordinators_section_manual">Dodaj jedną ręcznie</string>
|
||||
<string name="cordn_backup_section_passphrase">Hasło</string>
|
||||
<string name="cordn_backup_section_export">Utwórz kopię zapasową</string>
|
||||
<string name="cordn_backup_section_restore">Przywróć z kopii zapasowej</string>
|
||||
<string name="cordn_hub_section_service">Koordynator</string>
|
||||
<string name="cordn_hub_section_device">Urządzenie</string>
|
||||
<string name="cordn_hub_coordinators">Koordynatorzy</string>
|
||||
<string name="cordn_hub_coordinators_desc">Serwery z Twoimi grupami</string>
|
||||
<string name="cordn_hub_keypackages">Pakiety kluczy</string>
|
||||
<string name="cordn_hub_keypackages_desc">Co pozwala innym osobom dodać cię do grupy</string>
|
||||
<string name="cordn_hub_backup">Kopia zapasowa i przywracanie</string>
|
||||
<string name="cordn_hub_backup_desc">Przechowywany plik zaszyfrowany hasłem</string>
|
||||
<string name="cordn_hub_migrate">Przenieś na nowy telefon</string>
|
||||
<string name="cordn_hub_migrate_desc">Przekaż swoje grupy na urządzenie, na które się przełączasz</string>
|
||||
<string name="cordn_migrate_title">Przenieś na nowy telefon</string>
|
||||
<string name="cordn_migrate_explainer">Twoje grupy Cordn są przechowywane na tym urządzeniu. Przeniesienie ich wymaga jednego kodu: ten telefon je publikuje, nowy telefon je odczytuje, a ten telefon przestaje je wyświetlać.</string>
|
||||
<string name="cordn_migrate_sign_in_first">Najpierw zaloguj się na nowym telefonie przy użyciu tego samego konta. Spowoduje to przeniesienie twoich grup, ale w żadnym wypadku nie twojego klucza.</string>
|
||||
<string name="cordn_migrate_export">Rozpocznij transfer</string>
|
||||
<string name="cordn_migrate_exporting">Publikowanie…</string>
|
||||
<string name="cordn_migrate_scan_this">Zeskanuj to na nowym telefonie</string>
|
||||
<string name="cordn_migrate_code_note">Kod to tylko wskazówka. Ktokolwiek go sfotografuje, nic się nie dowie — to, na co wskazuje, jest dla ciebie zastrzeżone.</string>
|
||||
<string name="cordn_migrate_handed_off">To urządzenie przeniosło swoje grupy</string>
|
||||
<string name="cordn_migrate_handed_off_desc">Aplikacja przestała wysyłać i odbierać wiadomości, ponieważ wysyłanie wiadomości przez dwa telefony z tej samej grupy spowodowałoby zakłócenia dla wszystkich jej członków. Twoje grupy nadal znajdują się na tym urządzeniu i nic nie zostało usunięte.</string>
|
||||
<string name="cordn_migrate_cancel">Przywróć to urządzenie</string>
|
||||
<string name="cordn_migrate_cancel_desc">Skorzystaj z tej opcji, jeśli przenoszenie nie zostało zakończone. Zrób to tylko wtedy, gdy nowy telefon jeszcze nie rozpoczął wysyłania danych.</string>
|
||||
<string name="cordn_migrate_receive">Odbierz z innego telefonu</string>
|
||||
<string name="cordn_migrate_scan">Zeskanuj kod</string>
|
||||
<string name="cordn_migrate_paste">lub wklej</string>
|
||||
<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>
|
||||
<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>
|
||||
<string name="cordn_migrate_exposure_body">Stan Twojej grupy jest szyfrowany i przesyłany na serwer multimediów, aby drugi telefon mógł go pobrać. Serwer ten nie jest w stanie odczytać tych danych – widzi jedynie rozmiar i czas. Jeśli chcesz, aby nic nie pozostało, usuń te pliki po zakończeniu.</string>
|
||||
<string name="sno_object_title">Obiekt 3D</string>
|
||||
<string name="sno_object_details">%1$d wierzchołków · %2$d ścian</string>
|
||||
<string name="sno_object_unreadable">Nie udało się odczytać tego obiektu 3D (reguła %1$s)</string>
|
||||
@@ -5468,16 +5589,141 @@
|
||||
<string name="cyberspace_bag_cancel">Stop</string>
|
||||
<string name="cyberspace_bag_measuring">Wycena wyszukiwania na tym urządzeniu…</string>
|
||||
<string name="cyberspace_bag_progress">Przeszukano %1$s z %2$s regionów</string>
|
||||
<string name="cyberspace_bag_too_slow_minutes">Poza zasięgiem: około %1$d minut wyszukiwania na tym urządzeniu</string>
|
||||
<string name="cyberspace_bag_too_slow_hours">Poza zasięgiem: około %1$d godzin wyszukiwania na tym urządzeniu</string>
|
||||
<plurals name="cyberspace_bag_too_slow_minutes">
|
||||
<item quantity="one">Poza zasięgiem: około %1$d minuty wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="few">Poza zasięgiem: około %1$d minut wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="many">Poza zasięgiem: około %1$d minut wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="other">Poza zasięgiem: około %1$d minuty wyszukiwania na tym urządzeniu</item>
|
||||
</plurals>
|
||||
<plurals name="cyberspace_bag_too_slow_hours">
|
||||
<item quantity="one">Poza zasięgiem: około %1$d godziny wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="few">Poza zasięgiem: około %1$d godzin wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="many">Poza zasięgiem: około %1$d godzin wyszukiwania na tym urządzeniu</item>
|
||||
<item quantity="other">Poza zasięgiem: około %1$d godziny wyszukiwania na tym urządzeniu</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_not_found">W pudełku nie ma podpowiedzi o nazwie</string>
|
||||
<string name="cyberspace_bag_damaged">Znaleziono region, ale nie udało się odczytać jego zawartości</string>
|
||||
<string name="cyberspace_bag_dropped">%1$d element ukryty w tym miejscu nie pasował do swojej sygnatury podpisu i został usunięty</string>
|
||||
<string name="cyberspace_bag_dropped_many">%1$d ukrytych tutaj elementów nie pasowało do swoich sygnatur i zostało usuniętych</string>
|
||||
<plurals name="cyberspace_bag_dropped">
|
||||
<item quantity="one">%1$d element ukryty w tym miejscu nie pasował do swojej sygnatury podpisu i został usunięty</item>
|
||||
<item quantity="few">%1$d elementy ukryte tutaj nie pasowały do swoich sygnatur i zostały usunięte</item>
|
||||
<item quantity="many">%1$d ukrytych tutaj elementów nie pasowało do swoich sygnatur i zostało usuniętych</item>
|
||||
<item quantity="other">%1$d ukrytego tutaj elementu nie pasowało do swoich sygnatur i zostało usuniętych</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_empty">Otworzyłem, a w środku nic nie było</string>
|
||||
<string name="cyberspace_bag_unsigned">Brak podpisu, więc autor to tylko domysł</string>
|
||||
<string name="cyberspace_bag_unknown_kind">Element typu %1$d, którego ten klient nie wyświetla</string>
|
||||
<string name="cyberspace_bag_opaque">%1$d bajtów danych, których ten klient nie odczytuje</string>
|
||||
<plurals name="cyberspace_bag_opaque">
|
||||
<item quantity="one">%1$d bajt danych, których ten klient nie odczytuje</item>
|
||||
<item quantity="few">%1$d bajty danych, których ten klient nie odczytuje</item>
|
||||
<item quantity="many">%1$d bajtów danych, których ten klient nie odczytuje</item>
|
||||
<item quantity="other">%1$d bajta danych, których ten klient nie odczytuje</item>
|
||||
</plurals>
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
<string name="browser_pill_close">Zamknij</string>
|
||||
<string name="browser_pill_tile_copy">Kopiuj link</string>
|
||||
<string name="browser_pill_tile_find">Znajdź</string>
|
||||
<string name="browser_pill_tile_text">Rozmiar tekstu</string>
|
||||
<string name="browser_pill_tile_desktop">Pulpit</string>
|
||||
<string name="browser_pill_tile_home">Dodaj do strony głównej</string>
|
||||
<string name="browser_pill_tile_other">Inna przeglądarka</string>
|
||||
<string name="browser_pill_tile_full">Pełny ekran</string>
|
||||
<string name="browser_pill_edit_address">Edytuj adres</string>
|
||||
<string name="browser_pill_back">Wróć</string>
|
||||
<string name="browser_pill_forward">Przekaż</string>
|
||||
<string name="browser_pill_reload">Odśwież</string>
|
||||
<string name="browser_pill_stop">Zatrzymaj wczytywanie</string>
|
||||
<string name="browser_pill_favorite_add">Dodaj do ulubionych</string>
|
||||
<string name="browser_pill_favorite_remove">Usuń z ulubionych</string>
|
||||
<string name="browser_pill_share">Udostępnij</string>
|
||||
<string name="browser_pill_copy">Kopiuj link</string>
|
||||
<string name="browser_pill_find">Znajdź na stronie</string>
|
||||
<string name="browser_pill_text_size">Rozmiar tekstu</string>
|
||||
<string name="browser_pill_add_home">Dodaj do strony głównej</string>
|
||||
<string name="browser_pill_desktop">Witryna stacjonarna</string>
|
||||
<string name="browser_pill_other_browser">Otwórz w przeglądarce</string>
|
||||
<string name="browser_pill_other_browser_named">Otwórz w %1$s</string>
|
||||
<string name="browser_pill_full_screen">Pełny ekran</string>
|
||||
<string name="browser_pill_left_site">Opuściłeś %1$s</string>
|
||||
<string name="browser_pill_back_to_app">Powrót do aplikacji</string>
|
||||
<string name="browser_pill_text_smaller">Mniejszy tekst</string>
|
||||
<string name="browser_pill_text_larger">Większy tekst</string>
|
||||
<string name="browser_pill_text_reset">Zresetuj</string>
|
||||
<string name="browser_pill_text_value">%1$d%</string>
|
||||
<string name="browser_pill_privacy">Prywatność</string>
|
||||
<string name="browser_pill_tor_title">Przekierowanie Onion</string>
|
||||
<string name="browser_pill_tor_on">Witryna nie widzi Twojego adresu IP</string>
|
||||
<string name="browser_pill_tor_off">Witryna może wykryć Twój adres IP</string>
|
||||
<string name="browser_pill_site_settings">Ustawienia witryny</string>
|
||||
<string name="browser_pill_site_settings_none">Na razie nic nie jest dozwolone</string>
|
||||
<string name="browser_pill_access">Do czego ma dostęp</string>
|
||||
<string name="browser_pill_access_desc">Twoje klucze nigdy nie opuszczają Amethystu</string>
|
||||
<string name="browser_pill_access_keys_desc">Każdy wpis, publikacja, przesłanie treści lub płatność wymaga Twojej zgody</string>
|
||||
<string name="browser_pill_access_none">Brak specjalnego dostępu</string>
|
||||
<string name="browser_pill_access_none_desc">Działa w środowisku izolowanym i nie ma dostępu do Twojego konta</string>
|
||||
<string name="browser_pill_access_manage">Zarządzaj uprawnieniami</string>
|
||||
<string name="browser_pill_access_nsite">nSite · w środowisku izolowanym</string>
|
||||
<string name="browser_pill_access_napplet">nApplet · w środowisku izolowanym</string>
|
||||
<string name="browser_pill_console">Konsola</string>
|
||||
<string name="browser_pill_security_https">Bezpieczne połączenie</string>
|
||||
<string name="browser_pill_security_http">Niezabezpieczone</string>
|
||||
<string name="browser_pill_security_tor">Przekierowanie przez Onion</string>
|
||||
<string name="browser_pill_security_sandbox">Aplikacja w środowisku izolowanym</string>
|
||||
<string name="browser_pill_permission_camera">Aparat</string>
|
||||
<string name="browser_pill_permission_microphone">Mikrofon</string>
|
||||
<string name="browser_pill_permission_location">Lokalizacja</string>
|
||||
<string name="browser_pill_decision_ask">Zapytaj</string>
|
||||
<string name="browser_pill_decision_allow">Zezwól</string>
|
||||
<string name="browser_pill_decision_block">Zablokuj</string>
|
||||
<string name="browser_pill_permission_state">%1$s %2$s</string>
|
||||
<string name="browser_pill_decision_allowed">dozwolone</string>
|
||||
<string name="browser_pill_decision_blocked">zablokowane</string>
|
||||
<string name="browser_pill_address_hint">Szukaj lub wprowadź adres</string>
|
||||
<string name="browser_pill_go">Przejdź</string>
|
||||
<string name="browser_pill_clear">Wyczyść</string>
|
||||
<string name="browser_pill_paste_go">Wklej i przejdź</string>
|
||||
<string name="browser_pill_fill_in">Użyj tego adresu</string>
|
||||
<string name="browser_pill_find_hint">Znajdź na stronie</string>
|
||||
<string name="browser_pill_find_count">%1$d x %2$d</string>
|
||||
<string name="browser_pill_find_none">Brak wyników</string>
|
||||
<string name="browser_pill_find_previous">Poprzedni wynik</string>
|
||||
<string name="browser_pill_find_next">Następne wynik</string>
|
||||
<string name="browser_pill_find_close">Zamknij wyszukiwanie na stronie</string>
|
||||
<string name="browser_pill_console_all">Wszytko</string>
|
||||
<string name="browser_pill_console_errors">Błędy</string>
|
||||
<string name="browser_pill_console_warnings">Ostrzeżenia</string>
|
||||
<string name="browser_pill_console_copy">Kopiuj</string>
|
||||
<string name="browser_pill_console_clear">Wyczyść</string>
|
||||
<string name="browser_pill_console_empty">Nic nie zalogowano</string>
|
||||
<string name="browser_pill_perm_title">Ta strona chce użyć</string>
|
||||
<string name="browser_pill_perm_camera_desc">Zobacz, co widzi Twoja kamera</string>
|
||||
<string name="browser_pill_perm_microphone_desc">Usłysz, co słyszy Twój mikrofon</string>
|
||||
<string name="browser_pill_perm_location_desc">Wiedz mniej więcej, gdzie się znajdujesz</string>
|
||||
<string name="browser_pill_perm_tor_note">Połączenia mogą ujawnić Twój adres IP nawet przy korzystaniu z sieci Tor.</string>
|
||||
<string name="browser_pill_perm_allow">Zezwól podczas odwiedzin</string>
|
||||
<string name="browser_pill_perm_once">Tylko tym razem</string>
|
||||
<string name="browser_pill_perm_deny">Nie zezwalaj</string>
|
||||
<string name="browser_pill_dialog_generic">Na tej stronie napisano</string>
|
||||
<string name="browser_pill_dialog_block">Nie pozwól tej stronie wyświetlać więcej dialogów</string>
|
||||
<string name="browser_pill_dialog_answer">Twoja odpowiedź</string>
|
||||
<string name="browser_pill_dialog_leave_title">Opuścić witrynę?</string>
|
||||
<string name="browser_pill_dialog_leave_message">Wprowadzone zmiany mogą nie zostać zapisane.</string>
|
||||
<string name="browser_pill_dialog_leave">Wyjdź</string>
|
||||
<string name="browser_pill_ok">OK</string>
|
||||
<string name="browser_pill_cancel">Anuluj</string>
|
||||
<string name="browser_pill_info_connection">Połączenie</string>
|
||||
<string name="browser_pill_info_https">Połączenie jest zaszyfrowane</string>
|
||||
<string name="browser_pill_info_https_desc">Przesyłane przez Ciebie informacje nie mogą zostać odczytane podczas przesyłania.</string>
|
||||
<string name="browser_pill_info_http">Połączenie nie jest zaszyfrowane</string>
|
||||
<string name="browser_pill_info_http_desc">Nie wpisuj haseł ani danych płatności.</string>
|
||||
<string name="browser_pill_info_tor">Przekierowanie typu Onion przez sieć Tor</string>
|
||||
<string name="browser_pill_info_open">Otwarta sieć</string>
|
||||
<string name="browser_pill_info_certificate">Certyfikat</string>
|
||||
<string name="browser_pill_info_certificate_desc">Wydany dla %1$s przez %2$s · ważny do %3$s</string>
|
||||
<string name="browser_pill_info_permissions">Uprawnienia</string>
|
||||
<string name="browser_pill_info_site_data">Pliki cookie i dane witryny</string>
|
||||
<string name="browser_pill_info_site_data_desc">Loginy i preferencje tej witryny zapisane dla tego konta</string>
|
||||
<string name="browser_pill_info_clear">Wyczyść dane witryny</string>
|
||||
<string name="browser_pill_info_clear_confirm">Wylogować się z tej witryny i usunąć dane?</string>
|
||||
<string name="backup_action_block_again">Zablokuj %1$s ponownie</string>
|
||||
<string name="backup_action_keep_count">Zachowaj %1$s</string>
|
||||
<string name="backup_action_rejoin">Ponów %1$s</string>
|
||||
@@ -5775,13 +6021,23 @@
|
||||
<string name="backup_review_renamed">zmieniono nazwę</string>
|
||||
<string name="backup_review_renamed_tag">Zmieniono nazwę</string>
|
||||
<string name="backup_review_saved">Na tym urządzeniu</string>
|
||||
<string name="backup_review_search_people">Szukaj %1$s osób</string>
|
||||
<plurals name="backup_review_search_people">
|
||||
<item quantity="one">Szukaj %1$s osoby</item>
|
||||
<item quantity="few">Szukaj %1$s osób</item>
|
||||
<item quantity="many">Szukaj %1$s osób</item>
|
||||
<item quantity="other">Szukaj %1$s osoby</item>
|
||||
</plurals>
|
||||
<string name="backup_review_searching_tag">Szukam</string>
|
||||
<string name="backup_review_service">Serwis</string>
|
||||
<string name="backup_review_service_followers">Obserwujący</string>
|
||||
<string name="backup_review_service_rank">Ranking</string>
|
||||
<string name="backup_review_service_topics">Tematy</string>
|
||||
<string name="backup_review_services_changed">Zmieniono %1$s z %2$s serwisów</string>
|
||||
<plurals name="backup_review_services_changed">
|
||||
<item quantity="one">Zmieniono %1$s z %2$s serwisu</item>
|
||||
<item quantity="few">Zmieniono %1$s z %2$s serwisów</item>
|
||||
<item quantity="many">Zmieniono %1$s z %2$s serwisów</item>
|
||||
<item quantity="other">Zmieniono %1$s z %2$s serwisu</item>
|
||||
</plurals>
|
||||
<string name="backup_review_services_changed_explainer">Teraz pochodzą od kogoś innego albo od nikogo</string>
|
||||
<string name="backup_review_still_blocked">Nadal zablokowana</string>
|
||||
<string name="backup_review_storing_tag">Przechowywanie</string>
|
||||
@@ -5856,4 +6112,24 @@
|
||||
<string name="backup_type_trust_providers_explainer">Serwisy, którym ufasz, a które zajmują się klasyfikowaniem i weryfikacją osób w Twoim imieniu.</string>
|
||||
<string name="backup_type_trusted_relays">lista zaufanych transmiterów</string>
|
||||
<string name="backup_type_trusted_relays_explainer">Zaufane transmitery, z którymi bez wahania nawiązujesz połączenie.</string>
|
||||
<string name="cordn_action_delete">Usuń</string>
|
||||
<string name="cordn_action_edit">Edytuj</string>
|
||||
<string name="cordn_action_editing">Edycja wiadomości</string>
|
||||
<string name="cordn_action_go_to_message">Przejdź do wiadomości</string>
|
||||
<string name="cordn_action_pin">Przypnij</string>
|
||||
<string name="cordn_action_reply">Odpowiedz</string>
|
||||
<string name="cordn_action_unpin">Odepnij</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>
|
||||
<string name="cordn_chat_empty_description">Wszystkie wiadomości wysyłane tutaj są szyfrowane dla tej grupy. Koordynator przekazuje je dalej, nie mając możliwości ich odczytania.</string>
|
||||
<string name="cordn_chat_empty_title">Brak wiadomości</string>
|
||||
<string name="cordn_chat_unread_divider">Nowe wiadomości</string>
|
||||
<string name="cordn_chat_yesterday">Wczoraj</string>
|
||||
<string name="cordn_composer_hint">Wiadomość</string>
|
||||
<string name="cordn_coordinators_add_action">Dodaj</string>
|
||||
<string name="cordn_coordinators_add_failed">Nie można otworzyć tego koordynatora.</string>
|
||||
<string name="cordn_coordinators_copy_key">Skopiuj npub koordynatora</string>
|
||||
<string name="cordn_coordinators_discover_action">Szukaj koordynatorów</string>
|
||||
<string name="cordn_coordinators_discover_add">Dodaj</string>
|
||||
</resources>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2913,4 +2913,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -3000,4 +3000,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2981,4 +2981,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -5000,4 +5000,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2958,4 +2958,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2933,4 +2933,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2922,4 +2922,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2763,4 +2763,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2929,4 +2929,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2987,4 +2987,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2938,4 +2938,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2883,4 +2883,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -3899,4 +3899,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2948,4 +2948,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2948,4 +2948,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -2919,4 +2919,5 @@
|
||||
<!-- cordn device migration (spec/applications/multi-device.md §9/§11), as a
|
||||
one-shot handoff rather than continuous sync. The exposure strings say
|
||||
what leaves the device; the fork strings say why the old phone stops. -->
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
</resources>
|
||||
|
||||
@@ -219,7 +219,10 @@
|
||||
<string name="geocache_hunt_new">New hunt…</string>
|
||||
<string name="geocache_hunt_none_yet">You have not made a hunt yet.</string>
|
||||
<string name="geocache_hunt_already_on">Already on this hunt</string>
|
||||
<string name="geocache_caches_here">%1$d caches here</string>
|
||||
<plurals name="geocache_caches_here">
|
||||
<item quantity="one">%1$d cache here</item>
|
||||
<item quantity="other">%1$d caches here</item>
|
||||
</plurals>
|
||||
<string name="geocache_photo_remove">Remove this photo</string>
|
||||
<string name="geocache_archived_notice">This cache has been archived. It is no longer in play.</string>
|
||||
<string name="geocache_ftf_won_by">First to find claimed by %1$s</string>
|
||||
@@ -278,7 +281,6 @@
|
||||
<string name="geocache_map_recenter">Centre on me</string>
|
||||
<string name="geocache_map_long_press">Long-press the map to hide a cache there</string>
|
||||
<string name="geocache_map_open">Open</string>
|
||||
<string name="geocache_map_pin_count">%1$d caches</string>
|
||||
<string name="geocache_new_section_where">Where</string>
|
||||
<string name="geocache_new_section_what">What</string>
|
||||
<string name="geocache_new_section_extras">Extras</string>
|
||||
@@ -306,7 +308,10 @@
|
||||
<string name="geocache_new_needs_location">Pick where the cache is hidden.</string>
|
||||
<string name="geocache_hunt_progress">%1$d of %2$d found</string>
|
||||
<string name="geocache_hunt_start">Start the hunt</string>
|
||||
<string name="geocache_hunt_caches">%1$d caches</string>
|
||||
<plurals name="geocache_hunt_caches">
|
||||
<item quantity="one">%1$d cache</item>
|
||||
<item quantity="other">%1$d caches</item>
|
||||
</plurals>
|
||||
<string name="geocache_hunt_title">Title</string>
|
||||
<string name="geocache_hunt_description">Description</string>
|
||||
<string name="geocache_hunt_banner">Banner image</string>
|
||||
@@ -355,7 +360,10 @@
|
||||
<string name="qr_scanner_no_code_in_image">No QR code found in that picture</string>
|
||||
<string name="qr_scanner_clipboard_empty">Nothing on the clipboard to scan</string>
|
||||
<string name="qr_scanner_pick_one">Tap the code you want</string>
|
||||
<string name="qr_scanner_sequence_progress">Captured %1$s of %2$s parts — keep going</string>
|
||||
<plurals name="qr_scanner_sequence_progress">
|
||||
<item quantity="one">Captured %1$s of %2$s part — keep going</item>
|
||||
<item quantity="other">Captured %1$s of %2$s parts — keep going</item>
|
||||
</plurals>
|
||||
<string name="qr_scanner_zoom_reset">Reset zoom</string>
|
||||
<string name="qr_scanner_unsupported_title">Amethyst can't open this code</string>
|
||||
<string name="qr_scanner_unsupported_secret">This code carries a private key or a pairing secret, so its contents are not shown here. Use the screen that expects it.</string>
|
||||
@@ -5335,7 +5343,10 @@
|
||||
<string name="cordn_health_unknown">Not contacted yet</string>
|
||||
<string name="cordn_health_ok">Responding</string>
|
||||
<string name="cordn_health_down">Not responding</string>
|
||||
<string name="cordn_health_failures">%1$d failed attempts in a row</string>
|
||||
<plurals name="cordn_health_failures">
|
||||
<item quantity="one">%1$d failed attempt in a row</item>
|
||||
<item quantity="other">%1$d failed attempts in a row</item>
|
||||
</plurals>
|
||||
|
||||
<string name="cordn_link_explainer">Paste a cordn1… link someone shared with you to see which coordinator carries that group, and what that operator would learn about you if you joined.</string>
|
||||
<string name="cordn_link_field">cordn1…</string>
|
||||
@@ -5431,7 +5442,10 @@
|
||||
<string name="cordn_migrate_import">Bring the groups here</string>
|
||||
<string name="cordn_migrate_importing">Fetching…</string>
|
||||
<string name="cordn_migrate_replaces_warning">This replaces any cordn groups already on this phone. They cannot be merged.</string>
|
||||
<string name="cordn_migrate_done">%1$d groups moved</string>
|
||||
<plurals name="cordn_migrate_done">
|
||||
<item quantity="one">%1$d group moved</item>
|
||||
<item quantity="other">%1$d groups moved</item>
|
||||
</plurals>
|
||||
<string name="cordn_migrate_no_groups">There are no cordn groups on this device to move.</string>
|
||||
<string name="cordn_migrate_no_server">Set a media server first — the encrypted documents need somewhere to sit while the other phone fetches them.</string>
|
||||
<string name="cordn_migrate_exposure_title">What leaves this device</string>
|
||||
@@ -5457,16 +5471,27 @@
|
||||
<string name="cyberspace_bag_cancel">Stop</string>
|
||||
<string name="cyberspace_bag_measuring">Pricing the search on this device…</string>
|
||||
<string name="cyberspace_bag_progress">Searched %1$s of %2$s regions</string>
|
||||
<string name="cyberspace_bag_too_slow_minutes">Out of reach: about %1$d minutes of searching on this device</string>
|
||||
<string name="cyberspace_bag_too_slow_hours">Out of reach: about %1$d hours of searching on this device</string>
|
||||
<plurals name="cyberspace_bag_too_slow_minutes">
|
||||
<item quantity="one">Out of reach: about %1$d minute of searching on this device</item>
|
||||
<item quantity="other">Out of reach: about %1$d minutes of searching on this device</item>
|
||||
</plurals>
|
||||
<plurals name="cyberspace_bag_too_slow_hours">
|
||||
<item quantity="one">Out of reach: about %1$d hour of searching on this device</item>
|
||||
<item quantity="other">Out of reach: about %1$d hours of searching on this device</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_not_found">Not in the box the hint named</string>
|
||||
<string name="cyberspace_bag_damaged">Found the region, but the contents could not be read</string>
|
||||
<string name="cyberspace_bag_dropped">%1$d item hidden here did not match its signature and was dropped</string>
|
||||
<string name="cyberspace_bag_dropped_many">%1$d items hidden here did not match their signatures and were dropped</string>
|
||||
<plurals name="cyberspace_bag_dropped">
|
||||
<item quantity="one">%1$d item hidden here did not match its signature and was dropped</item>
|
||||
<item quantity="other">%1$d items hidden here did not match their signatures and were dropped</item>
|
||||
</plurals>
|
||||
<string name="cyberspace_bag_empty">Opened, and there was nothing inside</string>
|
||||
<string name="cyberspace_bag_unsigned">Unsigned, so this author is a claim</string>
|
||||
<string name="cyberspace_bag_unknown_kind">An item of kind %1$d, which this client does not draw</string>
|
||||
<string name="cyberspace_bag_opaque">%1$d bytes of something this client does not read</string>
|
||||
<plurals name="cyberspace_bag_opaque">
|
||||
<item quantity="one">%1$d byte of something this client does not read</item>
|
||||
<item quantity="other">%1$d bytes of something this client does not read</item>
|
||||
</plurals>
|
||||
<!-- Browser pill (redesign prototypes, see amethyst/plans/2026-09-26-browser-ui-review.md) -->
|
||||
<string name="browser_pill_close">Close</string>
|
||||
<string name="browser_pill_tile_copy">Copy link</string>
|
||||
@@ -5811,13 +5836,19 @@
|
||||
<string name="backup_review_renamed">renamed</string>
|
||||
<string name="backup_review_renamed_tag">Renamed</string>
|
||||
<string name="backup_review_saved">On this device</string>
|
||||
<string name="backup_review_search_people">Search %1$s people</string>
|
||||
<plurals name="backup_review_search_people">
|
||||
<item quantity="one">Search %1$s person</item>
|
||||
<item quantity="other">Search %1$s people</item>
|
||||
</plurals>
|
||||
<string name="backup_review_searching_tag">Searching</string>
|
||||
<string name="backup_review_service">Service</string>
|
||||
<string name="backup_review_service_followers">Followers</string>
|
||||
<string name="backup_review_service_rank">Rank</string>
|
||||
<string name="backup_review_service_topics">Topics</string>
|
||||
<string name="backup_review_services_changed">%1$s of %2$s services changed</string>
|
||||
<plurals name="backup_review_services_changed">
|
||||
<item quantity="one">%1$s of %2$s service changed</item>
|
||||
<item quantity="other">%1$s of %2$s services changed</item>
|
||||
</plurals>
|
||||
<string name="backup_review_services_changed_explainer">They now come from someone else, or no one</string>
|
||||
<string name="backup_review_still_blocked">Still blocked</string>
|
||||
<string name="backup_review_storing_tag">Storing</string>
|
||||
@@ -5935,9 +5966,15 @@
|
||||
<string name="cordn_coordinators_discover_none">Nobody is announcing on your relays.</string>
|
||||
<string name="cordn_coordinators_discover_seen">Announced %1$s ago</string>
|
||||
<string name="cordn_coordinators_discover_seen_on">Last announced %1$s</string>
|
||||
<string name="cordn_coordinators_discover_unheard">Nothing found, and %1$d of your relays did not answer.</string>
|
||||
<plurals name="cordn_coordinators_discover_unheard">
|
||||
<item quantity="one">Nothing found, and %1$d of your relays did not answer.</item>
|
||||
<item quantity="other">Nothing found, and %1$d of your relays did not answer.</item>
|
||||
</plurals>
|
||||
<string name="cordn_coordinators_explainer">A coordinator orders one group's messages and is the only thing that can. Losing it loses the ordering, and a second one does not mirror the first — so these are named things you choose, not interchangeable relays.</string>
|
||||
<string name="cordn_coordinators_health_down">Not answering — %1$d calls in a row have failed. Groups on it are not syncing.</string>
|
||||
<plurals name="cordn_coordinators_health_down">
|
||||
<item quantity="one">Not answering — %1$d call in a row has failed. Groups on it are not syncing.</item>
|
||||
<item quantity="other">Not answering — %1$d calls in a row have failed. Groups on it are not syncing.</item>
|
||||
</plurals>
|
||||
<string name="cordn_coordinators_health_ok">Answering.</string>
|
||||
<string name="cordn_coordinators_health_retrying">A call failed; retrying.</string>
|
||||
<string name="cordn_coordinators_health_unknown">Nothing asked of it yet.</string>
|
||||
@@ -5961,7 +5998,10 @@
|
||||
<string name="cordn_coordinators_server_silent">Answered, but named nothing.</string>
|
||||
<string name="cordn_coordinators_show_all">Show all %1$d</string>
|
||||
<string name="cordn_coordinators_show_fewer">Show fewer</string>
|
||||
<string name="cordn_coordinators_show_older">Show %1$d that stopped announcing</string>
|
||||
<plurals name="cordn_coordinators_show_older">
|
||||
<item quantity="one">Show %1$d that stopped announcing</item>
|
||||
<item quantity="other">Show %1$d that stopped announcing</item>
|
||||
</plurals>
|
||||
<string name="cordn_coordinators_stale_note">These have not announced in over a month. Creating a group on one that has gone away will fail.</string>
|
||||
<string name="cordn_create_action">Create group</string>
|
||||
<plurals name="cordn_create_action_invite">
|
||||
@@ -5983,7 +6023,10 @@
|
||||
<string name="cordn_create_coordinator_new">Another coordinator</string>
|
||||
<string name="cordn_create_coordinator_pubkey">Coordinator public key (hex or npub)</string>
|
||||
<string name="cordn_create_coordinator_relays">Relays it answers on, one per line</string>
|
||||
<string name="cordn_create_coverage_all">Reaches all %1$d of your people</string>
|
||||
<plurals name="cordn_create_coverage_all">
|
||||
<item quantity="one">Reaches your %1$d person</item>
|
||||
<item quantity="other">Reaches all %1$d of your people</item>
|
||||
</plurals>
|
||||
<string name="cordn_create_coverage_partial">Reaches %1$d of %2$d — the rest would be left out</string>
|
||||
<string name="cordn_create_coverage_unknown">Not checked — picking it will ask</string>
|
||||
<string name="cordn_create_description">Description (optional)</string>
|
||||
|
||||
+30
-13
@@ -26,15 +26,23 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.withFrameMillis
|
||||
import androidx.compose.runtime.withFrameNanos
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Collects [spectrum] into a decayed [FloatArray] and optionally runs a monotonic time clock,
|
||||
* then calls [draw] inside the Canvas draw lambda. The fast-changing state is read
|
||||
* ONLY in the draw lambda, so new frames trigger the draw phase, never recomposition.
|
||||
* Pass [animated] = false for non-time-varying styles (bars, radial) to avoid 60fps redraws.
|
||||
*
|
||||
* Frames are released through [SpectrumTrail] as the audio they describe comes due. The pacing loop
|
||||
* only writes state when a frame is due, and parks entirely while nothing is queued (paused, idle),
|
||||
* so on its own it redraws at the ~43-47 Hz the fft produces and costs nothing when silent.
|
||||
*
|
||||
* Pass [animated] = false for non-time-varying styles (bars, radial): that drops the monotonic clock,
|
||||
* whose whole purpose is to redraw every frame even when the spectrum has not moved.
|
||||
*/
|
||||
@Composable
|
||||
fun SpectrumCanvas(
|
||||
@@ -46,18 +54,27 @@ fun SpectrumCanvas(
|
||||
draw: DrawScope.(bins: FloatArray, timeSec: Float, palette: VisualizerPalette) -> Unit,
|
||||
) {
|
||||
val smoothed = remember { mutableStateOf(FloatArray(0)) }
|
||||
LaunchedEffect(spectrum, decay) {
|
||||
var prev = FloatArray(0)
|
||||
spectrum.collect { frame ->
|
||||
// A fresh array each frame is intentional: mutableStateOf compares by reference, so a new
|
||||
// instance is what signals Compose to redraw. Do NOT switch to in-place mutation.
|
||||
val next =
|
||||
FloatArray(frame.bins.size) { i ->
|
||||
val prior = if (i < prev.size) prev[i] * decay else 0f
|
||||
if (frame.bins[i] > prior) frame.bins[i] else prior
|
||||
}
|
||||
smoothed.value = next
|
||||
prev = next
|
||||
|
||||
val trail = remember(spectrum, decay) { SpectrumTrail(decay) }
|
||||
val arrivals = remember(trail) { Channel<Unit>(Channel.CONFLATED) }
|
||||
LaunchedEffect(spectrum, trail) {
|
||||
spectrum.collect {
|
||||
trail.offer(it)
|
||||
arrivals.trySend(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(trail) {
|
||||
while (true) {
|
||||
val next = trail.nextOrNull(withFrameNanos { it })
|
||||
if (next != null) {
|
||||
smoothed.value = next
|
||||
} else if (trail.isEmpty()) {
|
||||
// Park off the frame clock until the next offer. This must follow a nextOrNull that
|
||||
// saw the empty queue: that call records the starvation which stops the next cluster
|
||||
// from being dumped at once to "catch up".
|
||||
arrivals.receive()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.commons.resources.cordn_health_down
|
||||
import com.vitorpamplona.amethyst.commons.resources.cordn_health_failures
|
||||
import com.vitorpamplona.amethyst.commons.resources.cordn_health_ok
|
||||
import com.vitorpamplona.amethyst.commons.resources.cordn_health_unknown
|
||||
import org.jetbrains.compose.resources.pluralStringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,7 @@ fun CoordinatorHealthRow(
|
||||
// deserves no words at all.
|
||||
if (state.isDown) {
|
||||
Text(
|
||||
text = stringResource(Res.string.cordn_health_failures, state.consecutiveFailures),
|
||||
text = pluralStringResource(Res.plurals.cordn_health_failures, state.consecutiveFailures, state.consecutiveFailures),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
@@ -124,9 +124,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"user": "rajs19420616",
|
||||
"user": "summoner001",
|
||||
"languages": [
|
||||
"Hindi"
|
||||
"Hungarian"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -136,9 +136,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"user": "summoner001",
|
||||
"user": "rajs19420616",
|
||||
"languages": [
|
||||
"Hungarian"
|
||||
"Hindi"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -147,6 +147,15 @@
|
||||
"Russian"
|
||||
]
|
||||
},
|
||||
{
|
||||
"user": "davotoula",
|
||||
"languages": [
|
||||
"Czech",
|
||||
"German",
|
||||
"Portuguese, Brazilian",
|
||||
"Swedish"
|
||||
]
|
||||
},
|
||||
{
|
||||
"user": "greenart7c3",
|
||||
"languages": []
|
||||
@@ -219,10 +228,6 @@
|
||||
"user": "adhrasreoshiathoi",
|
||||
"languages": []
|
||||
},
|
||||
{
|
||||
"user": "davotoula",
|
||||
"languages": []
|
||||
},
|
||||
{
|
||||
"user": "crackadoo",
|
||||
"languages": []
|
||||
|
||||
+25
@@ -155,6 +155,9 @@ class NappletBrowserActivity : ComponentActivity() {
|
||||
// same address don't each trigger a round-trip.
|
||||
private var lastFavoriteQueryUrl: String? = null
|
||||
|
||||
/** The origin whose site permissions the pill is already showing. */
|
||||
private var lastSitePermissionOrigin: String? = null
|
||||
|
||||
// What Recents shows for this task: the page's title, favicon and theme colour.
|
||||
private var pageTitle: String? = null
|
||||
private var pageIcon: Bitmap? = null
|
||||
@@ -771,6 +774,20 @@ class NappletBrowserActivity : ComponentActivity() {
|
||||
copy(chrome = chrome.copy(url = url), title = if (newSite) BrowserChrome.displayHost(url) else title, isFavorite = false)
|
||||
}
|
||||
}
|
||||
// The pill's "Site settings" line summarises this origin's camera/mic/location answers, and the
|
||||
// registry that holds them lives in the main process. Until this was asked for on navigation, the
|
||||
// only thing that ever filled it was opening page info — so a window said "Nothing allowed yet"
|
||||
// about a site it had already been granted the camera on, and only stopped lying once you opened
|
||||
// the sheet that made it ask.
|
||||
BrowserChrome.originOf(url)?.let { origin ->
|
||||
if (origin != lastSitePermissionOrigin) {
|
||||
lastSitePermissionOrigin = origin
|
||||
querySitePermissions(origin) { decisions ->
|
||||
updateUi { copy(sitePermissions = decisions.filterValues { it != Decision.ASK }) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (url == lastFavoriteQueryUrl) return
|
||||
lastFavoriteQueryUrl = url
|
||||
val msg =
|
||||
@@ -1383,6 +1400,14 @@ class NappletBrowserActivity : ComponentActivity() {
|
||||
decision: Decision,
|
||||
) {
|
||||
BrowserChrome.originOf(currentUrl())?.let { rememberSitePermission(it, permission, decision) }
|
||||
// Keep the pill's summary in step with the sheet the change was made in. The registry
|
||||
// is authoritative and lives in the other process, but it does not call back, so an
|
||||
// edit made here would otherwise not show up until the next navigation.
|
||||
updateUi {
|
||||
val next = sitePermissions.toMutableMap()
|
||||
if (decision == Decision.ASK) next.remove(permission) else next[permission] = decision
|
||||
copy(sitePermissions = next)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClearSiteData() {
|
||||
|
||||
+19
@@ -20,12 +20,17 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.experimental.decentralizedLists
|
||||
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.names
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.tags.NamesTag
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.tags.SingularPlural
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.tags.TitlesTag
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.titles
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.comments
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.name
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.tags.CommentsTag
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.tags.NameTag
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.tags.TitleTag
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.title
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.tags.DescriptionTag
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||
import com.vitorpamplona.quartz.nip01Core.core.fastForEach
|
||||
@@ -84,6 +89,20 @@ fun TagArray.forEachSearchableListField(visitor: IndexableFieldVisitor): Boolean
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* The TITLE role of [forEachSearchableListField], for search engines that weight fields: what the
|
||||
* list or item is called — the header's `names` and `titles` (singular, then plural) and the
|
||||
* item's `name` and `title`. Same first-well-formed-tag rule as the walk.
|
||||
*/
|
||||
fun TagArray.searchableListTitles(): List<String?> {
|
||||
val names = names()
|
||||
val titles = titles()
|
||||
return listOf(names?.singular, names?.plural, titles?.singular, titles?.plural, name(), title())
|
||||
}
|
||||
|
||||
/** The DESCRIPTION role of [forEachSearchableListField]: `description`, then `comments`. */
|
||||
fun TagArray.searchableListDescriptions(): List<String?> = listOf(description(), comments())
|
||||
|
||||
/** The write-path join of [forEachSearchableListField]: one field per line. */
|
||||
fun TagArray.searchableListContent() =
|
||||
buildString {
|
||||
|
||||
+18
-1
@@ -29,6 +29,9 @@ import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
|
||||
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
|
||||
import com.vitorpamplona.quartz.experimental.birdstar.BirdDetectionEvent
|
||||
import com.vitorpamplona.quartz.experimental.birdstar.BirdexEvent
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.DecentralizedListEvent
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.searchableListDescriptions
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.searchableListTitles
|
||||
import com.vitorpamplona.quartz.experimental.edits.TextNoteModificationEvent
|
||||
import com.vitorpamplona.quartz.experimental.fitness.workout.ExerciseTemplateEvent
|
||||
import com.vitorpamplona.quartz.experimental.fitness.workout.WorkoutRecordEvent
|
||||
@@ -380,8 +383,11 @@ object SearchFieldExtractor {
|
||||
tiers(event, event.title(), event.description(), null)
|
||||
}
|
||||
|
||||
// kind 30063 -- the body is a NIP-82 release's notes, and nothing for a
|
||||
// NIP-51 set (its content may be encrypted private items); the event
|
||||
// owns that guard, so both search paths apply the same one.
|
||||
is ReleaseArtifactSetEvent -> {
|
||||
tiers(event, event.title(), event.description(), null)
|
||||
tiers(event, event.title(), event.description(), event.searchableReleaseNotes())
|
||||
}
|
||||
|
||||
is AppCurationSetEvent -> {
|
||||
@@ -617,6 +623,17 @@ object SearchFieldExtractor {
|
||||
tiers(event, null, null, event.content)
|
||||
}
|
||||
|
||||
// kinds 9998/39998/9999/39999 -- a list's or item's names and titles are
|
||||
// what it is called, its description and comments what it is about. The
|
||||
// `t` values indexableContent() appends are the funnel's hashtag role
|
||||
// already, so -- as for 1111/1311/30382 -- they are not passed again, and
|
||||
// content is not part of the spec. One branch for all four: an item may
|
||||
// carry header tags (the spec's nonstandard method), and the tag helpers
|
||||
// read whichever are present.
|
||||
is DecentralizedListEvent -> {
|
||||
tiers(event, event.tags.searchableListTitles(), event.tags.searchableListDescriptions(), null)
|
||||
}
|
||||
|
||||
// kind 1 LAST among the explicit branches, defensively: a future
|
||||
// kind extending the text-note base must hit its own branch first.
|
||||
is TextNoteEvent -> {
|
||||
|
||||
+8
-4
@@ -81,10 +81,14 @@ class ReleaseArtifactSetEvent(
|
||||
visitor.visit(searchableReleaseNotes())
|
||||
}
|
||||
|
||||
// Only NIP-82 releases carry release notes in `content`. A NIP-51 set may keep
|
||||
// encrypted private items there, which must never reach the index. The blank
|
||||
// check runs first so empty sets skip the two tag scans on every search.
|
||||
private fun searchableReleaseNotes() = if (content.isNotBlank() && isNip82SoftwareRelease()) content else null
|
||||
/**
|
||||
* The release notes when they are safe to index, else null. Only NIP-82 releases carry
|
||||
* release notes in `content`; a NIP-51 set may keep encrypted private items there, which
|
||||
* must never reach the index. The blank check runs first so empty sets skip the two tag
|
||||
* scans on every search. `SearchFieldExtractor` reads this too, so both search paths
|
||||
* apply the same guard.
|
||||
*/
|
||||
fun searchableReleaseNotes() = if (content.isNotBlank() && isNip82SoftwareRelease()) content else null
|
||||
|
||||
override fun eventHints() = tags.mapNotNull(EventBookmark::parseAsHint)
|
||||
|
||||
|
||||
+7
-3
@@ -59,11 +59,15 @@ class TextTrackEvent(
|
||||
AddressHintProvider,
|
||||
SearchableEvent {
|
||||
// The cue text is the only searchable thing here: the `d` tag is a slug and the rest is
|
||||
// plumbing. Indexing it makes a video findable by what is said in it.
|
||||
override fun indexableContent() = content
|
||||
// plumbing. Indexing it makes a video findable by what is said in it — the words only,
|
||||
// not the timings, cue settings and markup around them (see WebVttText). Content with no
|
||||
// cue at all is not a caption file and is indexed as written.
|
||||
override fun indexableContent() = if (WebVttText.hasCues(content)) WebVttText.cueText(content) else content
|
||||
|
||||
// The read path: the same lines cueText() joins, one visit per line so a hit early in the
|
||||
// track stops the walk before the rest is cleaned.
|
||||
override fun forEachIndexableField(visitor: IndexableFieldVisitor) {
|
||||
visitor.visit(content)
|
||||
if (WebVttText.hasCues(content)) WebVttText.forEachCueLine(content, visitor) else visitor.visit(content)
|
||||
}
|
||||
|
||||
override fun addressHints() = tags.mapNotNull(ATag::parseAsHint)
|
||||
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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.quartz.nip71Video.textTrack
|
||||
|
||||
import com.vitorpamplona.quartz.nip50Search.IndexableFieldVisitor
|
||||
|
||||
/**
|
||||
* The words a WebVTT document says: every cue's payload lines with their markup removed, and
|
||||
* nothing else.
|
||||
*
|
||||
* Search is the reason this exists. A text track's `content` is the whole document, so indexing
|
||||
* it raw puts `WEBVTT`, every `00:01:02.500 --> 00:01:04.000` timing line, cue settings
|
||||
* (`align:start`), cue ids, `NOTE` and `STYLE` blocks, and inline tags (`<v Roger>`, `<i>`,
|
||||
* `<00:00:01.000>`) into the index beside the dialogue. A query for "00" or "align" then
|
||||
* matches every caption ever published, and the terms that matter are diluted by markup.
|
||||
*
|
||||
* ## What counts as a cue line
|
||||
*
|
||||
* One pass over the lines, no model built. A line containing `-->` opens a cue (it is the
|
||||
* timing line; the optional identifier line before it is skipped because nothing is open yet),
|
||||
* and every non-blank line after it until the next blank line is payload. Everything outside a
|
||||
* cue — the `WEBVTT` header, `NOTE`, `STYLE`, `REGION` — is skipped by the same rule, since none
|
||||
* of it may contain `-->`. SRT happens to fit the same shape (a numeric id, a timing line, the
|
||||
* text), so a publisher that wraps SRT instead of WebVTT is read correctly too.
|
||||
*
|
||||
* A document with no timing line at all is not a caption file, so it is indexed as written
|
||||
* rather than discarded: [hasCues] is the switch, and callers pass such content through
|
||||
* unchanged.
|
||||
*
|
||||
* ## Markup
|
||||
*
|
||||
* Inline tags are removed, not their contents: `<i>really</i>` is `really`. Voice spans lose the
|
||||
* speaker name with the tag (`<v Roger>Hello` is `Hello`): the name is an annotation, not
|
||||
* something said. The HTML character references WebVTT allows are decoded — the named ones the
|
||||
* spec lists, plus numeric ones — so `Tom & Jerry` is indexed as `Tom & Jerry`. An unknown
|
||||
* reference is kept as written.
|
||||
*/
|
||||
object WebVttText {
|
||||
private const val TIMING_ARROW = "-->"
|
||||
|
||||
/** Whether [document] has at least one cue. Without one it is not a caption file. */
|
||||
fun hasCues(document: String) = document.contains(TIMING_ARROW)
|
||||
|
||||
/**
|
||||
* The cue text of [document], one payload line per line. Callers should check [hasCues]
|
||||
* first; a document without cues yields an empty string here.
|
||||
*/
|
||||
fun cueText(document: String): String {
|
||||
val out = StringBuilder(document.length)
|
||||
forEachCueLine(document) { line ->
|
||||
if (out.isNotEmpty()) out.append('\n')
|
||||
out.append(line)
|
||||
true
|
||||
}
|
||||
return out.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Hands each cleaned, non-empty payload line of [document] to [visitor] in order. Joining
|
||||
* them with `"\n"` gives exactly [cueText]. Returns false when the visitor stopped the walk.
|
||||
*
|
||||
* Lines without markup are passed as substrings; only a line carrying a tag or a character
|
||||
* reference is rebuilt.
|
||||
*/
|
||||
fun forEachCueLine(
|
||||
document: String,
|
||||
visitor: IndexableFieldVisitor,
|
||||
): Boolean {
|
||||
var inCue = false
|
||||
var start = 0
|
||||
val length = document.length
|
||||
while (start <= length) {
|
||||
var end = start
|
||||
while (end < length && document[end] != '\n' && document[end] != '\r') end++
|
||||
|
||||
if (isBlank(document, start, end)) {
|
||||
inCue = false
|
||||
} else if (!inCue) {
|
||||
// Header, NOTE / STYLE / REGION blocks and cue identifiers all end up here and
|
||||
// are skipped; only a timing line opens a cue.
|
||||
if (hasArrow(document, start, end)) inCue = true
|
||||
} else {
|
||||
val line = clean(document, start, end)
|
||||
if (line != null && !visitor.visit(line)) return false
|
||||
}
|
||||
|
||||
if (end >= length) break
|
||||
// A CRLF pair is one line break.
|
||||
start = if (document[end] == '\r' && end + 1 < length && document[end + 1] == '\n') end + 2 else end + 1
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** Bounded to the line: an unbounded indexOf would rescan up to the next cue from every skipped line. */
|
||||
private fun hasArrow(
|
||||
s: String,
|
||||
start: Int,
|
||||
end: Int,
|
||||
): Boolean {
|
||||
for (i in start until end - 2) {
|
||||
if (s[i] == '-' && s[i + 1] == '-' && s[i + 2] == '>') return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isBlank(
|
||||
s: String,
|
||||
start: Int,
|
||||
end: Int,
|
||||
): Boolean {
|
||||
for (i in start until end) if (!s[i].isWhitespace()) return false
|
||||
return true
|
||||
}
|
||||
|
||||
/** The payload line in `[start, end)` without tags, references decoded and trimmed; null when nothing is left. */
|
||||
private fun clean(
|
||||
s: String,
|
||||
start: Int,
|
||||
end: Int,
|
||||
): String? {
|
||||
var markup = false
|
||||
for (i in start until end) {
|
||||
val c = s[i]
|
||||
if (c == '<' || c == '&') {
|
||||
markup = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!markup) return s.substring(start, end).trim().ifEmpty { null }
|
||||
|
||||
val out = StringBuilder(end - start)
|
||||
var i = start
|
||||
while (i < end) {
|
||||
val c = s[i]
|
||||
when (c) {
|
||||
'<' -> {
|
||||
val close = s.indexOf('>', i + 1)
|
||||
// An unterminated tag runs to the end of the line, as the WebVTT parser reads it.
|
||||
i = if (close < 0 || close >= end) end else close + 1
|
||||
}
|
||||
|
||||
'&' -> {
|
||||
val semi = s.indexOf(';', i + 1)
|
||||
val decoded = if (semi in (i + 1) until end) decodeReference(s, i + 1, semi) else null
|
||||
if (decoded == null) {
|
||||
out.append(c)
|
||||
i++
|
||||
} else {
|
||||
appendCodePoint(out, decoded)
|
||||
i = semi + 1
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
out.append(c)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.toString().trim().ifEmpty { null }
|
||||
}
|
||||
|
||||
/** The code point named by the reference body in `[start, end)` (between `&` and `;`), or null. */
|
||||
private fun decodeReference(
|
||||
s: String,
|
||||
start: Int,
|
||||
end: Int,
|
||||
): Int? {
|
||||
if (end - start > 10) return null
|
||||
if (s[start] == '#') {
|
||||
val hex = start + 1 < end && (s[start + 1] == 'x' || s[start + 1] == 'X')
|
||||
val digits = s.substring(if (hex) start + 2 else start + 1, end)
|
||||
val code = digits.toIntOrNull(if (hex) 16 else 10) ?: return null
|
||||
return if (code in 1..0x10FFFF && code !in 0xD800..0xDFFF) code else null
|
||||
}
|
||||
return when (s.substring(start, end)) {
|
||||
"amp" -> '&'.code
|
||||
"lt" -> '<'.code
|
||||
"gt" -> '>'.code
|
||||
"quot" -> '"'.code
|
||||
"apos" -> '\''.code
|
||||
"nbsp" -> 0x00A0
|
||||
"lrm" -> 0x200E
|
||||
"rlm" -> 0x200F
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun appendCodePoint(
|
||||
out: StringBuilder,
|
||||
code: Int,
|
||||
) {
|
||||
if (code <= 0xFFFF) {
|
||||
out.append(code.toChar())
|
||||
} else {
|
||||
val v = code - 0x10000
|
||||
out.append((0xD800 + (v shr 10)).toChar())
|
||||
out.append((0xDC00 + (v and 0x3FF)).toChar())
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -23,6 +23,8 @@ package com.vitorpamplona.quartz.nip50Search
|
||||
import com.vitorpamplona.quartz.buzz.agentProfiles.AgentProfileEvent
|
||||
import com.vitorpamplona.quartz.experimental.birdstar.BirdDetectionEvent
|
||||
import com.vitorpamplona.quartz.experimental.birdstar.BirdexEvent
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.header.ListHeaderEvent
|
||||
import com.vitorpamplona.quartz.experimental.decentralizedLists.item.AddressableListItemEvent
|
||||
import com.vitorpamplona.quartz.experimental.nip95.header.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.quartz.experimental.ps1saves.Ps1SaveEvent
|
||||
import com.vitorpamplona.quartz.experimental.trustedLists.users.UserTrustedListEvent
|
||||
@@ -38,9 +40,11 @@ import com.vitorpamplona.quartz.nip29RelayGroups.moderation.GroupEditMetadataEve
|
||||
import com.vitorpamplona.quartz.nip32Labeling.LabelEvent
|
||||
import com.vitorpamplona.quartz.nip34Git.repository.GitRepositoryEvent
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.releaseArtifactSet.ReleaseArtifactSetEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.meetingSpaces.MeetingSpaceEvent
|
||||
import com.vitorpamplona.quartz.nip5aStaticWebsites.NamedSiteEvent
|
||||
import com.vitorpamplona.quartz.nip69P2pOrderEvents.P2POrderEvent
|
||||
import com.vitorpamplona.quartz.nip71Video.textTrack.TextTrackEvent
|
||||
import com.vitorpamplona.quartz.nip85TrustedAssertions.users.UserAssertionEvent
|
||||
import com.vitorpamplona.quartz.nip88Polls.poll.PollEvent
|
||||
import com.vitorpamplona.quartz.nip89AppHandlers.definition.AppDefinitionEvent
|
||||
@@ -412,6 +416,73 @@ class SearchFieldExtractorTest {
|
||||
assertEquals(IndexableFields.Tiered(secondary = listOf("spam"), text = "obvious bot"), fields)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nip82ReleaseNotesAreTheBodyOfARelease() {
|
||||
// indexableContent() already carried the notes; the branch used to drop them, so an
|
||||
// engine reading this extractor could not find a release by what changed in it.
|
||||
val tags = arrayOf(arrayOf("d", "com.example.app@1.2.0"), arrayOf("i", "com.example.app"), arrayOf("version", "1.2.0"), arrayOf("title", "Example 1.2"))
|
||||
val fields = SearchFieldExtractor.extract(ReleaseArtifactSetEvent("2e".repeat(32), alice, 1L, tags, "fixes the offline sync crash", ""))
|
||||
assertEquals(IndexableFields.Tiered(primary = listOf("Example 1.2"), text = "fixes the offline sync crash"), fields)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nip51ReleaseSetContentIsNeverTheBody() {
|
||||
// A NIP-51 set (no `i` + `version`) may keep encrypted private items in content.
|
||||
val tags = arrayOf(arrayOf("d", "release"), arrayOf("title", "Example"), arrayOf("description", "all builds"))
|
||||
val fields = SearchFieldExtractor.extract(ReleaseArtifactSetEvent("2f".repeat(32), alice, 1L, tags, "AgJ0b3BzZWNyZXQ=", ""))
|
||||
assertEquals(IndexableFields.Tiered(primary = listOf("Example"), secondary = listOf("all builds")), fields)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun decentralizedListHeadersSplitWhatTheyAreCalledFromWhatTheyAreAbout() {
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("names", "podcast", "podcasts"),
|
||||
arrayOf("titles", "Podcast", "Podcasts"),
|
||||
arrayOf("description", "shows worth a listen"),
|
||||
arrayOf("t", "audio"),
|
||||
)
|
||||
val fields = SearchFieldExtractor.extract(ListHeaderEvent("3a".repeat(32), alice, 1L, tags, "", ""))
|
||||
assertEquals(
|
||||
IndexableFields.Tiered(
|
||||
primary = listOf("podcast", "podcasts", "Podcast", "Podcasts"),
|
||||
secondary = listOf("shows worth a listen"),
|
||||
hashtags = listOf("audio"),
|
||||
),
|
||||
fields,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun decentralizedListItemHashtagsAreNotIndexedTwice() {
|
||||
// indexableContent() appends the `t` values; the funnel already carries them as
|
||||
// hashtags, so the branch leaves them out of every tier (the 1111 reasoning).
|
||||
val tags =
|
||||
arrayOf(
|
||||
arrayOf("z", "podcasts"),
|
||||
arrayOf("title", "Bitcoin Audible"),
|
||||
arrayOf("description", "long reads, read aloud"),
|
||||
arrayOf("comments", "start with the classics"),
|
||||
arrayOf("t", "bitcoin"),
|
||||
)
|
||||
val fields = SearchFieldExtractor.extract(AddressableListItemEvent("3b".repeat(32), alice, 1L, tags + arrayOf(arrayOf("d", "ba")), "", ""))
|
||||
assertEquals(
|
||||
IndexableFields.Tiered(
|
||||
primary = listOf("Bitcoin Audible"),
|
||||
secondary = listOf("long reads, read aloud", "start with the classics"),
|
||||
hashtags = listOf("bitcoin"),
|
||||
),
|
||||
fields,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun textTracksIndexWhatIsSaidNotTheTimings() {
|
||||
val vtt = "WEBVTT\n\n1\n00:00:00.000 --> 00:00:02.000 align:start\n<v Roger>Hello nostr\n"
|
||||
val fields = SearchFieldExtractor.extract(TextTrackEvent("3c".repeat(32), alice, 1L, arrayOf(arrayOf("d", "subtitles:v1")), vtt, ""))
|
||||
assertEquals(IndexableFields.Tiered(text = "Hello nostr"), fields)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun commentHashtagsAreNotIndexedTwice() {
|
||||
// indexableContent() concatenates the `t` tags INTO the body for kind
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.quartz.nip71Video.textTrack
|
||||
|
||||
import com.vitorpamplona.quartz.nip50Search.IndexableFieldVisitor
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class WebVttTextTest {
|
||||
private val document =
|
||||
"""
|
||||
WEBVTT - the whole header line is skipped
|
||||
Kind: captions
|
||||
|
||||
STYLE
|
||||
::cue { color: yellow }
|
||||
|
||||
NOTE this block is a comment
|
||||
and so is this line
|
||||
|
||||
intro
|
||||
00:00:00.000 --> 00:00:02.000 align:start position:10%
|
||||
<v Roger Bingham>We are in New York City
|
||||
|
||||
00:00:02.500 --> 00:00:04.000
|
||||
<i>Really</i>? Tom & Jerry!
|
||||
<c.loud>on <00:00:03.000>two lines</c>
|
||||
|
||||
00:00:05.000 --> 00:00:06.000
|
||||
<b></b>
|
||||
""".trimIndent()
|
||||
|
||||
@Test
|
||||
fun keepsOnlyTheWordsOfEachCue() {
|
||||
assertEquals("We are in New York City\nReally? Tom & Jerry!\non two lines", WebVttText.cueText(document))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theVisitedLinesRejoinToTheCueText() {
|
||||
val lines = mutableListOf<String>()
|
||||
assertTrue(WebVttText.forEachCueLine(document, IndexableFieldVisitor { lines.add(it!!) }))
|
||||
assertEquals(WebVttText.cueText(document), lines.joinToString("\n"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aVisitorCanStopTheWalk() {
|
||||
val lines = mutableListOf<String>()
|
||||
assertFalse(
|
||||
WebVttText.forEachCueLine(document, IndexableFieldVisitor { lines.add(it!!) && false }),
|
||||
)
|
||||
assertEquals(listOf("We are in New York City"), lines)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun crlfAndSrtAreReadTheSameWay() {
|
||||
val srt = "1\r\n00:00:01,000 --> 00:00:02,000\r\nHello\r\n\r\n2\r\n00:00:03,000 --> 00:00:04,000\r\nworld\r\n"
|
||||
assertEquals("Hello\nworld", WebVttText.cueText(srt))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun unknownReferencesAndStrayAmpersandsStayAsWritten() {
|
||||
val vtt = "WEBVTT\n\n00:00.000 --> 00:01.000\nfish & chips &unknown; &#xZZ;"
|
||||
assertEquals("fish & chips &unknown; &#xZZ;", WebVttText.cueText(vtt))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun anUnterminatedTagRunsToTheEndOfTheLine() {
|
||||
val vtt = "WEBVTT\n\n00:00.000 --> 00:01.000\nkept <i unterminated\nnext line"
|
||||
assertEquals("kept\nnext line", WebVttText.cueText(vtt))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plainTextIsNotACaptionFile() {
|
||||
assertFalse(WebVttText.hasCues("just a description of the track"))
|
||||
assertTrue(WebVttText.hasCues(document))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theEventIndexesCueTextAndPassesPlainContentThrough() {
|
||||
val tags = arrayOf(arrayOf("d", "subtitles:v1"))
|
||||
val track = TextTrackEvent("1".repeat(64), "a1".repeat(32), 1L, tags, document, "")
|
||||
assertEquals(WebVttText.cueText(document), track.indexableContent())
|
||||
|
||||
val visited = mutableListOf<String?>()
|
||||
track.forEachIndexableField { visited.add(it) }
|
||||
assertEquals(track.indexableContent(), visited.joinToString(track.indexableSeparator()))
|
||||
|
||||
val plain = TextTrackEvent("2".repeat(64), "a1".repeat(32), 1L, tags, "no cues here", "")
|
||||
assertEquals("no cues here", plain.indexableContent())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user