kopia lustrzana https://github.com/vitorpamplona/amethyst
Add report & block screen
rodzic
0272073636
commit
0241bf0913
|
@ -170,7 +170,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 +185,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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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
|
||||||
|
@ -57,6 +58,7 @@ 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 kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
fun lightenColor(color: Color, amount: Float): Color {
|
fun lightenColor(color: Color, amount: Float): Color {
|
||||||
|
@ -88,6 +90,7 @@ 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 showReportDialog by remember { mutableStateOf(false) }
|
||||||
val isOwnNote = note.author == accountViewModel.userProfile()
|
val isOwnNote = note.author == accountViewModel.userProfile()
|
||||||
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author!!)
|
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author!!)
|
||||||
|
|
||||||
|
@ -134,6 +137,14 @@ 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 (note.author != accountViewModel.accountLiveData.value?.account?.userProfile()) {
|
||||||
|
VerticalDivider(primaryLight)
|
||||||
|
|
||||||
|
NoteQuickActionItem(Icons.Default.Block, "Block") {
|
||||||
|
showReportDialog = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Divider(
|
Divider(
|
||||||
color = primaryLight,
|
color = primaryLight,
|
||||||
|
@ -187,6 +198,7 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
|
||||||
ContextCompat.startActivity(context, shareIntent, null)
|
ContextCompat.startActivity(context, shareIntent, null)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
|
VerticalDivider(primaryLight)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,36 +212,14 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDeleteAlertDialog) {
|
if (showDeleteAlertDialog) {
|
||||||
AlertDialog(
|
DeleteAlertDialog(note, accountViewModel, onDismiss)
|
||||||
onDismissRequest = { onDismiss() },
|
}
|
||||||
title = {
|
|
||||||
Text(text = stringResource(R.string.quick_action_request_deletion_alert_title))
|
if (showReportDialog) {
|
||||||
},
|
ReportNoteDialog(note, accountViewModel) {
|
||||||
text = {
|
showReportDialog = false
|
||||||
Text(text = stringResource(R.string.quick_action_request_deletion_alert_body))
|
onDismiss()
|
||||||
},
|
}
|
||||||
buttons = {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.padding(all = 8.dp).fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
TextButton(
|
|
||||||
onClick = {
|
|
||||||
accountViewModel.setHideDeleteRequestInfo()
|
|
||||||
accountViewModel.delete(note)
|
|
||||||
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 +235,47 @@ 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) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
title = {
|
||||||
|
Text(text = stringResource(R.string.quick_action_request_deletion_alert_title))
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(text = stringResource(R.string.quick_action_request_deletion_alert_body))
|
||||||
|
},
|
||||||
|
buttons = {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(all = 8.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
accountViewModel.setHideDeleteRequestInfo()
|
||||||
|
accountViewModel.delete(note)
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
@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()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val warningColor = Color(0xFFC62828)
|
||||||
|
|
||||||
|
@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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -228,5 +228,19 @@
|
||||||
<string name="account_switch_has_private_key">Has private key</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="account_switch_pubkey_only">Read only, no private key</string>
|
||||||
<string name="back">Back</string>
|
<string name="back">Back</string>
|
||||||
|
<string name="report_dialog_spam">Spam or scams</string>
|
||||||
|
<string name="report_dialog_profanity">Profanity or hateful conduct</string>
|
||||||
|
<string name="report_dialog_impersonation">Malicious impersonation</string>
|
||||||
|
<string name="report_dialog_nudity">Nudity or graphic content</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_block_hide_user_btn"><![CDATA[Block & Hide User]]></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>
|
||||||
|
|
Ładowanie…
Reference in New Issue