From ad4e6d6596277bd81bf245bfff6d826f1ebaa82a Mon Sep 17 00:00:00 2001 From: maxmoney21m Date: Wed, 15 Mar 2023 13:40:59 +0800 Subject: [PATCH] Add Block button and dialog --- .../amethyst/LocalPreferences.kt | 16 ++- .../vitorpamplona/amethyst/model/Account.kt | 12 +- .../amethyst/ui/note/NoteQuickActionMenu.kt | 126 ++++++++++++++---- .../ui/screen/loggedIn/AccountViewModel.kt | 14 +- .../ui/screen/loggedIn/ReportNoteDialog.kt | 5 +- .../vitorpamplona/amethyst/ui/theme/Color.kt | 2 + app/src/main/res/values/strings.xml | 44 +++--- 7 files changed, 160 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 7adb1244d..9b96d1430 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -47,7 +47,8 @@ private object PrefKeys { const val TRANSLATE_TO = "translateTo" const val ZAP_AMOUNTS = "zapAmounts" 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" } } @@ -183,7 +184,8 @@ object LocalPreferences { putString(PrefKeys.TRANSLATE_TO, account.translateTo) putString(PrefKeys.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices)) 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.PROFILE_PICTURE_URL, account.userProfile().profilePicture()) }.apply() @@ -230,7 +232,8 @@ object LocalPreferences { 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( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -241,7 +244,8 @@ object LocalPreferences { languagePreferences, translateTo, zapAmountChoices, - hideDeleteRequestInfo, + hideDeleteRequestDialog, + hideBlockAlertDialog, latestContactList ) } @@ -289,8 +293,8 @@ object LocalPreferences { stringPrefs.forEach { userPrefs.putString(it, appPrefs.getString(it, null)) } stringSetPrefs.forEach { userPrefs.putStringSet(it, appPrefs.getStringSet(it, null)) } userPrefs.putBoolean( - PrefKeys.HIDE_DELETE_REQUEST_INFO, - appPrefs.getBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, false) + PrefKeys.HIDE_DELETE_REQUEST_DIALOG, + appPrefs.getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false) ) }.apply() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index b6ada4a6c..484edafa2 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -59,7 +59,8 @@ class Account( var languagePreferences: Map = mapOf(), var translateTo: String = Locale.getDefault().language, var zapAmountChoices: List = listOf(500L, 1000L, 5000L), - var hideDeleteRequestInfo: Boolean = false, + var hideDeleteRequestDialog: Boolean = false, + var hideBlockAlertDialog: Boolean = false, var backupContactList: ContactListEvent? = null ) { var transientHiddenUsers: Set = setOf() @@ -553,8 +554,13 @@ class Account( saveable.invalidateData() } - fun setHideDeleteRequestInfo() { - hideDeleteRequestInfo = true + fun setHideDeleteRequestDialog() { + hideDeleteRequestDialog = true + saveable.invalidateData() + } + + fun setHideBlockAlertDialog() { + hideBlockAlertDialog = true saveable.invalidateData() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index 912f579bb..170ba719c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth 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.material.AlertDialog import androidx.compose.material.Button +import androidx.compose.material.ButtonColors +import androidx.compose.material.ButtonDefaults import androidx.compose.material.Card import androidx.compose.material.Divider 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.PersonAdd import androidx.compose.material.icons.filled.PersonRemove +import androidx.compose.material.icons.filled.Report import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable 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.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog +import com.vitorpamplona.amethyst.ui.theme.WarningColor import kotlinx.coroutines.launch -fun lightenColor(color: Color, amount: Float): Color { +private fun lightenColor(color: Color, amount: Float): Color { var argb = color.toArgb() val hslOut = floatArrayOf(0f, 0f, 0f) 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()}" } @Composable -fun VerticalDivider(color: Color) = +private fun VerticalDivider(color: Color) = Divider( color = color, modifier = Modifier @@ -90,8 +95,9 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni val scope = rememberCoroutineScope() var showSelectTextDialog by remember { mutableStateOf(false) } var showDeleteAlertDialog by remember { mutableStateOf(false) } + var showBlockAlertDialog 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 showToast = { stringResource: Int -> @@ -138,11 +144,16 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni onDismiss() } - if (note.author != accountViewModel.accountLiveData.value?.account?.userProfile()) { + if (!isOwnNote) { VerticalDivider(primaryLight) - NoteQuickActionItem(Icons.Default.Block, "Block") { - showReportDialog = true + NoteQuickActionItem(Icons.Default.Block, stringResource(R.string.quick_action_block)) { + 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)) { if (isOwnNote) { NoteQuickActionItem(Icons.Default.Delete, stringResource(R.string.quick_action_delete)) { - if (accountViewModel.hideDeleteRequestInfo()) { + if (accountViewModel.hideDeleteRequestDialog) { accountViewModel.delete(note) onDismiss() } else { @@ -198,7 +209,14 @@ fun NoteQuickActionMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Uni ContextCompat.startActivity(context, shareIntent, null) 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) { - DeleteAlertDialog(note, accountViewModel, onDismiss) + DeleteAlertDialog(note, accountViewModel) { + showDeleteAlertDialog = false + onDismiss() + } + } + + if (showBlockAlertDialog) { + BlockAlertDialog(note, accountViewModel) { + showBlockAlertDialog = false + onDismiss() + } } if (showReportDialog) { @@ -245,14 +273,65 @@ fun NoteQuickActionItem(icon: ImageVector, label: String, onClick: () -> Unit) { } @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( onDismissRequest = onDismiss, title = { - Text(text = stringResource(R.string.quick_action_request_deletion_alert_title)) + Text(title) }, text = { - Text(text = stringResource(R.string.quick_action_request_deletion_alert_body)) + Text(textContent) }, buttons = { Row( @@ -261,19 +340,20 @@ fun DeleteAlertDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: .fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { - TextButton( - onClick = { - accountViewModel.setHideDeleteRequestInfo() - accountViewModel.delete(note) - onDismiss() - } - ) { + TextButton(onClick = onClickDontShowAgain) { Text(stringResource(R.string.quick_action_dont_show_again_button)) } - Button( - onClick = { accountViewModel.delete(note); onDismiss() } - ) { - Text(stringResource(R.string.quick_action_delete_button)) + Button(onClick = onClickDoOnce, colors = buttonColors) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = buttonIcon, + contentDescription = null + ) + Spacer(Modifier.width(8.dp)) + Text(buttonText) + } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 2b40c8399..3f94694d7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -129,11 +129,17 @@ class AccountViewModel(private val account: Account) : ViewModel() { return account.userProfile().isFollowing(user) } - fun hideDeleteRequestInfo(): Boolean { - return account.hideDeleteRequestInfo + val hideDeleteRequestDialog: Boolean + get() = account.hideDeleteRequestDialog + + fun dontShowDeleteRequestDialog() { + account.setHideDeleteRequestDialog() } - fun setHideDeleteRequestInfo() { - account.setHideDeleteRequestInfo() + val hideBlockAlertDialog: Boolean + get() = account.hideBlockAlertDialog + + fun dontShowBlockAlertDialog() { + account.setHideBlockAlertDialog() } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt index e3a7571e6..db2fc1b3d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ReportNoteDialog.kt @@ -40,6 +40,7 @@ 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) { @@ -138,8 +139,6 @@ fun ReportNoteDialog(note: Note, accountViewModel: AccountViewModel, onDismiss: } } -private val warningColor = Color(0xFFC62828) - @Composable 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( onClick = onClick, enabled = enabled, - colors = ButtonDefaults.buttonColors(backgroundColor = warningColor), + colors = ButtonDefaults.buttonColors(backgroundColor = WarningColor), modifier = Modifier.fillMaxWidth() ) { Row( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt index 0186afcd4..f2609a161 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/theme/Color.kt @@ -12,3 +12,5 @@ val Following = Color(0xFF03DAC5) val Nip05 = Color(0xFF01BAFF) val FollowsFollow = Color.Yellow val NIP05Verified = Color.Blue + +val WarningColor = Color(0xFFC62828) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 877d9122d..1c279ee91 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -198,6 +198,23 @@ Copied author’s @npub to clipboard Copied note ID (@note1) to clipboard Select Text + Github Gist w/ Proof + Telegram + Mastodon Post ID w/ Proof + Twitter Status w/ Proof + https://gist.github.com/<user>/<gist> + https://t.me/<proof post> + https://<server>/<user>/<proof post> + https://twitter.com/<user>/status/<proof post> + "<Unable to decrypt private message>\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s." + Add New Account + Accounts + Select Account + Add New Account + Active account + Has private key + Read only, no private key + Back Select Share Browser Link Share @@ -209,38 +226,25 @@ Follow Request Deletion 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. - Github Gist w/ Proof - Telegram - Mastodon Post ID w/ Proof - Twitter Status w/ Proof - https://gist.github.com/<user>/<gist> - https://t.me/<proof post> - https://<server>/<user>/<proof post> - https://twitter.com/<user>/status/<proof post> - "<Unable to decrypt private message>\n\nYou were cited in a private/encrypted conversation between %1$s and %2$s." + Block + Delete + Block + Report Delete Don\'t show again - Add New Account - Accounts - Select Account - Add New Account - Active account - Has private key - Read only, no private key - Back Spam or scams Profanity or hateful conduct Malicious impersonation Nudity or graphic content Illegal Behavior - Blocking a user will hide their content in your app. Your notes are still publicly viewable, including to people you block. + 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. Report Abuse All reports posted will be publicly visible. - Optionally provide additional context about your report... + Optionally provide additional context about your report… Additional Context Reason - Select a reason... + Select a reason… Post Report