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 reports = Collections.synchronizedSet(mutableSetOf<Note>())
val relaysBeingUsed = mutableMapOf<String, RelayInfo>()
val relaysBeingUsed = Collections.synchronizedMap(mutableMapOf<String, RelayInfo>())
fun toBestDisplayName(): String {
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 {
val messagesToUser = messages[user] ?: return false

View File

@ -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() }
}
}
}

View File

@ -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<User.RelayInfo> { 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

View File

@ -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()) {