- Adds Support for Kind 16
- Migrates citations to `e` when they were supposed to be `a` - Removes original tags from Reposts -
This commit is contained in:
@@ -331,9 +331,15 @@ class Account(
|
||||
}
|
||||
|
||||
note.event?.let {
|
||||
val event = RepostEvent.create(it, loggedIn.privKey!!)
|
||||
Client.send(event)
|
||||
LocalCache.consume(event)
|
||||
if (it.kind() == 1) {
|
||||
val event = RepostEvent.create(it, loggedIn.privKey!!)
|
||||
Client.send(event)
|
||||
LocalCache.consume(event)
|
||||
} else {
|
||||
val event = GenericRepostEvent.create(it, loggedIn.privKey!!)
|
||||
Client.send(event)
|
||||
LocalCache.consume(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,7 +1117,7 @@ class Account(
|
||||
return note.author?.let { isAcceptable(it) } ?: true && // if user hasn't hided this author
|
||||
isAcceptableDirect(note) &&
|
||||
(
|
||||
note.event !is RepostEvent ||
|
||||
(note.event !is RepostEvent && note.event !is GenericRepostEvent) ||
|
||||
(note.replyTo?.firstOrNull { isAcceptableDirect(it) } != null)
|
||||
) // is not a reaction about a blocked post
|
||||
}
|
||||
@@ -1119,7 +1125,7 @@ class Account(
|
||||
fun getRelevantReports(note: Note): Set<Note> {
|
||||
val followsPlusMe = userProfile().latestContactList?.verifiedFollowKeySetAndMe ?: emptySet()
|
||||
|
||||
val innerReports = if (note.event is RepostEvent) {
|
||||
val innerReports = if (note.event is RepostEvent || note.event is GenericRepostEvent) {
|
||||
note.replyTo?.map { getRelevantReports(it) }?.flatten() ?: emptyList()
|
||||
} else {
|
||||
emptyList()
|
||||
|
||||
@@ -70,7 +70,14 @@ object LocalCache {
|
||||
return checkGetOrCreateAddressableNote(key)
|
||||
}
|
||||
if (isValidHexNpub(key)) {
|
||||
return getOrCreateNote(key)
|
||||
val note = getOrCreateNote(key)
|
||||
val noteEvent = note.event
|
||||
if (noteEvent is AddressableEvent) {
|
||||
// upgrade to the latest
|
||||
return checkGetOrCreateAddressableNote(noteEvent.address().toTag())
|
||||
} else {
|
||||
return note
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -185,6 +192,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -245,6 +253,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
if (relay != null) {
|
||||
@@ -316,6 +325,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
if (note.event?.id() == event.id()) return
|
||||
@@ -334,6 +344,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
if (note.event?.id() == event.id()) return
|
||||
@@ -352,6 +363,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
if (note.event?.id() == event.id()) return
|
||||
@@ -370,6 +382,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -389,6 +402,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -408,6 +422,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -451,6 +466,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -470,6 +486,7 @@ object LocalCache {
|
||||
|
||||
if (version.event == null) {
|
||||
version.loadEvent(event, author, emptyList())
|
||||
version.moveAllReferencesTo(note)
|
||||
}
|
||||
|
||||
// Already processed this event.
|
||||
@@ -605,6 +622,31 @@ object LocalCache {
|
||||
refreshObservers(note)
|
||||
}
|
||||
|
||||
fun consume(event: GenericRepostEvent) {
|
||||
val note = getOrCreateNote(event.id)
|
||||
|
||||
// Already processed this event.
|
||||
if (note.event != null) return
|
||||
|
||||
// Log.d("TN", "New Boost (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
|
||||
|
||||
val author = getOrCreateUser(event.pubKey)
|
||||
val repliesTo = event.boostedPost().mapNotNull { checkGetOrCreateNote(it) } +
|
||||
event.taggedAddresses().mapNotNull { getOrCreateAddressableNote(it) }
|
||||
|
||||
note.loadEvent(event, author, repliesTo)
|
||||
|
||||
// Prepares user's profile view.
|
||||
author.addNote(note)
|
||||
|
||||
// Counts the replies
|
||||
repliesTo.forEach {
|
||||
it.addBoost(note)
|
||||
}
|
||||
|
||||
refreshObservers(note)
|
||||
}
|
||||
|
||||
fun consume(event: ReactionEvent) {
|
||||
val note = getOrCreateNote(event.id)
|
||||
|
||||
@@ -1154,6 +1196,12 @@ object LocalCache {
|
||||
}
|
||||
consume(event)
|
||||
}
|
||||
is GenericRepostEvent -> {
|
||||
event.containedPost()?.let {
|
||||
verifyAndConsume(it, relay)
|
||||
}
|
||||
consume(event)
|
||||
}
|
||||
is TextNoteEvent -> consume(event, relay)
|
||||
is PollNoteEvent -> consume(event, relay)
|
||||
else -> {
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.vitorpamplona.amethyst.service.model.*
|
||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||
import com.vitorpamplona.amethyst.service.relays.EOSETime
|
||||
import com.vitorpamplona.amethyst.service.relays.Relay
|
||||
import com.vitorpamplona.amethyst.ui.actions.updated
|
||||
import com.vitorpamplona.amethyst.ui.components.BundledUpdate
|
||||
import com.vitorpamplona.amethyst.ui.note.toShortenHex
|
||||
import fr.acinq.secp256k1.Hex
|
||||
@@ -96,7 +97,7 @@ open class Note(val idHex: String) {
|
||||
*/
|
||||
fun replyLevelSignature(cachedSignatures: MutableMap<Note, String> = mutableMapOf()): String {
|
||||
val replyTo = replyTo
|
||||
if (replyTo == null || replyTo.isEmpty()) {
|
||||
if (event is RepostEvent || event is GenericRepostEvent || replyTo == null || replyTo.isEmpty()) {
|
||||
return "/" + formattedDateTime(createdAt() ?: 0) + ";"
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ open class Note(val idHex: String) {
|
||||
|
||||
fun replyLevel(cachedLevels: MutableMap<Note, Int> = mutableMapOf()): Int {
|
||||
val replyTo = replyTo
|
||||
if (replyTo == null || replyTo.isEmpty()) {
|
||||
if (event is RepostEvent || event is GenericRepostEvent || replyTo == null || replyTo.isEmpty()) {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -372,7 +373,7 @@ open class Note(val idHex: String) {
|
||||
}
|
||||
|
||||
fun isNewThread(): Boolean {
|
||||
return event is RepostEvent || replyTo == null || replyTo?.size == 0
|
||||
return event is RepostEvent || event is GenericRepostEvent || replyTo == null || replyTo?.size == 0
|
||||
}
|
||||
|
||||
fun hasZapped(loggedIn: User): Boolean {
|
||||
@@ -400,6 +401,42 @@ open class Note(val idHex: String) {
|
||||
return boosts.filter { it.author == loggedIn }
|
||||
}
|
||||
|
||||
fun moveAllReferencesTo(note: AddressableNote) {
|
||||
// migrates these comments to a new version
|
||||
replies.forEach {
|
||||
note.addReply(it)
|
||||
it.replyTo = it.replyTo?.updated(this, note)
|
||||
}
|
||||
reactions.forEach {
|
||||
it.value.forEach {
|
||||
note.addReaction(it)
|
||||
it.replyTo = it.replyTo?.updated(this, note)
|
||||
}
|
||||
}
|
||||
boosts.forEach {
|
||||
note.addBoost(it)
|
||||
it.replyTo = it.replyTo?.updated(this, note)
|
||||
}
|
||||
reports.forEach {
|
||||
it.value.forEach {
|
||||
note.addReport(it)
|
||||
it.replyTo = it.replyTo?.updated(this, note)
|
||||
}
|
||||
}
|
||||
zaps.forEach {
|
||||
note.addZap(it.key, it.value)
|
||||
it.key.replyTo = it.key.replyTo?.updated(this, note)
|
||||
it.value?.replyTo = it.value?.replyTo?.updated(this, note)
|
||||
}
|
||||
|
||||
replyTo = null
|
||||
replies = emptySet()
|
||||
reactions = emptyMap()
|
||||
boosts = emptySet()
|
||||
reports = emptyMap()
|
||||
zaps = emptyMap()
|
||||
}
|
||||
|
||||
var liveSet: NoteLiveSet? = null
|
||||
|
||||
fun live(): NoteLiveSet {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.vitorpamplona.amethyst.model
|
||||
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.service.model.ATag
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTimedValue
|
||||
|
||||
@@ -10,6 +12,8 @@ class ThreadAssembler {
|
||||
private fun searchRoot(note: Note, testedNotes: MutableSet<Note> = mutableSetOf()): Note? {
|
||||
if (note.replyTo == null || note.replyTo?.isEmpty() == true) return note
|
||||
|
||||
if (note.event is RepostEvent || note.event is GenericRepostEvent) return note
|
||||
|
||||
testedNotes.add(note)
|
||||
|
||||
val markedAsRoot = note.event?.tags()?.firstOrNull { it[0] == "e" && it.size > 3 && it[3] == "root" }?.getOrNull(1)
|
||||
|
||||
@@ -88,6 +88,7 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
|
||||
PollNoteEvent.kind,
|
||||
ReactionEvent.kind,
|
||||
RepostEvent.kind,
|
||||
GenericRepostEvent.kind,
|
||||
ReportEvent.kind,
|
||||
LnZapEvent.kind,
|
||||
LnZapPaymentResponseEvent.kind,
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.service
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.UserState
|
||||
import com.vitorpamplona.amethyst.service.model.AudioTrackEvent
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PinListEvent
|
||||
@@ -59,7 +60,16 @@ object NostrHomeDataSource : NostrDataSource("HomeFeed") {
|
||||
return TypedFilter(
|
||||
types = setOf(FeedType.FOLLOWS),
|
||||
filter = JsonFilter(
|
||||
kinds = listOf(TextNoteEvent.kind, RepostEvent.kind, LongTextNoteEvent.kind, PollNoteEvent.kind, HighlightEvent.kind, AudioTrackEvent.kind, PinListEvent.kind),
|
||||
kinds = listOf(
|
||||
TextNoteEvent.kind,
|
||||
RepostEvent.kind,
|
||||
GenericRepostEvent.kind,
|
||||
LongTextNoteEvent.kind,
|
||||
PollNoteEvent.kind,
|
||||
HighlightEvent.kind,
|
||||
AudioTrackEvent.kind,
|
||||
PinListEvent.kind
|
||||
),
|
||||
authors = followSet,
|
||||
limit = 400,
|
||||
since = latestEOSEs.users[account.userProfile()]?.followList?.get(account.defaultHomeFollowList)?.relayList
|
||||
|
||||
@@ -26,7 +26,7 @@ object NostrSingleEventDataSource : NostrDataSource("SingleEventFeed") {
|
||||
filter = JsonFilter(
|
||||
kinds = listOf(
|
||||
TextNoteEvent.kind, LongTextNoteEvent.kind,
|
||||
ReactionEvent.kind, RepostEvent.kind, ReportEvent.kind,
|
||||
ReactionEvent.kind, RepostEvent.kind, GenericRepostEvent.kind, ReportEvent.kind,
|
||||
LnZapEvent.kind, LnZapRequestEvent.kind,
|
||||
BadgeAwardEvent.kind, BadgeDefinitionEvent.kind, BadgeProfilesEvent.kind,
|
||||
PollNoteEvent.kind, AudioTrackEvent.kind, PinListEvent.kind,
|
||||
@@ -77,6 +77,7 @@ object NostrSingleEventDataSource : NostrDataSource("SingleEventFeed") {
|
||||
LongTextNoteEvent.kind,
|
||||
ReactionEvent.kind,
|
||||
RepostEvent.kind,
|
||||
GenericRepostEvent.kind,
|
||||
ReportEvent.kind,
|
||||
LnZapEvent.kind,
|
||||
LnZapRequestEvent.kind,
|
||||
|
||||
@@ -28,7 +28,16 @@ object NostrUserProfileDataSource : NostrDataSource("UserProfileFeed") {
|
||||
TypedFilter(
|
||||
types = COMMON_FEED_TYPES,
|
||||
filter = JsonFilter(
|
||||
kinds = listOf(TextNoteEvent.kind, RepostEvent.kind, LongTextNoteEvent.kind, AudioTrackEvent.kind, PinListEvent.kind, PollNoteEvent.kind, HighlightEvent.kind),
|
||||
kinds = listOf(
|
||||
TextNoteEvent.kind,
|
||||
GenericRepostEvent.kind,
|
||||
RepostEvent.kind,
|
||||
LongTextNoteEvent.kind,
|
||||
AudioTrackEvent.kind,
|
||||
PinListEvent.kind,
|
||||
PollNoteEvent.kind,
|
||||
HighlightEvent.kind
|
||||
),
|
||||
authors = listOf(it.pubkeyHex),
|
||||
limit = 200
|
||||
)
|
||||
|
||||
@@ -245,6 +245,7 @@ open class Event(
|
||||
FileHeaderEvent.kind -> FileHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileStorageEvent.kind -> FileStorageEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
FileStorageHeaderEvent.kind -> FileStorageHeaderEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
GenericRepostEvent.kind -> GenericRepostEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
HighlightEvent.kind -> HighlightEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LiveActivitiesEvent.kind -> LiveActivitiesEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LnZapEvent.kind -> LnZapEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.vitorpamplona.amethyst.service.model
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.amethyst.model.HexKey
|
||||
import com.vitorpamplona.amethyst.model.toHexKey
|
||||
import com.vitorpamplona.amethyst.service.relays.Client
|
||||
import nostr.postr.Utils
|
||||
import java.util.Date
|
||||
|
||||
@Immutable
|
||||
class GenericRepostEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: List<List<String>>,
|
||||
content: String,
|
||||
sig: HexKey
|
||||
) : Event(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||
|
||||
fun boostedPost() = tags.filter { it.firstOrNull() == "e" }.mapNotNull { it.getOrNull(1) }
|
||||
fun originalAuthor() = tags.filter { it.firstOrNull() == "p" }.mapNotNull { it.getOrNull(1) }
|
||||
|
||||
fun containedPost() = try {
|
||||
fromJson(content, Client.lenient)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val kind = 16
|
||||
|
||||
fun create(boostedPost: EventInterface, privateKey: ByteArray, createdAt: Long = Date().time / 1000): GenericRepostEvent {
|
||||
val content = boostedPost.toJson()
|
||||
|
||||
val replyToPost = listOf("e", boostedPost.id())
|
||||
val replyToAuthor = listOf("p", boostedPost.pubKey())
|
||||
|
||||
val pubKey = Utils.pubkeyCreate(privateKey).toHexKey()
|
||||
var tags: List<List<String>> = listOf(replyToPost, replyToAuthor)
|
||||
|
||||
if (boostedPost is AddressableEvent) {
|
||||
tags = tags + listOf(listOf("a", boostedPost.address().toTag()))
|
||||
}
|
||||
|
||||
tags = tags + listOf(listOf("k", "${boostedPost.kind()}"))
|
||||
|
||||
val id = generateId(pubKey, createdAt, kind, tags, content)
|
||||
val sig = Utils.sign(id, privateKey)
|
||||
return GenericRepostEvent(id.toHexKey(), pubKey, createdAt, tags, content, sig.toHexKey())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class RepostEvent(
|
||||
val replyToAuthor = listOf("p", boostedPost.pubKey())
|
||||
|
||||
val pubKey = Utils.pubkeyCreate(privateKey).toHexKey()
|
||||
var tags: List<List<String>> = boostedPost.tags().plus(listOf(replyToPost, replyToAuthor))
|
||||
var tags: List<List<String>> = listOf(replyToPost, replyToAuthor)
|
||||
|
||||
if (boostedPost is AddressableEvent) {
|
||||
tags = tags + listOf(listOf("a", boostedPost.address().toTag()))
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.service.model.AudioTrackEvent
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||
@@ -26,19 +27,24 @@ class HomeNewThreadFeedFilter(val account: Account) : AdditiveFeedFilter<Note>()
|
||||
val followingKeySet = account.selectedUsersFollowList(account.defaultHomeFollowList) ?: emptySet()
|
||||
val followingTagSet = account.selectedTagsFollowList(account.defaultHomeFollowList) ?: emptySet()
|
||||
|
||||
val oneHr = 60 * 60
|
||||
|
||||
return collection
|
||||
.asSequence()
|
||||
.filter { it ->
|
||||
val noteEvent = it.event
|
||||
(noteEvent is TextNoteEvent || noteEvent is RepostEvent || noteEvent is LongTextNoteEvent || noteEvent is PollNoteEvent || noteEvent is HighlightEvent || noteEvent is AudioTrackEvent) &&
|
||||
(noteEvent is TextNoteEvent || noteEvent is RepostEvent || noteEvent is GenericRepostEvent || noteEvent is LongTextNoteEvent || noteEvent is PollNoteEvent || noteEvent is HighlightEvent || noteEvent is AudioTrackEvent) &&
|
||||
(it.author?.pubkeyHex in followingKeySet || (noteEvent.isTaggedHashes(followingTagSet))) &&
|
||||
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
||||
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true &&
|
||||
it.isNewThread() &&
|
||||
(
|
||||
noteEvent !is RepostEvent || // not a repost
|
||||
(it.replyTo?.lastOrNull()?.author?.pubkeyHex !in followingKeySet) // or a repost of by a non-follower's post (likely not seen yet)
|
||||
) // || (noteEvent.createdAt > (it.replyTo?.lastOrNull()?.createdAt() ?: 0) + 60*60*1000 )) //
|
||||
(noteEvent !is RepostEvent && noteEvent !is GenericRepostEvent) || // not a repost
|
||||
(
|
||||
it.replyTo?.lastOrNull()?.author?.pubkeyHex !in followingKeySet ||
|
||||
(noteEvent.createdAt() > (it.replyTo?.lastOrNull()?.createdAt() ?: 0) + oneHr)
|
||||
) // or a repost of by a non-follower's post (likely not seen yet)
|
||||
)
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class NotificationFeedFilter(val account: Account) : AdditiveFeedFilter<Note>()
|
||||
return note.replyTo?.lastOrNull()?.author?.pubkeyHex == authorHex
|
||||
}
|
||||
|
||||
if (event is RepostEvent) {
|
||||
if (event is RepostEvent || event is GenericRepostEvent) {
|
||||
return note.replyTo?.lastOrNull()?.author?.pubkeyHex == authorHex
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
||||
import com.vitorpamplona.amethyst.service.model.EventInterface
|
||||
import com.vitorpamplona.amethyst.service.model.FileHeaderEvent
|
||||
import com.vitorpamplona.amethyst.service.model.FileStorageHeaderEvent
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||
@@ -520,7 +521,7 @@ private fun RenderNoteWithReactions(
|
||||
|
||||
val showSecondRow by remember {
|
||||
derivedStateOf {
|
||||
baseNote.event !is RepostEvent && !isBoostedNote && !isQuotedNote
|
||||
baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent && !isBoostedNote && !isQuotedNote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +555,7 @@ private fun RenderNoteWithReactions(
|
||||
)
|
||||
}
|
||||
|
||||
if (!makeItShort && baseNote.event !is RepostEvent) {
|
||||
if (!makeItShort && baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent) {
|
||||
ReactionsRow(
|
||||
baseNote = baseNote,
|
||||
showReactionDetail = notBoostedNorQuote,
|
||||
@@ -562,7 +563,7 @@ private fun RenderNoteWithReactions(
|
||||
nav = nav
|
||||
)
|
||||
} else {
|
||||
if (!isBoostedNote && baseNote.event !is RepostEvent) {
|
||||
if (!isBoostedNote && baseNote.event !is RepostEvent && baseNote.event !is GenericRepostEvent) {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
@@ -648,6 +649,10 @@ private fun RenderNoteRow(
|
||||
RenderRepost(baseNote, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is GenericRepostEvent -> {
|
||||
RenderRepost(baseNote, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is ReportEvent -> {
|
||||
RenderReport(baseNote, backgroundColor, accountViewModel, nav)
|
||||
}
|
||||
@@ -1421,7 +1426,7 @@ private fun RenderReaction(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderRepost(
|
||||
fun RenderRepost(
|
||||
note: Note,
|
||||
backgroundColor: MutableState<Color>,
|
||||
accountViewModel: AccountViewModel,
|
||||
@@ -1754,7 +1759,7 @@ private fun FirstUserInfoRow(
|
||||
NoteUsernameDisplay(baseNote, remember { Modifier.weight(1f) })
|
||||
}
|
||||
|
||||
if (eventNote is RepostEvent) {
|
||||
if (eventNote is RepostEvent || eventNote is GenericRepostEvent) {
|
||||
Text(
|
||||
" ${stringResource(id = R.string.boosted)}",
|
||||
fontWeight = FontWeight.Bold,
|
||||
@@ -1828,7 +1833,7 @@ private fun DrawAuthorImages(baseNote: Note, accountViewModel: AccountViewModel,
|
||||
Box(modifier = modifier, contentAlignment = Alignment.BottomEnd) {
|
||||
NoteAuthorPicture(baseNote, nav, accountViewModel, 55.dp)
|
||||
|
||||
if (baseNote.event is RepostEvent) {
|
||||
if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) {
|
||||
RepostNoteAuthorPicture(baseNote, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@@ -1839,7 +1844,7 @@ private fun DrawAuthorImages(baseNote: Note, accountViewModel: AccountViewModel,
|
||||
}
|
||||
}
|
||||
|
||||
if (baseNote.event is RepostEvent) {
|
||||
if (baseNote.event is RepostEvent || baseNote.event is GenericRepostEvent) {
|
||||
val baseReply = remember {
|
||||
baseNote.replyTo?.lastOrNull()
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
||||
import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.model.User
|
||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ReactionEvent
|
||||
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
@@ -178,9 +179,9 @@ class UserReactionsViewModel(val account: Account) : ViewModel() {
|
||||
reactions[netDate] = (reactions[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
} else if (noteEvent is RepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
} else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey() != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt())
|
||||
boosts[netDate] = (boosts[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
}
|
||||
@@ -229,9 +230,9 @@ class UserReactionsViewModel(val account: Account) : ViewModel() {
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
}
|
||||
} else if (noteEvent is RepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt)
|
||||
} else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) {
|
||||
if (noteEvent.isTaggedUser(currentUser) && noteEvent.pubKey() != currentUser) {
|
||||
val netDate = formatDate(noteEvent.createdAt())
|
||||
boosts[netDate] = (boosts[netDate] ?: 0) + 1
|
||||
takenIntoAccount.add(noteEvent.id())
|
||||
hasNewElements = true
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||
import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ChannelMetadataEvent
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||
import com.vitorpamplona.amethyst.service.model.ReactionEvent
|
||||
@@ -162,7 +163,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
|
||||
val boostsPerEvent = mutableMapOf<Note, MutableList<Note>>()
|
||||
notes
|
||||
.filter { it.event is RepostEvent }
|
||||
.filter { it.event is RepostEvent || it.event is GenericRepostEvent }
|
||||
.forEach {
|
||||
val boostedPost = it.replyTo?.lastOrNull() { it.event !is ChannelMetadataEvent && it.event !is ChannelCreateEvent }
|
||||
if (boostedPost != null) {
|
||||
@@ -197,7 +198,7 @@ open class CardFeedViewModel(val localFilter: FeedFilter<Note>) : ViewModel() {
|
||||
)
|
||||
}
|
||||
|
||||
val textNoteCards = notes.filter { it.event !is ReactionEvent && it.event !is RepostEvent && it.event !is LnZapEvent }.map {
|
||||
val textNoteCards = notes.filter { it.event !is ReactionEvent && it.event !is RepostEvent && it.event !is GenericRepostEvent && it.event !is LnZapEvent }.map {
|
||||
if (it.event is PrivateDmEvent) {
|
||||
MessageSetCard(it)
|
||||
} else if (it.event is BadgeAwardEvent) {
|
||||
|
||||
@@ -57,12 +57,14 @@ import com.vitorpamplona.amethyst.model.Note
|
||||
import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent
|
||||
import com.vitorpamplona.amethyst.service.model.AudioTrackEvent
|
||||
import com.vitorpamplona.amethyst.service.model.BadgeDefinitionEvent
|
||||
import com.vitorpamplona.amethyst.service.model.GenericRepostEvent
|
||||
import com.vitorpamplona.amethyst.service.model.HighlightEvent
|
||||
import com.vitorpamplona.amethyst.service.model.LongTextNoteEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PeopleListEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PinListEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PollNoteEvent
|
||||
import com.vitorpamplona.amethyst.service.model.RelaySetEvent
|
||||
import com.vitorpamplona.amethyst.service.model.RepostEvent
|
||||
import com.vitorpamplona.amethyst.ui.components.ObserveDisplayNip05Status
|
||||
import com.vitorpamplona.amethyst.ui.note.*
|
||||
import com.vitorpamplona.amethyst.ui.note.BadgeDisplay
|
||||
@@ -401,6 +403,8 @@ fun NoteMaster(
|
||||
accountViewModel,
|
||||
nav
|
||||
)
|
||||
} else if (noteEvent is RepostEvent || noteEvent is GenericRepostEvent) {
|
||||
RenderRepost(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is PollNoteEvent) {
|
||||
val canPreview = note.author == account.userProfile() ||
|
||||
(note.author?.let { account.userProfile().isFollowingCached(it) } ?: true) ||
|
||||
|
||||
@@ -2,14 +2,12 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -55,9 +53,7 @@ fun ThreadScreen(noteId: String?, accountViewModel: AccountViewModel, nav: (Stri
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
Column() {
|
||||
ThreadFeedView(noteId, feedViewModel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user