Avoiding the creation of new sets when looping through maps in User and Note

This commit is contained in:
Vitor Pamplona
2023-12-14 18:31:00 -05:00
parent b795ca06d1
commit d1c43f8147
8 changed files with 79 additions and 91 deletions
@@ -287,7 +287,7 @@ open class Note(val idHex: String) {
val tags = note.event?.tags() ?: emptyArray() val tags = note.event?.tags() ?: emptyArray()
val reaction = note.event?.content()?.firstFullCharOrEmoji(ImmutableListOfLists(tags)) ?: "+" val reaction = note.event?.content()?.firstFullCharOrEmoji(ImmutableListOfLists(tags)) ?: "+"
if (reaction in reactions.keys && reactions[reaction]?.contains(note) == true) { if (reactions[reaction]?.contains(note) == true) {
reactions[reaction]?.let { reactions[reaction]?.let {
if (note in it) { if (note in it) {
val newList = it.minus(note) val newList = it.minus(note)
@@ -306,7 +306,7 @@ open class Note(val idHex: String) {
fun removeReport(deleteNote: Note) { fun removeReport(deleteNote: Note) {
val author = deleteNote.author ?: return val author = deleteNote.author ?: return
if (author in reports.keys && reports[author]?.contains(deleteNote) == true) { if (reports[author]?.contains(deleteNote) == true) {
reports[author]?.let { reports[author]?.let {
reports = reports + Pair(author, it.minus(deleteNote)) reports = reports + Pair(author, it.minus(deleteNote))
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
@@ -327,12 +327,11 @@ open class Note(val idHex: String) {
} }
fun removeZapPayment(note: Note) { fun removeZapPayment(note: Note) {
if (zapPayments[note] != null) { if (zapPayments.containsKey(note)) {
zapPayments = zapPayments.minus(note) zapPayments = zapPayments.minus(note)
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
} else if (zapPayments.containsValue(note)) { } else if (zapPayments.containsValue(note)) {
val toRemove = zapPayments.filterValues { it == note } zapPayments = zapPayments.filterValues { it != note }
zapPayments = zapPayments.minus(toRemove.keys)
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
} }
} }
@@ -346,10 +345,7 @@ open class Note(val idHex: String) {
@Synchronized @Synchronized
private fun innerAddZap(zapRequest: Note, zap: Note?): Boolean { private fun innerAddZap(zapRequest: Note, zap: Note?): Boolean {
if (zapRequest !in zaps.keys) { if (zaps[zapRequest] == null) {
zaps = zaps + Pair(zapRequest, zap)
return true
} else if (zaps[zapRequest] == null) {
zaps = zaps + Pair(zapRequest, zap) zaps = zaps + Pair(zapRequest, zap)
return true return true
} }
@@ -359,13 +355,8 @@ open class Note(val idHex: String) {
fun addZap(zapRequest: Note, zap: Note?) { fun addZap(zapRequest: Note, zap: Note?) {
checkNotInMainThread() checkNotInMainThread()
if (zapRequest !in zaps.keys) {
val inserted = innerAddZap(zapRequest, zap) if (zaps[zapRequest] == null) {
if (inserted) {
updateZapTotal()
liveSet?.innerZaps?.invalidateData()
}
} else if (zaps[zapRequest] == null) {
val inserted = innerAddZap(zapRequest, zap) val inserted = innerAddZap(zapRequest, zap)
if (inserted) { if (inserted) {
updateZapTotal() updateZapTotal()
@@ -376,10 +367,7 @@ open class Note(val idHex: String) {
@Synchronized @Synchronized
private fun innerAddZapPayment(zapPaymentRequest: Note, zapPayment: Note?): Boolean { private fun innerAddZapPayment(zapPaymentRequest: Note, zapPayment: Note?): Boolean {
if (zapPaymentRequest !in zapPayments.keys) { if (zapPayments[zapPaymentRequest] == null) {
zapPayments = zapPayments + Pair(zapPaymentRequest, zapPayment)
return true
} else if (zapPayments[zapPaymentRequest] == null) {
zapPayments = zapPayments + Pair(zapPaymentRequest, zapPayment) zapPayments = zapPayments + Pair(zapPaymentRequest, zapPayment)
return true return true
} }
@@ -389,12 +377,7 @@ open class Note(val idHex: String) {
fun addZapPayment(zapPaymentRequest: Note, zapPayment: Note?) { fun addZapPayment(zapPaymentRequest: Note, zapPayment: Note?) {
checkNotInMainThread() checkNotInMainThread()
if (zapPaymentRequest !in zapPayments.keys) { if (zapPayments[zapPaymentRequest] == null) {
val inserted = innerAddZapPayment(zapPaymentRequest, zapPayment)
if (inserted) {
liveSet?.innerZaps?.invalidateData()
}
} else if (zapPayments[zapPaymentRequest] == null) {
val inserted = innerAddZapPayment(zapPaymentRequest, zapPayment) val inserted = innerAddZapPayment(zapPaymentRequest, zapPayment)
if (inserted) { if (inserted) {
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
@@ -406,11 +389,12 @@ open class Note(val idHex: String) {
val tags = note.event?.tags() ?: emptyArray() val tags = note.event?.tags() ?: emptyArray()
val reaction = note.event?.content()?.firstFullCharOrEmoji(ImmutableListOfLists(tags)) ?: "+" val reaction = note.event?.content()?.firstFullCharOrEmoji(ImmutableListOfLists(tags)) ?: "+"
if (reaction !in reactions.keys) { val listOfAuthors = reactions[reaction]
if (listOfAuthors == null) {
reactions = reactions + Pair(reaction, listOf(note)) reactions = reactions + Pair(reaction, listOf(note))
liveSet?.innerReactions?.invalidateData() liveSet?.innerReactions?.invalidateData()
} else if (reactions[reaction]?.contains(note) == false) { } else if (!listOfAuthors.contains(note)) {
reactions = reactions + Pair(reaction, (reactions[reaction] ?: emptySet()) + note) reactions = reactions + Pair(reaction, listOfAuthors + note)
liveSet?.innerReactions?.invalidateData() liveSet?.innerReactions?.invalidateData()
} }
} }
@@ -418,11 +402,13 @@ open class Note(val idHex: String) {
fun addReport(note: Note) { fun addReport(note: Note) {
val author = note.author ?: return val author = note.author ?: return
if (author !in reports.keys) { val reportsByAuthor = reports[author]
if (reportsByAuthor == null) {
reports = reports + Pair(author, listOf(note)) reports = reports + Pair(author, listOf(note))
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
} else if (reports[author]?.contains(note) == false) { } else if (!reportsByAuthor.contains(note)) {
reports = reports + Pair(author, (reports[author] ?: emptySet()) + note) reports = reports + Pair(author, reportsByAuthor + note)
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
} }
} }
@@ -523,17 +509,17 @@ open class Note(val idHex: String) {
return reports[user]?.isNotEmpty() ?: false return reports[user]?.isNotEmpty() ?: false
} }
fun reportAuthorsBy(users: Set<HexKey>): List<User> {
return reports.keys.filter { it.pubkeyHex in users }
}
fun countReportAuthorsBy(users: Set<HexKey>): Int { fun countReportAuthorsBy(users: Set<HexKey>): Int {
return reports.keys.count { it.pubkeyHex in users } return reports.count { it.key.pubkeyHex in users }
} }
fun reportsBy(users: Set<HexKey>): List<Note> { fun reportsBy(users: Set<HexKey>): List<Note> {
return reportAuthorsBy(users).mapNotNull { return reports.mapNotNull {
reports[it] if (it.key.pubkeyHex in users) {
it.value
} else {
null
}
}.flatten() }.flatten()
} }
@@ -541,8 +527,8 @@ open class Note(val idHex: String) {
var sumOfAmounts = BigDecimal.ZERO var sumOfAmounts = BigDecimal.ZERO
// Regular Zap Receipts // Regular Zap Receipts
zaps.values.forEach { zaps.forEach {
val noteEvent = it?.event val noteEvent = it?.value?.event
if (noteEvent is LnZapEvent) { if (noteEvent is LnZapEvent) {
sumOfAmounts += noteEvent.amount ?: BigDecimal.ZERO sumOfAmounts += noteEvent.amount ?: BigDecimal.ZERO
} }
@@ -647,8 +633,8 @@ open class Note(val idHex: String) {
val dayAgo = TimeUtils.oneDayAgo() val dayAgo = TimeUtils.oneDayAgo()
return reports.isNotEmpty() || return reports.isNotEmpty() ||
( (
author?.reports?.values?.any { author?.reports?.any {
it.firstOrNull { (it.createdAt() ?: 0) > dayAgo } != null it.value.firstOrNull { (it.createdAt() ?: 0) > dayAgo } != null
} ?: false } ?: false
) )
} }
@@ -863,7 +849,9 @@ class NoteLiveSet(u: Note) {
}.distinctUntilChanged() }.distinctUntilChanged()
val reactionCount = innerReactions.map { val reactionCount = innerReactions.map {
it.note.reactions.values.sumOf { it.size } var total = 0
it.note.reactions.forEach { total += it.value.size }
total
}.distinctUntilChanged() }.distinctUntilChanged()
val boostCount = innerBoosts.map { val boostCount = innerBoosts.map {
@@ -130,11 +130,12 @@ class User(val pubkeyHex: String) {
fun addReport(note: Note) { fun addReport(note: Note) {
val author = note.author ?: return val author = note.author ?: return
if (author !in reports.keys) { val reportsBy = reports[author]
if (reportsBy == null) {
reports = reports + Pair(author, setOf(note)) reports = reports + Pair(author, setOf(note))
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
} else if (reports[author]?.contains(note) == false) { } else if (!reportsBy.contains(note)) {
reports = reports + Pair(author, (reports[author] ?: emptySet()) + note) reports = reports + Pair(author, reportsBy + note)
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
} }
} }
@@ -142,7 +143,7 @@ class User(val pubkeyHex: String) {
fun removeReport(deleteNote: Note) { fun removeReport(deleteNote: Note) {
val author = deleteNote.author ?: return val author = deleteNote.author ?: return
if (author in reports.keys && reports[author]?.contains(deleteNote) == true) { if (reports[author]?.contains(deleteNote) == true) {
reports[author]?.let { reports[author]?.let {
reports = reports + Pair(author, it.minus(deleteNote)) reports = reports + Pair(author, it.minus(deleteNote))
liveSet?.innerReports?.invalidateData() liveSet?.innerReports?.invalidateData()
@@ -151,48 +152,49 @@ class User(val pubkeyHex: String) {
} }
fun addZap(zapRequest: Note, zap: Note?) { fun addZap(zapRequest: Note, zap: Note?) {
if (zapRequest !in zaps.keys) { if (zaps[zapRequest] == null) {
zaps = zaps + Pair(zapRequest, zap)
liveSet?.innerZaps?.invalidateData()
} else if (zapRequest in zaps.keys && zaps[zapRequest] == null) {
zaps = zaps + Pair(zapRequest, zap) zaps = zaps + Pair(zapRequest, zap)
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
} }
} }
fun removeZap(zapRequestOrZapEvent: Note) { fun removeZap(zapRequestOrZapEvent: Note) {
if (zapRequestOrZapEvent in zaps.keys) { if (zaps.containsKey(zapRequestOrZapEvent)) {
zaps = zaps.minus(zapRequestOrZapEvent) zaps = zaps.minus(zapRequestOrZapEvent)
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
} else if (zapRequestOrZapEvent in zaps.values) { } else if (zaps.containsValue(zapRequestOrZapEvent)) {
zaps = zaps.filter { it.value != zapRequestOrZapEvent } zaps = zaps.filter { it.value != zapRequestOrZapEvent }
liveSet?.innerZaps?.invalidateData() liveSet?.innerZaps?.invalidateData()
} }
} }
fun zappedAmount(): BigDecimal { fun zappedAmount(): BigDecimal {
return zaps.mapNotNull { it.value?.event } var amount = BigDecimal.ZERO
.filterIsInstance<LnZapEvent>() zaps.forEach {
.mapNotNull { val itemValue = (it.value?.event as? LnZapEvent)?.amount
it.amount if (itemValue != null) {
}.sumOf { it } amount += itemValue
}
}
return amount
} }
fun reportsBy(user: User): Set<Note> { fun reportsBy(user: User): Set<Note> {
return reports[user] ?: emptySet() return reports[user] ?: emptySet()
} }
fun reportAuthorsBy(users: Set<HexKey>): List<User> {
return reports.keys.filter { it.pubkeyHex in users }
}
fun countReportAuthorsBy(users: Set<HexKey>): Int { fun countReportAuthorsBy(users: Set<HexKey>): Int {
return reports.keys.count { it.pubkeyHex in users } return reports.count { it.key.pubkeyHex in users }
} }
fun reportsBy(users: Set<HexKey>): List<Note> { fun reportsBy(users: Set<HexKey>): List<Note> {
return reportAuthorsBy(users).mapNotNull { return reports.mapNotNull {
reports[it] if (it.key.pubkeyHex in users) {
it.value
} else {
null
}
}.flatten() }.flatten()
} }
@@ -314,7 +316,7 @@ class User(val pubkeyHex: String) {
} }
suspend fun transientFollowerCount(): Int { suspend fun transientFollowerCount(): Int {
return LocalCache.users.values.count { it.latestContactList?.isTaggedUser(pubkeyHex) ?: false } return LocalCache.users.count { it.value.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
} }
fun cachedFollowingKeySet(): Set<HexKey> { fun cachedFollowingKeySet(): Set<HexKey> {
@@ -338,7 +340,7 @@ class User(val pubkeyHex: String) {
} }
suspend fun cachedFollowerCount(): Int { suspend fun cachedFollowerCount(): Int {
return LocalCache.users.values.count { it.latestContactList?.isTaggedUser(pubkeyHex) ?: false } return LocalCache.users.count { it.value.latestContactList?.isTaggedUser(pubkeyHex) ?: false }
} }
fun hasSentMessagesTo(key: ChatroomKey?): Boolean { fun hasSentMessagesTo(key: ChatroomKey?): Boolean {
@@ -64,7 +64,7 @@ abstract class NostrDataSource(val debugName: String) {
// Relay.Type.EOSE -> "sent all events it had stored." // Relay.Type.EOSE -> "sent all events it had stored."
// }}") // }}")
if (type == Relay.StateType.EOSE && subscriptionId != null && subscriptionId in subscriptions.keys) { if (type == Relay.StateType.EOSE && subscriptionId != null && subscriptions.containsKey(subscriptionId)) {
markAsEOSE(subscriptionId, relay) markAsEOSE(subscriptionId, relay)
} }
} }
@@ -177,7 +177,7 @@ abstract class NostrDataSource(val debugName: String) {
subscriptions.values.forEach { updatedSubscription -> subscriptions.values.forEach { updatedSubscription ->
val updatedSubscriptionNewFilters = updatedSubscription.typedFilters val updatedSubscriptionNewFilters = updatedSubscription.typedFilters
if (updatedSubscription.id in currentFilters.keys) { if (currentFilters.containsKey(updatedSubscription.id)) {
if (updatedSubscriptionNewFilters == null) { if (updatedSubscriptionNewFilters == null) {
// was active and is not active anymore, just close. // was active and is not active anymore, just close.
Client.close(updatedSubscription.id) Client.close(updatedSubscription.id)
@@ -213,8 +213,8 @@ object Client : RelayPool.Listener {
listeners = listeners.minus(listener) listeners = listeners.minus(listener)
} }
fun allSubscriptions(): List<String> { fun allSubscriptions(): Set<String> {
return subscriptions.keys.toList() return subscriptions.keys
} }
fun getSubscriptionFilters(subId: String): List<TypedFilter> { fun getSubscriptionFilters(subId: String): List<TypedFilter> {
@@ -21,7 +21,7 @@ class ChannelFeedFilter(val channel: Channel, val account: Account) : AdditiveFe
override fun applyFilter(collection: Set<Note>): Set<Note> { override fun applyFilter(collection: Set<Note>): Set<Note> {
return collection return collection
.filter { it.idHex in channel.notes.keys && account.isAcceptable(it) } .filter { channel.notes.containsKey(it.idHex) && account.isAcceptable(it) }
.toSet() .toSet()
} }
@@ -20,19 +20,17 @@ class ChatroomListKnownFeedFilter(val account: Account) : AdditiveFeedFilter<Not
val me = account.userProfile() val me = account.userProfile()
val followingKeySet = account.followingKeySet() val followingKeySet = account.followingKeySet()
val privateChatrooms = me.privateChatrooms val messagingWith = me.privateChatrooms.filter {
val messagingWith = privateChatrooms.keys.filter {
( (
privateChatrooms[it]?.senderIntersects(followingKeySet) == true || it.value.senderIntersects(followingKeySet) || me.hasSentMessagesTo(it.key)
me.hasSentMessagesTo(it) ) && !account.isAllHidden(it.key.users)
) && !account.isAllHidden(it.users)
} }
val privateMessages = messagingWith.mapNotNull { it -> val privateMessages = messagingWith.mapNotNull { it ->
privateChatrooms[it] it.value
?.roomMessages .roomMessages
?.sortedWith(compareBy({ it.createdAt() }, { it.idHex })) .sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
?.lastOrNull { it.event != null } .lastOrNull { it.event != null }
} }
val publicChannels = account.selectedChatsFollowList().mapNotNull { val publicChannels = account.selectedChatsFollowList().mapNotNull {
@@ -20,16 +20,15 @@ class ChatroomListNewFeedFilter(val account: Account) : AdditiveFeedFilter<Note>
val followingKeySet = account.followingKeySet() val followingKeySet = account.followingKeySet()
val privateChatrooms = account.userProfile().privateChatrooms val privateChatrooms = account.userProfile().privateChatrooms
val messagingWith = privateChatrooms.keys.filter { val messagingWith = privateChatrooms.filter {
privateChatrooms[it]?.senderIntersects(followingKeySet) == false && !it.value.senderIntersects(followingKeySet) && !me.hasSentMessagesTo(it.key) && !account.isAllHidden(it.key.users)
!me.hasSentMessagesTo(it) && !account.isAllHidden(it.users)
} }
val privateMessages = messagingWith.mapNotNull { it -> val privateMessages = messagingWith.mapNotNull { it ->
privateChatrooms[it] it.value
?.roomMessages .roomMessages
?.sortedWith(compareBy({ it.createdAt() }, { it.idHex })) .sortedWith(compareBy({ it.createdAt() }, { it.idHex }))
?.lastOrNull { it.event != null } .lastOrNull { it.event != null }
} }
return privateMessages return privateMessages
@@ -335,8 +335,9 @@ private fun getRouteWithArguments(
): String? { ): String? {
var route = destination.route ?: return null var route = destination.route ?: return null
arguments?.let { bundle -> arguments?.let { bundle ->
destination.arguments.keys.forEach { key -> destination.arguments.forEach {
val value = destination.arguments[key]?.type?.get(bundle, key)?.toString() val key = it.key
val value = it.value.type[bundle, key]?.toString()
if (value == null) { if (value == null) {
val keyStart = route.indexOf("{$key}") val keyStart = route.indexOf("{$key}")
// if it is a parameter, removes the complete segment `var={key}` and adjust connectors `#`, `&` or `&` // if it is a parameter, removes the complete segment `var={key}` and adjust connectors `#`, `&` or `&`