mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-09 22:22:30 +02:00
Adds a user list to each connected relay to know where this is coming from
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStat
|
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStat
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
|
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
@@ -31,6 +32,7 @@ data class BasicRelaySetupInfo(
|
|||||||
val relayStat: RelayStat,
|
val relayStat: RelayStat,
|
||||||
val paidRelay: Boolean = false,
|
val paidRelay: Boolean = false,
|
||||||
val forcesTor: Boolean = false,
|
val forcesTor: Boolean = false,
|
||||||
|
val users: List<User> = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun relaySetupInfoBuilder(
|
fun relaySetupInfoBuilder(
|
||||||
|
@@ -22,26 +22,37 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
|
|||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalClipboardManager
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache.users
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.nav
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon
|
import com.vitorpamplona.amethyst.ui.note.RenderRelayIcon
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.UserPicture
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.header.loadRelayInfo
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.publicChannels.ephemChat.header.loadRelayInfo
|
||||||
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfHorzPadding
|
import com.vitorpamplona.amethyst.ui.theme.HalfHorzPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding
|
import com.vitorpamplona.amethyst.ui.theme.HalfStartPadding
|
||||||
import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding
|
import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Height25Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.LargeRelayIconModifier
|
import com.vitorpamplona.amethyst.ui.theme.LargeRelayIconModifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeightChatMaxWidth
|
import com.vitorpamplona.amethyst.ui.theme.ReactionRowHeightChatMaxWidth
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.Size25dp
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@@ -53,6 +64,7 @@ fun BasicRelaySetupInfoClickableRow(
|
|||||||
onDelete: ((BasicRelaySetupInfo) -> Unit)?,
|
onDelete: ((BasicRelaySetupInfo) -> Unit)?,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: INav,
|
||||||
) {
|
) {
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
Column(
|
Column(
|
||||||
@@ -90,6 +102,8 @@ fun BasicRelaySetupInfoClickableRow(
|
|||||||
ReactionRowHeightChatMaxWidth,
|
ReactionRowHeightChatMaxWidth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
UsedBy(item, accountViewModel, nav)
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = ReactionRowHeightChatMaxWidth,
|
modifier = ReactionRowHeightChatMaxWidth,
|
||||||
@@ -106,3 +120,56 @@ fun BasicRelaySetupInfoClickableRow(
|
|||||||
HorizontalDivider(thickness = DividerThickness)
|
HorizontalDivider(thickness = DividerThickness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
@Composable
|
||||||
|
fun UsedBy(
|
||||||
|
item: BasicRelaySetupInfo,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: INav,
|
||||||
|
) {
|
||||||
|
if (item.users.isNotEmpty()) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
item.users.getOrNull(0)?.let {
|
||||||
|
UserPicture(
|
||||||
|
user = it,
|
||||||
|
size = Size25dp,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item.users.getOrNull(1)?.let {
|
||||||
|
UserPicture(
|
||||||
|
user = it,
|
||||||
|
size = Size25dp,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item.users.getOrNull(2)?.let {
|
||||||
|
UserPicture(
|
||||||
|
user = it,
|
||||||
|
size = Size25dp,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item.users.getOrNull(3)?.let {
|
||||||
|
UserPicture(
|
||||||
|
user = it,
|
||||||
|
size = Size25dp,
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = nav,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (item.users.size > 4) {
|
||||||
|
Box(contentAlignment = Alignment.Center, modifier = Height25Modifier) {
|
||||||
|
Text(
|
||||||
|
text = stringRes(R.string.and_more, item.users.size - 4),
|
||||||
|
maxLines = 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -44,5 +44,6 @@ fun BasicRelaySetupInfoDialog(
|
|||||||
onDelete = onDelete,
|
onDelete = onDelete,
|
||||||
accountViewModel = accountViewModel,
|
accountViewModel = accountViewModel,
|
||||||
onClick = { nav.nav(Route.RelayInfo(item.relay.url)) },
|
onClick = { nav.nav(Route.RelayInfo(item.relay.url)) },
|
||||||
|
nav = nav,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -83,11 +83,10 @@ abstract class BasicRelaySetupInfoModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
open fun relayListBuilder(): List<BasicRelaySetupInfo> {
|
||||||
_relays.update {
|
|
||||||
val relayList = getRelayList() ?: emptyList()
|
val relayList = getRelayList() ?: emptyList()
|
||||||
|
|
||||||
relayList
|
return relayList
|
||||||
.map {
|
.map {
|
||||||
relaySetupInfoBuilder(
|
relaySetupInfoBuilder(
|
||||||
normalized = it,
|
normalized = it,
|
||||||
@@ -99,6 +98,9 @@ abstract class BasicRelaySetupInfoModel : ViewModel() {
|
|||||||
.sortedBy { it.relayStat.receivedBytes }
|
.sortedBy { it.relayStat.receivedBytes }
|
||||||
.reversed()
|
.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
_relays.update { relayListBuilder() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addRelay(relay: BasicRelaySetupInfo) {
|
fun addRelay(relay: BasicRelaySetupInfo) {
|
||||||
|
@@ -20,10 +20,34 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected
|
||||||
|
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoModel
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.stats.RelayStats
|
||||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
|
||||||
class ConnectedRelayListViewModel : BasicRelaySetupInfoModel() {
|
class ConnectedRelayListViewModel : BasicRelaySetupInfoModel() {
|
||||||
|
override fun relayListBuilder(): List<BasicRelaySetupInfo> {
|
||||||
|
val relayList = getRelayList()
|
||||||
|
|
||||||
|
return relayList
|
||||||
|
.map {
|
||||||
|
BasicRelaySetupInfo(
|
||||||
|
relay = it,
|
||||||
|
relayStat = RelayStats.get(it),
|
||||||
|
forcesTor =
|
||||||
|
account.torRelayState.flow.value
|
||||||
|
.useTor(it),
|
||||||
|
users =
|
||||||
|
account.followsPerRelay.value[it]?.mapNotNull { hex ->
|
||||||
|
LocalCache.checkGetOrCreateUser(hex)
|
||||||
|
} ?: emptyList(),
|
||||||
|
)
|
||||||
|
}.distinctBy { it.relay }
|
||||||
|
.sortedBy { it.relayStat.receivedBytes }
|
||||||
|
.reversed()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getRelayList(): List<NormalizedRelayUrl> =
|
override fun getRelayList(): List<NormalizedRelayUrl> =
|
||||||
account.client
|
account.client
|
||||||
.relayStatusFlow()
|
.relayStatusFlow()
|
||||||
|
@@ -189,6 +189,7 @@ val UserNameMaxRowHeight = Modifier.fillMaxWidth()
|
|||||||
|
|
||||||
val Height24dpModifier = Modifier.height(24.dp)
|
val Height24dpModifier = Modifier.height(24.dp)
|
||||||
val Height4dpModifier = Modifier.height(4.dp)
|
val Height4dpModifier = Modifier.height(4.dp)
|
||||||
|
val Height25Modifier = Modifier.height(Size25dp)
|
||||||
|
|
||||||
val Height24dpFilledModifier = Modifier.fillMaxWidth().height(24.dp)
|
val Height24dpFilledModifier = Modifier.fillMaxWidth().height(24.dp)
|
||||||
val Height4dpFilledModifier = Modifier.fillMaxWidth().height(4.dp)
|
val Height4dpFilledModifier = Modifier.fillMaxWidth().height(4.dp)
|
||||||
|
Reference in New Issue
Block a user