Add Block button and dialog

This commit is contained in:
maxmoney21m
2023-03-15 13:40:59 +08:00
parent e94d2b5340
commit ad4e6d6596
7 changed files with 160 additions and 59 deletions
@@ -47,7 +47,8 @@ private object PrefKeys {
const val TRANSLATE_TO = "translateTo" const val TRANSLATE_TO = "translateTo"
const val ZAP_AMOUNTS = "zapAmounts" const val ZAP_AMOUNTS = "zapAmounts"
const val LATEST_CONTACT_LIST = "latestContactList" const val LATEST_CONTACT_LIST = "latestContactList"
const val HIDE_DELETE_REQUEST_INFO = "hideDeleteRequestInfo" const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog"
const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog"
val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } val LAST_READ: (String) -> String = { route -> "last_read_route_$route" }
} }
@@ -183,7 +184,8 @@ object LocalPreferences {
putString(PrefKeys.TRANSLATE_TO, account.translateTo) putString(PrefKeys.TRANSLATE_TO, account.translateTo)
putString(PrefKeys.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices)) putString(PrefKeys.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices))
putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList))
putBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, account.hideDeleteRequestInfo) putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog)
putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog)
putString(PrefKeys.DISPLAY_NAME, account.userProfile().toBestDisplayName()) putString(PrefKeys.DISPLAY_NAME, account.userProfile().toBestDisplayName())
putString(PrefKeys.PROFILE_PICTURE_URL, account.userProfile().profilePicture()) putString(PrefKeys.PROFILE_PICTURE_URL, account.userProfile().profilePicture())
}.apply() }.apply()
@@ -230,7 +232,8 @@ object LocalPreferences {
mapOf() mapOf()
} }
val hideDeleteRequestInfo = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, false) val hideDeleteRequestDialog = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false)
val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false)
return Account( return Account(
Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()),
@@ -241,7 +244,8 @@ object LocalPreferences {
languagePreferences, languagePreferences,
translateTo, translateTo,
zapAmountChoices, zapAmountChoices,
hideDeleteRequestInfo, hideDeleteRequestDialog,
hideBlockAlertDialog,
latestContactList latestContactList
) )
} }
@@ -289,8 +293,8 @@ object LocalPreferences {
stringPrefs.forEach { userPrefs.putString(it, appPrefs.getString(it, null)) } stringPrefs.forEach { userPrefs.putString(it, appPrefs.getString(it, null)) }
stringSetPrefs.forEach { userPrefs.putStringSet(it, appPrefs.getStringSet(it, null)) } stringSetPrefs.forEach { userPrefs.putStringSet(it, appPrefs.getStringSet(it, null)) }
userPrefs.putBoolean( userPrefs.putBoolean(
PrefKeys.HIDE_DELETE_REQUEST_INFO, PrefKeys.HIDE_DELETE_REQUEST_DIALOG,
appPrefs.getBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, false) appPrefs.getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false)
) )
}.apply() }.apply()
} }
@@ -59,7 +59,8 @@ class Account(
var languagePreferences: Map<String, String> = mapOf(), var languagePreferences: Map<String, String> = mapOf(),
var translateTo: String = Locale.getDefault().language, var translateTo: String = Locale.getDefault().language,
var zapAmountChoices: List<Long> = listOf(500L, 1000L, 5000L), var zapAmountChoices: List<Long> = listOf(500L, 1000L, 5000L),
var hideDeleteRequestInfo: Boolean = false, var hideDeleteRequestDialog: Boolean = false,
var hideBlockAlertDialog: Boolean = false,
var backupContactList: ContactListEvent? = null var backupContactList: ContactListEvent? = null
) { ) {
var transientHiddenUsers: Set<String> = setOf() var transientHiddenUsers: Set<String> = setOf()
@@ -553,8 +554,13 @@ class Account(
saveable.invalidateData() saveable.invalidateData()
} }
fun setHideDeleteRequestInfo() { fun setHideDeleteRequestDialog() {
hideDeleteRequestInfo = true hideDeleteRequestDialog = true
saveable.invalidateData()
}
fun setHideBlockAlertDialog() {
hideBlockAlertDialog = true
saveable.invalidateData() saveable.invalidateData()
} }
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -16,6 +17,8 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.AlertDialog import androidx.compose.material.AlertDialog
import androidx.compose.material.Button import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.Divider import androidx.compose.material.Divider
import androidx.compose.material.Icon import androidx.compose.material.Icon
@@ -30,6 +33,7 @@ import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.FormatQuote import androidx.compose.material.icons.filled.FormatQuote
import androidx.compose.material.icons.filled.PersonAdd import androidx.compose.material.icons.filled.PersonAdd
import androidx.compose.material.icons.filled.PersonRemove import androidx.compose.material.icons.filled.PersonRemove
import androidx.compose.material.icons.filled.Report
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -59,9 +63,10 @@ import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.components.SelectTextDialog import com.vitorpamplona.amethyst.ui.components.SelectTextDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
import com.vitorpamplona.amethyst.ui.theme.WarningColor
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
fun lightenColor(color: Color, amount: Float): Color { private fun lightenColor(color: Color, amount: Float): Color {
var argb = color.toArgb() var argb = color.toArgb()
val hslOut = floatArrayOf(0f, 0f, 0f) val hslOut = floatArrayOf(0f, 0f, 0f)
ColorUtils.colorToHSL(argb, hslOut) ColorUtils.colorToHSL(argb, hslOut)
@@ -73,7 +78,7 @@ fun lightenColor(color: Color, amount: Float): Color {
val externalLinkForNote = { note: Note -> "https://snort.social/e/${note.idNote()}" } val externalLinkForNote = { note: Note -> "https://snort.social/e/${note.idNote()}" }
@Composable @Composable
fun VerticalDivider(color: Color) = private fun VerticalDivider(color: Color) =
Divider( Divider(
color = color, color = color,
modifier = Modifier modifier = Modifier
@@ -90,8 +95,9 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var showSelectTextDialog by remember { mutableStateOf(false) } var showSelectTextDialog by remember { mutableStateOf(false) }
var showDeleteAlertDialog by remember { mutableStateOf(false) } var showDeleteAlertDialog by remember { mutableStateOf(false) }
var showBlockAlertDialog by remember { mutableStateOf(false) }
var showReportDialog by remember { mutableStateOf(false) } var showReportDialog by remember { mutableStateOf(false) }
val isOwnNote = note.author == accountViewModel.userProfile() val isOwnNote = note.author == accountViewModel.accountLiveData.value?.account?.userProfile()
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author!!) val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author!!)
val showToast = { stringResource: Int -> val showToast = { stringResource: Int ->
@@ -138,11 +144,16 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
onDismiss() onDismiss()
} }
if (note.author != accountViewModel.accountLiveData.value?.account?.userProfile()) { if (!isOwnNote) {
VerticalDivider(primaryLight) VerticalDivider(primaryLight)
NoteQuickActionItem(Icons.Default.Block, "Block") { NoteQuickActionItem(Icons.Default.Block, stringResource(R.string.quick_action_block)) {
showReportDialog = true if (accountViewModel.hideBlockAlertDialog) {
note.author?.let { accountViewModel.hide(it) }
onDismiss()
} else {
showBlockAlertDialog = true
}
} }
} }
} }
@@ -155,7 +166,7 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
Row(modifier = Modifier.height(IntrinsicSize.Min)) { Row(modifier = Modifier.height(IntrinsicSize.Min)) {
if (isOwnNote) { if (isOwnNote) {
NoteQuickActionItem(Icons.Default.Delete, stringResource(R.string.quick_action_delete)) { NoteQuickActionItem(Icons.Default.Delete, stringResource(R.string.quick_action_delete)) {
if (accountViewModel.hideDeleteRequestInfo()) { if (accountViewModel.hideDeleteRequestDialog) {
accountViewModel.delete(note) accountViewModel.delete(note)
onDismiss() onDismiss()
} else { } else {
@@ -198,7 +209,14 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
ContextCompat.startActivity(context, shareIntent, null) ContextCompat.startActivity(context, shareIntent, null)
onDismiss() onDismiss()
} }
VerticalDivider(primaryLight)
if (!isOwnNote) {
VerticalDivider(primaryLight)
NoteQuickActionItem(Icons.Default.Report, stringResource(R.string.quick_action_report)) {
showReportDialog = true
}
}
} }
} }
} }
@@ -212,7 +230,17 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
} }
if (showDeleteAlertDialog) { if (showDeleteAlertDialog) {
DeleteAlertDialog(note, accountViewModel, onDismiss) DeleteAlertDialog(note, accountViewModel) {
showDeleteAlertDialog = false
onDismiss()
}
}
if (showBlockAlertDialog) {
BlockAlertDialog(note, accountViewModel) {
showBlockAlertDialog = false
onDismiss()
}
} }
if (showReportDialog) { if (showReportDialog) {
@@ -245,14 +273,65 @@ fun NoteQuickActionItem(icon: ImageVector, label: String, onClick: () -> Unit) {
} }
@Composable @Composable
fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) { fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) =
QuickActionAlertDialog(
title = stringResource(R.string.quick_action_request_deletion_alert_title),
textContent = stringResource(R.string.quick_action_request_deletion_alert_body),
buttonIcon = Icons.Default.Delete,
buttonText = stringResource(R.string.quick_action_delete_dialog_btn),
onClickDoOnce = {
accountViewModel.delete(note)
onDismiss()
},
onClickDontShowAgain = {
accountViewModel.delete(note)
accountViewModel.dontShowDeleteRequestDialog()
onDismiss()
},
onDismiss = onDismiss
)
@Composable
private fun BlockAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) =
QuickActionAlertDialog(
title = stringResource(R.string.report_dialog_block_hide_user_btn),
textContent = stringResource(R.string.report_dialog_blocking_a_user),
buttonIcon = Icons.Default.Block,
buttonText = stringResource(R.string.quick_action_block_dialog_btn),
buttonColors = ButtonDefaults.buttonColors(
backgroundColor = WarningColor,
contentColor = Color.White
),
onClickDoOnce = {
note.author?.let { accountViewModel.hide(it) }
onDismiss()
},
onClickDontShowAgain = {
note.author?.let { accountViewModel.hide(it) }
accountViewModel.dontShowBlockAlertDialog()
onDismiss()
},
onDismiss = onDismiss
)
@Composable
private fun QuickActionAlertDialog(
title: String,
textContent: String,
buttonIcon: ImageVector,
buttonText: String,
buttonColors: ButtonColors = ButtonDefaults.buttonColors(),
onClickDoOnce: () -> Unit,
onClickDontShowAgain: () -> Unit,
onDismiss: () -> Unit
) {
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { title = {
Text(text = stringResource(R.string.quick_action_request_deletion_alert_title)) Text(title)
}, },
text = { text = {
Text(text = stringResource(R.string.quick_action_request_deletion_alert_body)) Text(textContent)
}, },
buttons = { buttons = {
Row( Row(
@@ -261,19 +340,20 @@ fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss:
.fillMaxWidth(), .fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
TextButton( TextButton(onClick = onClickDontShowAgain) {
onClick = {
accountViewModel.setHideDeleteRequestInfo()
accountViewModel.delete(note)
onDismiss()
}
) {
Text(stringResource(R.string.quick_action_dont_show_again_button)) Text(stringResource(R.string.quick_action_dont_show_again_button))
} }
Button( Button(onClick = onClickDoOnce, colors = buttonColors) {
onClick = { accountViewModel.delete(note); onDismiss() } Row(
) { verticalAlignment = Alignment.CenterVertically
Text(stringResource(R.string.quick_action_delete_button)) ) {
Icon(
imageVector = buttonIcon,
contentDescription = null
)
Spacer(Modifier.width(8.dp))
Text(buttonText)
}
} }
} }
} }
@@ -129,11 +129,17 @@ class AccountViewModel(private val account: Account) : ViewModel() {
return account.userProfile().isFollowing(user) return account.userProfile().isFollowing(user)
} }
fun hideDeleteRequestInfo(): Boolean { val hideDeleteRequestDialog: Boolean
return account.hideDeleteRequestInfo get() = account.hideDeleteRequestDialog
fun dontShowDeleteRequestDialog() {
account.setHideDeleteRequestDialog()
} }
fun setHideDeleteRequestInfo() { val hideBlockAlertDialog: Boolean
account.setHideDeleteRequestInfo() get() = account.hideBlockAlertDialog
fun dontShowBlockAlertDialog() {
account.setHideBlockAlertDialog()
} }
} }
@@ -40,6 +40,7 @@ import androidx.compose.ui.window.DialogProperties
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.ReportEvent import com.vitorpamplona.amethyst.service.model.ReportEvent
import com.vitorpamplona.amethyst.ui.theme.WarningColor
@Composable @Composable
fun ReportNoteDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) { fun ReportNoteDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) {
@@ -138,8 +139,6 @@ fun ReportNoteDialog(note: Note, accountViewModel: AccountViewModel, onDismiss:
} }
} }
private val warningColor = Color(0xFFC62828)
@Composable @Composable
private fun SpacerH16() = Spacer(modifier = Modifier.height(16.dp)) private fun SpacerH16() = Spacer(modifier = Modifier.height(16.dp))
@@ -155,7 +154,7 @@ private fun SectionHeader(text: String) = Text(
private fun ActionButton(text: String, icon: ImageVector, enabled: Boolean = true, onClick: () -> Unit) = Button( private fun ActionButton(text: String, icon: ImageVector, enabled: Boolean = true, onClick: () -> Unit) = Button(
onClick = onClick, onClick = onClick,
enabled = enabled, enabled = enabled,
colors = ButtonDefaults.buttonColors(backgroundColor = warningColor), colors = ButtonDefaults.buttonColors(backgroundColor = WarningColor),
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Row( Row(
@@ -12,3 +12,5 @@ val Following = Color(0xFF03DAC5)
val Nip05 = Color(0xFF01BAFF) val Nip05 = Color(0xFF01BAFF)
val FollowsFollow = Color.Yellow val FollowsFollow = Color.Yellow
val NIP05Verified = Color.Blue val NIP05Verified = Color.Blue
val WarningColor = Color(0xFFC62828)
+24 -20
View File
@@ -198,6 +198,23 @@
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">Copied authors @npub to clipboard</string> <string name="copied_user_id_to_clipboard" tools:ignore="Typos">Copied authors @npub to clipboard</string>
<string name="copied_note_id_to_clipboard" tools:ignore="Typos">Copied note ID (@note1) to clipboard</string> <string name="copied_note_id_to_clipboard" tools:ignore="Typos">Copied note ID (@note1) to clipboard</string>
<string name="select_text_dialog_top">Select Text</string> <string name="select_text_dialog_top">Select Text</string>
<string name="github" translatable="false">Github Gist w/ Proof</string>
<string name="telegram" translatable="false">Telegram</string>
<string name="mastodon" translatable="false">Mastodon Post ID w/ Proof</string>
<string name="twitter" translatable="false">Twitter Status w/ Proof</string>
<string name="github_proof_url_template" translatable="false">https://gist.github.com/&lt;user&gt;/&lt;gist&gt;</string>
<string name="telegram_proof_url_template" translatable="false">https://t.me/&lt;proof post&gt;</string>
<string name="mastodon_proof_url_template" translatable="false">https://&lt;server&gt;/&lt;user&gt;/&lt;proof post&gt;</string>
<string name="twitter_proof_url_template" translatable="false">https://twitter.com/&lt;user&gt;/status/&lt;proof post&gt;</string>
<string name="private_conversation_notification">"&lt;Unable to decrypt private message&gt;\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s."</string>
<string name="account_switch_add_account_dialog_title">Add New Account</string>
<string name="drawer_accounts">Accounts</string>
<string name="account_switch_select_account">Select Account</string>
<string name="account_switch_add_account_btn">Add New Account</string>
<string name="account_switch_active_account">Active account</string>
<string name="account_switch_has_private_key">Has private key</string>
<string name="account_switch_pubkey_only">Read only, no private key</string>
<string name="back">Back</string>
<string name="quick_action_select">Select</string> <string name="quick_action_select">Select</string>
<string name="quick_action_share_browser_link">Share Browser Link</string> <string name="quick_action_share_browser_link">Share Browser Link</string>
<string name="quick_action_share">Share</string> <string name="quick_action_share">Share</string>
@@ -209,38 +226,25 @@
<string name="quick_action_follow">Follow</string> <string name="quick_action_follow">Follow</string>
<string name="quick_action_request_deletion_alert_title">Request Deletion</string> <string name="quick_action_request_deletion_alert_title">Request Deletion</string>
<string name="quick_action_request_deletion_alert_body">Amethyst will request that your note be deleted from the relays you are currently connected to. There is no guarantee that your note will be permanently deleted from those relays, or from other relays where it may be stored.</string> <string name="quick_action_request_deletion_alert_body">Amethyst will request that your note be deleted from the relays you are currently connected to. There is no guarantee that your note will be permanently deleted from those relays, or from other relays where it may be stored.</string>
<string name="github" translatable="false">Github Gist w/ Proof</string> <string name="quick_action_block_dialog_btn">Block</string>
<string name="telegram" translatable="false">Telegram</string> <string name="quick_action_delete_dialog_btn">Delete</string>
<string name="mastodon" translatable="false">Mastodon Post ID w/ Proof</string> <string name="quick_action_block">Block</string>
<string name="twitter" translatable="false">Twitter Status w/ Proof</string> <string name="quick_action_report">Report</string>
<string name="github_proof_url_template" translatable="false">https://gist.github.com/&lt;user&gt;/&lt;gist&gt;</string>
<string name="telegram_proof_url_template" translatable="false">https://t.me/&lt;proof post&gt;</string>
<string name="mastodon_proof_url_template" translatable="false">https://&lt;server&gt;/&lt;user&gt;/&lt;proof post&gt;</string>
<string name="twitter_proof_url_template" translatable="false">https://twitter.com/&lt;user&gt;/status/&lt;proof post&gt;</string>
<string name="private_conversation_notification">"&lt;Unable to decrypt private message&gt;\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s."</string>
<string name="quick_action_delete_button">Delete</string> <string name="quick_action_delete_button">Delete</string>
<string name="quick_action_dont_show_again_button">Don\'t show again</string> <string name="quick_action_dont_show_again_button">Don\'t show again</string>
<string name="account_switch_add_account_dialog_title">Add New Account</string>
<string name="drawer_accounts">Accounts</string>
<string name="account_switch_select_account">Select Account</string>
<string name="account_switch_add_account_btn">Add New Account</string>
<string name="account_switch_active_account">Active account</string>
<string name="account_switch_has_private_key">Has private key</string>
<string name="account_switch_pubkey_only">Read only, no private key</string>
<string name="back">Back</string>
<string name="report_dialog_spam">Spam or scams</string> <string name="report_dialog_spam">Spam or scams</string>
<string name="report_dialog_profanity">Profanity or hateful conduct</string> <string name="report_dialog_profanity">Profanity or hateful conduct</string>
<string name="report_dialog_impersonation">Malicious impersonation</string> <string name="report_dialog_impersonation">Malicious impersonation</string>
<string name="report_dialog_nudity">Nudity or graphic content</string> <string name="report_dialog_nudity">Nudity or graphic content</string>
<string name="report_dialog_illegal">Illegal Behavior</string> <string name="report_dialog_illegal">Illegal Behavior</string>
<string name="report_dialog_blocking_a_user">Blocking a user will hide their content in your app. Your notes are still publicly viewable, including to people you block.</string> <string name="report_dialog_blocking_a_user">Blocking a user will hide their content in your app. Your notes are still publicly viewable, including to people you block. Blocked users are listed on the Security Filters screen.</string>
<string name="report_dialog_block_hide_user_btn"><![CDATA[Block & Hide User]]></string> <string name="report_dialog_block_hide_user_btn"><![CDATA[Block & Hide User]]></string>
<string name="report_dialog_report_btn">Report Abuse</string> <string name="report_dialog_report_btn">Report Abuse</string>
<string name="report_dialog_reminder_public">All reports posted will be publicly visible.</string> <string name="report_dialog_reminder_public">All reports posted will be publicly visible.</string>
<string name="report_dialog_additional_reason_placeholder">Optionally provide additional context about your report...</string> <string name="report_dialog_additional_reason_placeholder">Optionally provide additional context about your report</string>
<string name="report_dialog_additional_reason_label">Additional Context</string> <string name="report_dialog_additional_reason_label">Additional Context</string>
<string name="report_dialog_select_reason_label">Reason</string> <string name="report_dialog_select_reason_label">Reason</string>
<string name="report_dialog_select_reason_placeholder">Select a reason...</string> <string name="report_dialog_select_reason_placeholder">Select a reason</string>
<string name="report_dialog_post_report_btn">Post Report</string> <string name="report_dialog_post_report_btn">Post Report</string>
</resources> </resources>