diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt index 55448fd4c..d0a584ad6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -1,29 +1,20 @@ package com.vitorpamplona.amethyst.model 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.model.LnZapEvent 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.ui.note.toShortenHex import fr.acinq.secp256k1.Hex import java.math.BigDecimal -import java.util.Collections -import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicBoolean -import kotlin.time.ExperimentalTime -import kotlin.time.measureTimedValue import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import nostr.postr.events.ContactListEvent -import nostr.postr.events.Event import nostr.postr.events.MetadataEvent import nostr.postr.toNpub @@ -61,10 +52,11 @@ class User(val pubkeyHex: String) { var relaysBeingUsed = mapOf() private set - var messages = mapOf>() + data class Chatroom(var roomMessages: Set) + + var privateChatrooms = mapOf() private set - var latestMetadataRequestEOSE: Long? = null var latestReportRequestEOSE: Long? = null fun toBestDisplayName(): String { @@ -103,8 +95,10 @@ class User(val pubkeyHex: String) { fun follow(users: Set, followedAt: Long) { follows = follows + users users.forEach { - it.followers = it.followers + this - it.liveFollows.invalidateData() + if (this !in followers) { + it.followers = it.followers + this + it.liveFollows.invalidateData() + } } liveFollows.invalidateData() @@ -113,8 +107,10 @@ class User(val pubkeyHex: String) { fun unfollow(users: Set) { follows = follows - users users.forEach { - it.followers = it.followers - this - it.liveFollows.invalidateData() + if (this in followers) { + it.followers = it.followers - this + it.liveFollows.invalidateData() + } } liveFollows.invalidateData() } @@ -178,18 +174,18 @@ class User(val pubkeyHex: String) { } @Synchronized - fun getOrCreateChannel(user: User): Set { - return messages[user] ?: run { - val channel = setOf() - messages = messages + Pair(user, channel) - channel + fun getOrCreatePrivateChatroom(user: User): Chatroom { + return privateChatrooms[user] ?: run { + val privateChatroom = Chatroom(setOf()) + privateChatrooms = privateChatrooms + Pair(user, privateChatroom) + privateChatroom } } fun addMessage(user: User, msg: Note) { - val channel = getOrCreateChannel(user) - if (msg !in channel) { - messages = messages + Pair(user, channel + msg) + val privateChatroom = getOrCreatePrivateChatroom(user) + if (msg !in privateChatroom.roomMessages) { + privateChatroom.roomMessages = privateChatroom.roomMessages + msg liveMessages.invalidateData() } } @@ -243,9 +239,9 @@ class User(val pubkeyHex: String) { } 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 { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatRoomDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatRoomDataSource.kt index f9b404ff7..5c27273dc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatRoomDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatRoomDataSource.kt @@ -56,9 +56,9 @@ object NostrChatRoomDataSource: NostrDataSource("ChatroomFeed") { // returns the last Note of each user. override fun feed(): List { - 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() { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt index 0d3b9d5cd..be7f400ee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrChatroomListDataSource.kt @@ -75,11 +75,11 @@ object NostrChatroomListDataSource: NostrDataSource("MailBoxFeed") { // returns the last Note of each user. override fun feed(): List { - val messages = account.userProfile().messages - val messagingWith = messages.keys.filter { account.isAcceptable(it) } + val privateChatrooms = account.userProfile().privateChatrooms + val messagingWith = privateChatrooms.keys.filter { account.isAcceptable(it) } 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 { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 857f124ca..227084702 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt @@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note 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.ChannelHideMessageEvent import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent @@ -33,11 +34,14 @@ import nostr.postr.events.TextNoteEvent abstract class NostrDataSource(val debugName: String) { private var subscriptions = mapOf() - private var eventCounter = mapOf() + + data class Counter(var counter:Int) + + private var eventCounter = mapOf() fun printCounter() { eventCounter.forEach { - println("AAA Count ${it.key}: ${it.value}") + println("AAA Count ${it.key}: ${it.value.counter}") } } @@ -47,9 +51,9 @@ abstract class NostrDataSource(val debugName: String) { val key = "${debugName} ${subscriptionId} ${event.kind}" val keyValue = eventCounter.get(key) if (keyValue != null) { - eventCounter = eventCounter + Pair(key, keyValue + 1) + keyValue.counter++ } else { - eventCounter = eventCounter + Pair(key, 1) + eventCounter = eventCounter + Pair(key, Counter(1)) } try { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt index df57ab200..5e3386aae 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrSingleEventDataSource.kt @@ -28,7 +28,7 @@ object NostrSingleEventDataSource: NostrDataSource("SingleEventFeed") { val now = Date().time / 1000 return reactionsToWatch.filter { - val lastTime = it.lastReactionsDownloadTime; + val lastTime = it.lastReactionsDownloadTime lastTime == null || lastTime < (now - 10) }.map { TypedFilter( @@ -78,7 +78,7 @@ object NostrSingleEventDataSource: NostrDataSource("SingleEventFeed") { ) } - val singleEventChannel = requestNewChannel() { time -> + val singleEventChannel = requestNewChannel { time -> eventsToWatch.forEach { LocalCache.getOrCreateNote(it).lastReactionsDownloadTime = time }