Merge pull request #275 from maxmoney21m/feature/216-merge-reports
Add separate screen for report & block
This commit is contained in:
@@ -68,6 +68,7 @@ render.experimental.xml
|
|||||||
.idea/**/caches/
|
.idea/**/caches/
|
||||||
.idea/**/libraries/
|
.idea/**/libraries/
|
||||||
.idea/**/shelf/
|
.idea/**/shelf/
|
||||||
|
.idea/**/codeStyles
|
||||||
.idea/**/workspace.xml
|
.idea/**/workspace.xml
|
||||||
.idea/**/tasks.xml
|
.idea/**/tasks.xml
|
||||||
.idea/**/.name
|
.idea/**/.name
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -170,7 +171,7 @@ class Account(
|
|||||||
return LnZapRequestEvent.create(userPubKeyHex, userProfile().latestContactList?.relays()?.keys?.ifEmpty { null } ?: localRelays.map { it.url }.toSet(), loggedIn.privKey!!)
|
return LnZapRequestEvent.create(userPubKeyHex, userProfile().latestContactList?.relays()?.keys?.ifEmpty { null } ?: localRelays.map { it.url }.toSet(), loggedIn.privKey!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun report(note: Note, type: ReportEvent.ReportType) {
|
fun report(note: Note, type: ReportEvent.ReportType, content: String = "") {
|
||||||
if (!isWriteable()) return
|
if (!isWriteable()) return
|
||||||
|
|
||||||
if (note.hasReacted(userProfile(), "⚠️")) {
|
if (note.hasReacted(userProfile(), "⚠️")) {
|
||||||
@@ -185,7 +186,7 @@ class Account(
|
|||||||
}
|
}
|
||||||
|
|
||||||
note.event?.let {
|
note.event?.let {
|
||||||
val event = ReportEvent.create(it, type, loggedIn.privKey!!)
|
val event = ReportEvent.create(it, type, loggedIn.privKey!!, content = content)
|
||||||
Client.send(event)
|
Client.send(event)
|
||||||
LocalCache.consume(event, null)
|
LocalCache.consume(event, null)
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,13 @@ class ReportEvent(
|
|||||||
companion object {
|
companion object {
|
||||||
const val kind = 1984
|
const val kind = 1984
|
||||||
|
|
||||||
fun create(reportedPost: EventInterface, type: ReportType, privateKey: ByteArray, createdAt: Long = Date().time / 1000): ReportEvent {
|
fun create(
|
||||||
val content = ""
|
reportedPost: EventInterface,
|
||||||
|
type: ReportType,
|
||||||
|
privateKey: ByteArray,
|
||||||
|
content: String = "",
|
||||||
|
createdAt: Long = Date().time / 1000
|
||||||
|
): ReportEvent {
|
||||||
val reportPostTag = listOf("e", reportedPost.id(), type.name.lowercase())
|
val reportPostTag = listOf("e", reportedPost.id(), type.name.lowercase())
|
||||||
val reportAuthorTag = listOf("p", reportedPost.pubKey(), type.name.lowercase())
|
val reportAuthorTag = listOf("p", reportedPost.pubKey(), type.name.lowercase())
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Divider
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TextSpinner(label: String, placeholder: String, options: List<String>, onSelect: (Int) -> Unit, modifier: Modifier = Modifier) {
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
var optionsShowing by remember { mutableStateOf(false) }
|
||||||
|
var currentText by remember { mutableStateOf(placeholder) }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = currentText,
|
||||||
|
onValueChange = {},
|
||||||
|
readOnly = true,
|
||||||
|
label = { Text(label) },
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.matchParentSize()
|
||||||
|
.clickable(
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
indication = null
|
||||||
|
) {
|
||||||
|
optionsShowing = true
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionsShowing) {
|
||||||
|
options.isNotEmpty().also {
|
||||||
|
SpinnerSelectionDialog(options = options, onDismiss = { optionsShowing = false }) {
|
||||||
|
currentText = options[it]
|
||||||
|
optionsShowing = false
|
||||||
|
onSelect(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SpinnerSelectionDialog(options: List<String>, onDismiss: () -> Unit, onSelect: (Int) -> Unit) {
|
||||||
|
Dialog(onDismissRequest = onDismiss) {
|
||||||
|
Surface(
|
||||||
|
border = BorderStroke(0.25.dp, Color.LightGray),
|
||||||
|
shape = RoundedCornerShape(5.dp)
|
||||||
|
) {
|
||||||
|
LazyColumn() {
|
||||||
|
itemsIndexed(options) { index, item ->
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp, 16.dp)
|
||||||
|
.clickable {
|
||||||
|
onSelect(index)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = item, color = MaterialTheme.colors.onSurface)
|
||||||
|
}
|
||||||
|
if (index < options.lastIndex) {
|
||||||
|
Divider(color = Color.LightGray, thickness = 0.25.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -344,7 +344,7 @@ fun ChatroomMessageCompose(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteDropDownMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
NoteQuickActionMenu(note, popupExpanded, { popupExpanded = false }, accountViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.ui.components.RobohashFallbackAsyncImage
|
|||||||
import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer
|
import com.vitorpamplona.amethyst.ui.components.TranslateableRichTextViewer
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Following
|
import com.vitorpamplona.amethyst.ui.theme.Following
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -779,6 +780,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
|||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
val appContext = LocalContext.current.applicationContext
|
val appContext = LocalContext.current.applicationContext
|
||||||
val actContext = LocalContext.current
|
val actContext = LocalContext.current
|
||||||
|
var reportDialogShowing by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = popupExpanded,
|
expanded = popupExpanded,
|
||||||
@@ -832,49 +834,16 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
|||||||
}
|
}
|
||||||
if (note.author != accountViewModel.accountLiveData.value?.account?.userProfile()) {
|
if (note.author != accountViewModel.accountLiveData.value?.account?.userProfile()) {
|
||||||
Divider()
|
Divider()
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = { reportDialogShowing = true }) {
|
||||||
note.author?.let {
|
Text("Block / Report")
|
||||||
accountViewModel.hide(it)
|
|
||||||
}; onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.block_hide_user))
|
|
||||||
}
|
|
||||||
Divider()
|
|
||||||
DropdownMenuItem(onClick = {
|
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.SPAM)
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.report_spam_scam))
|
|
||||||
}
|
|
||||||
DropdownMenuItem(onClick = {
|
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.PROFANITY)
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.report_hateful_speech))
|
|
||||||
}
|
|
||||||
DropdownMenuItem(onClick = {
|
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.IMPERSONATION)
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.report_impersonation))
|
|
||||||
}
|
|
||||||
DropdownMenuItem(onClick = {
|
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.NUDITY)
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.report_nudity_porn))
|
|
||||||
}
|
|
||||||
DropdownMenuItem(onClick = {
|
|
||||||
accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL)
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.report_illegal_behaviour))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reportDialogShowing) {
|
||||||
|
ReportNoteDialog(note = note, accountViewModel = accountViewModel) {
|
||||||
|
reportDialogShowing = false
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -24,11 +27,13 @@ import androidx.compose.material.Text
|
|||||||
import androidx.compose.material.TextButton
|
import androidx.compose.material.TextButton
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AlternateEmail
|
import androidx.compose.material.icons.filled.AlternateEmail
|
||||||
|
import androidx.compose.material.icons.filled.Block
|
||||||
import androidx.compose.material.icons.filled.ContentCopy
|
import androidx.compose.material.icons.filled.ContentCopy
|
||||||
import androidx.compose.material.icons.filled.Delete
|
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
|
||||||
@@ -57,9 +62,11 @@ import com.vitorpamplona.amethyst.R
|
|||||||
import com.vitorpamplona.amethyst.model.Note
|
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.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)
|
||||||
@@ -71,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
|
||||||
@@ -88,7 +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) }
|
||||||
val isOwnNote = note.author == accountViewModel.userProfile()
|
var showBlockAlertDialog by remember { mutableStateOf(false) }
|
||||||
|
var showReportDialog by remember { mutableStateOf(false) }
|
||||||
|
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 ->
|
||||||
@@ -134,6 +143,19 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
|
|||||||
showToast(R.string.copied_note_id_to_clipboard)
|
showToast(R.string.copied_note_id_to_clipboard)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isOwnNote) {
|
||||||
|
VerticalDivider(primaryLight)
|
||||||
|
|
||||||
|
NoteQuickActionItem(Icons.Default.Block, stringResource(R.string.quick_action_block)) {
|
||||||
|
if (accountViewModel.hideBlockAlertDialog) {
|
||||||
|
note.author?.let { accountViewModel.hide(it) }
|
||||||
|
onDismiss()
|
||||||
|
} else {
|
||||||
|
showBlockAlertDialog = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Divider(
|
Divider(
|
||||||
color = primaryLight,
|
color = primaryLight,
|
||||||
@@ -144,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 {
|
||||||
@@ -187,6 +209,14 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
|
|||||||
ContextCompat.startActivity(context, shareIntent, null)
|
ContextCompat.startActivity(context, shareIntent, null)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isOwnNote) {
|
||||||
|
VerticalDivider(primaryLight)
|
||||||
|
|
||||||
|
NoteQuickActionItem(Icons.Default.Report, stringResource(R.string.quick_action_report)) {
|
||||||
|
showReportDialog = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,36 +230,24 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (showDeleteAlertDialog) {
|
if (showDeleteAlertDialog) {
|
||||||
AlertDialog(
|
DeleteAlertDialog(note, accountViewModel) {
|
||||||
onDismissRequest = { onDismiss() },
|
showDeleteAlertDialog = false
|
||||||
title = {
|
onDismiss()
|
||||||
Text(text = stringResource(R.string.quick_action_request_deletion_alert_title))
|
}
|
||||||
},
|
}
|
||||||
text = {
|
|
||||||
Text(text = stringResource(R.string.quick_action_request_deletion_alert_body))
|
if (showBlockAlertDialog) {
|
||||||
},
|
BlockAlertDialog(note, accountViewModel) {
|
||||||
buttons = {
|
showBlockAlertDialog = false
|
||||||
Row(
|
onDismiss()
|
||||||
modifier = Modifier.padding(all = 8.dp).fillMaxWidth(),
|
}
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
}
|
||||||
) {
|
|
||||||
TextButton(
|
if (showReportDialog) {
|
||||||
onClick = {
|
ReportNoteDialog(note, accountViewModel) {
|
||||||
accountViewModel.setHideDeleteRequestInfo()
|
showReportDialog = false
|
||||||
accountViewModel.delete(note)
|
onDismiss()
|
||||||
onDismiss()
|
}
|
||||||
}
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.quick_action_dont_show_again_button))
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = { accountViewModel.delete(note); onDismiss() }
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.quick_action_delete_button))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,9 +263,99 @@ fun NoteQuickActionItem(icon: ImageVector, label: String, onClick: () -> Unit) {
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
imageVector = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(24.dp).padding(bottom = 5.dp),
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
.padding(bottom = 5.dp),
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
Text(text = label, fontSize = 12.sp, color = Color.White, textAlign = TextAlign.Center)
|
Text(text = label, fontSize = 12.sp, color = Color.White, textAlign = TextAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
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(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
title = {
|
||||||
|
Text(title)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(textContent)
|
||||||
|
},
|
||||||
|
buttons = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(all = 8.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
TextButton(onClick = onClickDontShowAgain) {
|
||||||
|
Text(stringResource(R.string.quick_action_dont_show_again_button))
|
||||||
|
}
|
||||||
|
Button(onClick = onClickDoOnce, colors = buttonColors) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = buttonIcon,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text(buttonText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+12
-6
@@ -73,8 +73,8 @@ class AccountViewModel(private val account: Account) : ViewModel() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun report(note: Note, type: ReportEvent.ReportType) {
|
fun report(note: Note, type: ReportEvent.ReportType, content: String = "") {
|
||||||
account.report(note, type)
|
account.report(note, type, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun report(user: User, type: ReportEvent.ReportType) {
|
fun report(user: User, type: ReportEvent.ReportType) {
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.Button
|
||||||
|
import androidx.compose.material.ButtonDefaults
|
||||||
|
import androidx.compose.material.Divider
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.IconButton
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.OutlinedTextField
|
||||||
|
import androidx.compose.material.Scaffold
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TopAppBar
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Block
|
||||||
|
import androidx.compose.material.icons.filled.Report
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.service.model.ReportEvent
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.WarningColor
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReportNoteDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: () -> Unit) {
|
||||||
|
val reportTypes = listOf(
|
||||||
|
Pair(ReportEvent.ReportType.SPAM, stringResource(R.string.report_dialog_spam)),
|
||||||
|
Pair(ReportEvent.ReportType.PROFANITY, stringResource(R.string.report_dialog_profanity)),
|
||||||
|
Pair(ReportEvent.ReportType.IMPERSONATION, stringResource(R.string.report_dialog_impersonation)),
|
||||||
|
Pair(ReportEvent.ReportType.NUDITY, stringResource(R.string.report_dialog_nudity)),
|
||||||
|
Pair(ReportEvent.ReportType.ILLEGAL, stringResource(R.string.report_dialog_illegal))
|
||||||
|
)
|
||||||
|
|
||||||
|
val reasonOptions = reportTypes.map { it.second }
|
||||||
|
var additionalReason by remember { mutableStateOf("") }
|
||||||
|
var selectedReason by remember { mutableStateOf(-1) }
|
||||||
|
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||||
|
) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text(text = "Block and Report") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onDismiss) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.back),
|
||||||
|
tint = MaterialTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backgroundColor = MaterialTheme.colors.surface,
|
||||||
|
elevation = 0.dp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { pad ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(16.dp, pad.calculateTopPadding(), 16.dp, pad.calculateBottomPadding()),
|
||||||
|
verticalArrangement = Arrangement.SpaceAround
|
||||||
|
) {
|
||||||
|
SpacerH16()
|
||||||
|
SectionHeader(text = "Block")
|
||||||
|
SpacerH16()
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.report_dialog_blocking_a_user)
|
||||||
|
)
|
||||||
|
SpacerH16()
|
||||||
|
ActionButton(
|
||||||
|
text = stringResource(R.string.report_dialog_block_hide_user_btn),
|
||||||
|
icon = Icons.Default.Block,
|
||||||
|
onClick = {
|
||||||
|
note.author?.let { accountViewModel.hide(it) }
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SpacerH16()
|
||||||
|
|
||||||
|
Divider(color = MaterialTheme.colors.onSurface, thickness = 0.25.dp)
|
||||||
|
|
||||||
|
SpacerH16()
|
||||||
|
SectionHeader(text = stringResource(R.string.report_dialog_report_btn))
|
||||||
|
SpacerH16()
|
||||||
|
Text(stringResource(R.string.report_dialog_reminder_public))
|
||||||
|
SpacerH16()
|
||||||
|
TextSpinner(
|
||||||
|
label = stringResource(R.string.report_dialog_select_reason_label),
|
||||||
|
placeholder = stringResource(R.string.report_dialog_select_reason_placeholder),
|
||||||
|
options = reasonOptions,
|
||||||
|
onSelect = {
|
||||||
|
selectedReason = it
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
SpacerH16()
|
||||||
|
OutlinedTextField(
|
||||||
|
value = additionalReason,
|
||||||
|
onValueChange = { additionalReason = it },
|
||||||
|
placeholder = { Text(text = stringResource(R.string.report_dialog_additional_reason_placeholder)) },
|
||||||
|
label = { Text(stringResource(R.string.report_dialog_additional_reason_label)) },
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
SpacerH16()
|
||||||
|
ActionButton(
|
||||||
|
text = stringResource(R.string.report_dialog_post_report_btn),
|
||||||
|
icon = Icons.Default.Report,
|
||||||
|
enabled = selectedReason in 0..reportTypes.lastIndex,
|
||||||
|
onClick = {
|
||||||
|
accountViewModel.report(note, reportTypes[selectedReason].first, additionalReason)
|
||||||
|
note.author?.let { accountViewModel.hide(it) }
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SpacerH16() = Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SectionHeader(text: String) = Text(
|
||||||
|
text = text,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colors.onSurface,
|
||||||
|
fontSize = 18.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ActionButton(text: String, icon: ImageVector, enabled: Boolean = true, onClick: () -> Unit) = Button(
|
||||||
|
onClick = onClick,
|
||||||
|
enabled = enabled,
|
||||||
|
colors = ButtonDefaults.buttonColors(backgroundColor = WarningColor),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color.White
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(text = text, color = Color.White)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -197,6 +197,23 @@
|
|||||||
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">Copied author’s @npub to clipboard</string>
|
<string name="copied_user_id_to_clipboard" tools:ignore="Typos">Copied author’s @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/<user>/<gist></string>
|
||||||
|
<string name="telegram_proof_url_template" translatable="false">https://t.me/<proof post></string>
|
||||||
|
<string name="mastodon_proof_url_template" translatable="false">https://<server>/<user>/<proof post></string>
|
||||||
|
<string name="twitter_proof_url_template" translatable="false">https://twitter.com/<user>/status/<proof post></string>
|
||||||
|
<string name="private_conversation_notification">"<Unable to decrypt private message>\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>
|
||||||
@@ -208,24 +225,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/<user>/<gist></string>
|
|
||||||
<string name="telegram_proof_url_template" translatable="false">https://t.me/<proof post></string>
|
|
||||||
<string name="mastodon_proof_url_template" translatable="false">https://<server>/<user>/<proof post></string>
|
|
||||||
<string name="twitter_proof_url_template" translatable="false">https://twitter.com/<user>/status/<proof post></string>
|
|
||||||
<string name="private_conversation_notification">"<Unable to decrypt private message>\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="report_dialog_spam">Spam or scams</string>
|
||||||
<string name="drawer_accounts">Accounts</string>
|
<string name="report_dialog_profanity">Profanity or hateful conduct</string>
|
||||||
<string name="account_switch_select_account">Select Account</string>
|
<string name="report_dialog_impersonation">Malicious impersonation</string>
|
||||||
<string name="account_switch_add_account_btn">Add New Account</string>
|
<string name="report_dialog_nudity">Nudity or graphic content</string>
|
||||||
<string name="account_switch_active_account">Active account</string>
|
<string name="report_dialog_illegal">Illegal Behavior</string>
|
||||||
<string name="account_switch_has_private_key">Has private key</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="account_switch_pubkey_only">Read only, no private key</string>
|
<string name="report_dialog_block_hide_user_btn"><![CDATA[Block & Hide User]]></string>
|
||||||
<string name="back">Back</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_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_select_reason_label">Reason</string>
|
||||||
|
<string name="report_dialog_select_reason_placeholder">Select a reason…</string>
|
||||||
|
<string name="report_dialog_post_report_btn">Post Report</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user