Vitor Pamplona
2023-02-01 10:52:54 -03:00
parent 4b894c5b33
commit 663eb9c604
4 changed files with 55 additions and 29 deletions

View File

@ -41,7 +41,7 @@ class User(val pubkeyHex: String) {
val messages = ConcurrentHashMap<User, MutableSet<Note>>() val messages = ConcurrentHashMap<User, MutableSet<Note>>()
val reports = Collections.synchronizedSet(mutableSetOf<Note>()) val reports = Collections.synchronizedSet(mutableSetOf<Note>())
val relaysBeingUsed = mutableMapOf<String, RelayInfo>() val relaysBeingUsed = Collections.synchronizedMap(mutableMapOf<String, RelayInfo>())
fun toBestDisplayName(): String { fun toBestDisplayName(): String {
return bestDisplayName() ?: bestUsername() ?: pubkeyDisplayHex return bestDisplayName() ?: bestUsername() ?: pubkeyDisplayHex
@ -191,6 +191,18 @@ class User(val pubkeyHex: String) {
} }
} }
fun getRelayKeysBeingUsed(): Set<String> {
return synchronized(relaysBeingUsed) {
relaysBeingUsed.keys.toSet()
}
}
fun getRelayValuesBeingUsed(): List<RelayInfo> {
return synchronized(relaysBeingUsed) {
relaysBeingUsed.values.toList()
}
}
fun hasSentMessagesTo(user: User?): Boolean { fun hasSentMessagesTo(user: User?): Boolean {
val messagesToUser = messages[user] ?: return false val messagesToUser = messages[user] ?: return false

View File

@ -65,7 +65,7 @@ fun RelayCompose(
} }
Text( Text(
"${relay.counter} events received", "${relay.counter} posts received",
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f), color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
@ -73,12 +73,10 @@ fun RelayCompose(
} }
Column(modifier = Modifier.padding(start = 10.dp)) { 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() } AddRelayButton { onAddRelay() }
} else { } else {
RemoveRelayButton { RemoveRelayButton { onRemoveRelay() }
onRemoveRelay()
}
} }
} }
} }

View File

@ -23,12 +23,14 @@ import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.actions.NewRelayListView import com.vitorpamplona.amethyst.ui.actions.NewRelayListView
import com.vitorpamplona.amethyst.ui.note.RelayCompose import com.vitorpamplona.amethyst.ui.note.RelayCompose
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class RelayFeedViewModel: ViewModel() { class RelayFeedViewModel: ViewModel() {
val order = compareByDescending<User.RelayInfo> { it.lastEvent }.thenByDescending { it.counter }.thenBy { it.url } val order = compareByDescending<User.RelayInfo> { it.lastEvent }.thenByDescending { it.counter }.thenBy { it.url }
@ -39,29 +41,27 @@ class RelayFeedViewModel: ViewModel() {
var currentUser: User? = null var currentUser: User? = null
fun refresh() { fun refresh() {
val beingUsed = currentUser?.relaysBeingUsed?.values?.toList() ?: emptyList() viewModelScope.launch(Dispatchers.Default) {
val beingUsedSet = currentUser?.relaysBeingUsed?.keys ?: emptySet() val beingUsed = currentUser?.getRelayValuesBeingUsed() ?: emptyList()
val beingUsedSet = currentUser?.getRelayKeysBeingUsed() ?: emptySet()
val newRelaysFromRecord = currentUser?.relays?.entries?.mapNotNull { val newRelaysFromRecord = currentUser?.relays?.entries?.mapNotNull {
if (it.key !in beingUsedSet) { if (it.key !in beingUsedSet) {
User.RelayInfo(it.key, 0, 0) User.RelayInfo(it.key, 0, 0)
} else { } else {
null null
} }
} ?: emptyList() } ?: emptyList()
val newList = (beingUsed + newRelaysFromRecord).sortedWith(order) val newList = (beingUsed + newRelaysFromRecord).sortedWith(order)
viewModelScope.launch { _feedContent.update { newList }
withContext(Dispatchers.Main) {
_feedContent.update { newList }
}
} }
} }
inner class CacheListener: User.Listener() { inner class CacheListener: User.Listener() {
override fun onNewRelayInfo() { refresh() } override fun onNewRelayInfo() { invalidateData() }
override fun onRelayChange() { refresh() } override fun onRelayChange() { invalidateData() }
} }
val listener = CacheListener() val listener = CacheListener()
@ -69,13 +69,31 @@ class RelayFeedViewModel: ViewModel() {
fun subscribeTo(user: User) { fun subscribeTo(user: User) {
currentUser = user currentUser = user
user.subscribe(listener) user.subscribe(listener)
refresh() invalidateData()
} }
fun unsubscribeTo(user: User) { fun unsubscribeTo(user: User) {
user.unsubscribe(listener) user.unsubscribe(listener)
currentUser = null 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 @Composable

View File

@ -39,6 +39,7 @@ import androidx.compose.material.icons.filled.Password
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -170,7 +171,7 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
0 -> TabNotes(user, accountViewModel, navController) 0 -> TabNotes(user, accountViewModel, navController)
1 -> TabFollows(user, accountViewModel, navController) 1 -> TabFollows(user, accountViewModel, navController)
2 -> TabFollowers(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) { fun TabRelays(user: User, accountViewModel: AccountViewModel, navController: NavController) {
val feedViewModel: RelayFeedViewModel = viewModel() val feedViewModel: RelayFeedViewModel = viewModel()
DisposableEffect(key1 = user) { LaunchedEffect(key1 = user) {
feedViewModel.subscribeTo(user) feedViewModel.subscribeTo(user)
onDispose {
feedViewModel.unsubscribeTo(user)
}
} }
Column(Modifier.fillMaxHeight()) { Column(Modifier.fillMaxHeight()) {