Adds new Highlight event kind from https://highlighter.com/
This commit is contained in:
@@ -396,10 +396,10 @@ class Account(
|
|||||||
)
|
)
|
||||||
|
|
||||||
Client.send(data)
|
Client.send(data)
|
||||||
LocalCache.consume(data)
|
LocalCache.consume(data, null)
|
||||||
|
|
||||||
Client.send(signedEvent)
|
Client.send(signedEvent)
|
||||||
LocalCache.consume(signedEvent)
|
LocalCache.consume(signedEvent, null)
|
||||||
|
|
||||||
return LocalCache.notes[signedEvent.id]
|
return LocalCache.notes[signedEvent.id]
|
||||||
}
|
}
|
||||||
@@ -418,7 +418,7 @@ class Account(
|
|||||||
)
|
)
|
||||||
|
|
||||||
Client.send(signedEvent)
|
Client.send(signedEvent)
|
||||||
LocalCache.consume(signedEvent)
|
LocalCache.consume(signedEvent, null)
|
||||||
|
|
||||||
return LocalCache.notes[signedEvent.id]
|
return LocalCache.notes[signedEvent.id]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -653,40 +653,72 @@ object LocalCache {
|
|||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun consume(event: FileHeaderEvent) {
|
fun consume(event: FileHeaderEvent, relay: Relay?) {
|
||||||
val note = getOrCreateNote(event.id)
|
val note = getOrCreateNote(event.id)
|
||||||
|
val author = getOrCreateUser(event.pubKey)
|
||||||
|
|
||||||
|
if (relay != null) {
|
||||||
|
author.addRelayBeingUsed(relay, event.createdAt)
|
||||||
|
note.addRelay(relay)
|
||||||
|
}
|
||||||
|
|
||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
val author = getOrCreateUser(event.pubKey)
|
|
||||||
|
|
||||||
note.loadEvent(event, author, emptyList())
|
note.loadEvent(event, author, emptyList())
|
||||||
|
|
||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun consume(event: FileStorageHeaderEvent) {
|
fun consume(event: FileStorageHeaderEvent, relay: Relay?) {
|
||||||
val note = getOrCreateNote(event.id)
|
val note = getOrCreateNote(event.id)
|
||||||
|
val author = getOrCreateUser(event.pubKey)
|
||||||
|
|
||||||
|
if (relay != null) {
|
||||||
|
author.addRelayBeingUsed(relay, event.createdAt)
|
||||||
|
note.addRelay(relay)
|
||||||
|
}
|
||||||
|
|
||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
val author = getOrCreateUser(event.pubKey)
|
|
||||||
|
|
||||||
note.loadEvent(event, author, emptyList())
|
note.loadEvent(event, author, emptyList())
|
||||||
|
|
||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun consume(event: FileStorageEvent) {
|
fun consume(event: HighlightEvent, relay: Relay?) {
|
||||||
val note = getOrCreateNote(event.id)
|
val note = getOrCreateNote(event.id)
|
||||||
|
val author = getOrCreateUser(event.pubKey)
|
||||||
|
|
||||||
|
if (relay != null) {
|
||||||
|
author.addRelayBeingUsed(relay, event.createdAt)
|
||||||
|
note.addRelay(relay)
|
||||||
|
}
|
||||||
|
|
||||||
// Already processed this event.
|
// Already processed this event.
|
||||||
if (note.event != null) return
|
if (note.event != null) return
|
||||||
|
|
||||||
|
note.loadEvent(event, author, emptyList())
|
||||||
|
|
||||||
|
// Adds to user profile
|
||||||
|
author.addNote(note)
|
||||||
|
|
||||||
|
refreshObservers(note)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun consume(event: FileStorageEvent, relay: Relay?) {
|
||||||
|
val note = getOrCreateNote(event.id)
|
||||||
val author = getOrCreateUser(event.pubKey)
|
val author = getOrCreateUser(event.pubKey)
|
||||||
|
|
||||||
|
if (relay != null) {
|
||||||
|
author.addRelayBeingUsed(relay, event.createdAt)
|
||||||
|
note.addRelay(relay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already processed this event.
|
||||||
|
if (note.event != null) return
|
||||||
|
|
||||||
note.loadEvent(event, author, emptyList())
|
note.loadEvent(event, author, emptyList())
|
||||||
|
|
||||||
refreshObservers(note)
|
refreshObservers(note)
|
||||||
|
|||||||
@@ -76,9 +76,10 @@ abstract class NostrDataSource(val debugName: String) {
|
|||||||
is ContactListEvent -> LocalCache.consume(event)
|
is ContactListEvent -> LocalCache.consume(event)
|
||||||
is DeletionEvent -> LocalCache.consume(event)
|
is DeletionEvent -> LocalCache.consume(event)
|
||||||
|
|
||||||
is FileHeaderEvent -> LocalCache.consume(event)
|
is FileHeaderEvent -> LocalCache.consume(event, relay)
|
||||||
is FileStorageEvent -> LocalCache.consume(event)
|
is FileStorageEvent -> LocalCache.consume(event, relay)
|
||||||
is FileStorageHeaderEvent -> LocalCache.consume(event)
|
is FileStorageHeaderEvent -> LocalCache.consume(event, relay)
|
||||||
|
is HighlightEvent -> LocalCache.consume(event, relay)
|
||||||
is LnZapEvent -> {
|
is LnZapEvent -> {
|
||||||
event.zapRequest?.let { onEvent(it, subscriptionId, relay) }
|
event.zapRequest?.let { onEvent(it, subscriptionId, relay) }
|
||||||
LocalCache.consume(event)
|
LocalCache.consume(event)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.vitorpamplona.amethyst.service
|
package com.vitorpamplona.amethyst.service
|
||||||
|
|
||||||
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
|
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
||||||
@@ -12,7 +13,7 @@ object NostrGlobalDataSource : NostrDataSource("GlobalFeed") {
|
|||||||
fun createGlobalFilter() = TypedFilter(
|
fun createGlobalFilter() = TypedFilter(
|
||||||
types = setOf(FeedType.GLOBAL),
|
types = setOf(FeedType.GLOBAL),
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(TextNoteEvent.kind, PollNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind),
|
kinds = listOf(TextNoteEvent.kind, PollNoteEvent.kind, ChannelMessageEvent.kind, LongTextNoteEvent.kind, HighlightEvent.kind),
|
||||||
limit = 200
|
limit = 200
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.service
|
|||||||
|
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.UserState
|
import com.vitorpamplona.amethyst.model.UserState
|
||||||
|
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.TextNoteEvent
|
||||||
@@ -55,7 +56,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
|
|||||||
return TypedFilter(
|
return TypedFilter(
|
||||||
types = setOf(FeedType.FOLLOWS),
|
types = setOf(FeedType.FOLLOWS),
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind),
|
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, HighlightEvent.kind),
|
||||||
authors = followSet,
|
authors = followSet,
|
||||||
limit = 400,
|
limit = 400,
|
||||||
since = latestEOSEs.users[account.userProfile()]?.relayList
|
since = latestEOSEs.users[account.userProfile()]?.relayList
|
||||||
@@ -71,7 +72,7 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
|
|||||||
return TypedFilter(
|
return TypedFilter(
|
||||||
types = setOf(FeedType.FOLLOWS),
|
types = setOf(FeedType.FOLLOWS),
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind),
|
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, HighlightEvent.kind),
|
||||||
tags = mapOf(
|
tags = mapOf(
|
||||||
"t" to hashToLoad.map {
|
"t" to hashToLoad.map {
|
||||||
listOf(it, it.lowercase(), it.uppercase(), it.capitalize())
|
listOf(it, it.lowercase(), it.uppercase(), it.capitalize())
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ object NostrSearchEventOrUserDataSource : NostrDataSource("SingleEventFeed") {
|
|||||||
TypedFilter(
|
TypedFilter(
|
||||||
types = COMMON_FEED_TYPES,
|
types = COMMON_FEED_TYPES,
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, ChannelMetadataEvent.kind, ChannelCreateEvent.kind, ChannelMessageEvent.kind),
|
kinds = listOf(TextNoteEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, ChannelMetadataEvent.kind, ChannelCreateEvent.kind, ChannelMessageEvent.kind, HighlightEvent.kind),
|
||||||
search = mySearchString,
|
search = mySearchString,
|
||||||
limit = 20
|
limit = 20
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ object NostrSingleEventDataSource : NostrDataSource("SingleEventFeed") {
|
|||||||
ReportEvent.kind,
|
ReportEvent.kind,
|
||||||
LnZapEvent.kind,
|
LnZapEvent.kind,
|
||||||
LnZapRequestEvent.kind,
|
LnZapRequestEvent.kind,
|
||||||
PollNoteEvent.kind
|
PollNoteEvent.kind,
|
||||||
|
HighlightEvent.kind
|
||||||
),
|
),
|
||||||
tags = mapOf("e" to listOf(it.idHex)),
|
tags = mapOf("e" to listOf(it.idHex)),
|
||||||
since = it.lastReactionsDownloadTime
|
since = it.lastReactionsDownloadTime
|
||||||
@@ -117,7 +118,8 @@ object NostrSingleEventDataSource : NostrDataSource("SingleEventFeed") {
|
|||||||
ChannelMessageEvent.kind, ChannelCreateEvent.kind, ChannelMetadataEvent.kind,
|
ChannelMessageEvent.kind, ChannelCreateEvent.kind, ChannelMetadataEvent.kind,
|
||||||
BadgeDefinitionEvent.kind, BadgeAwardEvent.kind, BadgeProfilesEvent.kind,
|
BadgeDefinitionEvent.kind, BadgeAwardEvent.kind, BadgeProfilesEvent.kind,
|
||||||
PrivateDmEvent.kind,
|
PrivateDmEvent.kind,
|
||||||
FileHeaderEvent.kind, FileStorageEvent.kind, FileStorageHeaderEvent.kind
|
FileHeaderEvent.kind, FileStorageEvent.kind, FileStorageHeaderEvent.kind,
|
||||||
|
HighlightEvent.kind
|
||||||
),
|
),
|
||||||
ids = interestedEvents.toList()
|
ids = interestedEvents.toList()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") {
|
|||||||
TypedFilter(
|
TypedFilter(
|
||||||
types = COMMON_FEED_TYPES,
|
types = COMMON_FEED_TYPES,
|
||||||
filter = JsonFilter(
|
filter = JsonFilter(
|
||||||
kinds = listOf(TextNoteEvent.kind, RepostEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind),
|
kinds = listOf(TextNoteEvent.kind, RepostEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, HighlightEvent.kind),
|
||||||
authors = listOf(it.pubkeyHex),
|
authors = listOf(it.pubkeyHex),
|
||||||
limit = 200
|
limit = 200
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ open class Event(
|
|||||||
fun taggedUsers() = tags.filter { it.size > 1 && it[0] == "p" }.map { it[1] }
|
fun taggedUsers() = tags.filter { it.size > 1 && it[0] == "p" }.map { it[1] }
|
||||||
fun taggedEvents() = tags.filter { it.size > 1 && it[0] == "e" }.map { it[1] }
|
fun taggedEvents() = tags.filter { it.size > 1 && it[0] == "e" }.map { it[1] }
|
||||||
|
|
||||||
|
fun taggedUrls() = tags.filter { it.size > 1 && it[0] == "r" }.map { it[1] }
|
||||||
|
|
||||||
override fun zapAddress() = tags.firstOrNull { it.size > 1 && it[0] == "zap" }?.get(1)
|
override fun zapAddress() = tags.firstOrNull { it.size > 1 && it[0] == "zap" }?.get(1)
|
||||||
|
|
||||||
fun taggedAddresses() = tags.filter { it.size > 1 && it[0] == "a" }.mapNotNull {
|
fun taggedAddresses() = tags.filter { it.size > 1 && it[0] == "a" }.mapNotNull {
|
||||||
@@ -227,6 +229,7 @@ open class Event(
|
|||||||
FileHeaderEvent.kind -> FileHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
FileHeaderEvent.kind -> FileHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
FileStorageEvent.kind -> FileStorageEvent(id, pubKey, createdAt, tags, content, sig)
|
FileStorageEvent.kind -> FileStorageEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
FileStorageHeaderEvent.kind -> FileStorageHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
FileStorageHeaderEvent.kind -> FileStorageHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
HighlightEvent.kind -> HighlightEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LnZapEvent.kind -> LnZapEvent(id, pubKey, createdAt, tags, content, sig)
|
LnZapEvent.kind -> LnZapEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LnZapPaymentRequestEvent.kind -> LnZapPaymentRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
LnZapPaymentRequestEvent.kind -> LnZapPaymentRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
LnZapPaymentResponseEvent.kind -> LnZapPaymentResponseEvent(id, pubKey, createdAt, tags, content, sig)
|
LnZapPaymentResponseEvent.kind -> LnZapPaymentResponseEvent(id, pubKey, createdAt, tags, content, sig)
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.vitorpamplona.amethyst.service.model
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.model.HexKey
|
||||||
|
import com.vitorpamplona.amethyst.model.toHexKey
|
||||||
|
import nostr.postr.Utils
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class HighlightEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
tags: List<List<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey
|
||||||
|
) : BaseTextNoteEvent(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
|
|
||||||
|
fun inUrl() = taggedUrls().firstOrNull()
|
||||||
|
fun author() = taggedUsers().firstOrNull()
|
||||||
|
fun quote() = content
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val kind = 9802
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
msg: String,
|
||||||
|
privateKey: ByteArray,
|
||||||
|
createdAt: Long = Date().time / 1000
|
||||||
|
): PollNoteEvent {
|
||||||
|
val pubKey = Utils.pubkeyCreate(privateKey).toHexKey()
|
||||||
|
val tags = mutableListOf<List<String>>()
|
||||||
|
val id = generateId(pubKey, createdAt, kind, tags, msg)
|
||||||
|
val sig = Utils.sign(id, privateKey)
|
||||||
|
return PollNoteEvent(id.toHexKey(), pubKey, createdAt, tags, msg, sig.toHexKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,7 +86,8 @@ fun RichTextViewer(
|
|||||||
navController: NavController
|
navController: NavController
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
if (content.startsWith("# ") ||
|
if (content.startsWith("> ") ||
|
||||||
|
content.startsWith("# ") ||
|
||||||
content.contains("##") ||
|
content.contains("##") ||
|
||||||
content.contains("**") ||
|
content.contains("**") ||
|
||||||
content.contains("__") ||
|
content.contains("__") ||
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.dal
|
|||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
|
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||||
@@ -30,7 +31,7 @@ object HomeNewThreadFeedFilter : AdditiveFeedFilter<Note>() {
|
|||||||
return collection
|
return collection
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it ->
|
.filter { it ->
|
||||||
(it.event is TextNoteEvent || it.event is RepostEvent || it.event is LongTextNoteEvent || it.event is PollNoteEvent) &&
|
(it.event is TextNoteEvent || it.event is RepostEvent || it.event is LongTextNoteEvent || it.event is PollNoteEvent || it.event is HighlightEvent) &&
|
||||||
(it.author?.pubkeyHex in followingKeySet || (it.event?.isTaggedHashes(followingTagSet) ?: false)) &&
|
(it.author?.pubkeyHex in followingKeySet || (it.event?.isTaggedHashes(followingTagSet) ?: false)) &&
|
||||||
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
||||||
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true &&
|
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true &&
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.ui.theme.Following
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
import java.net.URL
|
||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
import kotlin.time.measureTimedValue
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
@@ -517,6 +518,26 @@ fun NoteComposeInner(
|
|||||||
ReactionsRow(note, accountViewModel, navController)
|
ReactionsRow(note, accountViewModel, navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier.padding(top = 10.dp),
|
||||||
|
thickness = 0.25.dp
|
||||||
|
)
|
||||||
|
} else if (noteEvent is HighlightEvent) {
|
||||||
|
DisplayHighlight(
|
||||||
|
noteEvent.quote(),
|
||||||
|
noteEvent.author(),
|
||||||
|
noteEvent.inUrl(),
|
||||||
|
makeItShort,
|
||||||
|
canPreview,
|
||||||
|
backgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
navController
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!makeItShort) {
|
||||||
|
ReactionsRow(note, accountViewModel, navController)
|
||||||
|
}
|
||||||
|
|
||||||
Divider(
|
Divider(
|
||||||
modifier = Modifier.padding(top = 10.dp),
|
modifier = Modifier.padding(top = 10.dp),
|
||||||
thickness = 0.25.dp
|
thickness = 0.25.dp
|
||||||
@@ -574,6 +595,66 @@ fun NoteComposeInner(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DisplayHighlight(
|
||||||
|
highlight: String,
|
||||||
|
authorHex: String?,
|
||||||
|
url: String?,
|
||||||
|
makeItShort: Boolean,
|
||||||
|
canPreview: Boolean,
|
||||||
|
backgroundColor: Color,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navController: NavController
|
||||||
|
) {
|
||||||
|
val quote = highlight.split("\n").map { "> *${it.removeSuffix(" ")}*" }.joinToString("\n")
|
||||||
|
|
||||||
|
if (quote != null) {
|
||||||
|
TranslatableRichTextViewer(
|
||||||
|
quote,
|
||||||
|
canPreview = canPreview && !makeItShort,
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
emptyList(),
|
||||||
|
backgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowRow() {
|
||||||
|
authorHex?.let { authorHex ->
|
||||||
|
val userBase = LocalCache.checkGetOrCreateUser(authorHex)
|
||||||
|
|
||||||
|
if (userBase != null) {
|
||||||
|
val userState by userBase.live().metadata.observeAsState()
|
||||||
|
val user = userState?.user
|
||||||
|
|
||||||
|
if (user != null) {
|
||||||
|
CreateClickableText(
|
||||||
|
user.toBestDisplayName(),
|
||||||
|
"",
|
||||||
|
"User/${user.pubkeyHex}",
|
||||||
|
navController
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url?.let { url ->
|
||||||
|
val validatedUrl = try {
|
||||||
|
URL(url)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w("Note Compose", "Invalid URI: $url")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
validatedUrl?.host?.let { host ->
|
||||||
|
Text("on ")
|
||||||
|
ClickableUrl(urlText = host, url = url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DisplayFollowingHashtagsInPost(
|
fun DisplayFollowingHashtagsInPost(
|
||||||
noteEvent: EventInterface,
|
noteEvent: EventInterface,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import coil.compose.AsyncImage
|
|||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent
|
import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent
|
||||||
|
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||||
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
||||||
@@ -348,33 +349,46 @@ fun NoteMaster(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Column() {
|
Column() {
|
||||||
val eventContent = note.event?.content()
|
if (noteEvent is HighlightEvent) {
|
||||||
|
DisplayHighlight(
|
||||||
val canPreview = note.author == account.userProfile() ||
|
noteEvent.quote(),
|
||||||
(note.author?.let { account.userProfile().isFollowingCached(it) } ?: true) ||
|
noteEvent.author(),
|
||||||
!noteForReports.hasAnyReports()
|
noteEvent.inUrl(),
|
||||||
|
false,
|
||||||
if (eventContent != null) {
|
true,
|
||||||
TranslatableRichTextViewer(
|
backgroundColor,
|
||||||
eventContent,
|
|
||||||
canPreview,
|
|
||||||
Modifier.fillMaxWidth(),
|
|
||||||
note.event?.tags(),
|
|
||||||
MaterialTheme.colors.background,
|
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
navController
|
navController
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
val eventContent = note.event?.content()
|
||||||
|
|
||||||
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
val canPreview = note.author == account.userProfile() ||
|
||||||
|
(note.author?.let { account.userProfile().isFollowingCached(it) } ?: true) ||
|
||||||
|
!noteForReports.hasAnyReports()
|
||||||
|
|
||||||
if (noteEvent is PollNoteEvent) {
|
if (eventContent != null) {
|
||||||
PollNote(
|
TranslatableRichTextViewer(
|
||||||
note,
|
eventContent,
|
||||||
canPreview,
|
canPreview,
|
||||||
backgroundColor,
|
Modifier.fillMaxWidth(),
|
||||||
|
note.event?.tags(),
|
||||||
|
MaterialTheme.colors.background,
|
||||||
accountViewModel,
|
accountViewModel,
|
||||||
navController
|
navController
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController)
|
||||||
|
|
||||||
|
if (noteEvent is PollNoteEvent) {
|
||||||
|
PollNote(
|
||||||
|
note,
|
||||||
|
canPreview,
|
||||||
|
backgroundColor,
|
||||||
|
accountViewModel,
|
||||||
|
navController
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user