Merge branch 'vitorpamplona:main' into followset-improvements

This commit is contained in:
KotlinGeekDev
2025-10-03 14:39:45 +00:00
committed by GitHub
30 changed files with 335 additions and 73 deletions
+6
View File
@@ -151,6 +151,12 @@ android {
signingConfig = signingConfigs.debug
}
}
// TODO: remove this when lightcompressor uses one MP4 parser only
packaging {
resources {
resources.pickFirsts.add('builddef.lst')
}
}
flavorDimensions = ["channel"]
@@ -118,7 +118,6 @@ import com.vitorpamplona.quartz.experimental.profileGallery.mimeType
import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.core.value
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
import com.vitorpamplona.quartz.nip01Core.hints.AddressHintProvider
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.service.relayClient.reqCommand.user
import android.annotation.SuppressLint
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.model.Account
@@ -45,6 +45,7 @@ class MediaCompressor {
contentType: String?,
mediaQuality: CompressorQuality,
applicationContext: Context,
useH265: Boolean = false,
): MediaCompressorResult {
// Skip compression if user selected uncompressed
if (mediaQuality == CompressorQuality.UNCOMPRESSED) {
@@ -57,7 +58,7 @@ class MediaCompressor {
// branch into compression based on content type
return when {
contentType?.startsWith("video", ignoreCase = true) == true -> {
VideoCompressionHelper.compressVideo(uri, contentType, applicationContext, mediaQuality)
VideoCompressionHelper.compressVideo(uri, contentType, applicationContext, mediaQuality, useH265)
}
contentType?.startsWith("image", ignoreCase = true) == true &&
!contentType.contains("gif") &&
@@ -46,6 +46,8 @@ class MultiOrchestrator(
fun first() = list.first()
fun hasVideo() = list.any { it.media.mimeType?.startsWith("video", ignoreCase = true) == true }
suspend fun upload(
alt: String?,
contentWarningReason: String?,
@@ -53,6 +55,7 @@ class MultiOrchestrator(
server: ServerName,
account: Account,
context: Context,
useH265: Boolean = false,
): Result {
coroutineScope {
val jobs =
@@ -67,6 +70,7 @@ class MultiOrchestrator(
server,
account,
context,
useH265,
)
}
}
@@ -85,6 +89,7 @@ class MultiOrchestrator(
server: ServerName,
account: Account,
context: Context,
useH265: Boolean = false,
): Result {
coroutineScope {
val jobs =
@@ -100,6 +105,7 @@ class MultiOrchestrator(
server,
account,
context,
useH265,
)
}
}
@@ -288,9 +288,10 @@ class UploadOrchestrator {
mimeType: String?,
compressionQuality: CompressorQuality,
context: Context,
useH265: Boolean = false,
) = if (compressionQuality != CompressorQuality.UNCOMPRESSED) {
updateState(0.02, UploadingState.Compressing)
MediaCompressor().compress(uri, mimeType, compressionQuality, context.applicationContext)
MediaCompressor().compress(uri, mimeType, compressionQuality, context.applicationContext, useH265)
} else {
MediaCompressorResult(uri, mimeType, null)
}
@@ -304,8 +305,9 @@ class UploadOrchestrator {
server: ServerName,
account: Account,
context: Context,
useH265: Boolean = false,
): UploadingFinalState {
val compressed = compressIfNeeded(uri, mimeType, compressionQuality, context)
val compressed = compressIfNeeded(uri, mimeType, compressionQuality, context, useH265)
return when (server.type) {
ServerType.NIP95 -> uploadNIP95(compressed.uri, compressed.contentType, null, null, context)
@@ -324,8 +326,9 @@ class UploadOrchestrator {
server: ServerName,
account: Account,
context: Context,
useH265: Boolean = false,
): UploadingFinalState {
val compressed = compressIfNeeded(uri, mimeType, compressionQuality, context)
val compressed = compressIfNeeded(uri, mimeType, compressionQuality, context, useH265)
val encrypted = EncryptFiles().encryptFile(context, compressed.uri, encrypt)
return when (server.type) {
@@ -29,6 +29,7 @@ import android.text.format.Formatter.formatFileSize
import android.util.Log
import android.widget.Toast
import com.abedelazizshe.lightcompressorlibrary.CompressionListener
import com.abedelazizshe.lightcompressorlibrary.VideoCodec
import com.abedelazizshe.lightcompressorlibrary.VideoCompressor
import com.abedelazizshe.lightcompressorlibrary.config.AppSpecificStorageConfiguration
import com.abedelazizshe.lightcompressorlibrary.config.Configuration
@@ -88,11 +89,18 @@ data class CompressionRule(
val bitrateMbps: Float,
val description: String,
) {
fun getBitrateBps(framerate: Float): Int {
// Apply 1.5x multiplier for 60fps+ videos
val multiplier = if (framerate >= 60f) 1.5f else 1.0f
fun getBitrateBps(
framerate: Float,
useH265: Boolean,
): Int {
// Apply 1.3x multiplier for 60fps+ videos, 0.7x multiplier for H265
val framerateMultiplier = if (framerate >= 60f) 1.3f else 1.0f
val codecMultiplier = if (useH265) 0.7f else 1.0f
val finalMultiplier = framerateMultiplier * codecMultiplier
return (bitrateMbps * multiplier * MBPS_TO_BPS_MULTIPLIER).toInt()
Log.d("VideoCompressionHelper", "framerate: $framerate, useH265: $useH265, Bitrate multiplier: $finalMultiplier")
return (bitrateMbps * finalMultiplier * MBPS_TO_BPS_MULTIPLIER).toInt()
}
}
@@ -141,6 +149,7 @@ object VideoCompressionHelper {
contentType: String?,
applicationContext: Context,
mediaQuality: CompressorQuality,
useH265: Boolean,
timeoutMs: Long = 60_000L, // configurable, default 60s
): MediaCompressorResult {
val videoInfo = getVideoInfo(uri, applicationContext)
@@ -152,8 +161,8 @@ object VideoCompressionHelper {
.getValue(mediaQuality)
.getValue(info.resolution.getStandard())
val bitrateBps = rule.getBitrateBps(info.framerate)
Log.d(LOG_TAG, "Bitrate: ${bitrateBps}bps for ${info.resolution.getStandard()} quality=$mediaQuality framerate=${info.framerate}fps.")
val bitrateBps = rule.getBitrateBps(info.framerate, useH265)
Log.d(LOG_TAG, "Bitrate: ${bitrateBps}bps for ${info.resolution.getStandard()} quality=$mediaQuality framerate=${info.framerate}fps useH265=$useH265.")
Log.d(
LOG_TAG,
@@ -186,6 +195,7 @@ object VideoCompressionHelper {
resizer = resizer,
videoNames = listOf(UUID.randomUUID().toString()),
isMinBitrateCheckEnabled = false,
videoCodec = if (useH265) VideoCodec.H265 else VideoCodec.H264,
),
listener =
object : CompressionListener {
@@ -54,7 +54,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -255,13 +254,13 @@ fun EditPostView(
postViewModel.multiOrchestrator?.let {
Row(
verticalAlignment = Alignment.CenterVertically,
verticalAlignment = CenterVertically,
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
) {
ImageVideoDescription(
it,
accountViewModel.account.settings.defaultFileServer,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
onAdd = { alt, server, sensitiveContent, mediaQuality, _ ->
postViewModel.upload(alt, sensitiveContent, mediaQuality, false, server, accountViewModel.toastManager::toast, context)
if (server.type != ServerType.NIP95) {
accountViewModel.account.settings.changeDefaultFileServer(server)
@@ -279,7 +278,7 @@ fun EditPostView(
if (lud16 != null && postViewModel.wantsInvoice) {
Row(
verticalAlignment = Alignment.CenterVertically,
verticalAlignment = CenterVertically,
modifier = Modifier.padding(vertical = Size5dp, horizontal = Size10dp),
) {
InvoiceRequest(
@@ -87,6 +87,9 @@ open class EditPostViewModel : ViewModel() {
// Images and Videos
var multiOrchestrator by mutableStateOf<MultiOrchestrator?>(null)
// Codec selection: false = H264, true = H265
var useH265Codec by mutableStateOf(false)
// Invoices
var canAddInvoice by mutableStateOf(false)
var wantsInvoice by mutableStateOf(false)
@@ -201,6 +204,7 @@ open class EditPostViewModel : ViewModel() {
server,
myAccount,
context,
useH265Codec,
)
if (results.allGood) {
@@ -62,6 +62,9 @@ open class NewMediaModel : ViewModel() {
// 0 = Low, 1 = Medium, 2 = High, 3=UNCOMPRESSED
var mediaQualitySlider by mutableIntStateOf(1)
// Codec selection: false = H264, true = H265
var useH265Codec by mutableStateOf(false)
open fun load(
account: Account,
uris: ImmutableList<SelectedMedia>,
@@ -111,6 +114,7 @@ open class NewMediaModel : ViewModel() {
serverToUse,
myAccount,
context,
useH265Codec,
)
if (results.allGood) {
@@ -261,4 +261,18 @@ fun ImageVideoPost(
steps = 2,
)
}
// Only show H.265 codec option if there are videos in the upload
if (postViewModel.multiOrchestrator?.hasVideo() == true) {
SettingSwitchItem(
title = R.string.video_codec_h265_label,
description = R.string.video_codec_h265_description,
modifier =
Modifier
.fillMaxWidth()
.padding(top = 8.dp),
checked = postViewModel.useH265Codec,
onCheckedChange = { postViewModel.useH265Codec = it },
)
}
}
@@ -75,7 +75,7 @@ fun SettingSwitchItem(
text = stringRes(id = description),
style = MaterialTheme.typography.bodySmall,
color = Color.Gray,
maxLines = 2,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
)
}
@@ -78,7 +78,7 @@ import kotlinx.collections.immutable.toImmutableList
fun ImageVideoDescription(
uris: MultiOrchestrator,
defaultServer: ServerName,
onAdd: (String, ServerName, Boolean, Int) -> Unit,
onAdd: (String, ServerName, Boolean, Int, Boolean) -> Unit,
onDelete: (SelectedMediaProcessing) -> Unit,
onCancel: () -> Unit,
accountViewModel: AccountViewModel,
@@ -91,7 +91,7 @@ fun ImageVideoDescription(
uris: MultiOrchestrator,
defaultServer: ServerName,
includeNIP95: Boolean,
onAdd: (String, ServerName, Boolean, Int) -> Unit,
onAdd: (String, ServerName, Boolean, Int, Boolean) -> Unit,
onDelete: (SelectedMediaProcessing) -> Unit,
onCancel: () -> Unit,
accountViewModel: AccountViewModel,
@@ -128,6 +128,9 @@ fun ImageVideoDescription(
// 0 = Low, 1 = Medium, 2 = High, 3=UNCOMPRESSED
var mediaQualitySlider by remember { mutableIntStateOf(1) }
// Codec selection: false = H264, true = H265
var useH265Codec by remember { mutableStateOf(false) }
Column(
modifier =
Modifier
@@ -294,32 +297,40 @@ fun ImageVideoDescription(
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box(modifier = Modifier.fillMaxWidth()) {
Text(
text =
when (mediaQualitySlider) {
0 -> stringRes(R.string.media_compression_quality_low)
1 -> stringRes(R.string.media_compression_quality_medium)
2 -> stringRes(R.string.media_compression_quality_high)
3 -> stringRes(R.string.media_compression_quality_uncompressed)
else -> stringRes(R.string.media_compression_quality_medium)
},
modifier = Modifier.align(Alignment.Center),
)
}
Slider(
value = mediaQualitySlider.toFloat(),
onValueChange = { mediaQualitySlider = it.toInt() },
valueRange = 0f..3f,
steps = 2,
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Box(modifier = Modifier.fillMaxWidth()) {
Text(
text =
when (mediaQualitySlider) {
0 -> stringRes(R.string.media_compression_quality_low)
1 -> stringRes(R.string.media_compression_quality_medium)
2 -> stringRes(R.string.media_compression_quality_high)
3 -> stringRes(R.string.media_compression_quality_uncompressed)
else -> stringRes(R.string.media_compression_quality_medium)
},
modifier = Modifier.align(Alignment.Center),
)
}
Slider(
value = mediaQualitySlider.toFloat(),
onValueChange = { mediaQualitySlider = it.toInt() },
valueRange = 0f..3f,
steps = 2,
)
}
if (uris.first().media.isVideo() == true) {
SettingSwitchItem(
title = R.string.video_codec_h265_label,
description = R.string.video_codec_h265_description,
modifier =
Modifier
.fillMaxWidth()
.padding(top = 8.dp),
checked = useH265Codec,
onCheckedChange = { useH265Codec = it },
)
}
Button(
@@ -327,7 +338,7 @@ fun ImageVideoDescription(
Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
onClick = { onAdd(message, selectedServer, sensitiveContent, mediaQualitySlider) },
onClick = { onAdd(message, selectedServer, sensitiveContent, mediaQualitySlider, useH265Codec) },
shape = QuoteBorder,
colors =
ButtonDefaults.buttonColors(
@@ -285,7 +285,7 @@ private fun GenericCommentPostBody(
ImageVideoDescription(
it,
accountViewModel.account.settings.defaultFileServer,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
onAdd = { alt, server, sensitiveContent, mediaQuality, _ ->
postViewModel.upload(alt, if (sensitiveContent) "" else null, mediaQuality, server, accountViewModel.toastManager::toast, context)
if (server.type != ServerType.NIP95) {
accountViewModel.account.settings.changeDefaultFileServer(server)
@@ -278,7 +278,7 @@ fun GroupDMScreenContent(
ImageVideoDescription(
selectedFiles,
accountViewModel.account.settings.defaultFileServer,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
onAdd = { alt, server, sensitiveContent, mediaQuality, _ ->
postViewModel.uploadAndHold(
accountViewModel.toastManager::toast,
context,
@@ -266,7 +266,7 @@ private fun NewProductBody(
uris = it,
defaultServer = accountViewModel.account.settings.defaultFileServer,
includeNIP95 = false,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
onAdd = { alt, server, sensitiveContent, mediaQuality, _ ->
postViewModel.upload(alt, if (sensitiveContent) "" else null, mediaQuality, server, accountViewModel.toastManager::toast, context)
if (server.type != ServerType.NIP95) {
accountViewModel.account.settings.changeDefaultFileServer(server)
@@ -326,8 +326,8 @@ private fun NewPostScreenBody(
ImageVideoDescription(
it,
accountViewModel.account.settings.defaultFileServer,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
postViewModel.upload(alt, if (sensitiveContent) "" else null, mediaQuality, server, accountViewModel.toastManager::toast, context)
onAdd = { alt, server, sensitiveContent, mediaQuality, useH265 ->
postViewModel.upload(alt, if (sensitiveContent) "" else null, mediaQuality, server, accountViewModel.toastManager::toast, context, useH265)
if (server.type != ServerType.NIP95) {
accountViewModel.account.settings.changeDefaultFileServer(server)
}
@@ -624,8 +624,9 @@ open class ShortNotePostViewModel :
server: ServerName,
onError: (title: String, message: String) -> Unit,
context: Context,
useH265: Boolean,
) = try {
uploadUnsafe(alt, contentWarningReason, mediaQuality, server, onError, context)
uploadUnsafe(alt, contentWarningReason, mediaQuality, server, onError, context, useH265)
} catch (_: SignerExceptions.ReadOnlyException) {
onError(
stringRes(context, R.string.read_only_user),
@@ -640,6 +641,7 @@ open class ShortNotePostViewModel :
server: ServerName,
onError: (title: String, message: String) -> Unit,
context: Context,
useH265: Boolean,
) {
viewModelScope.launch(Dispatchers.Default) {
val myMultiOrchestrator = multiOrchestrator ?: return@launch
@@ -654,6 +656,7 @@ open class ShortNotePostViewModel :
server,
account,
context,
useH265,
)
if (results.allGood) {
@@ -231,7 +231,7 @@ fun PublicMessageScreenContent(
ImageVideoDescription(
it,
accountViewModel.account.settings.defaultFileServer,
onAdd = { alt, server, sensitiveContent, mediaQuality ->
onAdd = { alt, server, sensitiveContent, mediaQuality, _ ->
postViewModel.upload(alt, if (sensitiveContent) "" else null, mediaQuality, server, accountViewModel.toastManager::toast, context)
if (server.type != ServerType.NIP95) {
accountViewModel.account.settings.changeDefaultFileServer(server)
@@ -952,4 +952,35 @@
<string name="guidelines">Pokyny</string>
<string name="moderators">Moderátoři</string>
<string name="open_dropdown_menu">Otevřít rozbalovací nabídku</string>
<string name="follow_sets">Sady sledování</string>
<string name="labeled_bookmarks">Označené záložky</string>
<string name="general_bookmarks">Obecné záložky</string>
<string name="follow_set_type_public">Veřejné</string>
<string name="follow_set_type_private">Soukromé</string>
<string name="follow_set_type_mixed">Smíšené</string>
<string name="follow_set_empty_feed_msg">Zdá se, že zatím nemáte žádné sady sledování.\nKlepněte níže pro obnovení nebo použijte tlačítko přidat k vytvoření nové.</string>
<string name="follow_set_add_author_from_note_action">Přidat autora do sady sledování</string>
<string name="follow_set_profile_actions_menu_description">Přidat nebo odebrat uživatele ze seznamů, nebo vytvořit nový seznam s tímto uživatelem.</string>
<string name="follow_set_type_description">Ikona pro seznam %1$s</string>
<string name="follow_set_presence_indicator">%1$s je v tomto seznamu</string>
<string name="follow_set_absence_indicator">%1$s není v tomto seznamu</string>
<string name="follow_set_man_dialog_title">Vaše sady sledování</string>
<string name="follow_set_empty_dialog_msg">Nebyly nalezeny žádné sady sledování, nebo žádné nemáte. Klepněte níže pro obnovení nebo použijte menu pro vytvoření nové.</string>
<string name="follow_set_error_dialog_msg">Došlo k problému při načítání: %1$s</string>
<string name="follow_set_creation_menu_title">Vytvořit nový seznam</string>
<string name="follow_set_creation_item_label">Vytvořit nový seznam %1$s s uživatelem</string>
<string name="follow_set_creation_item_description">Vytvoří %1$s sadu sledování a přidá do ní %2$s.</string>
<string name="follow_set_creation_dialog_title">Nový seznam %1$s</string>
<string name="follow_set_creation_name_label">Název sady</string>
<string name="follow_set_creation_desc_label">Popis sady (volitelné)</string>
<string name="follow_set_creation_action_btn_label">Vytvořit sadu</string>
<string name="follow_set_rename_btn_label">Přejmenovat sadu</string>
<string name="follow_set_rename_dialog_indicator_first_part">Přejmenováváte z </string>
<string name="follow_set_rename_dialog_indicator_second_part"> na..</string>
<string name="rename">Přejmenovat</string>
<string name="torrent_no_info">Událost nemá dostatek informací pro vytvoření magnet odkazu</string>
<string name="my_lists_and_sets">Moje seznamy/sady</string>
<string name="select_signer">Vybrat podepisovatele</string>
<string name="video_codec_h265_label">Použít kodek H.265/HEVC</string>
<string name="video_codec_h265_description">Lepší kvalita při menší velikosti souboru, ale ne všechna zařízení podporují přehrávání H.265.</string>
</resources>
@@ -992,4 +992,35 @@ anz der Bedingungen ist erforderlich</string>
<string name="guidelines">Richtlinien</string>
<string name="moderators">Moderatoren</string>
<string name="open_dropdown_menu">Dropdown-Menü öffnen</string>
<string name="follow_sets">Folge-Sets</string>
<string name="labeled_bookmarks">Markierte Lesezeichen</string>
<string name="general_bookmarks">Allgemeine Lesezeichen</string>
<string name="follow_set_type_public">Öffentlich</string>
<string name="follow_set_type_private">Privat</string>
<string name="follow_set_type_mixed">Gemischt</string>
<string name="follow_set_empty_feed_msg">Es scheint, dass du noch keine Folge-Sets hast.\nTippe unten zum Aktualisieren oder verwende die Plus-Taste, um ein neues zu erstellen.</string>
<string name="follow_set_add_author_from_note_action">Autor zum Folge-Set hinzufügen</string>
<string name="follow_set_profile_actions_menu_description">Benutzer zu Listen hinzufügen oder entfernen, oder eine neue Liste mit diesem Benutzer erstellen.</string>
<string name="follow_set_type_description">Symbol für %1$s-Liste</string>
<string name="follow_set_presence_indicator">%1$s ist in dieser Liste</string>
<string name="follow_set_absence_indicator">%1$s ist nicht in dieser Liste</string>
<string name="follow_set_man_dialog_title">Deine Folge-Sets</string>
<string name="follow_set_empty_dialog_msg">Keine Folge-Sets gefunden oder du hast keine. Tippe unten zum Aktualisieren oder verwende das Menü, um eines zu erstellen.</string>
<string name="follow_set_error_dialog_msg">Beim Abrufen ist ein Problem aufgetreten: %1$s</string>
<string name="follow_set_creation_menu_title">Neue Liste erstellen</string>
<string name="follow_set_creation_item_label">Neue %1$s-Liste mit Benutzer erstellen</string>
<string name="follow_set_creation_item_description">Erstellt ein %1$s-Folge-Set und fügt %2$s hinzu.</string>
<string name="follow_set_creation_dialog_title">Neue %1$s-Liste</string>
<string name="follow_set_creation_name_label">Set-Name</string>
<string name="follow_set_creation_desc_label">Set-Beschreibung (optional)</string>
<string name="follow_set_creation_action_btn_label">Set erstellen</string>
<string name="follow_set_rename_btn_label">Set umbenennen</string>
<string name="follow_set_rename_dialog_indicator_first_part">Du benennst um von </string>
<string name="follow_set_rename_dialog_indicator_second_part"> zu..</string>
<string name="rename">Umbenennen</string>
<string name="torrent_no_info">Das Ereignis enthält nicht genügend Informationen, um einen Magnetlink zu erstellen</string>
<string name="my_lists_and_sets">Meine Listen/Sets</string>
<string name="select_signer">Signierer auswählen</string>
<string name="video_codec_h265_label">H.265/HEVC-Codec verwenden</string>
<string name="video_codec_h265_description">Bessere Qualität bei kleinerer Dateigröße, aber nicht alle Geräte unterstützen die H.265-Wiedergabe.</string>
</resources>
@@ -1065,4 +1065,5 @@
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">क्या आप निकटकालिक क्रमदोष सूचनापत्र एक सीधे सन्देश में अमेथिस्ट को भेजना चाहते हैं। कोई व्यक्तिगत जानकारी बाँटी नहीं जाएगी</string>
<string name="crashreport_found_send">भेजें</string>
<string name="this_message_will_disappear_in_days">यह सन्देश %1$d दिनों में अदृश्य हो जाएगा</string>
<string name="select_signer">हस्ताक्षरकर्ता चुनें</string>
</resources>
@@ -112,6 +112,7 @@
<string name="post">Közzététel</string>
<string name="save">Mentés</string>
<string name="create">Létrehozás</string>
<string name="rename">Átnevezés</string>
<string name="cancel">Mégse</string>
<string name="failed_to_upload_the_image">Nem sikerült feltölteni a képet</string>
<string name="relay_address">Atjátszó címe</string>
@@ -140,12 +141,12 @@
<string name="ln_address">LN-cím</string>
<string name="ln_url_outdated">LN-webcím (elavult)</string>
<string name="save_to_gallery">Mentés a galériába</string>
<string name="image_saved_to_the_gallery">Kép elmentve a képgalériába</string>
<string name="image_saved_to_the_gallery">Kép mentve a képgalériába</string>
<string name="video_download_has_started_toast">A videó letöltése megkezdődött…</string>
<string name="media_download_has_started_toast">A média letöltése megkezdődött…</string>
<string name="failed_to_save_the_image">Nem sikerült menteni a képet</string>
<string name="video_saved_to_the_gallery">Videó elmentve a videógalériába</string>
<string name="failed_to_save_the_video">Nem sikerült elmenteni a videót</string>
<string name="video_saved_to_the_gallery">Videó mentve a videógalériába</string>
<string name="failed_to_save_the_video">Nem sikerült menteni a videót</string>
<string name="upload_image">Kép feltöltése</string>
<string name="take_a_picture">Kép készítése</string>
<string name="record_a_video">Videó rögzítése</string>
@@ -445,6 +446,33 @@
<string name="follow_list_aroundme">Közelben lévők bejegyzései</string>
<string name="follow_list_global">Globális</string>
<string name="follow_list_mute_list">Némítottak bejegyzései</string>
<string name="follow_sets">Követési gyüjtemények</string>
<string name="labeled_bookmarks">Címkézett könyvjelzők</string>
<string name="general_bookmarks">Általános könyvjelzők</string>
<string name="follow_set_type_public">Nyílvános</string>
<string name="follow_set_type_private">Privát</string>
<string name="follow_set_type_mixed">Kevert</string>
<string name="follow_set_empty_feed_msg"> Úgy tűnik, hogy még egyetlen gyüjteményt sem követ.
\nKoppintson a frissítéshez vagy érintse meg a hozzáadás gombot a gyüjtemény létrehozásához.
</string>
<string name="follow_set_add_author_from_note_action">Szerző hozzáadása a követési gyűjteményhez</string>
<string name="follow_set_profile_actions_menu_description">Felhasználó hozzáadása vagy eltávolítása a listákból, vagy új lista létrehozása ezzel a felhasználóval.</string>
<string name="follow_set_type_description">Ikon a(z) %1$s nevű listához</string>
<string name="follow_set_presence_indicator">"A(z) %1$s már a létezik a listában"</string>
<string name="follow_set_absence_indicator">"A(z) %1$s nincs a listában"</string>
<string name="follow_set_man_dialog_title">Saját követési gyüjtemények</string>
<string name="follow_set_empty_dialog_msg">Nem találhatók követési gyüjtemények, vagy nincs követési gyüjteménye. Érintse meg az alábbi gombot a frissítéshez vagy használja a menüt egy gyüjtemény létrehozásához.</string>
<string name="follow_set_error_dialog_msg">Probléma történt a következő lekérdezésekor: %1$s</string>
<string name="follow_set_creation_menu_title">Új lista létrehozása</string>
<string name="follow_set_creation_item_label">Új %1$s lista létrehozása felhasználóval</string>
<string name="follow_set_creation_item_description">%1$s követési gyüjtemény létrehozása, és hozzáadás a következhöz: %2$s.</string>
<string name="follow_set_creation_dialog_title">Új %1$s lista</string>
<string name="follow_set_creation_name_label">Név megadása</string>
<string name="follow_set_creation_desc_label">Leírás megadása (nem kötelező)</string>
<string name="follow_set_creation_action_btn_label">Gyüjtemény létrehozása</string>
<string name="follow_set_rename_btn_label">Gyüjtemény átnevezése</string>
<string name="follow_set_rename_dialog_indicator_first_part">Ön átnevezi a követési gyüjteményt erről: </string>
<string name="follow_set_rename_dialog_indicator_second_part"> erre:</string>
<string name="connect_through_your_orbot_setup_short">Alapértelmezett port: 9050</string>
<string name="connect_through_your_orbot_setup_markdown"> ## Kapcsolódás a TORon keresztül az Orbot segítségével
\n\n1. Telepítse az [Orbotot](https://play.google.com/store/apps/details?id=org.torproject.android)
@@ -1014,6 +1042,8 @@
<string name="torrent_download">Letöltés</string>
<string name="torrent_failure">Nem sikerült megnyitni a fájlt</string>
<string name="torrent_no_apps">A fájl megnyitásához és letöltéséhez nincsenek torrent-alkalmazások telepítve.</string>
<string name="torrent_no_info">Az esemény nem tartalmaz elegendő információt a mágneshivatkozás létrehozásához</string>
<string name="my_lists_and_sets">Saját lista/gyüjtemény</string>
<string name="select_list_to_filter">Lista kiválasztása a hírfolyam szűréséhez</string>
<string name="temporary_account">Kijelentkeztetés az eszköz zárolása esetén</string>
<string name="private_message">Privát üzenet</string>
@@ -1035,4 +1065,5 @@
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Szeretné elküldeni a legutóbbi összeomlási jelentést az Amethystnek egy közvetlen üzenetben? A személyes adatait nem osztja meg</string>
<string name="crashreport_found_send">Küldés</string>
<string name="this_message_will_disappear_in_days">Ez az üzenet %1$d nap múlva eltűnik</string>
<string name="select_signer">Aláíró kiválasztása</string>
</resources>
@@ -112,6 +112,7 @@
<string name="post">Wyślij</string>
<string name="save">Zapisz</string>
<string name="create">Utwórz</string>
<string name="rename">Zmień nazwę</string>
<string name="cancel">Anuluj</string>
<string name="failed_to_upload_the_image">Nie udało się przesłać obrazu</string>
<string name="relay_address">Adres transmitera</string>
@@ -442,6 +443,33 @@
<string name="follow_list_aroundme">W pobliżu</string>
<string name="follow_list_global">Wszystkie</string>
<string name="follow_list_mute_list">Zablokowane</string>
<string name="follow_sets">Zbiory obserwowanych</string>
<string name="labeled_bookmarks">Oznaczone zakładki</string>
<string name="general_bookmarks">Ogólne zakładki</string>
<string name="follow_set_type_public">Publiczna</string>
<string name="follow_set_type_private">Prywatna</string>
<string name="follow_set_type_mixed">Mieszana</string>
<string name="follow_set_empty_feed_msg"> Wygląda na to, że nie masz jeszcze żadnych zbiorów obserwowanych.
\nDotknij poniżej, aby odświeżyć, lub naciśnij przycisk Dodaj, aby utworzyć nowy.
</string>
<string name="follow_set_add_author_from_note_action">Dodaj autora do zbioru obserwowanych</string>
<string name="follow_set_profile_actions_menu_description">Dodaj lub usuń użytkownika z list, lub utwórz nową listę z tym użytkownikiem.</string>
<string name="follow_set_type_description">Ikona dla listy %1$s</string>
<string name="follow_set_presence_indicator">"%1$s jest obecny na liście"</string>
<string name="follow_set_absence_indicator">"%1$s nie jest na liście"</string>
<string name="follow_set_man_dialog_title">Twój zbiór obserwowanych</string>
<string name="follow_set_empty_dialog_msg">Nie znaleziono zbiorów obserwowanych lub nie masz żadnych zbiorów obserwowanych. Dotknij poniżej, aby odświeżyć lub użyj menu, aby go utworzyć.</string>
<string name="follow_set_error_dialog_msg">Podczas pobierania wystąpił błąd: %1$s</string>
<string name="follow_set_creation_menu_title">Utwórz nową listę</string>
<string name="follow_set_creation_item_label">\"Utwórz nową listę %1$s z użytkownikiem</string>
<string name="follow_set_creation_item_description">Tworzy zbiór obserwowanych %1$s i dodaje do niego %2$s.</string>
<string name="follow_set_creation_dialog_title">Nowa lista %1$s</string>
<string name="follow_set_creation_name_label">Nazwa zbioru</string>
<string name="follow_set_creation_desc_label">Opis zbioru (opcjonalnie)</string>
<string name="follow_set_creation_action_btn_label">Utwórz zbiór</string>
<string name="follow_set_rename_btn_label">Zmień nazwę zbioru</string>
<string name="follow_set_rename_dialog_indicator_first_part">Zmieniasz nazwę z </string>
<string name="follow_set_rename_dialog_indicator_second_part"> do..</string>
<string name="connect_through_your_orbot_setup_short">Domyślny port to 9050</string>
<string name="connect_through_your_orbot_setup_markdown"> ## Połącz przez Tor z Orbotem
\n\n1. Zainstaluj [Orbota](https://play.google. om/store/apps/details?id= org.torproject.android)
@@ -1011,6 +1039,8 @@
<string name="torrent_download">Pobierz</string>
<string name="torrent_failure">Nie udało się otworzyć pliku</string>
<string name="torrent_no_apps">Brak zainstalowanych aplikacji torrent do otwarcia i pobrania pliku.</string>
<string name="torrent_no_info">Zdarzenie nie ma wystarczającej ilości informacji, aby zbudować link magnetyczny</string>
<string name="my_lists_and_sets">Moje Listy/Zbiory</string>
<string name="select_list_to_filter">Wybierz listę, aby filtrować aktualności</string>
<string name="temporary_account">Wyloguj się przy blokowaniu urządzenia</string>
<string name="private_message">Wiadomość prywatna</string>
@@ -1018,6 +1048,7 @@
<string name="group_relay">Transmiter Czatu</string>
<string name="group_relay_explanation">Transmiter, z którym łączą się wszyscy użytkownicy tego czatu</string>
<string name="share_image">Udostępnij zdjęcie…</string>
<string name="unable_to_share_image">Nie można udostępnić obrazu, spróbuj ponownie później…</string>
<string name="search_by_hashtag">Szukaj tagu: #%1$s</string>
<string name="dont_translate_from">Nie tłumacz z</string>
<string name="dont_translate_from_description">Języki wyświetlane tutaj nie będą tłumaczone. Wybierz język, aby usunąć go z listy języków nietłumaczonych.</string>
@@ -1031,4 +1062,5 @@
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Czy chcesz wysłać ostatni raport o awarii do Amethyst w DM? Żadne dane osobowe nie będą udostępnione</string>
<string name="crashreport_found_send">Prześlij</string>
<string name="this_message_will_disappear_in_days">Ta wiadomość zniknie za %1$d dni</string>
<string name="select_signer">Wybierz Sygnatariusza</string>
</resources>
@@ -112,6 +112,7 @@
<string name="post">Salvar</string>
<string name="save">Salvar</string>
<string name="create">Criar</string>
<string name="rename">Renomear</string>
<string name="cancel">Cancelar</string>
<string name="failed_to_upload_the_image">Falha ao enviar imagem</string>
<string name="relay_address">Endereço do Relay</string>
@@ -443,6 +444,31 @@
<string name="follow_list_aroundme">Perto de mim</string>
<string name="follow_list_global">Global</string>
<string name="follow_list_mute_list">Lista Silenciada</string>
<string name="follow_sets">Conjuntos de Seguimento</string>
<string name="labeled_bookmarks">Favoritos com etiqueta</string>
<string name="general_bookmarks">Favoritos gerais</string>
<string name="follow_set_type_public">Público</string>
<string name="follow_set_type_private">Privado</string>
<string name="follow_set_type_mixed">Misto</string>
<string name="follow_set_empty_feed_msg">Parece que você ainda não tem conjuntos de seguimento.\nToque abaixo para atualizar ou use o botão de adicionar para criar um novo.</string>
<string name="follow_set_add_author_from_note_action">Adicionar autor ao conjunto de seguimento</string>
<string name="follow_set_profile_actions_menu_description">Adicionar ou remover usuário de listas, ou criar uma nova lista com este usuário.</string>
<string name="follow_set_type_description">Ícone da lista %1$s</string>
<string name="follow_set_presence_indicator">"%1$s está presente nesta lista"</string>
<string name="follow_set_absence_indicator">"%1$s não está nesta lista"</string>
<string name="follow_set_man_dialog_title">Seus conjuntos de seguimento</string>
<string name="follow_set_empty_dialog_msg">Nenhum conjunto de seguimento foi encontrado ou você não possui nenhum. Toque abaixo para atualizar ou use o menu para criar um.</string>
<string name="follow_set_error_dialog_msg">Houve um problema ao buscar: %1$s</string>
<string name="follow_set_creation_menu_title">Criar nova lista</string>
<string name="follow_set_creation_item_label">Criar nova lista %1$s com usuário</string>
<string name="follow_set_creation_item_description">Cria um conjunto de seguimento %1$s e adiciona %2$s a ele.</string>
<string name="follow_set_creation_dialog_title">Nova lista %1$s</string>
<string name="follow_set_creation_name_label">Nome do conjunto</string>
<string name="follow_set_creation_desc_label">Descrição do conjunto (opcional)</string>
<string name="follow_set_creation_action_btn_label">Criar conjunto</string>
<string name="follow_set_rename_btn_label">Renomear conjunto</string>
<string name="follow_set_rename_dialog_indicator_first_part">Você está renomeando de </string>
<string name="follow_set_rename_dialog_indicator_second_part"> para..</string>
<string name="connect_through_your_orbot_setup_short">Porta padrão é 9050</string>
<string name="connect_through_your_orbot_setup_markdown"> ## Conecte-se através do Tor com o Orbot
\n\n1. Instale o [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android)
@@ -830,6 +856,8 @@
<string name="media_compression_quality_medium">Média</string>
<string name="media_compression_quality_high">Alta</string>
<string name="media_compression_quality_uncompressed">Sem compressão</string>
<string name="video_codec_h265_label">Usar codec H.265/HEVC</string>
<string name="video_codec_h265_description">Melhor qualidade em arquivos menores, mas nem todos os dispositivos suportam reprodução em H.265.</string>
<string name="edit_draft">Editar rascunho</string>
<string name="login_with_qr_code">Entrar com Código QR</string>
<string name="route">Rota</string>
@@ -1012,6 +1040,8 @@
<string name="torrent_download">Baixar</string>
<string name="torrent_failure">Falha ao abrir o arquivo</string>
<string name="torrent_no_apps">Nenhum aplicativo torrent instalado para abrir e baixar o arquivo.</string>
<string name="torrent_no_info">O evento não tem informações suficientes para criar um link magnético</string>
<string name="my_lists_and_sets">Minhas listas/conjuntos</string>
<string name="select_list_to_filter">Selecione uma lista para filtrar o feed</string>
<string name="temporary_account">Terminar sessão no bloqueio do dispositivo</string>
<string name="private_message">Mensagem Privada</string>
@@ -1033,4 +1063,5 @@
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Gostaria de enviar o relatório de falha recente para o Amethyst em uma DM? Nenhuma informação pessoal será compartilhada</string>
<string name="crashreport_found_send">Enviar</string>
<string name="this_message_will_disappear_in_days">Esta mensagem desaparecerá em %1$d dias</string>
<string name="select_signer">Selecionar assinador</string>
</resources>
@@ -456,6 +456,8 @@ Za podpisovanje se je potrebno prijaviti s privatnim ključem</string>
<string name="follow_list_aroundme">V moji okolici</string>
<string name="follow_list_global">Globalno</string>
<string name="follow_list_mute_list">Spisek utišanih</string>
<string name="follow_set_type_private">Zasebno</string>
<string name="follow_set_type_mixed">Mešano</string>
<string name="connect_through_your_orbot_setup_short">Prevzeta vrata so 9050</string>
<string name="connect_through_your_orbot_setup_markdown"> ## Poveži se preko Tor omrežja z Orbot aplikacijo
\n\n1. Namesti [Orbot aplikacijo](https://play.google.com/store/apps/details?id=org.torproject.android)
@@ -112,6 +112,7 @@
<string name="post">Dela</string>
<string name="save">Spara</string>
<string name="create">Skapa</string>
<string name="rename">Byt namn</string>
<string name="cancel">Avbryt</string>
<string name="failed_to_upload_the_image">Det gick inte att ladda upp bilden</string>
<string name="relay_address">Relä Adress</string>
@@ -443,6 +444,31 @@
<string name="follow_list_aroundme">Runt mig</string>
<string name="follow_list_global">Global</string>
<string name="follow_list_mute_list">Tyst listan</string>
<string name="follow_sets">Följ-set</string>
<string name="labeled_bookmarks">Märkta bokmärken</string>
<string name="general_bookmarks">Allmänna bokmärken</string>
<string name="follow_set_type_public">Offentlig</string>
<string name="follow_set_type_private">Privat</string>
<string name="follow_set_type_mixed">Blandad</string>
<string name="follow_set_empty_feed_msg">Det verkar som att du inte har några följ-set ännu.\nTryck nedan för att uppdatera eller använd plusknappen för att skapa ett nytt.</string>
<string name="follow_set_add_author_from_note_action">Lägg till författare i följ-set</string>
<string name="follow_set_profile_actions_menu_description">Lägg till eller ta bort användare från listor, eller skapa en ny lista med denna användare.</string>
<string name="follow_set_type_description">Ikon för %1$s-lista</string>
<string name="follow_set_presence_indicator">"%1$s finns i denna lista"</string>
<string name="follow_set_absence_indicator">"%1$s finns inte i denna lista"</string>
<string name="follow_set_man_dialog_title">Dina följ-set</string>
<string name="follow_set_empty_dialog_msg">Inga följ-set hittades, eller så har du inga. Tryck nedan för att uppdatera eller använd menyn för att skapa ett.</string>
<string name="follow_set_error_dialog_msg">Ett problem uppstod vid hämtning: %1$s</string>
<string name="follow_set_creation_menu_title">Skapa ny lista</string>
<string name="follow_set_creation_item_label">Skapa ny %1$s-lista med användare</string>
<string name="follow_set_creation_item_description">Skapar ett %1$s-följ-set och lägger till %2$s i det.</string>
<string name="follow_set_creation_dialog_title">Ny %1$s-lista</string>
<string name="follow_set_creation_name_label">Set-namn</string>
<string name="follow_set_creation_desc_label">Set-beskrivning (valfritt)</string>
<string name="follow_set_creation_action_btn_label">Skapa set</string>
<string name="follow_set_rename_btn_label">Byt namn på set</string>
<string name="follow_set_rename_dialog_indicator_first_part">Du byter namn från </string>
<string name="follow_set_rename_dialog_indicator_second_part"> till..</string>
<string name="connect_through_your_orbot_setup_short">Standardporten är 9050</string>
<string name="connect_through_your_orbot_setup_markdown"> ## Anslut genom Tor med Orbot
\n\n1. Installera [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android)
@@ -829,6 +855,8 @@
<string name="media_compression_quality_medium">Medel</string>
<string name="media_compression_quality_high">Hög</string>
<string name="media_compression_quality_uncompressed">Okomprimerad</string>
<string name="video_codec_h265_label">Använd H.265/HEVC-codec</string>
<string name="video_codec_h265_description">Bättre kvalitet med mindre filstorlek, men inte alla enheter stöder H.265-uppspelning.</string>
<string name="edit_draft">Redigera utkast</string>
<string name="login_with_qr_code">Logga in med QR-kod</string>
<string name="route">Rutt</string>
@@ -1011,6 +1039,8 @@
<string name="torrent_download">Ladda ner</string>
<string name="torrent_failure">Det gick inte att öppna filen</string>
<string name="torrent_no_apps">Inga torrent-appar installerade för att öppna och ladda ner filen.</string>
<string name="torrent_no_info">Händelsen har inte tillräcklig information för att skapa en magnetlänk</string>
<string name="my_lists_and_sets">Mina listor/set</string>
<string name="select_list_to_filter">Välj en lista för att filtrera flödet</string>
<string name="temporary_account">Logga ut när enheten låses</string>
<string name="private_message">Privat meddelande</string>
@@ -1032,4 +1062,5 @@
<string name="would_you_like_to_send_the_recent_crash_report_to_amethyst_in_a_dm_no_personal_information_will_be_shared">Vill du skicka den senaste kraschrapporten till Amethyst i ett DM? Ingen personlig information kommer att delas</string>
<string name="crashreport_found_send">Skicka</string>
<string name="this_message_will_disappear_in_days">Detta meddelande försvinner om %1$d dagar</string>
<string name="select_signer">Välj signatör</string>
</resources>
+2
View File
@@ -1042,6 +1042,8 @@
<string name="media_compression_quality_medium">Medium</string>
<string name="media_compression_quality_high">High</string>
<string name="media_compression_quality_uncompressed">Uncompressed</string>
<string name="video_codec_h265_label">Use H.265/HEVC Codec</string>
<string name="video_codec_h265_description">Better quality at smaller file sizes but not all devices support H.265 playback.</string>
<string name="edit_draft">Edit draft</string>