Merge branch 'vitorpamplona:main' into nostrbuildv2
This commit is contained in:
@@ -1514,9 +1514,9 @@ class Account(
|
||||
|
||||
private fun isAcceptableDirect(note: Note): Boolean {
|
||||
if (!warnAboutPostsWithReports) {
|
||||
return note.reportsBy(userProfile()).isEmpty()
|
||||
return !note.hasReportsBy(userProfile())
|
||||
}
|
||||
return note.reportsBy(userProfile()).isEmpty() && // if user has not reported this post
|
||||
return !note.hasReportsBy(userProfile()) && // if user has not reported this post
|
||||
note.countReportAuthorsBy(followingKeySet()) < 5 // if it has 5 reports by reliable users
|
||||
}
|
||||
|
||||
|
||||
@@ -51,20 +51,20 @@ open class Note(val idHex: String) {
|
||||
var replyTo: List<Note>? = null
|
||||
|
||||
// These fields are updated every time an event related to this note is received.
|
||||
var replies = setOf<Note>()
|
||||
var replies = listOf<Note>()
|
||||
private set
|
||||
var reactions = mapOf<String, Set<Note>>()
|
||||
var reactions = mapOf<String, List<Note>>()
|
||||
private set
|
||||
var boosts = setOf<Note>()
|
||||
var boosts = listOf<Note>()
|
||||
private set
|
||||
var reports = mapOf<User, Set<Note>>()
|
||||
var reports = mapOf<User, List<Note>>()
|
||||
private set
|
||||
var zaps = mapOf<Note, Note?>()
|
||||
private set
|
||||
var zapPayments = mapOf<Note, Note?>()
|
||||
private set
|
||||
|
||||
var relays = setOf<String>()
|
||||
var relays = listOf<String>()
|
||||
private set
|
||||
|
||||
var lastReactionsDownloadTime: Map<String, EOSETime> = emptyMap()
|
||||
@@ -151,15 +151,20 @@ open class Note(val idHex: String) {
|
||||
}
|
||||
|
||||
fun removeReply(note: Note) {
|
||||
replies = replies - note
|
||||
liveSet?.replies?.invalidateData()
|
||||
}
|
||||
fun removeBoost(note: Note) {
|
||||
boosts = boosts - note
|
||||
liveSet?.boosts?.invalidateData()
|
||||
if (note in replies) {
|
||||
replies = replies - note
|
||||
liveSet?.replies?.invalidateData()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAllChildNotes(): Set<Note> {
|
||||
fun removeBoost(note: Note) {
|
||||
if (note in boosts) {
|
||||
boosts = boosts - note
|
||||
liveSet?.boosts?.invalidateData()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAllChildNotes(): List<Note> {
|
||||
val toBeRemoved = replies +
|
||||
reactions.values.flatten() +
|
||||
boosts +
|
||||
@@ -169,13 +174,13 @@ open class Note(val idHex: String) {
|
||||
zapPayments.keys +
|
||||
zapPayments.values.filterNotNull()
|
||||
|
||||
replies = setOf<Note>()
|
||||
reactions = mapOf<String, Set<Note>>()
|
||||
boosts = setOf<Note>()
|
||||
reports = mapOf<User, Set<Note>>()
|
||||
replies = listOf<Note>()
|
||||
reactions = mapOf<String, List<Note>>()
|
||||
boosts = listOf<Note>()
|
||||
reports = mapOf<User, List<Note>>()
|
||||
zaps = mapOf<Note, Note?>()
|
||||
zapPayments = mapOf<Note, Note?>()
|
||||
relays = setOf<String>()
|
||||
relays = listOf<String>()
|
||||
lastReactionsDownloadTime = emptyMap()
|
||||
|
||||
liveSet?.replies?.invalidateData()
|
||||
@@ -193,14 +198,16 @@ open class Note(val idHex: String) {
|
||||
|
||||
if (reaction in reactions.keys && reactions[reaction]?.contains(note) == true) {
|
||||
reactions[reaction]?.let {
|
||||
val newList = it.minus(note)
|
||||
if (newList.isEmpty()) {
|
||||
reactions = reactions.minus(reaction)
|
||||
} else {
|
||||
reactions = reactions + Pair(reaction, newList)
|
||||
}
|
||||
if (note in it) {
|
||||
val newList = it.minus(note)
|
||||
if (newList.isEmpty()) {
|
||||
reactions = reactions.minus(reaction)
|
||||
} else {
|
||||
reactions = reactions + Pair(reaction, newList)
|
||||
}
|
||||
|
||||
liveSet?.reactions?.invalidateData()
|
||||
liveSet?.reactions?.invalidateData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +313,7 @@ open class Note(val idHex: String) {
|
||||
val reaction = note.event?.content()?.firstFullCharOrEmoji(ImmutableListOfLists(tags)) ?: "+"
|
||||
|
||||
if (reaction !in reactions.keys) {
|
||||
reactions = reactions + Pair(reaction, setOf(note))
|
||||
reactions = reactions + Pair(reaction, listOf(note))
|
||||
liveSet?.reactions?.invalidateData()
|
||||
} else if (reactions[reaction]?.contains(note) == false) {
|
||||
reactions = reactions + Pair(reaction, (reactions[reaction] ?: emptySet()) + note)
|
||||
@@ -318,7 +325,7 @@ open class Note(val idHex: String) {
|
||||
val author = note.author ?: return
|
||||
|
||||
if (author !in reports.keys) {
|
||||
reports = reports + Pair(author, setOf(note))
|
||||
reports = reports + Pair(author, listOf(note))
|
||||
liveSet?.reports?.invalidateData()
|
||||
} else if (reports[author]?.contains(note) == false) {
|
||||
reports = reports + Pair(author, (reports[author] ?: emptySet()) + note)
|
||||
@@ -411,8 +418,8 @@ open class Note(val idHex: String) {
|
||||
return boosts.any { it.author?.pubkeyHex == user.pubkeyHex }
|
||||
}
|
||||
|
||||
fun reportsBy(user: User): Set<Note> {
|
||||
return reports[user] ?: emptySet()
|
||||
fun hasReportsBy(user: User): Boolean {
|
||||
return reports[user]?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
fun reportAuthorsBy(users: Set<HexKey>): List<User> {
|
||||
@@ -576,9 +583,9 @@ open class Note(val idHex: String) {
|
||||
}
|
||||
|
||||
replyTo = null
|
||||
replies = emptySet()
|
||||
replies = emptyList()
|
||||
reactions = emptyMap()
|
||||
boosts = emptySet()
|
||||
boosts = emptyList()
|
||||
reports = emptyMap()
|
||||
zaps = emptyMap()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.vitorpamplona.amethyst.model.TimeUtils
|
||||
import com.vitorpamplona.amethyst.model.toHexKey
|
||||
import com.vitorpamplona.amethyst.service.CryptoUtils
|
||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||
import com.vitorpamplona.amethyst.service.relays.bytesUsedInMemory
|
||||
import fr.acinq.secp256k1.Hex
|
||||
import java.lang.reflect.Type
|
||||
import java.math.BigDecimal
|
||||
@@ -24,6 +25,16 @@ open class Event(
|
||||
val content: String,
|
||||
val sig: HexKey
|
||||
) : EventInterface {
|
||||
|
||||
override fun countMemory(): Long {
|
||||
return 12L +
|
||||
id.bytesUsedInMemory() +
|
||||
pubKey.bytesUsedInMemory() +
|
||||
tags.sumOf { it.sumOf { it.bytesUsedInMemory() } } +
|
||||
content.bytesUsedInMemory() +
|
||||
sig.bytesUsedInMemory()
|
||||
}
|
||||
|
||||
override fun id(): HexKey = id
|
||||
|
||||
override fun pubKey(): HexKey = pubKey
|
||||
|
||||
@@ -6,6 +6,8 @@ import java.math.BigDecimal
|
||||
|
||||
@Immutable
|
||||
interface EventInterface {
|
||||
fun countMemory(): Long
|
||||
|
||||
fun id(): HexKey
|
||||
|
||||
fun pubKey(): HexKey
|
||||
|
||||
@@ -56,9 +56,6 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val uri = intent?.data?.toString()
|
||||
val startingPage = uriToRoute(uri)
|
||||
|
||||
LocalPreferences.migrateSingleUserPrefs()
|
||||
val language = LocalPreferences.getPreferredLanguage()
|
||||
if (language.isNotBlank()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.components
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -64,19 +65,30 @@ fun RobohashFallbackAsyncImage(
|
||||
model = Robohash.imageRequest(context, robot)
|
||||
)
|
||||
|
||||
AsyncImage(
|
||||
model = model,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
placeholder = painter,
|
||||
fallback = painter,
|
||||
error = painter,
|
||||
alignment = alignment,
|
||||
contentScale = contentScale,
|
||||
alpha = alpha,
|
||||
colorFilter = colorFilter,
|
||||
filterQuality = filterQuality
|
||||
)
|
||||
if (model != null) {
|
||||
AsyncImage(
|
||||
model = model,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
placeholder = painter,
|
||||
fallback = painter,
|
||||
error = painter,
|
||||
alignment = alignment,
|
||||
contentScale = contentScale,
|
||||
alpha = alpha,
|
||||
colorFilter = colorFilter,
|
||||
filterQuality = filterQuality
|
||||
)
|
||||
} else {
|
||||
Image(
|
||||
painter = painter,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier,
|
||||
alignment = alignment,
|
||||
contentScale = contentScale,
|
||||
colorFilter = colorFilter
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -65,7 +65,6 @@ fun AppNavigation(
|
||||
|
||||
navController: NavHostController,
|
||||
accountViewModel: AccountViewModel,
|
||||
startingPage: String? = null,
|
||||
themeViewModel: ThemeViewModel
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -250,7 +249,10 @@ fun AppNavigation(
|
||||
}
|
||||
}
|
||||
|
||||
var actionableNextPage by remember { mutableStateOf(startingPage) }
|
||||
val activity = LocalContext.current.getActivity()
|
||||
var actionableNextPage by remember {
|
||||
mutableStateOf(uriToRoute(activity.intent?.data?.toString()?.ifBlank { null }))
|
||||
}
|
||||
actionableNextPage?.let {
|
||||
LaunchedEffect(it) {
|
||||
navController.navigate(it) {
|
||||
@@ -261,7 +263,6 @@ fun AppNavigation(
|
||||
actionableNextPage = null
|
||||
}
|
||||
|
||||
val activity = LocalContext.current.getActivity()
|
||||
DisposableEffect(navController) {
|
||||
val consumer = Consumer<Intent> { intent ->
|
||||
val uri = intent?.data?.toString()
|
||||
|
||||
@@ -514,6 +514,8 @@ fun debugState(context: Context) {
|
||||
Log.d("STATE DUMP", "Addressables: " + LocalCache.addressables.filter { it.value.event != null }.size + "/" + LocalCache.addressables.size)
|
||||
Log.d("STATE DUMP", "Users: " + LocalCache.users.filter { it.value.info?.latestMetadata != null }.size + "/" + LocalCache.users.size)
|
||||
|
||||
Log.d("STATE DUMP", "Memory used by Events: " + LocalCache.notes.values.sumOf { it.event?.countMemory() ?: 0 } / (1024 * 1024) + " MB")
|
||||
|
||||
LocalCache.notes.values.groupBy { it.event?.kind() }.forEach {
|
||||
Log.d("STATE DUMP", "Kind ${it.key}: \t${it.value.size} elements ")
|
||||
}
|
||||
|
||||
@@ -412,65 +412,97 @@ private fun ReactionDetailGallery(
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val zapsState by baseNote.live().zaps.observeAsState()
|
||||
val boostsState by baseNote.live().boosts.observeAsState()
|
||||
val reactionsState by baseNote.live().reactions.observeAsState()
|
||||
|
||||
val defaultBackgroundColor = MaterialTheme.colors.background
|
||||
val backgroundColor = remember { mutableStateOf<Color>(defaultBackgroundColor) }
|
||||
|
||||
val hasReactions by remember(zapsState, boostsState, reactionsState) {
|
||||
derivedStateOf {
|
||||
baseNote.zaps.isNotEmpty() ||
|
||||
baseNote.boosts.isNotEmpty() ||
|
||||
baseNote.reactions.isNotEmpty()
|
||||
}
|
||||
}
|
||||
val hasReactions by baseNote.live().zaps.combineWith(
|
||||
baseNote.live().boosts,
|
||||
baseNote.live().reactions
|
||||
) { zapState, boostState, reactionState ->
|
||||
zapState?.note?.zaps?.isNotEmpty() ?: false ||
|
||||
boostState?.note?.boosts?.isNotEmpty() ?: false ||
|
||||
reactionState?.note?.reactions?.isNotEmpty() ?: false
|
||||
}.distinctUntilChanged().observeAsState(
|
||||
baseNote.zaps.isNotEmpty() || baseNote.boosts.isNotEmpty() || baseNote.reactions.isNotEmpty()
|
||||
)
|
||||
|
||||
if (hasReactions) {
|
||||
Row(verticalAlignment = CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp)) {
|
||||
Column() {
|
||||
val zapEvents by remember(zapsState) { derivedStateOf { baseNote.zaps.mapNotNull { it.value?.let { zapEvent -> CombinedZap(it.key, zapEvent) } }.toImmutableList() } }
|
||||
val boostEvents by remember(boostsState) { derivedStateOf { baseNote.boosts.toImmutableList() } }
|
||||
val likeEvents by remember(reactionsState) { derivedStateOf { baseNote.reactions.toImmutableMap() } }
|
||||
|
||||
val hasZapEvents by remember(zapsState) { derivedStateOf { baseNote.zaps.isNotEmpty() } }
|
||||
val hasBoostEvents by remember(boostsState) { derivedStateOf { baseNote.boosts.isNotEmpty() } }
|
||||
val hasLikeEvents by remember(reactionsState) { derivedStateOf { baseNote.reactions.isNotEmpty() } }
|
||||
|
||||
if (hasZapEvents) {
|
||||
RenderZapGallery(
|
||||
zapEvents,
|
||||
backgroundColor,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
|
||||
if (hasBoostEvents) {
|
||||
RenderBoostGallery(
|
||||
boostEvents,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
|
||||
if (hasLikeEvents) {
|
||||
likeEvents.forEach {
|
||||
val reactions = remember(it.value) { it.value.toImmutableList() }
|
||||
RenderLikeGallery(
|
||||
it.key,
|
||||
reactions,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
WatchZapAndRenderGallery(baseNote, backgroundColor, nav, accountViewModel)
|
||||
WatchBoostsAndRenderGallery(baseNote, nav, accountViewModel)
|
||||
WatchReactionsAndRenderGallery(baseNote, nav, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchBoostsAndRenderGallery(
|
||||
baseNote: Note,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val boostsState by baseNote.live().boosts.observeAsState()
|
||||
val boostsEvents by remember(boostsState) {
|
||||
derivedStateOf { baseNote.boosts.toImmutableList() }
|
||||
}
|
||||
|
||||
if (boostsEvents.isNotEmpty()) {
|
||||
RenderBoostGallery(
|
||||
boostsEvents,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchReactionsAndRenderGallery(
|
||||
baseNote: Note,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val reactionsState by baseNote.live().reactions.observeAsState()
|
||||
val reactionEvents by remember(reactionsState) {
|
||||
derivedStateOf { baseNote.reactions.toImmutableMap() }
|
||||
}
|
||||
|
||||
if (reactionEvents.isNotEmpty()) {
|
||||
reactionEvents.forEach {
|
||||
val reactions = remember(it.value) { it.value.toImmutableList() }
|
||||
RenderLikeGallery(
|
||||
it.key,
|
||||
reactions,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchZapAndRenderGallery(
|
||||
baseNote: Note,
|
||||
backgroundColor: MutableState<Color>,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val zapsState by baseNote.live().zaps.observeAsState()
|
||||
val zapEvents by remember(zapsState) {
|
||||
derivedStateOf { baseNote.zaps.mapNotNull { it.value?.let { zapEvent -> CombinedZap(it.key, zapEvent) } }.toImmutableList() }
|
||||
}
|
||||
|
||||
if (zapEvents.isNotEmpty()) {
|
||||
RenderZapGallery(
|
||||
zapEvents,
|
||||
backgroundColor,
|
||||
nav,
|
||||
accountViewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BoostWithDialog(
|
||||
baseNote: Note,
|
||||
|
||||
@@ -169,7 +169,11 @@
|
||||
<string name="report_hateful_speech">Signaler Discours haineux</string>
|
||||
<string name="report_nudity_porn">Signaler Nudité / Porno</string>
|
||||
<string name="others">autres</string>
|
||||
<string name="account_backup_tips_md">
|
||||
<string name="mark_all_known_as_read">Marquer tous les Connus comme lu</string>
|
||||
<string name="mark_all_new_as_read">Marquer tous les Nouveaux comme lu</string>
|
||||
<string name="mark_all_as_read">Tout marquer comme lu</string>
|
||||
<string name="backup_keys">Clés de sauvegarde</string>
|
||||
<string name="account_backup_tips_md" tools:ignore="Typos">
|
||||
## Sauvegarde des clés et conseils de sécurité
|
||||
\n\nVotre compte est sécurisé par une clé secrète. La clé est une longue chaîne aléatoire commençant par **nsec1**. Toute personne ayant accès à votre clé secrète peut publier du contenu en utilisant votre identité.
|
||||
\n\n- Ne communiquez **jamais** votre clé secrète à un site Web ou un logiciel auquel vous ne faites pas confiance.
|
||||
@@ -177,5 +181,322 @@
|
||||
\n- **Conservez** une sauvegarde sécurisée de votre clé secrète pour la récupération de compte. Nous vous recommandons d\'utiliser un gestionnaire de mots de passe.
|
||||
</string>
|
||||
<string name="secret_key_copied_to_clipboard">Clé secrète (nsec) copiée dans le presse-papiers</string>
|
||||
<string name="backup_keys">Clés de sauvegarde</string>
|
||||
<string name="copy_my_secret_key">Copier ma clé secrète</string>
|
||||
<string name="biometric_authentication_failed">Échec de l'authentification</string>
|
||||
<string name="biometric_error">Erreur</string>
|
||||
<string name="badge_created_by">"Créé par %1$s"</string>
|
||||
<string name="badge_award_image_for">"Image de badge pour %1$s"</string>
|
||||
<string name="new_badge_award_notif">Vous avez reçu un nouveau Badge</string>
|
||||
<string name="award_granted_to">Le Badge a été décerné à</string>
|
||||
<string name="copied_note_text_to_clipboard">Copie du contenu de la note dans le presse-papiers</string>
|
||||
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">Copie du @npub utilisateur dans le presse-papiers</string>
|
||||
<string name="copied_note_id_to_clipboard" tools:ignore="Typos">Copie de l'ID de la note (@note1) dans le presse-papiers</string>
|
||||
<string name="select_text_dialog_top">Sélectionner le Texte</string>
|
||||
|
||||
<string name="private_conversation_notification">"<Impossible de déchiffrer le message privé>\n\nVous avez été cité dans une conversation privée/cryptée entre %1$s et %2$s."</string>
|
||||
<string name="account_switch_add_account_dialog_title">Ajouter un Nouveau Compte</string>
|
||||
<string name="drawer_accounts">Comptes</string>
|
||||
<string name="account_switch_select_account">Sélectionner un Compte</string>
|
||||
<string name="account_switch_add_account_btn">Ajouter un Nouveau Compte</string>
|
||||
<string name="account_switch_active_account">Compte actif</string>
|
||||
<string name="account_switch_has_private_key">Avec une clé privée</string>
|
||||
<string name="account_switch_pubkey_only">Lecture seule, pas de clé privée</string>
|
||||
<string name="back">Retour</string>
|
||||
<string name="quick_action_select">Sélectionner</string>
|
||||
<string name="quick_action_share_browser_link">Partager le Lien Navigateur</string>
|
||||
<string name="quick_action_share">Partager</string>
|
||||
<string name="quick_action_copy_user_id">ID Author</string>
|
||||
<string name="quick_action_copy_note_id">ID Note</string>
|
||||
<string name="quick_action_copy_text">Copier le Texte</string>
|
||||
<string name="quick_action_delete">Supprimer</string>
|
||||
<string name="quick_action_unfollow">Ne plus suivre</string>
|
||||
<string name="quick_action_follow">Suivre</string>
|
||||
<string name="quick_action_request_deletion_alert_title">Demande de Suppression</string>
|
||||
<string name="quick_action_request_deletion_alert_body">Amethyst demandera que votre note soit supprimée des relais auxquels vous êtes actuellement connecté. Il n'y a aucune garantie que votre note sera définitivement supprimée de ces relais, ou d'autres relais où elle peut être stockée.</string>
|
||||
<string name="quick_action_block_dialog_btn">Bloquer</string>
|
||||
<string name="quick_action_delete_dialog_btn">Supprimer</string>
|
||||
<string name="quick_action_block">Bloquer</string>
|
||||
<string name="quick_action_report">Signaler</string>
|
||||
<string name="quick_action_delete_button">Supprimer</string>
|
||||
<string name="quick_action_dont_show_again_button">Ne plus montrer</string>
|
||||
<string name="report_dialog_spam">Spam ou arnaque</string>
|
||||
<string name="report_dialog_profanity">Grossièreté ou contenu haineux</string>
|
||||
<string name="report_dialog_impersonation">Usurpation d'identité</string>
|
||||
<string name="report_dialog_nudity">Nudité ou contenu graphique</string>
|
||||
<string name="report_dialog_illegal">Comportement illégal</string>
|
||||
<string name="report_dialog_blocking_a_user">Bloquer un utilisateur cachera son contenu dans votre application. Vos notes sont toujours visibles publiquement, y compris pour les personnes que vous bloquez. Les utilisateurs bloqués sont listés sur l'écran Filtres de Sécurité.</string>
|
||||
<string name="report_dialog_block_hide_user_btn"><![CDATA[Bloquer et Masquer l'Utilisateur]]></string>
|
||||
<string name="report_dialog_report_btn">Signaler un Abus</string>
|
||||
<string name="report_dialog_reminder_public">Tous les rapports publiés seront visibles publiquement.</string>
|
||||
<string name="report_dialog_additional_reason_placeholder">Fournir un contexte optionnel supplémentaire sur votre signalement...</string>
|
||||
<string name="report_dialog_additional_reason_label">Contexte additionnel</string>
|
||||
<string name="report_dialog_select_reason_label">Raison</string>
|
||||
<string name="report_dialog_select_reason_placeholder">Sélectionner une raison...</string>
|
||||
<string name="report_dialog_post_report_btn">Publier le signalement</string>
|
||||
<string name="report_dialog_title">Bloquer et Signaler</string>
|
||||
<string name="block_only">Bloquer</string>
|
||||
|
||||
|
||||
<string name="bookmarks">Favoris</string>
|
||||
<string name="private_bookmarks">Favoris Privés</string>
|
||||
<string name="public_bookmarks">Favoris Publics</string>
|
||||
<string name="add_to_private_bookmarks">Ajouter aux Favoris Privés</string>
|
||||
<string name="add_to_public_bookmarks">Ajouter aux Favoris Publics</string>
|
||||
<string name="remove_from_private_bookmarks">Supprimer des Favoris Privés</string>
|
||||
<string name="remove_from_public_bookmarks">Supprimer des Favoris Publics</string>
|
||||
|
||||
<string name="wallet_connect_service">Service Wallet Connect</string>
|
||||
<string name="wallet_connect_service_explainer">Autorise un Nostr Secret à payer des zaps sans quitter l'application. Gardez le secret en toute sécurité et utilisez un relais privé si possible</string>
|
||||
<string name="wallet_connect_service_pubkey">Wallet Connect Pubkey</string>
|
||||
<string name="wallet_connect_service_relay">Wallet Connect Relay</string>
|
||||
<string name="wallet_connect_service_secret">Wallet Connect Secret</string>
|
||||
<string name="wallet_connect_service_show_secret">Montrer la clé secrète</string>
|
||||
<string name="wallet_connect_service_secret_placeholder">Clé privée nsec / hex</string>
|
||||
|
||||
<string name="pledge_amount_in_sats">Montant engagé en Sats</string>
|
||||
<string name="post_poll">Message Sondage</string>
|
||||
<string name="poll_heading_required">Champs requis:</string>
|
||||
<string name="poll_zap_recipients">Bénéficiaires du Zap</string>
|
||||
<string name="poll_primary_description">Description du sondage primaire...</string>
|
||||
<string name="poll_option_index">Option %s</string>
|
||||
<string name="poll_option_description">Description de l'option du Sondage</string>
|
||||
<string name="poll_heading_optional">Champs optionels:</string>
|
||||
<string name="poll_zap_value_min">Zap minimum</string>
|
||||
<string name="poll_zap_value_max">Zap maximum</string>
|
||||
<string name="poll_consensus_threshold">Consensus</string>
|
||||
<string name="poll_consensus_threshold_percent">(0–100)%</string>
|
||||
<string name="poll_closing_time">Clôturer après</string>
|
||||
<string name="poll_closing_time_days">jours</string>
|
||||
<string name="poll_is_closed">Le Sondage est fermé aux nouveaux votes</string>
|
||||
<string name="poll_zap_amount">Montant des Zap</string>
|
||||
<string name="one_vote_per_user_on_atomic_votes">Un seul vote par utilisateur est autorisé sur ce type de sondage</string>
|
||||
|
||||
<string name="looking_for_event">"Recherche de l'Evénement %1$s"</string>
|
||||
|
||||
<string name="custom_zaps_add_a_message">Ajouter un message public</string>
|
||||
<string name="custom_zaps_add_a_message_private">Ajouter un message privé</string>
|
||||
<string name="custom_zaps_add_a_message_nonzap">Ajouter un message facture</string>
|
||||
|
||||
<string name="custom_zaps_add_a_message_example">Merci pour tout votre travail !</string>
|
||||
|
||||
<string name="lightning_create_and_add_invoice">Créer et Ajouter</string>
|
||||
<string name="poll_author_no_vote">Les auteurs du sondage ne peuvent pas voter dans leurs propres sondages.</string>
|
||||
|
||||
<string name="hash_verification_passed">Ce contenu est le même depuis le message</string>
|
||||
<string name="hash_verification_failed">Ce contenu a changé. L'auteur n'a peut-être pas vu ou approuvé le changement</string>
|
||||
|
||||
<string name="content_description_add_image">Ajouter une Image</string>
|
||||
<string name="content_description_add_video">Ajouter une Vidéo</string>
|
||||
<string name="content_description_add_document">Ajouter un Document</string>
|
||||
|
||||
<string name="add_content">Ajouter au Message</string>
|
||||
<string name="content_description">Description des contenus</string>
|
||||
<string name="content_description_example">Un bateau bleu sur une plage de sable blanc au coucher du soleil</string>
|
||||
|
||||
|
||||
<string name="zap_type">Type de Zap</string>
|
||||
<string name="zap_type_explainer">Zap Type pour toutes les options</string>
|
||||
|
||||
<string name="zap_type_public">Public</string>
|
||||
<string name="zap_type_public_explainer">Tout le monde peut voir la transaction et le message</string>
|
||||
|
||||
<string name="zap_type_private">Privé</string>
|
||||
<string name="zap_type_private_explainer">L'expéditeur et le receveur peuvent se voir et lire le message</string>
|
||||
|
||||
<string name="zap_type_anonymous">Anonyme</string>
|
||||
<string name="zap_type_anonymous_explainer">Le receveur et le public ne savent pas qui a envoyé le paiement</string>
|
||||
|
||||
<string name="zap_type_nonzap">Non-Zap</string>
|
||||
<string name="zap_type_nonzap_explainer">Aucune trace sur Nostr, seulement sur le Lightning</string>
|
||||
|
||||
|
||||
<string name="file_server">Serveur fichier</string>
|
||||
<string name="zap_forward_lnAddress">Adresse LN ou @Utilisateur</string>
|
||||
|
||||
<string name="upload_server_imgur">imgur.com - de confiance</string>
|
||||
<string name="upload_server_imgur_explainer">Imgur peut modifier le fichier</string>
|
||||
|
||||
<string name="upload_server_nostrimg">nostrimg.com - de confiance</string>
|
||||
<string name="upload_server_nostrimg_explainer">NostrImg peut modifier le fichier</string>
|
||||
|
||||
<string name="upload_server_nostrbuild">nostr.build - de confiance</string>
|
||||
<string name="upload_server_nostrbuild_explainer">Nostr.build peut modifier le fichier</string>
|
||||
|
||||
<string name="upload_server_nostrfilesdev">nostrfiles.dev - de confiance</string>
|
||||
<string name="upload_server_nostrfilesdev_explainer">Nostrfiles.dev peut modifier le fichier</string>
|
||||
|
||||
<string name="upload_server_nostrcheckme">nostrcheck.me - de confiance</string>
|
||||
<string name="upload_server_nostrcheckme_explainer">nostrcheck.me peut modifier le fichier</string>
|
||||
|
||||
|
||||
<string name="upload_server_imgur_nip94">Verifiable Imgur (NIP-94)</string>
|
||||
<string name="upload_server_imgur_nip94_explainer">Vérifie si Imgur a modifié le fichier. Nouveau NIP: certains clients pourraient ne pas le voir</string>
|
||||
|
||||
<string name="upload_server_nostrimg_nip94">Verifiable NostrImg (NIP-94)</string>
|
||||
<string name="upload_server_nostrimg_nip94_explainer">Vérifie si NostrImg a modifié le fichier. Nouveau NIP: certains clients pourraient ne pas le voir</string>
|
||||
|
||||
<string name="upload_server_nostrbuild_nip94">Verifiable Nostr.build (NIP-94)</string>
|
||||
<string name="upload_server_nostrbuild_nip94_explainer">Vérifie si Nostr.build a modifié le fichier. Nouveau NIP: certains clients pourraient ne pas le voir</string>
|
||||
|
||||
<string name="upload_server_nostrfilesdev_nip94">Verifiable Nostrfiles.dev (NIP-94)</string>
|
||||
<string name="upload_server_nostrfilesdev_nip94_explainer">Vérifie si Nostrfiles.dev a modifié le fichier. Nouveau NIP: certains clients pourraient ne pas le voir</string>
|
||||
|
||||
<string name="upload_server_nostrcheckme_nip94">Verifiable Nostrcheck.me (NIP-94)</string>
|
||||
<string name="upload_server_nostrcheckme_nip94_explainer">Vérifie si Nostrcheck.me a modifié le fichier. Nouveau NIP: certains clients pourraient ne pas le voir</string>
|
||||
|
||||
<string name="upload_server_relays_nip95">Vos relais (NIP-95)</string>
|
||||
<string name="upload_server_relays_nip95_explainer">Les fichiers sont hébergés par vos relais. Nouveau NIP: vérifiez s'ils sont supportés</string>
|
||||
|
||||
<string name="connect_via_tor_short">Configuration Tor/Orbot</string>
|
||||
<string name="connect_via_tor">Se connecter à travers la configuration Orbot</string>
|
||||
|
||||
<string name="do_you_really_want_to_disable_tor_title">Se déconnecter de Orbot/Tor?</string>
|
||||
<string name="do_you_really_want_to_disable_tor_text">Vos données seront immédiatement transférées sur le réseau classique</string>
|
||||
<string name="yes">Oui</string>
|
||||
<string name="no">Non</string>
|
||||
|
||||
|
||||
<string name="follow_list_selection">Liste des Abonnés</string>
|
||||
<string name="follow_list_kind3follows">Tous les abonnements</string>
|
||||
<string name="follow_list_global">Global</string>
|
||||
<string name="connect_through_your_orbot_setup_markdown">
|
||||
## Se connecter à travers Tor avec Orbot
|
||||
\n\n1. Installe [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android)
|
||||
\n2. Démarre Orbot
|
||||
\n3. Dans Orbot, vérifie le port Socks. Par défaut 9050
|
||||
\n4. Si nécessaire change le port dans Orbot
|
||||
\n5. Configure le port Socks sur cet écran
|
||||
\n6. Appuyer sur le bouton Activer pour utiliser Orbot comme proxy
|
||||
</string>
|
||||
<string name="orbot_socks_port">Port Socks Orbot</string>
|
||||
<string name="invalid_port_number">Numéro de port invalide</string>
|
||||
<string name="use_orbot">Utiliser Orbot</string>
|
||||
<string name="disconnect_from_your_orbot_setup">Déconnecter Tor/Orbot</string>
|
||||
|
||||
<string name="app_notification_dms_channel_name">Messages privés</string>
|
||||
<string name="app_notification_dms_channel_description">Vous notifie lorsqu'un message privé est reçu</string>
|
||||
|
||||
<string name="app_notification_zaps_channel_name">Zaps reçus</string>
|
||||
<string name="app_notification_zaps_channel_description">Vous notifie lorsque quelqu'un vous zap</string>
|
||||
<string name="app_notification_zaps_channel_message">%1$s sats</string>
|
||||
<string name="app_notification_zaps_channel_message_from">De %1$s</string>
|
||||
<string name="app_notification_zaps_channel_message_for">pour %1$s</string>
|
||||
|
||||
|
||||
<string name="reply_notify">Notifier: </string>
|
||||
|
||||
<string name="channel_list_join_conversation">Rejoindre Conversation</string>
|
||||
<string name="channel_list_user_or_group_id">Utilisateur ou Groupe ID</string>
|
||||
<string name="channel_list_user_or_group_id_demo">npub, nevent ou hex</string>
|
||||
<string name="channel_list_create_channel">Créer</string>
|
||||
<string name="channel_list_join_channel">Rejoindre</string>
|
||||
|
||||
<string name="today">Aujourd'hui</string>
|
||||
|
||||
<string name="content_warning">Avertissement de contenu</string>
|
||||
<string name="content_warning_explanation">Ce message contient du contenu sensible que certaines personnes peuvent trouver offensant ou dérangeant</string>
|
||||
<string name="content_warning_hide_all_sensitive_content">Toujours cacher les contenus sensibles</string>
|
||||
<string name="content_warning_show_all_sensitive_content">Toujours afficher les contenus sensibles</string>
|
||||
<string name="content_warning_see_warnings">Toujours afficher les avertissements de contenu</string>
|
||||
|
||||
<string name="recommended_apps">Recommendations: </string>
|
||||
<string name="filter_spam_from_strangers">Filtrer le spam des étrangers</string>
|
||||
<string name="warn_when_posts_have_reports_from_your_follows">Avertir lorsque les messages ont été rapportés par vos abonnés</string>
|
||||
|
||||
<string name="new_reaction_symbol">Nouveau symbole de réaction</string>
|
||||
<string name="no_reaction_type_setup_long_press_to_change">Aucun type de réaction sélectionné. Appuyer longuement pour changer</string>
|
||||
|
||||
<string name="zapraiser">Zapraiser</string>
|
||||
<string name="zapraiser_explainer">Ajoute une quantité cible de sats pour ce message. Les clients compatible peuvent afficher une barre de progrès pour encourager les dons</string>
|
||||
<string name="zapraiser_target_amount_in_sats">Quantité ciblée en Sats</string>
|
||||
|
||||
<string name="sats_to_complete">Zapraiser à %1$s. %2$s sats pour objectif</string>
|
||||
<string name="read_from_relay">Lire depuis le Relay</string>
|
||||
<string name="write_to_relay">Écrire sur le Relay</string>
|
||||
<string name="an_error_occurred_trying_to_get_relay_information">Une erreur s'est produite en récupérant les informations du relay depuis %1$s</string>
|
||||
<string name="owner">Propriétaire</string>
|
||||
<string name="version">Version</string>
|
||||
<string name="software">Logiciel</string>
|
||||
<string name="contact">Contact</string>
|
||||
<string name="supports">NIPs supportés</string>
|
||||
<string name="admission_fees">Frais d'admission</string>
|
||||
<string name="payments_url">URL de payments</string>
|
||||
<string name="limitations">Limitations</string>
|
||||
<string name="countries">Pays</string>
|
||||
<string name="languages">Langages</string>
|
||||
<string name="tags">Tags</string>
|
||||
<string name="posting_policy">Politique de publication</string>
|
||||
<string name="message_length">Longueur du message</string>
|
||||
<string name="subscriptions">Abonnements</string>
|
||||
<string name="filters">Filtres</string>
|
||||
<string name="subscription_id_length">Longueur de l'id de souscription</string>
|
||||
<string name="minimum_prefix">Préfixe minimum</string>
|
||||
<string name="maximum_event_tags">Tags d'événement maximum</string>
|
||||
<string name="content_length">Longueur du contenu</string>
|
||||
<string name="minimum_pow">PoW minimum</string>
|
||||
<string name="auth">Authentification</string>
|
||||
<string name="payment">Paiement</string>
|
||||
<string name="cashu">Jeton Cashu</string>
|
||||
<string name="cashu_redeem">Échanger</string>
|
||||
<string name="no_lightning_address_set">Adresse Lightning non définie</string>
|
||||
<string name="copied_token_to_clipboard">Jeton copié dans le presse-papiers</string>
|
||||
|
||||
<string name="live_stream_live_tag">EN DIRECT</string>
|
||||
<string name="live_stream_offline_tag">DÉCONNECTÉ</string>
|
||||
<string name="live_stream_ended_tag">TERMINÉ</string>
|
||||
<string name="live_stream_planned_tag">PLANIFIÉ</string>
|
||||
|
||||
<string name="live_stream_is_offline">Livestream est déconnecté</string>
|
||||
<string name="live_stream_has_ended">Livestream terminé</string>
|
||||
<string name="are_you_sure_you_want_to_log_out">Se déconnecter supprime toutes vos informations locales. Assurez-vous d'avoir vos clés privées sauvegardées pour éviter de perdre votre compte. Voulez-vous continuer ?</string>
|
||||
<string name="followed_tags">Tags suivis</string>
|
||||
|
||||
<string name="relay_setup">Relays</string>
|
||||
|
||||
<string name="discover_live">Direct</string>
|
||||
<string name="discover_community">Communauté</string>
|
||||
<string name="discover_chat">Chats</string>
|
||||
<string name="community_approved_posts">Messages approuvés</string>
|
||||
|
||||
<string name="groups_no_descriptor">Ce groupe n'a pas de description ou de règles. Parlez au propriétaire pour en ajouter une</string>
|
||||
<string name="community_no_descriptor">Cette communauté n'a pas de description. Parlez au propriétaire pour en ajouter une</string>
|
||||
|
||||
<string name="add_sensitive_content_label">Contenu sensible</string>
|
||||
<string name="add_sensitive_content_description">Ajouter un avertissement de contenu sensible avant de montrer ce contenu</string>
|
||||
<string name="settings">Paramètres</string>
|
||||
<string name="connectivity_type_always">Toujours</string>
|
||||
<string name="connectivity_type_wifi_only">Wifi uniquement</string>
|
||||
<string name="connectivity_type_never">Jamais</string>
|
||||
|
||||
<string name="system">Système</string>
|
||||
<string name="light">Clair</string>
|
||||
<string name="dark">Sombre</string>
|
||||
<string name="application_preferences">Préférences de l'application</string>
|
||||
<string name="language">Langage</string>
|
||||
<string name="theme">Thème</string>
|
||||
<string name="automatically_load_images_gifs">Chargement automatique des images/gifs</string>
|
||||
<string name="automatically_play_videos">Démarrage automatique des vidéos</string>
|
||||
<string name="automatically_show_url_preview">Prévisualisation automatique des liens</string>
|
||||
<string name="load_image">Charger l'image</string>
|
||||
|
||||
<string name="spamming_users">Spammeurs</string>
|
||||
|
||||
<string name="muted_button">Silencieux. Cliquer pour réactiver le son</string>
|
||||
<string name="mute_button">Son activé. Cliquer pour mettre en silencieux</string>
|
||||
<string name="search_button">Recherche d'enregistrements locaux et distants</string>
|
||||
|
||||
<string name="nip05_verified">L'adresse Nostr a été vérfiée</string>
|
||||
<string name="nip05_failed">La vérification de l'adresse Nostr a échouée</string>
|
||||
<string name="nip05_checking">Vérification de l'adresse Nostr</string>
|
||||
<string name="select_deselect_all">Tout sélectionner/désélectionner</string>
|
||||
<string name="default_relays">Défaut</string>
|
||||
<string name="select_a_relay_to_continue">Sélectionner un relay pour continuer</string>
|
||||
|
||||
<string name="zap_forward_title">Transférer les Zaps à:</string>
|
||||
<string name="zap_forward_explainer">Les clients compatibles transmettront des zaps sur l'adresse LN ou le profil Utilisateur ci-dessous au lieu du vôtre.</string>
|
||||
|
||||
<string name="geohash_title">Révéler la localisation comme </string>
|
||||
<string name="geohash_explainer">Ajoute un Geohash de votre emplacement au message. Le public saura que vous êtes à moins de 5km de l'emplacement actuel</string>
|
||||
|
||||
<string name="add_sensitive_content_explainer">Ajoute un avertissement de contenu sensible avant de montrer votre contenu. C'est idéal pour tout contenu NSFW ou contenu que certaines personnes peuvent trouver offensant ou dérangeant</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user