diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 903579a7c..59f8501e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -2203,6 +2203,7 @@ class Account( url: String, ) { if (!isWriteable()) return + GalleryListEvent.addEvent( userProfile().latestGalleryList, idHex, @@ -2226,6 +2227,7 @@ class Account( GalleryListEvent.removeReplaceable( galleryentries, note.address, + url, signer, ) { Client.send(it) @@ -2235,6 +2237,7 @@ class Account( GalleryListEvent.removeEvent( galleryentries, note.idHex, + url, signer, ) { Client.send(it) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt index 8618ae622..239d88b0d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/VideoView.kt @@ -142,7 +142,6 @@ fun LoadThumbAndThenVideoView( roundedCorner: Boolean, isFiniteHeight: Boolean, nostrUriCallback: String? = null, - nostrIdCallback: String? = null, accountViewModel: AccountViewModel, onDialog: ((Boolean) -> Unit)? = null, ) { @@ -177,7 +176,6 @@ fun LoadThumbAndThenVideoView( artworkUri = thumbUri, authorName = authorName, nostrUriCallback = nostrUriCallback, - nostrIdCallback = nostrIdCallback, accountViewModel = accountViewModel, onDialog = onDialog, ) @@ -192,7 +190,6 @@ fun LoadThumbAndThenVideoView( artworkUri = thumbUri, authorName = authorName, nostrUriCallback = nostrUriCallback, - nostrIdCallback = nostrIdCallback, accountViewModel = accountViewModel, onDialog = onDialog, ) @@ -214,7 +211,6 @@ fun VideoView( dimensions: String? = null, blurhash: String? = null, nostrUriCallback: String? = null, - nostrIdCallback: String? = null, onDialog: ((Boolean) -> Unit)? = null, onControllerVisibilityChanged: ((Boolean) -> Unit)? = null, accountViewModel: AccountViewModel, @@ -256,7 +252,6 @@ fun VideoView( artworkUri = artworkUri, authorName = authorName, nostrUriCallback = nostrUriCallback, - nostrIDCallback = nostrIdCallback, automaticallyStartPlayback = automaticallyStartPlayback, onControllerVisibilityChanged = onControllerVisibilityChanged, onDialog = onDialog, @@ -310,7 +305,6 @@ fun VideoView( artworkUri = artworkUri, authorName = authorName, nostrUriCallback = nostrUriCallback, - nostrIDCallback = nostrIdCallback, automaticallyStartPlayback = automaticallyStartPlayback, onControllerVisibilityChanged = onControllerVisibilityChanged, onDialog = onDialog, @@ -335,7 +329,6 @@ fun VideoViewInner( artworkUri: String? = null, authorName: String? = null, nostrUriCallback: String? = null, - nostrIDCallback: String? = null, automaticallyStartPlayback: State, onControllerVisibilityChanged: ((Boolean) -> Unit)? = null, onDialog: ((Boolean) -> Unit)? = null, @@ -357,7 +350,6 @@ fun VideoViewInner( roundedCorner = roundedCorner, isFiniteHeight = isFiniteHeight, nostrUriCallback = nostrUriCallback, - nostrIDCallback = nostrIDCallback, waveform = waveform, keepPlaying = keepPlaying, automaticallyStartPlayback = automaticallyStartPlayback, @@ -705,7 +697,6 @@ private fun RenderVideoPlayer( roundedCorner: Boolean, isFiniteHeight: Boolean, nostrUriCallback: String?, - nostrIDCallback: String?, waveform: ImmutableList? = null, keepPlaying: MutableState, automaticallyStartPlayback: State, @@ -819,7 +810,7 @@ private fun RenderVideoPlayer( } AnimatedShareButton(controllerVisible, Modifier.align(Alignment.TopEnd).padding(end = Size165dp)) { popupExpanded, toggle -> - ShareImageAction(accountViewModel = accountViewModel, popupExpanded, videoUri, nostrUriCallback, nostrIDCallback, toggle) + ShareImageAction(accountViewModel = accountViewModel, popupExpanded, videoUri, nostrUriCallback, toggle) } } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt index 1f1ed554a..5fed68693 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentView.kt @@ -95,6 +95,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size75dp import com.vitorpamplona.amethyst.ui.theme.hashVerifierMark import com.vitorpamplona.amethyst.ui.theme.imageModifier import com.vitorpamplona.quartz.crypto.CryptoUtils +import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.toHexKey import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -138,7 +139,6 @@ fun ZoomableContentView( roundedCorner = roundedCorner, isFiniteHeight = isFiniteHeight, nostrUriCallback = content.uri, - nostrIdCallback = content.id, onDialog = { dialogOpen = true }, accountViewModel = accountViewModel, ) @@ -163,7 +163,6 @@ fun ZoomableContentView( roundedCorner = roundedCorner, isFiniteHeight = isFiniteHeight, nostrUriCallback = content.uri, - nostrIdCallback = content.id, onDialog = { dialogOpen = true }, accountViewModel = accountViewModel, ) @@ -609,7 +608,6 @@ fun ShareImageAction( popupExpanded = popupExpanded, videoUri = content.url, postNostrUri = content.uri, - postNostrid = content.id, onDismiss = onDismiss, ) } else if (content is MediaPreloadedContent) { @@ -618,7 +616,6 @@ fun ShareImageAction( popupExpanded = popupExpanded, videoUri = content.localFile?.toUri().toString(), postNostrUri = content.uri, - postNostrid = content.id, onDismiss = onDismiss, ) } @@ -631,7 +628,6 @@ fun ShareImageAction( popupExpanded: MutableState, videoUri: String?, postNostrUri: String?, - postNostrid: String?, onDismiss: () -> Unit, ) { DropdownMenu( @@ -665,13 +661,13 @@ fun ShareImageAction( text = { Text(stringRes(R.string.add_media_to_gallery)) }, onClick = { if (videoUri != null) { - if (postNostrid != null) { - print("TODO") - print(postNostrid) - // TODO this still crashes - accountViewModel.account.addToGallery(postNostrid, videoUri) + var n19 = Nip19Bech32.uriToRoute(postNostrUri)?.entity as? Nip19Bech32.NEvent + if (n19 != null) { + accountViewModel.addMediaToGallery(n19.hex, videoUri) + accountViewModel.toast(R.string.image_saved_to_the_gallery, R.string.image_saved_to_the_gallery) } } + onDismiss() }, ) 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 2cc7a5c62..957a0e77e 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 @@ -154,6 +154,38 @@ fun LongPressToQuickAction( } } +@Composable +fun LongPressToQuickActionGallery( + baseNote: Note, + accountViewModel: AccountViewModel, + content: @Composable (() -> Unit) -> Unit, +) { + val popupExpanded = remember { mutableStateOf(false) } + + content { popupExpanded.value = true } + + if (popupExpanded.value) { + NoteQuickActionMenuGallery( + note = baseNote, + onDismiss = { popupExpanded.value = false }, + accountViewModel = accountViewModel, + nav = {}, + ) + } +} + +@Composable +fun NoteQuickActionMenuGallery( + note: Note, + onDismiss: () -> Unit, + accountViewModel: AccountViewModel, + nav: (String) -> Unit, +) { + DeleteFromGalleryDialog(note, accountViewModel) { + onDismiss() + } +} + @Composable fun NoteQuickActionMenu( note: Note, @@ -435,6 +467,169 @@ private fun RenderMainPopup( } } +@Composable +private fun RenderDeleteFromGalleryPopup( + accountViewModel: AccountViewModel, + note: Note, + showDeleteAlertDialog: MutableState, + onDismiss: () -> 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 + .makeText( + context, + stringRes(context, stringRes), + Toast.LENGTH_SHORT, + ).show() + } + } + + 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) + } + + 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() + } + } + } + HorizontalDivider( + color = primaryLight, + ) + Row(modifier = Modifier.height(IntrinsicSize.Min)) { + if (isOwnNote) { + NoteQuickActionItem( + Icons.Default.Delete, + stringRes(R.string.quick_action_delete), + ) { + if (accountViewModel.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), + ) { + onDismiss() + } + } 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), + ) + ContextCompat.startActivity(context, shareIntent, null) + onDismiss() + } + } + } + } + } + } +} + @Composable fun NoteQuickActionItem( icon: ImageVector, @@ -462,6 +657,25 @@ fun NoteQuickActionItem( } } +@Composable +fun DeleteFromGalleryDialog( + note: Note, + accountViewModel: AccountViewModel, + onDismiss: () -> Unit, +) { + QuickActionAlertDialogOneButton( + title = stringRes(R.string.quick_action_request_deletion_gallery_title), + textContent = stringRes(R.string.quick_action_request_deletion_gallery_alert_body), + buttonIcon = Icons.Default.Delete, + buttonText = stringRes(R.string.quick_action_delete_dialog_btn), + onClickDoOnce = { + note.event?.firstTaggedUrl()?.let { accountViewModel.removefromMediaGallery(note, it) } + onDismiss() + }, + onDismiss = onDismiss, + ) +} + @Composable fun DeleteAlertDialog( note: Note, @@ -612,3 +826,95 @@ fun QuickActionAlertDialog( }, ) } + +@Composable +fun QuickActionAlertDialogOneButton( + title: String, + textContent: String, + buttonIcon: ImageVector, + buttonText: String, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + onClickDoOnce: () -> Unit, + onDismiss: () -> Unit, +) { + QuickActionAlertDialogOneButton( + title = title, + textContent = textContent, + icon = { + Icon( + imageVector = buttonIcon, + contentDescription = null, + ) + }, + buttonText = buttonText, + buttonColors = buttonColors, + onClickDoOnce = onClickDoOnce, + onDismiss = onDismiss, + ) +} + +@Composable +fun QuickActionAlertDialogOneButton( + title: String, + textContent: String, + buttonIconResource: Int, + buttonText: String, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + onClickDoOnce: () -> Unit, + onDismiss: () -> Unit, +) { + QuickActionAlertDialogOneButton( + title = title, + textContent = textContent, + icon = { + Icon( + painter = painterResource(buttonIconResource), + contentDescription = null, + ) + }, + buttonText = buttonText, + buttonColors = buttonColors, + onClickDoOnce = onClickDoOnce, + onDismiss = onDismiss, + ) +} + +@Composable +fun QuickActionAlertDialogOneButton( + title: String, + textContent: String, + icon: @Composable () -> Unit, + buttonText: String, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + onClickDoOnce: () -> Unit, + onDismiss: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(title) }, + text = { Text(textContent) }, + confirmButton = { + Row( + modifier = + Modifier + .padding(all = 8.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Button( + onClick = onClickDoOnce, + colors = buttonColors, + contentPadding = PaddingValues(horizontal = 16.dp), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + icon() + Spacer(Modifier.width(8.dp)) + Text(buttonText) + } + } + } + }, + ) +} diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt index f1879ea25..d7875628e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/AudioTrack.kt @@ -212,7 +212,6 @@ fun AudioHeader( isFiniteHeight = isFiniteHeight, accountViewModel = accountViewModel, nostrUriCallback = note.toNostrUri(), - nostrIdCallback = note.idHex, ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt index 766aeea97..6d0a16f35 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/LiveActivity.kt @@ -160,7 +160,6 @@ fun RenderLiveActivityEventInner( isFiniteHeight = false, accountViewModel = accountViewModel, nostrUriCallback = "nostr:${baseNote.toNEvent()}", - nostrIdCallback = baseNote.idHex, ) } } else { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index b1e5c4eef..5c6504503 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -669,6 +669,20 @@ class AccountViewModel( viewModelScope.launch(Dispatchers.IO) { account.addEmojiPack(usersEmojiList, emojiList) } } + fun addMediaToGallery( + hex: String, + url: String, + ) { + viewModelScope.launch(Dispatchers.IO) { account.addToGallery(hex, url) } + } + + fun removefromMediaGallery( + note: Note, + url: String, + ) { + viewModelScope.launch(Dispatchers.IO) { account.removeFromGallery(note, url) } + } + fun addPrivateBookmark(note: Note) { viewModelScope.launch(Dispatchers.IO) { account.addBookmark(note, true) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt index df02459ae..53271adfb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileGallery.kt @@ -22,15 +22,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridState @@ -39,7 +36,6 @@ import androidx.compose.foundation.lazy.grid.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.MutableState @@ -51,8 +47,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -64,7 +58,7 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled import com.vitorpamplona.amethyst.ui.components.SensitivityWarning import com.vitorpamplona.amethyst.ui.note.CheckHiddenFeedWatchBlockAndReport import com.vitorpamplona.amethyst.ui.note.ClickableNote -import com.vitorpamplona.amethyst.ui.note.LongPressToQuickAction +import com.vitorpamplona.amethyst.ui.note.LongPressToQuickActionGallery import com.vitorpamplona.amethyst.ui.note.WatchAuthor import com.vitorpamplona.amethyst.ui.note.WatchNoteEvent import com.vitorpamplona.amethyst.ui.note.calculateBackgroundColor @@ -78,7 +72,6 @@ import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.HalfPadding import com.vitorpamplona.amethyst.ui.theme.QuoteBorder -import com.vitorpamplona.amethyst.ui.theme.Size5dp import com.vitorpamplona.quartz.events.TextNoteEvent @Composable @@ -247,8 +240,7 @@ fun GalleryCard( nav: (String) -> Unit, ) { // baseNote.event?.let { Text(text = it.pubKey()) } - LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> - + LongPressToQuickActionGallery(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup -> CheckNewAndRenderChannelCard( baseNote, modifier, @@ -400,7 +392,7 @@ fun InnerRenderGalleryThumb( ) } ?: run { DisplayGalleryAuthorBanner(note) } - Row( + /* Row( Modifier .fillMaxWidth() .background(Color.Black.copy(0.6f)) @@ -417,7 +409,7 @@ fun InnerRenderGalleryThumb( modifier = Modifier.weight(1f), ) } - /* + card.price?.let { val priceTag = remember(card) { @@ -438,8 +430,8 @@ fun InnerRenderGalleryThumb( overflow = TextOverflow.Ellipsis, color = Color.White, ) - }*/ - } + } + }*/ } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index e15700961..0a0ec78a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -157,6 +157,7 @@ import com.vitorpamplona.amethyst.ui.screen.RefresheableFeedView import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView import com.vitorpamplona.amethyst.ui.screen.RelayFeedView import com.vitorpamplona.amethyst.ui.screen.RelayFeedViewModel +import com.vitorpamplona.amethyst.ui.screen.SaveableGridFeedState import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange @@ -1571,14 +1572,17 @@ fun TabGallery( modifier = Modifier.padding(vertical = 0.dp), ) { var state = LazyGridState() - RenderGalleryFeed( - feedViewModel, - null, - 0, - state, - accountViewModel = accountViewModel, - nav = nav, - ) + + SaveableGridFeedState(feedViewModel, scrollStateKey = "gallery") { listState -> + RenderGalleryFeed( + feedViewModel, + null, + 0, + state, + accountViewModel = accountViewModel, + nav = nav, + ) + } } } } diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index 37aa8a5e0..4803fe72d 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -270,6 +270,8 @@ Delete Unfollow Follow + Delete from Gallery + Remove this media from your Gallery, you can readd it later 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. Block diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/events/GalleryListEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/events/GalleryListEvent.kt index 4311407c8..1b65359c0 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/events/GalleryListEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/events/GalleryListEvent.kt @@ -60,7 +60,7 @@ class GalleryListEvent( ) { add( earlierVersion, - arrayOf(arrayOf(tagName, url, tagValue)), + arrayOf(arrayOf(tagName, tagValue, url)), signer, createdAt, onReady, @@ -76,7 +76,7 @@ class GalleryListEvent( ) { create( content = earlierVersion?.content ?: "", - tags = (earlierVersion?.tags ?: arrayOf(arrayOf("d", DEFAULT_D_TAG_GALLERY))).plus(listNewTags), + tags = listNewTags.plus(earlierVersion?.tags ?: arrayOf(arrayOf("d", DEFAULT_D_TAG_GALLERY))), signer = signer, createdAt = createdAt, onReady = onReady, @@ -86,23 +86,26 @@ class GalleryListEvent( fun removeEvent( earlierVersion: GalleryListEvent, eventId: HexKey, + url: String, signer: NostrSigner, createdAt: Long = TimeUtils.now(), onReady: (GalleryListEvent) -> Unit, - ) = removeTag(earlierVersion, "e", eventId, signer, createdAt, onReady) + ) = removeTag(earlierVersion, "g", eventId, url, signer, createdAt, onReady) fun removeReplaceable( earlierVersion: GalleryListEvent, aTag: ATag, + url: String, signer: NostrSigner, createdAt: Long = TimeUtils.now(), onReady: (GalleryListEvent) -> Unit, - ) = removeTag(earlierVersion, "a", aTag.toTag(), signer, createdAt, onReady) + ) = removeTag(earlierVersion, "g", aTag.toTag(), url, signer, createdAt, onReady) private fun removeTag( earlierVersion: GalleryListEvent, tagName: String, tagValue: HexKey, + url: String, signer: NostrSigner, createdAt: Long = TimeUtils.now(), onReady: (GalleryListEvent) -> Unit, @@ -111,7 +114,7 @@ class GalleryListEvent( content = earlierVersion.content, tags = earlierVersion.tags - .filter { it.size <= 1 || !(it[0] == tagName && it[1] == tagValue) } + .filter { it.size <= 1 || !(it[0] == tagName && it[1] == tagValue && it[2] == url) } .toTypedArray(), signer = signer, createdAt = createdAt, @@ -135,30 +138,5 @@ class GalleryListEvent( signer.sign(createdAt, KIND, newTags, content, onReady) } - - fun create( - name: String = "", - images: List? = null, - videos: List? = null, - audios: List? = null, - privEvents: List? = null, - privUsers: List? = null, - privAddresses: List? = null, - signer: NostrSigner, - createdAt: Long = TimeUtils.now(), - onReady: (GalleryListEvent) -> Unit, - ) { - val tags = mutableListOf>() - tags.add(arrayOf("d", name)) - - images?.forEach { tags.add(arrayOf("g", it)) } - videos?.forEach { tags.add(arrayOf("g", it)) } - audios?.forEach { tags.add(arrayOf("g", it)) } - tags.add(arrayOf("alt", ALT)) - - createPrivateTags(privEvents, privUsers, privAddresses, signer) { content -> - signer.sign(createdAt, KIND, tags.toTypedArray(), content, onReady) - } - } } }