* 'main' of https://github.com/vitorpamplona/amethyst: (48 commits)
  Use accountViewModel.viewModelScope instead of rememberCoroutineScope() to allow download/share to finish even when controls auto-close.
  Add content parameter to allow sharing of video from video player
  New Crowdin translations by GitHub Action
  - use a valid hex key - check the value of the tags
  Fixed NullPointerException when filter contain tags
  Fix assertEquals order
  fix Jackson deserialization for empty Filters and add regression test
  New Crowdin translations by GitHub Action
  Consume File.delete() return values Extract duplicated "https://" literal into a private const val HTTPS_PREFIX
  New Crowdin translations by GitHub Action
  New Crowdin translations by GitHub Action
  New Crowdin translations by GitHub Action
  Load and save payment targets
  refactor(commons): migrate from Moko to Compose Multiplatform Resources
  feat(broadcast): Enhance retry, multi-broadcast UI, and post tracking (#1682)
  wip: Add BroadcastTracker to AccountViewModel (#1682)
  feat(broadcast): Add transparent event broadcasting feedback (#1682)
  Enabled the reactions expand control for zapraisers even when there are no zaps
  New Crowdin translations by GitHub Action
  refactor to reduce complexity encodePcmToAac
  ...

# Conflicts:
#	amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/CardFeedState.kt
This commit is contained in:
Vitor Pamplona
2026-02-04 14:35:35 -05:00
167 changed files with 10411 additions and 770 deletions
@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.quartz.experimental.nipA3
import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
@@ -36,6 +37,8 @@ class PaymentTargetsEvent(
companion object {
const val KIND = 10133
fun createAddress(pubKey: HexKey): Address = Address(KIND, pubKey, FIXED_D_TAG)
suspend fun updatePaymentTargets(
earlierVersion: PaymentTargetsEvent,
targets: List<PaymentTarget>,
@@ -49,7 +49,6 @@ import com.vitorpamplona.quartz.nip19Bech32.pubKeys
import com.vitorpamplona.quartz.nip31Alts.alt
import com.vitorpamplona.quartz.nip50Search.SearchableEvent
import com.vitorpamplona.quartz.utils.TimeUtils
import kotlinx.serialization.json.JsonNull.content
@Immutable
class TextNoteEvent(
@@ -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(),
)
}
}
@@ -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"))
}
}