diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index f2401812b..9e11efe18 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -29,11 +29,18 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.LocalTextStyle import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.Immutable @@ -46,10 +53,12 @@ import androidx.compose.runtime.rememberCoroutineScope 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.layout.ContentScale import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.Placeholder import androidx.compose.ui.text.PlaceholderVerticalAlign @@ -77,11 +86,15 @@ import com.vitorpamplona.amethyst.ui.note.DownloadForOfflineIcon import com.vitorpamplona.amethyst.ui.note.HashCheckFailedIcon import com.vitorpamplona.amethyst.ui.note.HashCheckIcon import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.Font17SP +import com.vitorpamplona.amethyst.ui.theme.Size20Modifier import com.vitorpamplona.amethyst.ui.theme.Size20dp import com.vitorpamplona.amethyst.ui.theme.Size24dp import com.vitorpamplona.amethyst.ui.theme.Size30dp +import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.amethyst.ui.theme.imageModifier +import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.quartz.crypto.CryptoUtils import com.vitorpamplona.quartz.encoders.toHexKey import kotlinx.collections.immutable.ImmutableList @@ -184,13 +197,20 @@ fun ZoomableContentView( roundedCorner: Boolean, accountViewModel: AccountViewModel ) { - val clipboardManager = LocalClipboardManager.current - // store the dialog open or close state var dialogOpen by remember { mutableStateOf(false) } + // store the dialog open or close state + val shareOpen = remember { + mutableStateOf(false) + } + + if (shareOpen.value) { + ShareImageAction(shareOpen, content) { shareOpen.value = false } + } + var mainImageModifier = if (roundedCorner) { MaterialTheme.colors.imageModifier } else { @@ -200,12 +220,12 @@ fun ZoomableContentView( if (content is ZoomableUrlContent) { mainImageModifier = mainImageModifier.combinedClickable( onClick = { dialogOpen = true }, - onLongClick = { clipboardManager.setText(AnnotatedString(content.uri ?: content.url)) } + onLongClick = { shareOpen.value = true } ) } else if (content is ZoomablePreloadedContent) { mainImageModifier = mainImageModifier.combinedClickable( onClick = { dialogOpen = true }, - onLongClick = { clipboardManager.setText(AnnotatedString(content.uri)) } + onLongClick = { shareOpen.value = true } ) } else { mainImageModifier = mainImageModifier.clickable { @@ -649,7 +669,10 @@ fun ZoomableImageDialog( val myContent = allImages[pagerState.currentPage] if (myContent is ZoomableUrlContent) { - SaveToGallery(url = myContent.url) + Row() { + CopyToClipboard(content = myContent) + SaveToGallery(url = myContent.url) + } } else if (myContent is ZoomableLocalImage && myContent.localFile != null) { SaveToGallery( localFile = myContent.localFile, @@ -662,6 +685,64 @@ fun ZoomableImageDialog( } } +@Composable +private fun CopyToClipboard( + content: ZoomableContent +) { + val popupExpanded = remember { mutableStateOf(false) } + + Button( + modifier = Modifier.padding(horizontal = Size5dp), + onClick = { popupExpanded.value = true }, + shape = ButtonBorder, + colors = ButtonDefaults + .buttonColors( + backgroundColor = MaterialTheme.colors.placeholderText + ) + ) { + Icon( + tint = Color.White, + imageVector = Icons.Default.Share, + modifier = Size20Modifier, + contentDescription = stringResource(R.string.copy_url_to_clipboard) + ) + + ShareImageAction(popupExpanded, content) { popupExpanded.value = false } + } +} + +@Composable +private fun ShareImageAction( + popupExpanded: + MutableState, + content: ZoomableContent, + onDismiss: () -> Unit +) { + DropdownMenu( + expanded = popupExpanded.value, + onDismissRequest = onDismiss + ) { + val clipboardManager = LocalClipboardManager.current + + if (content is ZoomableUrlContent) { + DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(content.url)); onDismiss() }) { + Text(stringResource(R.string.copy_url_to_clipboard)) + } + if (content.uri != null) { + DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(content.uri)); onDismiss() }) { + Text(stringResource(R.string.copy_the_note_id_to_the_clipboard)) + } + } + } + + if (content is ZoomablePreloadedContent) { + DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(content.uri)); onDismiss() }) { + Text(stringResource(R.string.copy_the_note_id_to_the_clipboard)) + } + } + } +} + @Composable private fun RenderImageOrVideo(content: ZoomableContent, roundedCorner: Boolean, accountViewModel: AccountViewModel) { val mainModifier = Modifier diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index e7bea1543..2f3468937 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -685,9 +685,6 @@ private fun ProfileHeader( ) { MessageButton(baseUser, accountViewModel, nav) - // No need for this button anymore - // NPubCopyButton(baseUser) - ProfileActions(baseUser, accountViewModel) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4f9bf83ac..9558dbd7f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -103,7 +103,7 @@ Uploading… User does not have a lightning address setup to receive sats "reply here.. " - Copies the Note ID to the clipboard for sharing + Copies the Note ID to the clipboard for sharing in Nostr Copy Channel ID (Note) to the Clipboard Edits the Channel Metadata Join @@ -544,4 +544,6 @@ Show URL previews When to load images + Copy URL to clipboard + Copy Note ID to clipboard