diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt index 8ce168b26..4375b823c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/LocalCache.kt @@ -52,7 +52,7 @@ import com.vitorpamplona.quartz.nip01Core.checkSignature import com.vitorpamplona.quartz.nip01Core.core.AddressableEvent import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.matchTag1With +import com.vitorpamplona.quartz.nip01Core.core.tagValueContains import com.vitorpamplona.quartz.nip01Core.hasValidSignature import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag import com.vitorpamplona.quartz.nip01Core.tags.addressables.mapTaggedAddress @@ -1850,7 +1850,7 @@ object LocalCache { return@filter false } - if (note.event?.tags?.matchTag1With(text) == true || + if (note.event?.tags?.tagValueContains(text, true) == true || note.idHex.startsWith(text, true) ) { if (!note.isHiddenFor(forAccount.flowHiddenUsers.value)) { @@ -1881,7 +1881,7 @@ object LocalCache { return@filter false } - if (addressable.event?.tags?.matchTag1With(text) == true || + if (addressable.event?.tags?.tagValueContains(text, true) == true || addressable.idHex.startsWith(text, true) ) { if (!addressable.isHiddenFor(forAccount.flowHiddenUsers.value)) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt index 6f4007870..e3aae9135 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Highlight.kt @@ -249,7 +249,7 @@ fun DisplayEntryForNote( val noteEvent = noteState?.note?.event as? BaseTextNoteEvent ?: return - val description = noteEvent.tags.firstTagValueFor("title", "subject", "alt") + val description = remember(noteEvent) { noteEvent.tags.firstTagValueFor("title", "subject", "alt") } Text("-", maxLines = 1) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt index 256eabbea..6cbc97a19 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/RelayList.kt @@ -75,15 +75,20 @@ fun DisplayRelaySet( val noteEvent = baseNote.event as? RelaySetEvent ?: return val relays by - remember(baseNote) { + remember(noteEvent) { mutableStateOf( noteEvent.relays().map { RelayBriefInfoCache.RelayBriefInfo(it) }.toImmutableList(), ) } + val relayListName = + remember(noteEvent) { + noteEvent.tags.firstTagValueFor("title", "name") ?: "#${noteEvent.dTag()}" + } + DisplayRelaySet( relays, - noteEvent.tags.firstTagValueFor("title", "name") ?: "#${noteEvent.dTag()}", + relayListName, noteEvent.description(), backgroundColor, accountViewModel, diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt index 5b304441d..aa665d136 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/core/TagArray.kt @@ -24,46 +24,64 @@ import com.vitorpamplona.quartz.nip01Core.HexKey typealias TagArray = Array> +/** + * Performs the given [action] on each tag that matches the given [tagName]. + */ fun TagArray.forEachTagged( tagName: String, - onEach: (eventId: HexKey) -> Unit, + action: (eventId: HexKey) -> Unit, ) = this.forEach { if (it.size > 1 && it[0] == tagName) { - onEach(it[1]) + action(it[1]) } } +/** + * Returns `true` if at least one tag matches the given [tagName] and the action. + */ fun TagArray.anyTagged( tagName: String, - onEach: (tagValue: String) -> Boolean, -) = this.any { - if (it.size > 1 && it[0] == tagName) { - onEach(it[1]) - } else { - false - } -} + predicate: (tagValue: String) -> Boolean, +) = this.any { it.size > 1 && it[0] == tagName && predicate(it[1]) } +/** + * Returns `true` if at least one tag matches the given [tagName]. + */ fun TagArray.anyTagged(tagName: String) = this.any { it.size > 0 && it[0] == tagName } -fun TagArray.anyTagWithValueStartingWithIgnoreCase( +/** + * Returns `true` if at least one tag matches the given [tagName] and its value starts with a prefix + */ +fun TagArray.anyTagWithValueStartingWith( tagName: String, valuePrefix: String, -): Boolean = this.any { it.size > 1 && it[0] == tagName && it[1].startsWith(valuePrefix, true) } + ignoreCase: Boolean = true, +): Boolean = this.any { it.size > 1 && it[0] == tagName && it[1].startsWith(valuePrefix, ignoreCase) } +/** + * Returns `true` if at least one tag matches the given name and has a value + */ fun TagArray.hasTagWithContent(tagName: String) = this.any { it.size > 1 && it[0] == tagName } +/** + * Returns a list containing only the non-null results of applying the tag value to the given [transform] function + * to each tag that matches the [tagName] + */ fun TagArray.mapValueTagged( tagName: String, - map: (tagValue: String) -> R, + transform: (tagValue: String) -> R, ) = this.mapNotNull { if (it.size > 1 && it[0] == tagName) { - map(it[1]) + transform(it[1]) } else { null } } +/** + * Returns a list containing only the non-null results of applying the tag array to the given [transform] function + * to each tag that matches the [tagName] + */ fun TagArray.mapTagged( tagName: String, map: (tagValue: Array) -> R, @@ -75,6 +93,9 @@ fun TagArray.mapTagged( } } +/** + * Returns a list containing only the non-null tag values that match the [tagName] + */ fun TagArray.mapValues(tagName: String) = this.mapNotNull { if (it.size > 1 && it[0] == tagName) { @@ -84,39 +105,76 @@ fun TagArray.mapValues(tagName: String) = } } +/** + * Returns the first non-null value produced by [transform] function being applied to all tags + * that match the [tagName] + */ fun TagArray.firstMapTagged( tagName: String, - map: (tagValue: Array) -> R, + transform: (tagValue: Array) -> R, ) = this.firstNotNullOfOrNull { if (it.size > 1 && it[0] == tagName) { - map(it) + transform(it) } else { null } } +/** + * Returns a list of tags that match the given [tagName]. + */ fun TagArray.filterByTag(tagName: String) = this.filter { it.size > 0 && it[0] == tagName } +/** + * Returns a list of tags that match the given [tagName] and have a tag value. + */ fun TagArray.filterByTagWithValue(tagName: String) = this.filter { it.size > 1 && it[0] == tagName } +/** + * Returns the first tag that match the given [tagName] and have a tag value. + */ fun TagArray.firstTag(key: String) = this.firstOrNull { it.size > 1 && it[0] == key } +/** + * Returns the first tag value that match the given [tagName] and have a tag value. + */ fun TagArray.firstTagValue(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1] } +/** + * Returns the first tag value that match the given [tagName] and have a tag value as integer + */ fun TagArray.firstTagValueAsInt(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toIntOrNull() } +/** + * Returns the first tag value that match the given [tagName] and have a tag value as long + */ fun TagArray.firstTagValueAsLong(key: String) = this.firstOrNull { it.size > 1 && it[0] == key }?.let { it[1].toLongOrNull() } -fun TagArray.firstTagValueFor(vararg key: String) = this.firstOrNull { it.size > 1 && it[0] in key }?.let { it[1] } +/** + * Returns the first tag value that match any of the given [tagNames] and have a tag value + */ +fun TagArray.firstTagValueFor(vararg tagNames: String) = this.firstOrNull { it.size > 1 && it[0] in tagNames }?.let { it[1] } +/** + * Returns `true` if at least one tag matches the given [tagName] and [tagValue] + */ fun TagArray.isTagged( - key: String, - tag: String, -) = this.any { it.size > 1 && it[0] == key && it[1] == tag } + tagName: String, + tagValue: String, +) = this.any { it.size > 1 && it[0] == tagName && it[1] == tagValue } +/** + * Returns `true` if at least one tag matches the given [tagName] and is in [tagValues] + */ fun TagArray.isAnyTagged( - key: String, - tags: Set, -) = this.any { it.size > 1 && it[0] == key && it[1] in tags } + tagName: String, + tagValues: Set, +) = this.any { it.size > 1 && it[0] == tagName && it[1] in tagValues } -fun TagArray.matchTag1With(text: String) = this.any { it.size > 1 && it[1].contains(text, true) } +/** + * Returns `true` if at least one tag has value that contains [text] + */ +fun TagArray.tagValueContains( + text: String, + ignoreCase: Boolean = false, +) = this.any { it.size > 1 && it[1].contains(text, ignoreCase) } diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt index 5ac61cdbf..a5aef9f3f 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip01Core/tags/geohash/TagArrayExt.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.quartz.nip01Core.tags.geohash import com.vitorpamplona.quartz.nip01Core.core.TagArray -import com.vitorpamplona.quartz.nip01Core.core.anyTagWithValueStartingWithIgnoreCase +import com.vitorpamplona.quartz.nip01Core.core.anyTagWithValueStartingWith import com.vitorpamplona.quartz.nip01Core.core.hasTagWithContent import com.vitorpamplona.quartz.nip01Core.core.isAnyTagged import com.vitorpamplona.quartz.nip01Core.core.mapValues @@ -30,7 +30,7 @@ fun TagArray.hasGeohashes() = this.hasTagWithContent("g") fun TagArray.isTaggedGeoHashes(hashtags: Set) = this.isAnyTagged("g", hashtags) -fun TagArray.isTaggedGeoHash(hashtag: String) = this.anyTagWithValueStartingWithIgnoreCase("g", hashtag) +fun TagArray.isTaggedGeoHash(hashtag: String) = this.anyTagWithValueStartingWith("g", hashtag) fun TagArray.geohashes() = this.mapValues("g") diff --git a/quartz/src/main/java/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt b/quartz/src/main/java/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt index 87c4aaafa..84475ac03 100644 --- a/quartz/src/main/java/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt +++ b/quartz/src/main/java/com/vitorpamplona/quartz/nip84Highlights/HighlightEvent.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.quartz.nip84Highlights import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.HexKey import com.vitorpamplona.quartz.nip01Core.core.firstTagValue -import com.vitorpamplona.quartz.nip01Core.core.firstTagValueFor import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner import com.vitorpamplona.quartz.nip01Core.tags.addressables.firstTaggedAddress import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent @@ -47,7 +46,7 @@ class HighlightEvent( fun quote() = content - fun context() = tags.firstTagValueFor("context") + fun context() = tags.firstTagValue("context") fun inPost() = firstTaggedAddress()