From f6d283dafbf37b954db6d7177ecb12423d701875 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 2 Sep 2025 15:32:28 -0400 Subject: [PATCH] Refining the performance of the QuickAction menu bar --- .../amethyst/ui/note/NoteQuickActionMenu.kt | 315 +++++++++--------- .../vitorpamplona/amethyst/ui/theme/Shape.kt | 4 + 2 files changed, 168 insertions(+), 151 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt index c2afd3651..16c45590a 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteQuickActionMenu.kt @@ -34,7 +34,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AlternateEmail import androidx.compose.material.icons.filled.Block @@ -65,7 +64,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.vector.ImageVector @@ -82,6 +80,7 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.scope import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo import com.vitorpamplona.amethyst.ui.painterRes @@ -89,6 +88,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.LightRedColor +import com.vitorpamplona.amethyst.ui.theme.QuickActionPopupShadow +import com.vitorpamplona.amethyst.ui.theme.SmallestBorder import com.vitorpamplona.amethyst.ui.theme.isLight import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent @@ -231,20 +232,40 @@ private fun RenderMainPopup( showDeleteAlertDialog: MutableState, showReportDialog: MutableState, onWantsToEditDraft: () -> Unit, +) { + Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) { + val backgroundColor = + if (MaterialTheme.colorScheme.isLight) { + MaterialTheme.colorScheme.primary + } else { + MaterialTheme.colorScheme.secondaryButtonBackground + } + + Card( + modifier = QuickActionPopupShadow, + shape = SmallestBorder, + colors = CardDefaults.cardColors(containerColor = backgroundColor), + ) { + CardBody(accountViewModel, note, onDismiss, showBlockAlertDialog, showDeleteAlertDialog, showReportDialog, onWantsToEditDraft) + } + } +} + +@Composable +fun CardBody( + accountViewModel: AccountViewModel, + note: Note, + onDismiss: () -> Unit, + showBlockAlertDialog: MutableState, + showDeleteAlertDialog: MutableState, + showReportDialog: MutableState, + onWantsToEditDraft: () -> Unit, ) { val context = LocalContext.current val primaryLight = lightenColor(MaterialTheme.colorScheme.primary, 0.1f) - val cardShape = RoundedCornerShape(5.dp) val clipboardManager = LocalClipboardManager.current val scope = rememberCoroutineScope() - val backgroundColor = - if (MaterialTheme.colorScheme.isLight) { - MaterialTheme.colorScheme.primary - } else { - MaterialTheme.colorScheme.secondaryButtonBackground - } - val showToast = { stringRes: Int -> scope.launch { Toast @@ -259,157 +280,149 @@ private fun RenderMainPopup( val isOwnNote = accountViewModel.isLoggedUser(note.author) val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author) - Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) { - Card( - modifier = Modifier.shadow(elevation = 6.dp, shape = cardShape), - shape = cardShape, - colors = CardDefaults.cardColors(containerColor = backgroundColor), - ) { - Column(modifier = Modifier.width(IntrinsicSize.Min)) { - Row(modifier = Modifier.height(IntrinsicSize.Min)) { - NoteQuickActionItem( - icon = Icons.Default.ContentCopy, - label = stringRes(R.string.quick_action_copy_text), - ) { - accountViewModel.decrypt(note) { - clipboardManager.setText(AnnotatedString(it)) - showToast(R.string.copied_note_text_to_clipboard) - } + Column(modifier = Modifier.width(IntrinsicSize.Min)) { + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + NoteQuickActionItem( + icon = Icons.Default.ContentCopy, + label = stringRes(R.string.quick_action_copy_text), + ) { + accountViewModel.decrypt(note) { + clipboardManager.setText(AnnotatedString(it)) + showToast(R.string.copied_note_text_to_clipboard) + } + onDismiss() + } + VerticalDivider(color = primaryLight) + NoteQuickActionItem( + Icons.Default.AlternateEmail, + stringRes(R.string.quick_action_copy_user_id), + ) { + note.author?.let { + scope.launch { + clipboardManager.setText(AnnotatedString(it.toNostrUri())) + showToast(R.string.copied_user_id_to_clipboard) onDismiss() } - VerticalDivider(color = primaryLight) - NoteQuickActionItem( - Icons.Default.AlternateEmail, - stringRes(R.string.quick_action_copy_user_id), - ) { - note.author?.let { - scope.launch { - clipboardManager.setText(AnnotatedString(it.toNostrUri())) - showToast(R.string.copied_user_id_to_clipboard) - onDismiss() - } - } - } - VerticalDivider(color = primaryLight) - NoteQuickActionItem( - Icons.Default.FormatQuote, - stringRes(R.string.quick_action_copy_note_id), - ) { - scope.launch { - clipboardManager.setText(AnnotatedString(note.toNostrUri())) - showToast(R.string.copied_note_id_to_clipboard) - onDismiss() - } - } - - if (!isOwnNote) { - VerticalDivider(color = primaryLight) - - NoteQuickActionItem( - Icons.Default.Block, - stringRes(R.string.quick_action_block), - ) { - if (accountViewModel.account.settings.hideBlockAlertDialog) { - note.author?.let { accountViewModel.hide(it) } - onDismiss() - } else { - showBlockAlertDialog.value = true - } - } - } } - HorizontalDivider( - color = primaryLight, - ) - Row(modifier = Modifier.height(IntrinsicSize.Min)) { - if (isOwnNote) { - NoteQuickActionItem( - Icons.Default.Delete, - stringRes(R.string.quick_action_delete), - ) { - if (accountViewModel.account.settings.hideDeleteRequestDialog) { - accountViewModel.delete(note) - onDismiss() - } else { - showDeleteAlertDialog.value = true - } - } - } else if (isFollowingUser) { - NoteQuickActionItem( - Icons.Default.PersonRemove, - stringRes(R.string.quick_action_unfollow), - ) { - accountViewModel.unfollow(note.author!!) - onDismiss() - } - } else { - NoteQuickActionItem( - Icons.Default.PersonAdd, - stringRes(R.string.quick_action_follow), - ) { - accountViewModel.follow(note.author!!) - onDismiss() - } - } + } + VerticalDivider(color = primaryLight) + NoteQuickActionItem( + Icons.Default.FormatQuote, + stringRes(R.string.quick_action_copy_note_id), + ) { + scope.launch { + clipboardManager.setText(AnnotatedString(note.toNostrUri())) + showToast(R.string.copied_note_id_to_clipboard) + onDismiss() + } + } - VerticalDivider(color = primaryLight) - NoteQuickActionItem( - icon = ImageVector.vectorResource(id = R.drawable.relays), - label = stringRes(R.string.broadcast), - ) { - accountViewModel.broadcast(note) - // showSelectTextDialog = true + if (!isOwnNote) { + VerticalDivider(color = primaryLight) + + NoteQuickActionItem( + Icons.Default.Block, + stringRes(R.string.quick_action_block), + ) { + if (accountViewModel.account.settings.hideBlockAlertDialog) { + note.author?.let { accountViewModel.hide(it) } onDismiss() - } - VerticalDivider(color = primaryLight) - if (isOwnNote && note.isDraft()) { - NoteQuickActionItem( - Icons.Default.Edit, - stringRes(R.string.edit_draft), - ) { - onWantsToEditDraft() - } } else { - NoteQuickActionItem( - icon = Icons.Default.Share, - label = stringRes(R.string.quick_action_share), - ) { - val sendIntent = - Intent().apply { - action = Intent.ACTION_SEND - type = "text/plain" - putExtra( - Intent.EXTRA_TEXT, - externalLinkForNote(note), - ) - putExtra( - Intent.EXTRA_TITLE, - stringRes(context, R.string.quick_action_share_browser_link), - ) - } - - val shareIntent = - Intent.createChooser( - sendIntent, - stringRes(context, R.string.quick_action_share), - ) - context.startActivity(shareIntent) - onDismiss() - } + showBlockAlertDialog.value = true } - - if (!isOwnNote) { - VerticalDivider(color = primaryLight) - - NoteQuickActionItem( - Icons.Default.Report, - stringRes(R.string.quick_action_report), - ) { - showReportDialog.value = true - } + } + } + } + HorizontalDivider( + color = primaryLight, + ) + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + if (isOwnNote) { + NoteQuickActionItem( + Icons.Default.Delete, + stringRes(R.string.quick_action_delete), + ) { + if (accountViewModel.account.settings.hideDeleteRequestDialog) { + accountViewModel.delete(note) + onDismiss() + } else { + showDeleteAlertDialog.value = true } } + } else if (isFollowingUser) { + NoteQuickActionItem( + Icons.Default.PersonRemove, + stringRes(R.string.quick_action_unfollow), + ) { + accountViewModel.unfollow(note.author!!) + onDismiss() + } + } else { + NoteQuickActionItem( + Icons.Default.PersonAdd, + stringRes(R.string.quick_action_follow), + ) { + accountViewModel.follow(note.author!!) + onDismiss() + } + } + + VerticalDivider(color = primaryLight) + NoteQuickActionItem( + icon = ImageVector.vectorResource(id = R.drawable.relays), + label = stringRes(R.string.broadcast), + ) { + accountViewModel.broadcast(note) + // showSelectTextDialog = true + onDismiss() + } + VerticalDivider(color = primaryLight) + if (isOwnNote && note.isDraft()) { + NoteQuickActionItem( + Icons.Default.Edit, + stringRes(R.string.edit_draft), + ) { + onWantsToEditDraft() + } + } else { + NoteQuickActionItem( + icon = Icons.Default.Share, + label = stringRes(R.string.quick_action_share), + ) { + val sendIntent = + Intent().apply { + action = Intent.ACTION_SEND + type = "text/plain" + putExtra( + Intent.EXTRA_TEXT, + externalLinkForNote(note), + ) + putExtra( + Intent.EXTRA_TITLE, + stringRes(context, R.string.quick_action_share_browser_link), + ) + } + + val shareIntent = + Intent.createChooser( + sendIntent, + stringRes(context, R.string.quick_action_share), + ) + context.startActivity(shareIntent) + onDismiss() + } + } + + if (!isOwnNote) { + VerticalDivider(color = primaryLight) + + NoteQuickActionItem( + Icons.Default.Report, + stringRes(R.string.quick_action_report), + ) { + showReportDialog.value = true + } } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt index a0111937e..e55faca63 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/theme/Shape.kt @@ -42,6 +42,7 @@ import androidx.compose.material3.Shapes import androidx.compose.material3.ripple import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign @@ -61,6 +62,7 @@ val RippleRadius45dp = 45.dp // Ripple should be +10.dp over the component size val BottomTopHeight = Modifier.height(50.dp) val TabRowHeight = Modifier +val SmallestBorder = RoundedCornerShape(5.dp) val SmallBorder = RoundedCornerShape(7.dp) val SmallishBorder = RoundedCornerShape(9.dp) val QuoteBorder = RoundedCornerShape(15.dp) @@ -358,3 +360,5 @@ val MaxWidthPaddingTop5dp = Modifier.fillMaxWidth().padding(top = 5.dp) val VoiceHeightModifier = Modifier.fillMaxWidth().height(100.dp) val PaddingHorizontal12Modifier = Modifier.padding(horizontal = 12.dp) + +val QuickActionPopupShadow = Modifier.shadow(elevation = Size6dp, shape = SmallestBorder)