Merge branch 'vitorpamplona:main' into kmp-completeness
This commit is contained in:
+3
-2
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-12
@@ -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
|
||||
@@ -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) {
|
||||
@@ -733,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) }
|
||||
@@ -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
|
||||
|
||||
+7
-5
@@ -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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools"></resources>
|
||||
@@ -1202,6 +1202,9 @@ anz der Bedingungen ist erforderlich</string>
|
||||
<string name="group_relay_explanation">Das Relais, mit dem sich alle Benutzer dieses Chats verbinden</string>
|
||||
<string name="share_image">Bild teilen…</string>
|
||||
<string name="unable_to_share_image">Bild kann nicht geteilt werden, bitte versuchen Sie es später erneut…</string>
|
||||
<string name="share_video">Video teilen…</string>
|
||||
<string name="unable_to_share_video">Video kann nicht geteilt werden, bitte versuchen Sie es später erneut…</string>
|
||||
<string name="downloading_video_for_sharing">Video wird heruntergeladen…</string>
|
||||
<string name="search_by_hashtag">Suche Hashtag: #%1$s</string>
|
||||
<string name="dont_translate_from">Nicht übersetzen von</string>
|
||||
<string name="dont_translate_from_description">Die hier angezeigten Sprachen werden nicht übersetzt. Wählen Sie eine Sprache, um sie zu entfernen und lassen Sie sie erneut übersetzen.</string>
|
||||
|
||||
@@ -1202,6 +1202,9 @@
|
||||
<string name="group_relay_explanation">Az átjátszó, amelyhez a csevegés összes felhasználója csatlakozik</string>
|
||||
<string name="share_image">Kép megosztása…</string>
|
||||
<string name="unable_to_share_image">Nem lehetett megosztani a képet, próbálja meg újra később…</string>
|
||||
<string name="share_video">Videó megosztása…</string>
|
||||
<string name="unable_to_share_video">Nem sikerült megosztani a videót, próbálja meg újra később…</string>
|
||||
<string name="downloading_video_for_sharing">Videó letöltése…</string>
|
||||
<string name="search_by_hashtag">Hashtag keresése: #%1$s</string>
|
||||
<string name="dont_translate_from">Innentől NE fordítsa le</string>
|
||||
<string name="dont_translate_from_description">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.</string>
|
||||
|
||||
@@ -499,7 +499,7 @@
|
||||
<string name="no">Nie</string>
|
||||
<string name="follow_list_selection">Lista obserwowanych</string>
|
||||
<string name="follow_list_kind3follows">Obserwowane</string>
|
||||
<string name="follow_list_kind3follows_users_only">Obserwujące</string>
|
||||
<string name="follow_list_kind3follows_users_only">Obserwowane kontakty</string>
|
||||
<string name="follow_list_kind3_follows_users_only">Domyślna lista obserwowanych</string>
|
||||
<string name="follow_list_kind3follows_proxy">Obserwuje przez proxy</string>
|
||||
<string name="follow_list_aroundme">W pobliżu</string>
|
||||
@@ -1199,6 +1199,9 @@
|
||||
<string name="group_relay_explanation">Transmiter, z którym łączą się wszyscy użytkownicy tego czatu</string>
|
||||
<string name="share_image">Udostępnij zdjęcie…</string>
|
||||
<string name="unable_to_share_image">Nie można udostępnić obrazu, spróbuj ponownie później…</string>
|
||||
<string name="share_video">Udostępnij film…</string>
|
||||
<string name="unable_to_share_video">Nie można udostępnić filmu, spróbuj ponownie później…</string>
|
||||
<string name="downloading_video_for_sharing">Pobieranie filmu…</string>
|
||||
<string name="search_by_hashtag">Szukaj tagu: #%1$s</string>
|
||||
<string name="dont_translate_from">Nie tłumacz z</string>
|
||||
<string name="dont_translate_from_description">Języki wyświetlane tutaj nie będą tłumaczone. Wybierz język, aby usunąć go z listy języków nietłumaczonych.</string>
|
||||
|
||||
@@ -1197,6 +1197,9 @@
|
||||
<string name="group_relay_explanation">O relé a qual todos os usuários deste chat se conectam</string>
|
||||
<string name="share_image">Compartilhar imagem…</string>
|
||||
<string name="unable_to_share_image">Não é possível compartilhar a imagem, por favor tente novamente mais tarde…</string>
|
||||
<string name="share_video">Compartilhar vídeo…</string>
|
||||
<string name="unable_to_share_video">Não foi possível compartilhar o vídeo, tente novamente mais tarde…</string>
|
||||
<string name="downloading_video_for_sharing">Baixando vídeo…</string>
|
||||
<string name="search_by_hashtag">Pesquisar hashtag: #%1$s</string>
|
||||
<string name="dont_translate_from">Não Traduzir de</string>
|
||||
<string name="dont_translate_from_description">Os idiomas mostrados aqui não serão traduzidos. Selecione um idioma para removê-lo e traduzi-lo novamente.</string>
|
||||
|
||||
@@ -1196,6 +1196,9 @@
|
||||
<string name="group_relay_explanation">Reläet som alla användare av den här chatten ansluter till</string>
|
||||
<string name="share_image">Dela bild…</string>
|
||||
<string name="unable_to_share_image">Kunde inte dela bilden, försök igen senare…</string>
|
||||
<string name="share_video">Dela video…</string>
|
||||
<string name="unable_to_share_video">Det gick inte att dela videon, försök igen senare…</string>
|
||||
<string name="downloading_video_for_sharing">Laddar ner videon…</string>
|
||||
<string name="search_by_hashtag">Sök hashtag: #%1$s</string>
|
||||
<string name="dont_translate_from">Översätt inte från</string>
|
||||
<string name="dont_translate_from_description">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.</string>
|
||||
|
||||
@@ -1202,6 +1202,9 @@
|
||||
<string name="group_relay_explanation">此聊天所有用户都连接到的中继</string>
|
||||
<string name="share_image">分享图片…</string>
|
||||
<string name="unable_to_share_image">无法分享图片,请稍后重试…</string>
|
||||
<string name="share_video">分享视频…</string>
|
||||
<string name="unable_to_share_video">无法分享视频,请稍后重试…</string>
|
||||
<string name="downloading_video_for_sharing">正下载视频…</string>
|
||||
<string name="search_by_hashtag">搜索话题标签:#%1$s</string>
|
||||
<string name="dont_translate_from">不要翻译</string>
|
||||
<string name="dont_translate_from_description">此处显示的语言不会被翻译,请选择一种目标语言重新翻译并去除这个提示。</string>
|
||||
|
||||
+9
-9
@@ -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() },
|
||||
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(),
|
||||
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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -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,28 @@ class JacksonMapperTest {
|
||||
assertContentEquals(tag, deserialized.tags[index])
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldNotThrowExceptionWhenDeserializingEmptyFilter() {
|
||||
val json = Filter().toJson()
|
||||
val deserialized = JacksonMapper.fromJsonTo<Filter>(json)
|
||||
|
||||
assertEquals(null, deserialized.ids)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldNotThrowExceptionWhenDeserializingFilterTags() {
|
||||
val expectedTagValue = "3c39a7b53dec9ac85acf08b267637a9841e6df7b7b0f5e2ac56a8cf107de37da"
|
||||
val json =
|
||||
Filter(
|
||||
tags = mapOf("p" to listOf(expectedTagValue)),
|
||||
tagsAll = mapOf("p" to listOf(expectedTagValue)),
|
||||
).toJson()
|
||||
val deserialized = JacksonMapper.fromJsonTo<Filter>(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"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user