From 7793d2e2a39898ebe387b3af3af9a64a16c7d8ab Mon Sep 17 00:00:00 2001 From: davotoula Date: Wed, 28 Jan 2026 23:02:38 +0100 Subject: [PATCH 1/9] Consume File.delete() return values Extract duplicated "https://" literal into a private const val HTTPS_PREFIX --- .../ui/components/ZoomableContentView.kt | 26 ++++++++++++------- .../loggedIn/relays/RelayInformationScreen.kt | 12 +++++---- 2 files changed, 23 insertions(+), 15 deletions(-) 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 97d8e193d..d987e4b5f 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 @@ -246,8 +246,8 @@ fun LocalImageView( } val ratio = remember(content) { content.dim?.aspectRatio() ?: MediaAspectRatioCache.get(content.localFile.toString()) } - CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) { - if (it) { + CrossfadeIfEnabled(targetState = showImage.value, contentAlignment = Alignment.Center, accountViewModel = accountViewModel) { imageVisible -> + if (imageVisible) { SubcomposeAsyncImage( model = content.localFile, contentDescription = content.description, @@ -552,11 +552,7 @@ fun ShowHash(content: MediaUrlContent) { } @Composable -fun WaitAndDisplay( - content: - @Composable() - (AnimatedVisibilityScope.() -> Unit), -) { +fun WaitAndDisplay(content: @Composable (AnimatedVisibilityScope.() -> Unit)) { val visible = remember { mutableStateOf(false) } LaunchedEffect(Unit) { @@ -939,7 +935,11 @@ private suspend fun shareVideoFile( // GlobalScope is intentional: cleanup must survive after share UI is dismissed. GlobalScope.launch(Dispatchers.IO) { delay(SHARED_VIDEO_CLEANUP_DELAY_MS) - sharedFile?.delete() + sharedFile?.let { file -> + if (!file.delete()) { + Log.w("ZoomableContentView", "Failed to delete shared file: ${file.path}") + } + } } withContext(Dispatchers.Main) { @@ -950,8 +950,14 @@ private suspend fun shareVideoFile( Log.w("ZoomableContentView", "Failed to share video: $videoUrl", e) // Clean up temp file on error - tempFile.delete() - sharedFile?.delete() + if (!tempFile.delete()) { + Log.w("ZoomableContentView", "Failed to delete temp file: ${tempFile.path}") + } + sharedFile?.let { file -> + if (!file.delete()) { + Log.w("ZoomableContentView", "Failed to delete shared file: ${file.path}") + } + } withContext(Dispatchers.Main) { Toast diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt index 5e4fc7b20..0be396cda 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/relays/RelayInformationScreen.kt @@ -128,6 +128,8 @@ import kotlinx.collections.immutable.toImmutableList import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract +private const val HTTPS_PREFIX = "https://" + @Composable fun RelayInformationScreen( relayUrl: String, @@ -434,7 +436,7 @@ fun FeesCard( } payUrl?.let { val uri = LocalUriHandler.current - ClickableInfoRow(Icons.Default.Payment, stringRes(R.string.payments_url), it.removePrefix("https://")) { + ClickableInfoRow(Icons.Default.Payment, stringRes(R.string.payments_url), it.removePrefix(HTTPS_PREFIX)) { runCatching { uri.openUri(it) } @@ -583,8 +585,8 @@ fun SoftwareCard(relayInfo: Nip11RelayInformation) { Column(modifier = Modifier.padding(16.dp)) { val uri = LocalUriHandler.current relayInfo.software?.let { - if (it.contains("https://")) { - ClickableInfoRow(Icons.Default.Code, stringRes(R.string.software), it.removePrefix("git+https://").removePrefix("https://")) { + if (it.contains(HTTPS_PREFIX)) { + ClickableInfoRow(Icons.Default.Code, stringRes(R.string.software), it.removePrefix("git+https://").removePrefix(HTTPS_PREFIX)) { runCatching { uri.openUri(it.removePrefix("git+")) } @@ -809,7 +811,7 @@ fun PoliciesCard(relay: Nip11RelayInformation) { val pp = relay.privacy_policy if (pp != null) { - ClickableInfoRow(Icons.Default.PrivacyTip, stringRes(R.string.privacy_policy), pp.removePrefix("https://")) { + ClickableInfoRow(Icons.Default.PrivacyTip, stringRes(R.string.privacy_policy), pp.removePrefix(HTTPS_PREFIX)) { runCatching { uri.openUri(pp) } @@ -820,7 +822,7 @@ fun PoliciesCard(relay: Nip11RelayInformation) { val ts = relay.terms_of_service if (ts != null) { - ClickableInfoRow(Icons.Default.Gavel, stringRes(R.string.terms_and_conditions), ts.removePrefix("https://")) { + ClickableInfoRow(Icons.Default.Gavel, stringRes(R.string.terms_and_conditions), ts.removePrefix(HTTPS_PREFIX)) { runCatching { uri.openUri(ts) } From 781da12475ad2132f27da61ac66220d742f66e20 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 29 Jan 2026 07:23:27 +0000 Subject: [PATCH 2/9] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-de-rDE/strings.xml | 3 +++ amethyst/src/main/res/values-pl-rPL/strings.xml | 3 +++ amethyst/src/main/res/values-pt-rBR/strings.xml | 3 +++ amethyst/src/main/res/values-sv-rSE/strings.xml | 3 +++ 4 files changed, 12 insertions(+) diff --git a/amethyst/src/main/res/values-de-rDE/strings.xml b/amethyst/src/main/res/values-de-rDE/strings.xml index 9015e0965..77c479819 100644 --- a/amethyst/src/main/res/values-de-rDE/strings.xml +++ b/amethyst/src/main/res/values-de-rDE/strings.xml @@ -1202,6 +1202,9 @@ anz der Bedingungen ist erforderlich Das Relais, mit dem sich alle Benutzer dieses Chats verbinden Bild teilen… Bild kann nicht geteilt werden, bitte versuchen Sie es später erneut… + Video teilen… + Video kann nicht geteilt werden, bitte versuchen Sie es später erneut… + Video wird heruntergeladen… Suche Hashtag: #%1$s Nicht übersetzen von Die hier angezeigten Sprachen werden nicht übersetzt. Wählen Sie eine Sprache, um sie zu entfernen und lassen Sie sie erneut übersetzen. diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index eaf7cce96..3d1f659f8 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -1199,6 +1199,9 @@ Transmiter, z którym łączą się wszyscy użytkownicy tego czatu Udostępnij zdjęcie… Nie można udostępnić obrazu, spróbuj ponownie później… + Udostępnij film… + Nie można udostępnić filmu, spróbuj ponownie później… + Pobieranie filmu… Szukaj tagu: #%1$s Nie tłumacz z Języki wyświetlane tutaj nie będą tłumaczone. Wybierz język, aby usunąć go z listy języków nietłumaczonych. diff --git a/amethyst/src/main/res/values-pt-rBR/strings.xml b/amethyst/src/main/res/values-pt-rBR/strings.xml index a90421341..09aa6def8 100644 --- a/amethyst/src/main/res/values-pt-rBR/strings.xml +++ b/amethyst/src/main/res/values-pt-rBR/strings.xml @@ -1197,6 +1197,9 @@ O relé a qual todos os usuários deste chat se conectam Compartilhar imagem… Não é possível compartilhar a imagem, por favor tente novamente mais tarde… + Compartilhar vídeo… + Não foi possível compartilhar o vídeo, tente novamente mais tarde… + Baixando vídeo… Pesquisar hashtag: #%1$s Não Traduzir de Os idiomas mostrados aqui não serão traduzidos. Selecione um idioma para removê-lo e traduzi-lo novamente. diff --git a/amethyst/src/main/res/values-sv-rSE/strings.xml b/amethyst/src/main/res/values-sv-rSE/strings.xml index 44571cb2a..e8be7b477 100644 --- a/amethyst/src/main/res/values-sv-rSE/strings.xml +++ b/amethyst/src/main/res/values-sv-rSE/strings.xml @@ -1196,6 +1196,9 @@ Reläet som alla användare av den här chatten ansluter till Dela bild… Kunde inte dela bilden, försök igen senare… + Dela video… + Det gick inte att dela videon, försök igen senare… + Laddar ner videon… Sök hashtag: #%1$s Översätt inte från Språk som visas här kommer inte att översättas. Välj ett språk för att ta bort det och få det översatt igen. From 247e30beedd5d6e55d8c53cb9356b278ed02ec3a Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 30 Jan 2026 07:31:38 -0300 Subject: [PATCH 3/9] fix Jackson deserialization for empty Filters and add regression test --- .../nip01Core/relay/filters/FilterDeserializer.kt | 14 +++++++------- .../quartz/nip01Core/jackson/JacksonMapperTest.kt | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt index 556dda5de..5bf629536 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt @@ -52,15 +52,15 @@ class ManualFilterDeserializer { } return Filter( - ids = jsonObject.get("ids").mapNotNull { it.asTextOrNull() }, - authors = jsonObject.get("authors").mapNotNull { it.asTextOrNull() }, - kinds = jsonObject.get("kinds").mapNotNull { it.asIntOrNull() }, + ids = jsonObject.get("ids")?.mapNotNull { it.asTextOrNull() }, + authors = jsonObject.get("authors")?.mapNotNull { it.asTextOrNull() }, + kinds = jsonObject.get("kinds")?.mapNotNull { it.asIntOrNull() }, tags = tagsIn.associateWith { jsonObject.get(it).mapNotNull { it.asTextOrNull() } }, tagsAll = tagsAll.associateWith { jsonObject.get(it).mapNotNull { it.asTextOrNull() } }, - since = jsonObject.get("since").asLongOrNull(), - until = jsonObject.get("until").asLongOrNull(), - limit = jsonObject.get("limit").asIntOrNull(), - search = jsonObject.get("search").asTextOrNull(), + since = jsonObject.get("since")?.asLongOrNull(), + until = jsonObject.get("until")?.asLongOrNull(), + limit = jsonObject.get("limit")?.asIntOrNull(), + search = jsonObject.get("search")?.asTextOrNull(), ) } } diff --git a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt index b9cc65956..252b21789 100644 --- a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt +++ b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt @@ -21,6 +21,7 @@ package com.vitorpamplona.quartz.nip01Core.jackson import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate import com.vitorpamplona.quartz.nip51Lists.followList.FollowListEvent import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor @@ -152,4 +153,12 @@ class JacksonMapperTest { assertContentEquals(tag, deserialized.tags[index]) } } + + @Test + fun shouldNotThrowExceptionWhenDeserializingEmptyFilter() { + val json = Filter().toJson() + val deserialized = JacksonMapper.fromJsonTo(json) + + assertEquals(deserialized.ids, null) + } } From 8bfd670f8b4755133030c9749bd0d4df10021bfb Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 30 Jan 2026 08:50:09 -0300 Subject: [PATCH 4/9] Fix assertEquals order --- .../vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt index 252b21789..c691bd152 100644 --- a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt +++ b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt @@ -159,6 +159,6 @@ class JacksonMapperTest { val json = Filter().toJson() val deserialized = JacksonMapper.fromJsonTo(json) - assertEquals(deserialized.ids, null) + assertEquals(null, deserialized.ids) } } From f2d7b115d93c446292bf0fae98e4a66bce949eb6 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 30 Jan 2026 09:00:52 -0300 Subject: [PATCH 5/9] Fixed NullPointerException when filter contain tags --- .../nip01Core/relay/filters/FilterDeserializer.kt | 4 ++-- .../quartz/nip01Core/jackson/JacksonMapperTest.kt | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt index 5bf629536..618491580 100644 --- a/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt +++ b/quartz/src/jvmAndroid/kotlin/com/vitorpamplona/quartz/nip01Core/relay/filters/FilterDeserializer.kt @@ -55,8 +55,8 @@ class ManualFilterDeserializer { ids = jsonObject.get("ids")?.mapNotNull { it.asTextOrNull() }, authors = jsonObject.get("authors")?.mapNotNull { it.asTextOrNull() }, kinds = jsonObject.get("kinds")?.mapNotNull { it.asIntOrNull() }, - tags = tagsIn.associateWith { jsonObject.get(it).mapNotNull { it.asTextOrNull() } }, - tagsAll = tagsAll.associateWith { jsonObject.get(it).mapNotNull { it.asTextOrNull() } }, + tags = tagsIn.associateWith { jsonObject.get("#$it").mapNotNull { it.asTextOrNull() } }, + tagsAll = tagsAll.associateWith { jsonObject.get("&$it").mapNotNull { it.asTextOrNull() } }, since = jsonObject.get("since")?.asLongOrNull(), until = jsonObject.get("until")?.asLongOrNull(), limit = jsonObject.get("limit")?.asIntOrNull(), diff --git a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt index c691bd152..84844d0e2 100644 --- a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt +++ b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt @@ -161,4 +161,17 @@ class JacksonMapperTest { assertEquals(null, deserialized.ids) } + + @Test + fun shouldNotThrowExceptionWhenDeserializingFilterTags() { + val json = + Filter( + tags = mapOf("p" to listOf("123")), + tagsAll = mapOf("p" to listOf("123")), + ).toJson() + val deserialized = JacksonMapper.fromJsonTo(json) + + assertEquals(true, deserialized.tags?.keys?.contains("p")) + assertEquals(true, deserialized.tagsAll?.keys?.contains("p")) + } } From 577b4c0e0a1de0e41b8f3dd1b5d28d7d6964a2ad Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Fri, 30 Jan 2026 09:38:09 -0300 Subject: [PATCH 6/9] - use a valid hex key - check the value of the tags --- .../quartz/nip01Core/jackson/JacksonMapperTest.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt index 84844d0e2..b9b732596 100644 --- a/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt +++ b/quartz/src/jvmAndroidTest/kotlin/com/vitorpamplona/quartz/nip01Core/jackson/JacksonMapperTest.kt @@ -164,14 +164,17 @@ class JacksonMapperTest { @Test fun shouldNotThrowExceptionWhenDeserializingFilterTags() { + val expectedTagValue = "3c39a7b53dec9ac85acf08b267637a9841e6df7b7b0f5e2ac56a8cf107de37da" val json = Filter( - tags = mapOf("p" to listOf("123")), - tagsAll = mapOf("p" to listOf("123")), + tags = mapOf("p" to listOf(expectedTagValue)), + tagsAll = mapOf("p" to listOf(expectedTagValue)), ).toJson() val deserialized = JacksonMapper.fromJsonTo(json) assertEquals(true, deserialized.tags?.keys?.contains("p")) + assertEquals(listOf(expectedTagValue), deserialized.tags?.get("p")) assertEquals(true, deserialized.tagsAll?.keys?.contains("p")) + assertEquals(listOf(expectedTagValue), deserialized.tagsAll?.get("p")) } } From 863f93a621bad5b4e2cddee69b924dbd32263a16 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 30 Jan 2026 13:48:47 +0000 Subject: [PATCH 7/9] New Crowdin translations by GitHub Action --- amethyst/src/main/res/values-ca-rES/strings.xml | 2 ++ amethyst/src/main/res/values-hu-rHU/strings.xml | 3 +++ amethyst/src/main/res/values-pl-rPL/strings.xml | 2 +- amethyst/src/main/res/values-zh-rCN/strings.xml | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 amethyst/src/main/res/values-ca-rES/strings.xml diff --git a/amethyst/src/main/res/values-ca-rES/strings.xml b/amethyst/src/main/res/values-ca-rES/strings.xml new file mode 100644 index 000000000..66a570486 --- /dev/null +++ b/amethyst/src/main/res/values-ca-rES/strings.xml @@ -0,0 +1,2 @@ + + diff --git a/amethyst/src/main/res/values-hu-rHU/strings.xml b/amethyst/src/main/res/values-hu-rHU/strings.xml index dece24a0f..5c4b548ec 100644 --- a/amethyst/src/main/res/values-hu-rHU/strings.xml +++ b/amethyst/src/main/res/values-hu-rHU/strings.xml @@ -1202,6 +1202,9 @@ Az átjátszó, amelyhez a csevegés összes felhasználója csatlakozik Kép megosztása… Nem lehetett megosztani a képet, próbálja meg újra később… + Videó megosztása… + Nem sikerült megosztani a videót, próbálja meg újra később… + Videó letöltése… Hashtag keresése: #%1$s Innentől NE fordítsa le Az itt látható nyelvek nem lesznek lefordítva. Az eltávolításához és az újbóli fordításhoz válasszon ki egy nyelvet. diff --git a/amethyst/src/main/res/values-pl-rPL/strings.xml b/amethyst/src/main/res/values-pl-rPL/strings.xml index 3d1f659f8..557f88dc0 100644 --- a/amethyst/src/main/res/values-pl-rPL/strings.xml +++ b/amethyst/src/main/res/values-pl-rPL/strings.xml @@ -499,7 +499,7 @@ Nie Lista obserwowanych Obserwowane - Obserwujące + Obserwowane kontakty Domyślna lista obserwowanych Obserwuje przez proxy W pobliżu diff --git a/amethyst/src/main/res/values-zh-rCN/strings.xml b/amethyst/src/main/res/values-zh-rCN/strings.xml index 7f427f586..23e488f30 100644 --- a/amethyst/src/main/res/values-zh-rCN/strings.xml +++ b/amethyst/src/main/res/values-zh-rCN/strings.xml @@ -1202,6 +1202,9 @@ 此聊天所有用户都连接到的中继 分享图片… 无法分享图片,请稍后重试… + 分享视频… + 无法分享视频,请稍后重试… + 正下载视频… 搜索话题标签:#%1$s 不要翻译 此处显示的语言不会被翻译,请选择一种目标语言重新翻译并去除这个提示。 From 1cd8eeda4ec680c39c83af940a7cb0e4fbec0565 Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 30 Jan 2026 21:49:30 +0100 Subject: [PATCH 8/9] Add content parameter to allow sharing of video from video player --- .../playback/composable/controls/RenderControlButtons.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderControlButtons.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderControlButtons.kt index aab7ff6e9..5964bf660 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderControlButtons.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/controls/RenderControlButtons.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import com.vitorpamplona.amethyst.commons.richtext.MediaUrlVideo import com.vitorpamplona.amethyst.service.playback.composable.DEFAULT_MUTED_SETTING import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState import com.vitorpamplona.amethyst.service.playback.composable.mediaitem.MediaItemData @@ -71,11 +72,11 @@ fun RenderControlButtons( } AnimatedShareButton(controllerVisible, buttonPositionModifier.padding(end = Size165dp)) { popupExpanded, toggle -> - ShareMediaAction(accountViewModel = accountViewModel, popupExpanded, mediaData.videoUri, mediaData.callbackUri, null, null, null, mediaData.mimeType, toggle) + ShareMediaAction(accountViewModel = accountViewModel, popupExpanded, mediaData.videoUri, mediaData.callbackUri, null, null, null, mediaData.mimeType, toggle, content = MediaUrlVideo(url = mediaData.videoUri, mimeType = mediaData.mimeType, artworkUri = mediaData.artworkUri, authorName = mediaData.authorName, description = mediaData.title, uri = mediaData.callbackUri)) } } else { AnimatedShareButton(controllerVisible, buttonPositionModifier.padding(end = Size110dp)) { popupExpanded, toggle -> - ShareMediaAction(accountViewModel = accountViewModel, popupExpanded, mediaData.videoUri, mediaData.callbackUri, null, null, null, mediaData.mimeType, toggle) + ShareMediaAction(accountViewModel = accountViewModel, popupExpanded, mediaData.videoUri, mediaData.callbackUri, null, null, null, mediaData.mimeType, toggle, content = MediaUrlVideo(url = mediaData.videoUri, mimeType = mediaData.mimeType, artworkUri = mediaData.artworkUri, authorName = mediaData.authorName, description = mediaData.title, uri = mediaData.callbackUri)) } } } From f7b815bedb031f527413c47a26f86428293b2bf6 Mon Sep 17 00:00:00 2001 From: davotoula Date: Fri, 30 Jan 2026 22:01:12 +0100 Subject: [PATCH 9/9] Use accountViewModel.viewModelScope instead of rememberCoroutineScope() to allow download/share to finish even when controls auto-close. --- .../amethyst/ui/components/ZoomableContentView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 d987e4b5f..720539ac6 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 @@ -53,7 +53,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -69,6 +68,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.core.net.toUri +import androidx.lifecycle.viewModelScope import coil3.compose.AsyncImage import coil3.compose.AsyncImagePainter import coil3.compose.SubcomposeAsyncImage @@ -729,7 +729,7 @@ fun ShareMediaAction( onDismiss: () -> Unit, content: BaseMediaContent? = null, ) { - val scope = rememberCoroutineScope() + val scope = accountViewModel.viewModelScope // Track if video is downloading - hoisted here to block menu dismiss during download val isDownloadingVideo = remember { mutableStateOf(false) }