Adds helper classes to avoid recreating master lists.

This commit is contained in:
Vitor Pamplona
2023-02-14 17:44:03 -05:00
parent 4996c5a9d8
commit d964f93e67
5 changed files with 36 additions and 36 deletions
@@ -1,29 +1,20 @@
package com.vitorpamplona.amethyst.model package com.vitorpamplona.amethyst.model
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.vitorpamplona.amethyst.lnurl.LnInvoiceUtil
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.service.model.LnZapEvent import com.vitorpamplona.amethyst.service.model.LnZapEvent
import com.vitorpamplona.amethyst.service.model.ReportEvent import com.vitorpamplona.amethyst.service.model.ReportEvent
import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.service.relays.Relay import com.vitorpamplona.amethyst.service.relays.Relay
import com.vitorpamplona.amethyst.ui.note.toShortenHex import com.vitorpamplona.amethyst.ui.note.toShortenHex
import fr.acinq.secp256k1.Hex import fr.acinq.secp256k1.Hex
import java.math.BigDecimal import java.math.BigDecimal
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.time.ExperimentalTime
import kotlin.time.measureTimedValue
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import nostr.postr.events.ContactListEvent import nostr.postr.events.ContactListEvent
import nostr.postr.events.Event
import nostr.postr.events.MetadataEvent import nostr.postr.events.MetadataEvent
import nostr.postr.toNpub import nostr.postr.toNpub
@@ -61,10 +52,11 @@ class User(val pubkeyHex: String) {
var relaysBeingUsed = mapOf<String, RelayInfo>() var relaysBeingUsed = mapOf<String, RelayInfo>()
private set private set
var messages = mapOf<User, Set<Note>>() data class Chatroom(var roomMessages: Set<Note>)
var privateChatrooms = mapOf<User, Chatroom>()
private set private set
var latestMetadataRequestEOSE: Long? = null
var latestReportRequestEOSE: Long? = null var latestReportRequestEOSE: Long? = null
fun toBestDisplayName(): String { fun toBestDisplayName(): String {
@@ -103,8 +95,10 @@ class User(val pubkeyHex: String) {
fun follow(users: Set<User>, followedAt: Long) { fun follow(users: Set<User>, followedAt: Long) {
follows = follows + users follows = follows + users
users.forEach { users.forEach {
it.followers = it.followers + this if (this !in followers) {
it.liveFollows.invalidateData() it.followers = it.followers + this
it.liveFollows.invalidateData()
}
} }
liveFollows.invalidateData() liveFollows.invalidateData()
@@ -113,8 +107,10 @@ class User(val pubkeyHex: String) {
fun unfollow(users: Set<User>) { fun unfollow(users: Set<User>) {
follows = follows - users follows = follows - users
users.forEach { users.forEach {
it.followers = it.followers - this if (this in followers) {
it.liveFollows.invalidateData() it.followers = it.followers - this
it.liveFollows.invalidateData()
}
} }
liveFollows.invalidateData() liveFollows.invalidateData()
} }
@@ -178,18 +174,18 @@ class User(val pubkeyHex: String) {
} }
@Synchronized @Synchronized
fun getOrCreateChannel(user: User): Set<Note> { fun getOrCreatePrivateChatroom(user: User): Chatroom {
return messages[user] ?: run { return privateChatrooms[user] ?: run {
val channel = setOf<Note>() val privateChatroom = Chatroom(setOf<Note>())
messages = messages + Pair(user, channel) privateChatrooms = privateChatrooms + Pair(user, privateChatroom)
channel privateChatroom
} }
} }
fun addMessage(user: User, msg: Note) { fun addMessage(user: User, msg: Note) {
val channel = getOrCreateChannel(user) val privateChatroom = getOrCreatePrivateChatroom(user)
if (msg !in channel) { if (msg !in privateChatroom.roomMessages) {
messages = messages + Pair(user, channel + msg) privateChatroom.roomMessages = privateChatroom.roomMessages + msg
liveMessages.invalidateData() liveMessages.invalidateData()
} }
} }
@@ -243,9 +239,9 @@ class User(val pubkeyHex: String) {
} }
fun hasSentMessagesTo(user: User?): Boolean { fun hasSentMessagesTo(user: User?): Boolean {
val messagesToUser = messages[user] ?: return false val messagesToUser = privateChatrooms[user] ?: return false
return messagesToUser.firstOrNull { this == it.author } != null return messagesToUser.roomMessages.any { this == it.author }
} }
fun hasReport(loggedIn: User, type: ReportEvent.ReportType): Boolean { fun hasReport(loggedIn: User, type: ReportEvent.ReportType): Boolean {
@@ -56,9 +56,9 @@ object NostrChatRoomDataSource: NostrDataSource<Note>("ChatroomFeed") {
// returns the last Note of each user. // returns the last Note of each user.
override fun feed(): List<Note> { override fun feed(): List<Note> {
val messages = account.userProfile().messages[withUser] ?: return emptyList() val messages = account.userProfile().privateChatrooms[withUser] ?: return emptyList()
return messages.filter { account.isAcceptable(it) }.sortedBy { it.event?.createdAt }.reversed() return messages.roomMessages.filter { account.isAcceptable(it) }.sortedBy { it.event?.createdAt }.reversed()
} }
override fun updateChannelFilters() { override fun updateChannelFilters() {
@@ -75,11 +75,11 @@ object NostrChatroomListDataSource: NostrDataSource<Note>("MailBoxFeed") {
// returns the last Note of each user. // returns the last Note of each user.
override fun feed(): List<Note> { override fun feed(): List<Note> {
val messages = account.userProfile().messages val privateChatrooms = account.userProfile().privateChatrooms
val messagingWith = messages.keys.filter { account.isAcceptable(it) } val messagingWith = privateChatrooms.keys.filter { account.isAcceptable(it) }
val privateMessages = messagingWith.mapNotNull { val privateMessages = messagingWith.mapNotNull {
messages[it]?.sortedBy { it.event?.createdAt }?.lastOrNull { it.event != null } privateChatrooms[it]?.roomMessages?.sortedBy { it.event?.createdAt }?.lastOrNull { it.event != null }
} }
val publicChannels = account.followingChannels().map { val publicChannels = account.followingChannels().map {
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.service
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.model.UrlCachedPreviewer import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
import com.vitorpamplona.amethyst.model.toHexKey
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
import com.vitorpamplona.amethyst.service.model.ChannelHideMessageEvent import com.vitorpamplona.amethyst.service.model.ChannelHideMessageEvent
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
@@ -33,11 +34,14 @@ import nostr.postr.events.TextNoteEvent
abstract class NostrDataSource<T>(val debugName: String) { abstract class NostrDataSource<T>(val debugName: String) {
private var subscriptions = mapOf<String, Subscription>() private var subscriptions = mapOf<String, Subscription>()
private var eventCounter = mapOf<String, Int>()
data class Counter(var counter:Int)
private var eventCounter = mapOf<String, Counter>()
fun printCounter() { fun printCounter() {
eventCounter.forEach { eventCounter.forEach {
println("AAA Count ${it.key}: ${it.value}") println("AAA Count ${it.key}: ${it.value.counter}")
} }
} }
@@ -47,9 +51,9 @@ abstract class NostrDataSource<T>(val debugName: String) {
val key = "${debugName} ${subscriptionId} ${event.kind}" val key = "${debugName} ${subscriptionId} ${event.kind}"
val keyValue = eventCounter.get(key) val keyValue = eventCounter.get(key)
if (keyValue != null) { if (keyValue != null) {
eventCounter = eventCounter + Pair(key, keyValue + 1) keyValue.counter++
} else { } else {
eventCounter = eventCounter + Pair(key, 1) eventCounter = eventCounter + Pair(key, Counter(1))
} }
try { try {
@@ -28,7 +28,7 @@ object NostrSingleEventDataSource: NostrDataSource<Note>("SingleEventFeed") {
val now = Date().time / 1000 val now = Date().time / 1000
return reactionsToWatch.filter { return reactionsToWatch.filter {
val lastTime = it.lastReactionsDownloadTime; val lastTime = it.lastReactionsDownloadTime
lastTime == null || lastTime < (now - 10) lastTime == null || lastTime < (now - 10)
}.map { }.map {
TypedFilter( TypedFilter(
@@ -78,7 +78,7 @@ object NostrSingleEventDataSource: NostrDataSource<Note>("SingleEventFeed") {
) )
} }
val singleEventChannel = requestNewChannel() { time -> val singleEventChannel = requestNewChannel { time ->
eventsToWatch.forEach { eventsToWatch.forEach {
LocalCache.getOrCreateNote(it).lastReactionsDownloadTime = time LocalCache.getOrCreateNote(it).lastReactionsDownloadTime = time
} }