Improving performance with more precise filters.

This commit is contained in:
Vitor Pamplona 2023-01-18 11:44:31 -05:00
parent f2b913f7c8
commit 7d18f36e3e
22 changed files with 163 additions and 141 deletions

View File

@ -65,11 +65,11 @@ object LocalCache {
fun consume(event: MetadataEvent) {
//Log.d("MT", "New User ${users.size} ${event.contactMetaData.name}")
// new event
val oldUser = getOrCreateUser(event.pubKey)
if (event.createdAt > oldUser.updatedMetadataAt) {
//Log.d("MT", "New User ${users.size} ${event.contactMetaData.name}")
val newUser = try {
metadataParser.readValue<UserMetadata>(ByteArrayInputStream(event.content.toByteArray(Charsets.UTF_8)), UserMetadata::class.java)
} catch (e: Exception) {
@ -101,7 +101,7 @@ object LocalCache {
note.loadEvent(event, author, mentions, replyTo)
//Log.d("TN", "New Note (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${note.event?.content} ${formattedDateTime(event.createdAt)}")
//Log.d("TN", "New Note (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${note.event?.content?.take(100)} ${formattedDateTime(event.createdAt)}")
// Prepares user's profile view.
author.notes.add(note)
@ -188,7 +188,7 @@ object LocalCache {
// Already processed this event.
if (note.event != null) return
//Log.d("TN", "New Boost (${notes.size},${users.size}) ${note.author.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
//Log.d("TN", "New Boost (${notes.size},${users.size}) ${note.author?.toBestDisplayName()} ${formattedDateTime(event.createdAt)}")
val author = getOrCreateUser(event.pubKey)
val mentions = event.originalAuthor.map { getOrCreateUser(decodePublicKey(it)) }.toList()

View File

@ -102,14 +102,13 @@ class Note(val idHex: String) {
}
class NoteLiveData(val note: Note): LiveData<NoteState>(NoteState(note)) {
val scope = CoroutineScope(Job() + Dispatchers.Main)
fun refresh() {
postValue(NoteState(note))
}
override fun onActive() {
super.onActive()
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
NostrSingleEventDataSource.add(note.idHex)
}
@ -117,6 +116,7 @@ class NoteLiveData(val note: Note): LiveData<NoteState>(NoteState(note)) {
override fun onInactive() {
super.onInactive()
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
NostrSingleEventDataSource.remove(note.idHex)
}

View File

@ -1,10 +1,15 @@
package com.vitorpamplona.amethyst.model
import androidx.lifecycle.LiveData
import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.ui.note.toShortenHex
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import nostr.postr.events.ContactListEvent
class User(val pubkey: ByteArray) {
@ -138,12 +143,18 @@ class UserLiveData(val user: User): LiveData<UserState>(UserState(user)) {
override fun onActive() {
super.onActive()
NostrSingleUserDataSource.add(user.pubkeyHex)
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
NostrSingleUserDataSource.add(user.pubkeyHex)
}
}
override fun onInactive() {
super.onInactive()
NostrSingleUserDataSource.remove(user.pubkeyHex)
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
NostrSingleUserDataSource.remove(user.pubkeyHex)
}
}
}

View File

@ -6,5 +6,5 @@ import nostr.postr.JsonFilter
data class Channel (
val id: String = UUID.randomUUID().toString().substring(0,4)
) {
var filter: JsonFilter? = null // Inactive when null
var filter: List<JsonFilter>? = null // Inactive when null
}

View File

@ -29,31 +29,24 @@ object NostrAccountDataSource: NostrDataSource<Note>("AccountData") {
account.userProfile().live.removeObserver(cacheListener)
}
fun createAccountFilter(): JsonFilter {
fun createAccountContactListFilter(): JsonFilter {
return JsonFilter(
kinds = listOf(MetadataEvent.kind, ContactListEvent.kind),
kinds = listOf(ContactListEvent.kind),
authors = listOf(account.userProfile().pubkeyHex),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 7), // 4 days
limit = 1
)
}
val accountChannel = requestNewChannel()
fun <T> equalsIgnoreOrder(list1:List<T>?, list2:List<T>?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return list1.size == list2.size && list1.toSet() == list2.toSet()
fun createAccountMetadataFilter(): JsonFilter {
return JsonFilter(
kinds = listOf(MetadataEvent.kind),
authors = listOf(account.userProfile().pubkeyHex),
limit = 1
)
}
fun equalAuthors(list1:JsonFilter?, list2:JsonFilter?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return equalsIgnoreOrder(list1.authors, list2.authors)
}
val accountMetadataChannel = requestNewChannel()
val accountContactListChannel = requestNewChannel()
override fun feed(): List<Note> {
val user = account.userProfile()
@ -72,10 +65,10 @@ object NostrAccountDataSource: NostrDataSource<Note>("AccountData") {
override fun updateChannelFilters() {
// gets everthing about the user logged in
val newAccountFilter = createAccountFilter()
val newAccountMetadataFilter = createAccountMetadataFilter()
accountMetadataChannel.filter = listOf(newAccountMetadataFilter).ifEmpty { null }
if (!equalAuthors(newAccountFilter, accountChannel.filter)) {
accountChannel.filter = newAccountFilter
}
val newAccountContactListEvent = createAccountContactListFilter()
accountContactListChannel.filter = listOf(newAccountContactListEvent).ifEmpty { null }
}
}

View File

@ -15,7 +15,7 @@ object NostrChannelDataSource: NostrDataSource<Note>("ChatroomFeed") {
fun createMessagesToChannelFilter() = JsonFilter(
kinds = listOf(ChannelMessageEvent.kind),
tags = mapOf("e" to listOf(channel?.idHex).filterNotNull()),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 1), // 24 hours
limit = 100
)
val messagesChannel = requestNewChannel()
@ -26,6 +26,6 @@ object NostrChannelDataSource: NostrDataSource<Note>("ChatroomFeed") {
}
override fun updateChannelFilters() {
messagesChannel.filter = createMessagesToChannelFilter()
messagesChannel.filter = listOf(createMessagesToChannelFilter()).ifEmpty { null }
}
}

View File

@ -39,7 +39,7 @@ object NostrChatRoomDataSource: NostrDataSource<Note>("ChatroomFeed") {
}
override fun updateChannelFilters() {
incomingChannel.filter = createMessagesToMeFilter()
outgoingChannel.filter = createMessagesFromMeFilter()
incomingChannel.filter = listOf(createMessagesToMeFilter()).ifEmpty { null }
outgoingChannel.filter = listOf(createMessagesFromMeFilter()).ifEmpty { null }
}
}

View File

@ -26,16 +26,25 @@ object NostrChatroomListDataSource: NostrDataSource<Note>("MailBoxFeed") {
ids = account.followingChannels.toList()
)
fun createMyChannelsInfoFilter() = JsonFilter(
kinds = listOf(ChannelMetadataEvent.kind),
tags = mapOf("e" to account.followingChannels.toList())
)
fun createLastChannelInfoFilter(): List<JsonFilter> {
return account.followingChannels.map {
JsonFilter(
kinds = listOf(ChannelMetadataEvent.kind),
tags = mapOf("e" to listOf(it)),
limit = 1
)
}
}
fun createMessagesToMyChannelsFilter() = JsonFilter(
kinds = listOf(ChannelMessageEvent.kind),
tags = mapOf("e" to account.followingChannels.toList()),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 1), // 24 hours
)
fun createLastMessageOfEachChannelFilter(): List<JsonFilter> {
return account.followingChannels.map {
JsonFilter(
kinds = listOf(ChannelMessageEvent.kind),
tags = mapOf("e" to listOf(it)),
limit = 1
)
}
}
val incomingChannel = requestNewChannel()
val outgoingChannel = requestNewChannel()
@ -61,10 +70,10 @@ object NostrChatroomListDataSource: NostrDataSource<Note>("MailBoxFeed") {
}
override fun updateChannelFilters() {
incomingChannel.filter = createMessagesToMeFilter()
outgoingChannel.filter = createMessagesFromMeFilter()
myChannelsChannel.filter = createMyChannelsFilter()
myChannelsInfoChannel.filter = createMyChannelsInfoFilter()
myChannelsMessagesChannel.filter = createMessagesToMyChannelsFilter()
incomingChannel.filter = listOf(createMessagesToMeFilter()).ifEmpty { null }
outgoingChannel.filter = listOf(createMessagesFromMeFilter()).ifEmpty { null }
myChannelsChannel.filter = listOf(createMyChannelsFilter()).ifEmpty { null }
myChannelsInfoChannel.filter = createLastChannelInfoFilter().ifEmpty { null }
myChannelsMessagesChannel.filter = createLastMessageOfEachChannelFilter().ifEmpty { null }
}
}

View File

@ -23,9 +23,25 @@ abstract class NostrDataSource<T>(val debugName: String) {
private val channels = Collections.synchronizedSet(mutableSetOf<Channel>())
private val channelIds = Collections.synchronizedSet(mutableSetOf<String>())
private val eventCounter = mutableMapOf<String, Int>()
fun printCounter() {
eventCounter.forEach {
println("AAA Count ${it.key}: ${it.value}")
}
}
private val clientListener = object : Client.Listener() {
override fun onEvent(event: Event, subscriptionId: String, relay: Relay) {
if (subscriptionId in channelIds) {
val key = "${debugName} ${subscriptionId} ${event.kind}"
if (eventCounter.contains(key)) {
eventCounter.put(key, eventCounter.get(key)!! + 1)
} else {
eventCounter.put(key, 1)
}
//println("AAA ${debugName} ${subscriptionId} ${event.kind}")
when (event) {
is MetadataEvent -> LocalCache.consume(event)
is TextNoteEvent -> LocalCache.consume(event)
@ -109,7 +125,7 @@ abstract class NostrDataSource<T>(val debugName: String) {
// saves the channels that are currently active
val activeChannels = channels.filter { it.filter != null }
// saves the current content to only update if it changes
val currentFilter = activeChannels.associate { it.id to it.filter!!.toJson() }
val currentFilter = activeChannels.associate { it.id to it.filter!!.joinToString("|") { it.toJson() } }
updateChannelFilters()
@ -123,12 +139,12 @@ abstract class NostrDataSource<T>(val debugName: String) {
Client.close(channel.id)
} else {
// was active and is still active, check if it has changed.
if (channelsNewFilter.toJson() != currentFilter[channel.id]) {
if (channelsNewFilter.joinToString("|") { it.toJson() } != currentFilter[channel.id]) {
Client.close(channel.id)
Client.sendFilter(channel.id, mutableListOf(channelsNewFilter))
Client.sendFilter(channel.id, channelsNewFilter)
} else {
// hasn't changed, does nothing.
Client.sendFilterOnlyIfDisconnected(channel.id, mutableListOf(channelsNewFilter))
Client.sendFilterOnlyIfDisconnected(channel.id, channelsNewFilter)
}
}
} else {
@ -136,8 +152,8 @@ abstract class NostrDataSource<T>(val debugName: String) {
// was not active and is still not active, does nothing
} else {
// was not active and becomes active, sends the filter.
if (channelsNewFilter.toJson() != currentFilter[channel.id]) {
Client.sendFilter(channel.id, mutableListOf(channelsNewFilter))
if (channelsNewFilter.joinToString("|") { it.toJson() } != currentFilter[channel.id]) {
Client.sendFilter(channel.id, channelsNewFilter)
}
}
}

View File

@ -6,31 +6,13 @@ import nostr.postr.JsonFilter
import nostr.postr.events.TextNoteEvent
object NostrGlobalDataSource: NostrDataSource<Note>("GlobalFeed") {
val fifteenMinutes = (60*15) // 15 mins
fun createGlobalFilter() = JsonFilter(
kinds = listOf(TextNoteEvent.kind),
since = System.currentTimeMillis() / 1000 - fifteenMinutes
)
kinds = listOf(TextNoteEvent.kind),
limit = 200
)
val globalFeedChannel = requestNewChannel()
fun equalTime(list1:Long?, list2:Long?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return Math.abs(list1 - list2) < (4*fifteenMinutes)
}
fun equalFilters(list1:JsonFilter?, list2:JsonFilter?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return equalTime(list1.since, list2.since)
}
override fun feed() = LocalCache.notes.values
.filter {
it.event is TextNoteEvent && (it.event as TextNoteEvent).replyTos.isEmpty()
@ -39,10 +21,6 @@ object NostrGlobalDataSource: NostrDataSource<Note>("GlobalFeed") {
.reversed()
override fun updateChannelFilters() {
val newFilter = createGlobalFilter()
if (!equalFilters(newFilter, globalFeedChannel.filter)) {
globalFeedChannel.filter = newFilter
}
globalFeedChannel.filter = listOf(createGlobalFilter()).ifEmpty { null }
}
}

View File

@ -28,7 +28,7 @@ object NostrHomeDataSource: NostrDataSource<Note>("HomeFeed") {
account.userProfile().live.removeObserver(cacheListener)
}
fun createFollowAccountsFilter(): JsonFilter? {
fun createFollowAccountsFilter(): JsonFilter {
val follows = account.userProfile().follows ?: emptySet()
val followKeys = synchronized(follows) {
@ -39,12 +39,10 @@ object NostrHomeDataSource: NostrDataSource<Note>("HomeFeed") {
val followSet = followKeys.plus(account.userProfile().pubkeyHex.substring(0, 6))
if (followSet.isEmpty()) return null
return JsonFilter(
kinds = listOf(TextNoteEvent.kind, RepostEvent.kind),
authors = followSet,
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 1), // 24 hours
limit = 200
)
}
@ -85,8 +83,8 @@ object NostrHomeDataSource: NostrDataSource<Note>("HomeFeed") {
override fun updateChannelFilters() {
val newFollowAccountsFilter = createFollowAccountsFilter()
if (!equalAuthors(newFollowAccountsFilter, followAccountChannel.filter)) {
followAccountChannel.filter = newFollowAccountsFilter
if (!equalAuthors(newFollowAccountsFilter, followAccountChannel.filter?.firstOrNull())) {
followAccountChannel.filter = listOf(newFollowAccountsFilter).ifEmpty { null }
}
}
}

View File

@ -4,33 +4,16 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note
import nostr.postr.JsonFilter
object NostrNotificationDataSource: NostrDataSource<Note>("GlobalFeed") {
object NostrNotificationDataSource: NostrDataSource<Note>("NotificationFeed") {
lateinit var account: Account
fun createGlobalFilter() = JsonFilter(
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 7), // 7 days
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex).filterNotNull())
fun createNotificationFilter() = JsonFilter(
tags = mapOf("p" to listOf(account.userProfile().pubkeyHex)),
limit = 100
)
val notificationChannel = requestNewChannel()
fun <T> equalsIgnoreOrder(list1:List<T>?, list2:List<T>?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return list1.size == list2.size && list1.toSet() == list2.toSet()
}
fun equalFilters(list1:JsonFilter?, list2:JsonFilter?): Boolean {
if (list1 == null && list2 == null) return true
if (list1 == null) return false
if (list2 == null) return false
return equalsIgnoreOrder(list1.tags?.get("p"), list2.tags?.get("p"))
&& equalsIgnoreOrder(list1.tags?.get("e"), list2.tags?.get("e"))
}
override fun feed(): List<Note> {
val set = account.userProfile().taggedPosts
val filtered = synchronized(set) {
@ -41,10 +24,6 @@ object NostrNotificationDataSource: NostrDataSource<Note>("GlobalFeed") {
}
override fun updateChannelFilters() {
val newFilter = createGlobalFilter()
if (!equalFilters(newFilter, notificationChannel.filter)) {
notificationChannel.filter = newFilter
}
notificationChannel.filter = listOf(createNotificationFilter()).ifEmpty { null }
}
}

View File

@ -9,7 +9,7 @@ import nostr.postr.JsonFilter
import nostr.postr.events.TextNoteEvent
object NostrSingleEventDataSource: NostrDataSource<Note>("SingleEventFeed") {
private var eventsToWatch = listOf<String>()
private var eventsToWatch = setOf<String>()
private fun createRepliesAndReactionsFilter(): JsonFilter? {
val reactionsToWatch = eventsToWatch.map { it.substring(0, 8) }
@ -46,6 +46,7 @@ object NostrSingleEventDataSource: NostrDataSource<Note>("SingleEventFeed") {
// downloads linked events to this event.
return JsonFilter(
kinds = listOf(TextNoteEvent.kind, ReactionEvent.kind, RepostEvent.kind),
ids = interestedEvents
)
}
@ -60,12 +61,16 @@ object NostrSingleEventDataSource: NostrDataSource<Note>("SingleEventFeed") {
}
override fun updateChannelFilters() {
repliesAndReactionsChannel.filter = createRepliesAndReactionsFilter()
loadEventsChannel.filter = createLoadEventsIfNotLoadedFilter()
val reactions = createRepliesAndReactionsFilter()
val missing = createLoadEventsIfNotLoadedFilter()
repliesAndReactionsChannel.filter = listOfNotNull(reactions).ifEmpty { null }
loadEventsChannel.filter = listOfNotNull(missing).ifEmpty { null }
}
fun add(eventId: String) {
eventsToWatch = eventsToWatch.plus(eventId)
println("AAA: Event Watching ${eventsToWatch.size}")
resetFilters()
}

View File

@ -7,15 +7,18 @@ import nostr.postr.JsonFilter
import nostr.postr.events.MetadataEvent
object NostrSingleUserDataSource: NostrDataSource<Note>("SingleUserFeed") {
var usersToWatch = listOf<String>()
var usersToWatch = setOf<String>()
fun createUserFilter(): JsonFilter? {
fun createUserFilter(): List<JsonFilter>? {
if (usersToWatch.isEmpty()) return null
return JsonFilter(
kinds = listOf(MetadataEvent.kind),
authors = usersToWatch.map { it.substring(0, 8) }
)
return usersToWatch.map {
JsonFilter(
kinds = listOf(MetadataEvent.kind),
authors = listOf(it.substring(0, 8)),
limit = 1
)
}
}
val userChannel = requestNewChannel()
@ -32,6 +35,7 @@ object NostrSingleUserDataSource: NostrDataSource<Note>("SingleUserFeed") {
fun add(userId: String) {
usersToWatch = usersToWatch.plus(userId)
println("AAA: User Watching ${usersToWatch.size}")
resetFilters()
}

View File

@ -2,8 +2,11 @@ package com.vitorpamplona.amethyst.service
import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.ReactionEvent
import com.vitorpamplona.amethyst.service.model.RepostEvent
import java.util.Collections
import nostr.postr.JsonFilter
import nostr.postr.events.TextNoteEvent
object NostrThreadDataSource: NostrDataSource<Note>("SingleThreadFeed") {
val eventsToWatch = Collections.synchronizedList(mutableListOf<String>())
@ -16,6 +19,7 @@ object NostrThreadDataSource: NostrDataSource<Note>("SingleThreadFeed") {
}
return JsonFilter(
kinds = listOf(TextNoteEvent.kind, ReactionEvent.kind, RepostEvent.kind),
tags = mapOf("e" to reactionsToWatch)
)
}
@ -46,8 +50,8 @@ object NostrThreadDataSource: NostrDataSource<Note>("SingleThreadFeed") {
}
override fun updateChannelFilters() {
repliesAndReactionsChannel.filter = createRepliesAndReactionsFilter()
loadEventsChannel.filter = createLoadEventsIfNotLoadedFilter()
repliesAndReactionsChannel.filter = listOfNotNull(createRepliesAndReactionsFilter()).ifEmpty { null }
loadEventsChannel.filter = listOfNotNull(createLoadEventsIfNotLoadedFilter()).ifEmpty { null }
}
fun loadThread(noteId: String) {

View File

@ -19,7 +19,7 @@ object NostrUserProfileDataSource: NostrDataSource<Note>("UserProfileFeed") {
return JsonFilter(
kinds = listOf(MetadataEvent.kind),
authors = listOf(user!!.pubkeyHex),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 7)
limit = 1
)
}
@ -27,7 +27,7 @@ object NostrUserProfileDataSource: NostrDataSource<Note>("UserProfileFeed") {
return JsonFilter(
kinds = listOf(TextNoteEvent.kind),
authors = listOf(user!!.pubkeyHex),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 4)
limit = 100
)
}
@ -43,7 +43,7 @@ object NostrUserProfileDataSource: NostrDataSource<Note>("UserProfileFeed") {
}
override fun updateChannelFilters() {
userInfoChannel.filter = createUserInfoFilter()
notesChannel.filter = createUserPostsFilter()
userInfoChannel.filter = listOf(createUserInfoFilter()).ifEmpty { null }
notesChannel.filter = listOf(createUserPostsFilter()).ifEmpty { null }
}
}

View File

@ -15,8 +15,7 @@ object NostrUserProfileFollowersDataSource: NostrDataSource<User>("UserProfileFo
fun createFollowersFilter() = JsonFilter(
kinds = listOf(ContactListEvent.kind),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 7), // 7 days
tags = mapOf("p" to listOf(user!!.pubkeyHex).filterNotNull())
tags = mapOf("p" to listOf(user!!.pubkeyHex))
)
val followerChannel = requestNewChannel()
@ -30,6 +29,6 @@ object NostrUserProfileFollowersDataSource: NostrDataSource<User>("UserProfileFo
}
override fun updateChannelFilters() {
followerChannel.filter = createFollowersFilter()
followerChannel.filter = listOf(createFollowersFilter()).ifEmpty { null }
}
}

View File

@ -17,7 +17,7 @@ object NostrUserProfileFollowsDataSource: NostrDataSource<User>("UserProfileFoll
return JsonFilter(
kinds = listOf(ContactListEvent.kind),
authors = listOf(user!!.pubkeyHex),
since = System.currentTimeMillis() / 1000 - (60 * 60 * 24 * 7), // 4 days
limit = 1
)
}
@ -28,6 +28,6 @@ object NostrUserProfileFollowsDataSource: NostrDataSource<User>("UserProfileFoll
}
override fun updateChannelFilters() {
followChannel.filter = createFollowFilter()
followChannel.filter = listOf(createFollowFilter()).ifEmpty { null }
}
}

View File

@ -31,6 +31,19 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import coil.compose.AsyncImage
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.NostrAccountDataSource
import com.vitorpamplona.amethyst.service.NostrChannelDataSource
import com.vitorpamplona.amethyst.service.NostrChatRoomDataSource
import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource
import com.vitorpamplona.amethyst.service.NostrGlobalDataSource
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
import com.vitorpamplona.amethyst.service.NostrNotificationDataSource
import com.vitorpamplona.amethyst.service.NostrSingleEventDataSource
import com.vitorpamplona.amethyst.service.NostrSingleUserDataSource
import com.vitorpamplona.amethyst.service.NostrThreadDataSource
import com.vitorpamplona.amethyst.service.NostrUserProfileDataSource
import com.vitorpamplona.amethyst.service.NostrUserProfileFollowersDataSource
import com.vitorpamplona.amethyst.service.NostrUserProfileFollowsDataSource
import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.amethyst.ui.screen.RelayPoolViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@ -71,6 +84,23 @@ fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel)
Client.allSubscriptions().map { "${it} ${Client.getSubscriptionFilters(it).joinToString { it.toJson() }}" }.forEach {
Log.d("CURRENT FILTERS", it)
}
NostrAccountDataSource.printCounter()
NostrChannelDataSource.printCounter()
NostrChatRoomDataSource.printCounter()
NostrChatroomListDataSource.printCounter()
NostrGlobalDataSource.printCounter()
NostrHomeDataSource.printCounter()
NostrNotificationDataSource.printCounter()
NostrSingleEventDataSource.printCounter()
NostrSingleUserDataSource.printCounter()
NostrThreadDataSource.printCounter()
NostrUserProfileDataSource.printCounter()
NostrUserProfileFollowersDataSource.printCounter()
NostrUserProfileFollowsDataSource.printCounter()
}
) {
Icon(

View File

@ -107,13 +107,7 @@ fun NoteCompose(baseNote: Note, modifier: Modifier = Modifier, isInnerNote: Bool
}
}
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)
.clickable(onClick = {
note.let {
navController.navigate("Note/${note.idHex}")
}
})
) {
Column(modifier = Modifier.padding(start = if (!isInnerNote) 10.dp else 0.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
if (author != null)
UserDisplay(author)

View File

@ -6,12 +6,14 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import java.lang.System.currentTimeMillis
@Composable
fun HomeScreen(accountViewModel: AccountViewModel, navController: NavController) {

View File

@ -293,7 +293,7 @@ private fun MessageButton(user: User, navController: NavController) {
painter = painterResource(R.drawable.ic_dm),
"Send a Direct Message",
modifier = Modifier.size(20.dp),
tint = Color.Unspecified
tint = Color.White
)
}
}