From 663eb9c60491f0a3789e50e592bdb1fef2bd5ff0 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 1 Feb 2023 10:52:54 -0300 Subject: [PATCH] Solves https://github.com/vitorpamplona/amethyst/issues/58 --- .../com/vitorpamplona/amethyst/model/User.kt | 14 ++++- .../amethyst/ui/note/RelayCompose.kt | 8 ++- .../amethyst/ui/screen/RelayFeedView.kt | 54 ++++++++++++------- .../ui/screen/loggedIn/ProfileScreen.kt | 8 ++- 4 files changed, 55 insertions(+), 29 deletions(-) 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 278c5a70d..37ab1e984 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/User.kt @@ -41,7 +41,7 @@ class User(val pubkeyHex: String) { val messages = ConcurrentHashMap>() val reports = Collections.synchronizedSet(mutableSetOf()) - val relaysBeingUsed = mutableMapOf() + val relaysBeingUsed = Collections.synchronizedMap(mutableMapOf()) fun toBestDisplayName(): String { return bestDisplayName() ?: bestUsername() ?: pubkeyDisplayHex @@ -191,6 +191,18 @@ class User(val pubkeyHex: String) { } } + fun getRelayKeysBeingUsed(): Set { + return synchronized(relaysBeingUsed) { + relaysBeingUsed.keys.toSet() + } + } + + fun getRelayValuesBeingUsed(): List { + return synchronized(relaysBeingUsed) { + relaysBeingUsed.values.toList() + } + } + fun hasSentMessagesTo(user: User?): Boolean { val messagesToUser = messages[user] ?: return false diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt index d84a81d56..2361e53e4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/RelayCompose.kt @@ -65,7 +65,7 @@ fun RelayCompose( } Text( - "${relay.counter} events received", + "${relay.counter} posts received", color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), maxLines = 1, overflow = TextOverflow.Ellipsis @@ -73,12 +73,10 @@ fun RelayCompose( } Column(modifier = Modifier.padding(start = 10.dp)) { - if (account.activeRelays()?.filter { it.url == relay.url }?.isEmpty() == true) { + if (account.activeRelays()?.none { it.url == relay.url } == true) { AddRelayButton { onAddRelay() } } else { - RemoveRelayButton { - onRemoveRelay() - } + RemoveRelayButton { onRemoveRelay() } } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt index 0cd15945f..39223bf6d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/RelayFeedView.kt @@ -23,12 +23,14 @@ import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.note.RelayCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class RelayFeedViewModel: ViewModel() { val order = compareByDescending { it.lastEvent }.thenByDescending { it.counter }.thenBy { it.url } @@ -39,29 +41,27 @@ class RelayFeedViewModel: ViewModel() { var currentUser: User? = null fun refresh() { - val beingUsed = currentUser?.relaysBeingUsed?.values?.toList() ?: emptyList() - val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet() + viewModelScope.launch(Dispatchers.Default) { + val beingUsed = currentUser?.getRelayValuesBeingUsed() ?: emptyList() + val beingUsedSet = currentUser?.getRelayKeysBeingUsed() ?: emptySet() - val newRelaysFromRecord = currentUser?.relays?.entries?.mapNotNull { - if (it.key !in beingUsedSet) { - User.RelayInfo(it.key, 0, 0) - } else { - null - } - } ?: emptyList() + val newRelaysFromRecord = currentUser?.relays?.entries?.mapNotNull { + if (it.key !in beingUsedSet) { + User.RelayInfo(it.key, 0, 0) + } else { + null + } + } ?: emptyList() - val newList = (beingUsed + newRelaysFromRecord).sortedWith(order) + val newList = (beingUsed + newRelaysFromRecord).sortedWith(order) - viewModelScope.launch { - withContext(Dispatchers.Main) { - _feedContent.update { newList } - } + _feedContent.update { newList } } } inner class CacheListener: User.Listener() { - override fun onNewRelayInfo() { refresh() } - override fun onRelayChange() { refresh() } + override fun onNewRelayInfo() { invalidateData() } + override fun onRelayChange() { invalidateData() } } val listener = CacheListener() @@ -69,13 +69,31 @@ class RelayFeedViewModel: ViewModel() { fun subscribeTo(user: User) { currentUser = user user.subscribe(listener) - refresh() + invalidateData() } fun unsubscribeTo(user: User) { user.unsubscribe(listener) currentUser = null } + + override fun onCleared() { + currentUser?.let { unsubscribeTo(it) } + } + + var handlerWaiting = false + @Synchronized + fun invalidateData() { + if (handlerWaiting) return + + handlerWaiting = true + val scope = CoroutineScope(Job() + Dispatchers.Default) + scope.launch { + delay(100) + refresh() + handlerWaiting = false + } + } } @Composable diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 6f6746847..41835c706 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -39,6 +39,7 @@ import androidx.compose.material.icons.filled.Password import androidx.compose.material.icons.filled.Share import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf @@ -170,7 +171,7 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro 0 -> TabNotes(user, accountViewModel, navController) 1 -> TabFollows(user, accountViewModel, navController) 2 -> TabFollowers(user, accountViewModel, navController) - 3 -> TabRelays(user, accountViewModel, navController) + 3 -> TabRelays(baseUser, accountViewModel, navController) } } } @@ -358,11 +359,8 @@ fun TabFollowers(user: User, accountViewModel: AccountViewModel, navController: fun TabRelays(user: User, accountViewModel: AccountViewModel, navController: NavController) { val feedViewModel: RelayFeedViewModel = viewModel() - DisposableEffect(key1 = user) { + LaunchedEffect(key1 = user) { feedViewModel.subscribeTo(user) - onDispose { - feedViewModel.unsubscribeTo(user) - } } Column(Modifier.fillMaxHeight()) {