mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-26 21:36:24 +02:00
Fixing Ephemeral Chat interface
This commit is contained in:
@@ -70,7 +70,6 @@ import com.vitorpamplona.amethyst.service.uploads.FileHeader
|
||||
import com.vitorpamplona.amethyst.ui.tor.TorType
|
||||
import com.vitorpamplona.quartz.experimental.bounties.BountyAddValueEvent
|
||||
import com.vitorpamplona.quartz.experimental.edits.TextNoteModificationEvent
|
||||
import com.vitorpamplona.quartz.experimental.ephemChat.chat.EphemeralChatEvent
|
||||
import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryBaseEvent
|
||||
import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryPrologueEvent
|
||||
import com.vitorpamplona.quartz.experimental.interactiveStories.InteractiveStoryReadingStateEvent
|
||||
@@ -145,9 +144,6 @@ import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay
|
||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NSec
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelCreateEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.admin.ChannelMetadataEvent
|
||||
import com.vitorpamplona.quartz.nip28PublicChat.message.ChannelMessageEvent
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.EmojiUrlTag
|
||||
import com.vitorpamplona.quartz.nip30CustomEmoji.emojis
|
||||
import com.vitorpamplona.quartz.nip35Torrents.TorrentCommentEvent
|
||||
@@ -163,8 +159,6 @@ import com.vitorpamplona.quartz.nip51Lists.BookmarkListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.FollowListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.GeneralListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.chat.LiveActivitiesChatMessageEvent
|
||||
import com.vitorpamplona.quartz.nip53LiveActivities.streaming.LiveActivitiesEvent
|
||||
import com.vitorpamplona.quartz.nip56Reports.ReportType
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapPrivateEvent
|
||||
@@ -815,33 +809,7 @@ class Account(
|
||||
?: cache.relayHints.hintsForKey(pubkey).toSet()
|
||||
}
|
||||
|
||||
private fun computeRelaysForChannels(event: Event): Set<NormalizedRelayUrl> {
|
||||
val isInChannel =
|
||||
if (
|
||||
event is ChannelMessageEvent ||
|
||||
event is ChannelMetadataEvent ||
|
||||
event is ChannelCreateEvent ||
|
||||
event is LiveActivitiesChatMessageEvent ||
|
||||
event is LiveActivitiesEvent ||
|
||||
event is EphemeralChatEvent
|
||||
) {
|
||||
(event as? ChannelMessageEvent)?.channelId()
|
||||
?: (event as? ChannelMetadataEvent)?.channelId()
|
||||
?: (event as? ChannelCreateEvent)?.id
|
||||
?: (event as? LiveActivitiesChatMessageEvent)?.activity()?.toTag()
|
||||
?: (event as? LiveActivitiesEvent)?.aTag()?.toTag()
|
||||
?: (event as? EphemeralChatEvent)?.roomId()?.toKey()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return if (isInChannel != null) {
|
||||
val channel = LocalCache.checkGetOrCreateChannel(isInChannel)
|
||||
channel?.relays() ?: emptySet()
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
}
|
||||
private fun computeRelaysForChannels(event: Event): Set<NormalizedRelayUrl> = LocalCache.getAnyChannel(event)?.relays() ?: emptySet()
|
||||
|
||||
fun computeRelayListToBroadcast(event: Event): Set<NormalizedRelayUrl> {
|
||||
if (event is MetadataEvent || event is AdvertisedRelayListEvent) {
|
||||
|
@@ -61,7 +61,6 @@ import com.vitorpamplona.quartz.nip01Core.hints.PubKeyHintProvider
|
||||
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.isLocalHost
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.ATag
|
||||
import com.vitorpamplona.quartz.nip01Core.tags.addressables.Address
|
||||
@@ -416,33 +415,16 @@ object LocalCache : ILocalCache {
|
||||
EphemeralChatChannel(key)
|
||||
}
|
||||
|
||||
fun checkGetOrCreateChannel(key: String): Channel? {
|
||||
checkNotInMainThread()
|
||||
|
||||
if (key.contains("@")) {
|
||||
val idParts = key.split("@")
|
||||
val relay = RelayUrlNormalizer.normalizeOrNull(idParts[1])
|
||||
|
||||
if (relay == null) {
|
||||
return null
|
||||
} else {
|
||||
getOrCreateEphemeralChannel(RoomId(idParts[0], relay))
|
||||
}
|
||||
}
|
||||
|
||||
fun checkGetOrCreatePublicChatChannel(key: String): PublicChatChannel? {
|
||||
if (isValidHex(key)) {
|
||||
return getOrCreatePublicChatChannel(key)
|
||||
}
|
||||
|
||||
val address = Address.parse(key)
|
||||
if (address != null) {
|
||||
return getOrCreateLiveChannel(address)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isValidHex(key: String): Boolean {
|
||||
if (key.isBlank()) return false
|
||||
if (key.length != 64) return false
|
||||
if (key.contains(":")) return false
|
||||
|
||||
return Hex.isHex(key)
|
||||
@@ -1622,12 +1604,12 @@ object LocalCache : ILocalCache {
|
||||
if (channelId.isNullOrBlank()) return false
|
||||
|
||||
// new event
|
||||
val oldChannel = checkGetOrCreateChannel(channelId) ?: return false
|
||||
val oldChannel = checkGetOrCreatePublicChatChannel(channelId) ?: return false
|
||||
|
||||
val author = getOrCreateUser(event.pubKey)
|
||||
val isVerified =
|
||||
if (event.createdAt > oldChannel.updatedMetadataAt) {
|
||||
if (oldChannel is PublicChatChannel && (wasVerified || justVerify(event))) {
|
||||
if (wasVerified || justVerify(event)) {
|
||||
oldChannel.updateChannelInfo(author, event)
|
||||
true
|
||||
} else {
|
||||
@@ -1653,44 +1635,18 @@ object LocalCache : ILocalCache {
|
||||
relay: NormalizedRelayUrl?,
|
||||
wasVerified: Boolean,
|
||||
): Boolean {
|
||||
val channelId = event.channelId()
|
||||
val channelId = event.channelId() ?: return false
|
||||
|
||||
if (channelId.isNullOrBlank()) return false
|
||||
|
||||
val channel = checkGetOrCreateChannel(channelId) ?: return false
|
||||
val channel = checkGetOrCreatePublicChatChannel(channelId)
|
||||
if (channel == null) {
|
||||
Log.w("LocalCache", "Unable to create public chat channel for event ${event.toJson()}")
|
||||
return false
|
||||
}
|
||||
|
||||
val note = getOrCreateNote(event.id)
|
||||
channel.addNote(note, relay)
|
||||
|
||||
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 false
|
||||
|
||||
if (antiSpam.isSpam(event, relay)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (wasVerified || justVerify(event)) {
|
||||
val replyTo = computeReplyTo(event)
|
||||
|
||||
note.loadEvent(event, author, replyTo)
|
||||
|
||||
// Log.d("CM", "New Chat Note (${note.author?.toBestDisplayName()} ${note.event?.content}
|
||||
// ${formattedDateTime(event.createdAt)}")
|
||||
|
||||
// Counts the replies
|
||||
replyTo.forEach { it.addReply(note) }
|
||||
|
||||
refreshObservers(note)
|
||||
}
|
||||
|
||||
return true
|
||||
return consumeRegularEvent(event, relay, wasVerified)
|
||||
}
|
||||
|
||||
fun consume(
|
||||
@@ -1698,46 +1654,15 @@ object LocalCache : ILocalCache {
|
||||
relay: NormalizedRelayUrl?,
|
||||
wasVerified: Boolean,
|
||||
): Boolean {
|
||||
val roomId = event.roomId()
|
||||
if (roomId == null) return false
|
||||
|
||||
val channelId = roomId
|
||||
val channel = getOrCreateEphemeralChannel(channelId) ?: return false
|
||||
val roomId = event.roomId() ?: return false
|
||||
|
||||
val note = getOrCreateNote(event.id)
|
||||
val channel = getOrCreateEphemeralChannel(roomId)
|
||||
channel.addNote(note, relay)
|
||||
|
||||
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 false
|
||||
|
||||
if (antiSpam.isSpam(event, relay)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (wasVerified || justVerify(event)) {
|
||||
note.loadEvent(event, author, emptyList())
|
||||
|
||||
refreshObservers(note)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return consumeRegularEvent(event, relay, wasVerified)
|
||||
}
|
||||
|
||||
fun consume(
|
||||
event: CommentEvent,
|
||||
relay: NormalizedRelayUrl?,
|
||||
wasVerified: Boolean,
|
||||
) = consumeRegularEvent(event, relay, wasVerified)
|
||||
|
||||
fun consume(
|
||||
event: LiveActivitiesChatMessageEvent,
|
||||
relay: NormalizedRelayUrl?,
|
||||
@@ -1750,36 +1675,15 @@ object LocalCache : ILocalCache {
|
||||
val note = getOrCreateNote(event.id)
|
||||
channel.addNote(note, relay)
|
||||
|
||||
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 false
|
||||
|
||||
if (antiSpam.isSpam(event, relay)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (wasVerified || justVerify(event)) {
|
||||
val replyTo = computeReplyTo(event)
|
||||
|
||||
note.loadEvent(event, author, replyTo)
|
||||
|
||||
// Counts the replies
|
||||
replyTo.forEach { it.addReply(note) }
|
||||
|
||||
refreshObservers(note)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return consumeRegularEvent(event, relay, wasVerified)
|
||||
}
|
||||
|
||||
fun consume(
|
||||
event: CommentEvent,
|
||||
relay: NormalizedRelayUrl?,
|
||||
wasVerified: Boolean,
|
||||
) = consumeRegularEvent(event, relay, wasVerified)
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun consume(
|
||||
event: ChannelHideMessageEvent,
|
||||
@@ -2859,18 +2763,18 @@ object LocalCache : ILocalCache {
|
||||
}
|
||||
}
|
||||
is EphemeralChatEvent -> {
|
||||
draft.roomId()?.toKey()?.let {
|
||||
checkGetOrCreateChannel(it)?.addNote(note, null)
|
||||
draft.roomId()?.let {
|
||||
getOrCreateEphemeralChannel(it).addNote(note, null)
|
||||
}
|
||||
}
|
||||
is ChannelMessageEvent -> {
|
||||
draft.channelId()?.let { channelId ->
|
||||
checkGetOrCreateChannel(channelId)?.addNote(note, null)
|
||||
checkGetOrCreatePublicChatChannel(channelId)?.addNote(note, null)
|
||||
}
|
||||
}
|
||||
is LiveActivitiesChatMessageEvent -> {
|
||||
draft.activityAddress()?.let { channelId ->
|
||||
checkGetOrCreateChannel(channelId.toValue())?.addNote(note, null)
|
||||
getOrCreateLiveChannel(channelId).addNote(note, null)
|
||||
}
|
||||
}
|
||||
is TextNoteEvent -> {
|
||||
@@ -2937,12 +2841,17 @@ object LocalCache : ILocalCache {
|
||||
}
|
||||
is ChannelMessageEvent -> {
|
||||
draft.channelId()?.let { channelId ->
|
||||
checkGetOrCreateChannel(channelId)?.removeNote(draftWrap)
|
||||
getPublicChatChannelIfExists(channelId)?.removeNote(draftWrap)
|
||||
}
|
||||
}
|
||||
is EphemeralChatEvent -> {
|
||||
draft.roomId()?.let {
|
||||
getOrCreateEphemeralChannel(it).removeNote(draftWrap)
|
||||
getEphemeralChatChannelIfExists(it)?.removeNote(draftWrap)
|
||||
}
|
||||
}
|
||||
is LiveActivitiesChatMessageEvent -> {
|
||||
draft.activityAddress()?.let { channelId ->
|
||||
getLiveActivityChannelIfExists(channelId)?.removeNote(draftWrap)
|
||||
}
|
||||
}
|
||||
is TextNoteEvent -> {
|
||||
|
@@ -124,7 +124,7 @@ class HomeLiveFilter(
|
||||
}
|
||||
|
||||
fun sort(collection: Set<EphemeralChatChannel>): List<EphemeralChatChannel> {
|
||||
val topFilter = account.liveDiscoveryFollowLists.value
|
||||
val topFilter = account.liveHomeFollowLists.value
|
||||
val topFilterAuthors =
|
||||
when (topFilter) {
|
||||
is AuthorsByOutboxTopNavFilter -> topFilter.authors
|
||||
@@ -137,7 +137,7 @@ class HomeLiveFilter(
|
||||
val followingKeySet = topFilterAuthors ?: account.kind3FollowList.flow.value.authors
|
||||
|
||||
val followCounts =
|
||||
collection.associate { it to followsThatParticipateOn(it, followingKeySet) }
|
||||
collection.associateWith { followsThatParticipateOn(it, followingKeySet) }
|
||||
|
||||
return collection.sortedWith(
|
||||
compareByDescending<EphemeralChatChannel> { followCounts[it] }
|
||||
|
@@ -26,8 +26,17 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
||||
data class RoomId(
|
||||
val id: String,
|
||||
val relayUrl: NormalizedRelayUrl,
|
||||
) {
|
||||
) : Comparable<RoomId> {
|
||||
fun toKey() = "$id@$relayUrl"
|
||||
|
||||
fun toDisplayKey() = id + "@" + relayUrl.displayUrl()
|
||||
|
||||
override fun compareTo(other: RoomId): Int {
|
||||
val result = id.compareTo(other.id)
|
||||
return if (result == 0) {
|
||||
relayUrl.url.compareTo(other.relayUrl.url)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ class RelayTag {
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
|
||||
return RelayUrlNormalizer.normalizeOrNull(tag[1]) ?: return null
|
||||
return RelayUrlNormalizer.normalizeOrNull(tag[1])
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
@@ -149,7 +149,6 @@ open class BasicRelayClient(
|
||||
|
||||
override fun onMessage(text: String) {
|
||||
// Log.d(logTag, "Receiving: $text")
|
||||
|
||||
stats.addBytesReceived(text.bytesUsedInMemory())
|
||||
|
||||
try {
|
||||
|
Reference in New Issue
Block a user