1. Fixes crash when opening the relay selection dialog

2. Fixes color and size of ping labels on relays
3. Removes delete button for connected relay view.
This commit is contained in:
Vitor Pamplona
2025-07-08 10:20:54 -04:00
parent 1b86c3d85b
commit a05b2681ad
10 changed files with 105 additions and 46 deletions
@@ -61,7 +61,6 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
import com.vitorpamplona.quartz.nip11RelayInfo.Nip11RelayInformation
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import kotlin.collections.map import kotlin.collections.map
@@ -71,11 +70,6 @@ data class RelayList(
val isSelected: Boolean, val isSelected: Boolean,
) )
data class RelayInfoDialog(
val relay: NormalizedRelayUrl,
val relayInfo: Nip11RelayInformation,
)
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun RelaySelectionDialog( fun RelaySelectionDialog(
@@ -156,7 +150,7 @@ fun RelaySelectionDialog(
) { ) {
itemsIndexed( itemsIndexed(
relays, relays,
key = { _, item -> item.relay }, key = { _, item -> item.relay.url },
) { index, item -> ) { index, item ->
RenderRelaySwitch( RenderRelaySwitch(
item, item,
@@ -89,7 +89,7 @@ import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.amethyst.ui.theme.LightRedColor
import com.vitorpamplona.amethyst.ui.theme.isLight import com.vitorpamplona.amethyst.ui.theme.isLight
import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
@@ -480,7 +480,7 @@ private fun BlockAlertDialog(
buttonText = stringRes(R.string.quick_action_block_dialog_btn), buttonText = stringRes(R.string.quick_action_block_dialog_btn),
buttonColors = buttonColors =
ButtonDefaults.buttonColors( ButtonDefaults.buttonColors(
containerColor = WarningColor, containerColor = LightRedColor,
contentColor = Color.White, contentColor = Color.White,
), ),
onClickDoOnce = { onClickDoOnce = {
@@ -26,6 +26,7 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@@ -42,11 +43,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
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 androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.FeatureSetType
@@ -59,15 +61,19 @@ 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.screen.loggedIn.relays.RelayInformationDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.RelayInformationDialog
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.LargeRelayIconModifier
import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter import com.vitorpamplona.amethyst.ui.theme.RelayIconFilter
import com.vitorpamplona.amethyst.ui.theme.Size15Modifier import com.vitorpamplona.amethyst.ui.theme.Size15Modifier
import com.vitorpamplona.amethyst.ui.theme.Size17dp import com.vitorpamplona.amethyst.ui.theme.Size17dp
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.theme.allGoodColor
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.amethyst.ui.theme.redColorOnSecondSurface
import com.vitorpamplona.amethyst.ui.theme.relayIconModifier import com.vitorpamplona.amethyst.ui.theme.relayIconModifier
import com.vitorpamplona.amethyst.ui.theme.ripple24dp import com.vitorpamplona.amethyst.ui.theme.ripple24dp
import com.vitorpamplona.amethyst.ui.theme.warningColorOnSecondSurface
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
@Composable @Composable
public fun RelayBadgesHorizontal( public fun RelayBadgesHorizontal(
@@ -191,6 +197,39 @@ fun RenderRelay(
} }
} }
@Preview
@Composable
fun RenderRelayIconPreview() {
ThemeComparisonColumn {
Row {
RenderRelayIcon(
displayUrl = "wss://relay.damus.io",
iconUrl = "wss://relay.damus.io",
loadProfilePicture = true,
pingInMs = 100,
loadRobohash = true,
iconModifier = LargeRelayIconModifier,
)
RenderRelayIcon(
displayUrl = "wss://relay.damus.io",
iconUrl = "wss://relay.damus.io",
loadProfilePicture = true,
pingInMs = 300,
loadRobohash = true,
iconModifier = LargeRelayIconModifier,
)
RenderRelayIcon(
displayUrl = "wss://relay.damus.io",
iconUrl = "wss://relay.damus.io",
loadProfilePicture = true,
pingInMs = 500,
loadRobohash = true,
iconModifier = LargeRelayIconModifier,
)
}
}
}
@Composable @Composable
fun RenderRelayIcon( fun RenderRelayIcon(
displayUrl: String, displayUrl: String,
@@ -200,6 +239,9 @@ fun RenderRelayIcon(
pingInMs: Long, pingInMs: Long,
iconModifier: Modifier = MaterialTheme.colorScheme.relayIconModifier, iconModifier: Modifier = MaterialTheme.colorScheme.relayIconModifier,
) { ) {
val green = MaterialTheme.colorScheme.allGoodColor
val yellow = MaterialTheme.colorScheme.warningColorOnSecondSurface
val red = MaterialTheme.colorScheme.redColorOnSecondSurface
Box( Box(
contentAlignment = Alignment.TopEnd, contentAlignment = Alignment.TopEnd,
) { ) {
@@ -212,29 +254,35 @@ fun RenderRelayIcon(
loadProfilePicture = loadProfilePicture, loadProfilePicture = loadProfilePicture,
loadRobohash = loadRobohash, loadRobohash = loadRobohash,
) )
val textStyle =
remember(pingInMs) {
TextStyle(
color =
if (pingInMs <= 150) {
green
} else if (pingInMs <= 300) {
yellow
} else {
red
},
)
}
if (pingInMs > 0) { if (pingInMs > 0) {
Box( Box(
modifier = modifier =
Modifier Modifier
.clip(RoundedCornerShape(8.dp)) .clip(RoundedCornerShape(6.dp))
.background( .background(
Color.Gray, MaterialTheme.colorScheme.secondaryContainer,
), ),
) { ) {
Text( Text(
modifier = Modifier.padding(4.dp), modifier = Modifier.padding(3.dp),
style = style = textStyle,
TextStyle(
color =
if (pingInMs <= 150) {
Color.Green
} else if (pingInMs <= 300) {
Color.Yellow
} else {
Color.Red
},
),
text = "$pingInMs", text = "$pingInMs",
fontSize = 10.sp,
) )
} }
} }
@@ -20,6 +20,7 @@
*/ */
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
import android.R.attr.onClick
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.Column import androidx.compose.foundation.layout.Column
@@ -50,7 +51,7 @@ fun BasicRelaySetupInfoClickableRow(
item: BasicRelaySetupInfo, item: BasicRelaySetupInfo,
loadProfilePicture: Boolean, loadProfilePicture: Boolean,
loadRobohash: Boolean, loadRobohash: Boolean,
onDelete: (BasicRelaySetupInfo) -> Unit, onDelete: ((BasicRelaySetupInfo) -> Unit)?,
onClick: () -> Unit, onClick: () -> Unit,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
) { ) {
@@ -29,6 +29,7 @@ import androidx.compose.ui.platform.LocalContext
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.FeatureSetType import com.vitorpamplona.amethyst.model.FeatureSetType
import com.vitorpamplona.amethyst.service.Nip11Retriever import com.vitorpamplona.amethyst.service.Nip11Retriever
import com.vitorpamplona.amethyst.ui.navigation.EmptyNav.nav
import com.vitorpamplona.amethyst.ui.navigation.INav import com.vitorpamplona.amethyst.ui.navigation.INav
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
@@ -38,7 +39,7 @@ import com.vitorpamplona.amethyst.ui.stringRes
@Composable @Composable
fun BasicRelaySetupInfoDialog( fun BasicRelaySetupInfoDialog(
item: BasicRelaySetupInfo, item: BasicRelaySetupInfo,
onDelete: (BasicRelaySetupInfo) -> Unit, onDelete: ((BasicRelaySetupInfo) -> Unit)?,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
) { ) {
@@ -42,7 +42,7 @@ import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.painterRes import com.vitorpamplona.amethyst.ui.painterRes
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.WarningColor import com.vitorpamplona.amethyst.ui.theme.LightRedColor
import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.allGoodColor
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
@@ -51,7 +51,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.normalizer.displayUrl
fun RelayNameAndRemoveButton( fun RelayNameAndRemoveButton(
item: BasicRelaySetupInfo, item: BasicRelaySetupInfo,
onClick: () -> Unit, onClick: () -> Unit,
onDelete: (BasicRelaySetupInfo) -> Unit, onDelete: ((BasicRelaySetupInfo) -> Unit)?,
modifier: Modifier, modifier: Modifier,
) { ) {
val clipboardManager = LocalClipboardManager.current val clipboardManager = LocalClipboardManager.current
@@ -95,6 +95,7 @@ fun RelayNameAndRemoveButton(
} }
} }
if (onDelete != null) {
IconButton( IconButton(
modifier = Modifier.size(30.dp), modifier = Modifier.size(30.dp),
onClick = { onDelete(item) }, onClick = { onDelete(item) },
@@ -106,8 +107,9 @@ fun RelayNameAndRemoveButton(
Modifier Modifier
.padding(start = 10.dp) .padding(start = 10.dp)
.size(15.dp), .size(15.dp),
tint = WarningColor, tint = LightRedColor,
) )
} }
} }
}
} }
@@ -63,7 +63,7 @@ fun LazyListScope.renderConnectedItems(
itemsIndexed(feedState, key = { _, item -> "Connected" + item.relay }) { index, item -> itemsIndexed(feedState, key = { _, item -> "Connected" + item.relay }) { index, item ->
BasicRelaySetupInfoDialog( BasicRelaySetupInfoDialog(
item, item,
onDelete = { }, onDelete = null,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
nav, nav,
) )
@@ -66,7 +66,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer
import com.vitorpamplona.amethyst.ui.stringRes 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.WarningColor import com.vitorpamplona.amethyst.ui.theme.LightRedColor
import com.vitorpamplona.quartz.nip56Reports.ReportType import com.vitorpamplona.quartz.nip56Reports.ReportType
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@@ -195,7 +195,7 @@ private fun ActionButton(
) = Button( ) = Button(
onClick = onClick, onClick = onClick,
enabled = enabled, enabled = enabled,
colors = ButtonDefaults.buttonColors(containerColor = WarningColor), colors = ButtonDefaults.buttonColors(containerColor = LightRedColor),
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { ) {
Row( Row(
@@ -52,13 +52,20 @@ val Nip05EmailColorLight = Color(0xFFa770f3)
val DarkerGreen = Color.Green.copy(alpha = 0.32f) val DarkerGreen = Color.Green.copy(alpha = 0.32f)
val WarningColor = Color(0xFFC62828) val LightRedColor = Color(0xFFC62828)
val LighterRedColor = Color(0xFFFF0E0E)
val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) }) val RelayIconFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0.5f) })
val LightWarningColor = Color(0xFFffcc00) val LightWarningColor = Color(0xFFffcc00)
val DarkWarningColor = Color(0xFFF8DE22) val DarkWarningColor = Color(0xFFF8DE22)
val LightRedColorOnSecondSurface = Color(0xFFC62828)
val DarkRedColorOnSecondSurface = Color(0xFFF34747)
val LightWarningColorOnSecondSurface = Color(0xFFC09B14)
val DarkWarningColorOnSecondSurface = Color(0xFFE1C419)
val LightAllGoodColor = Color(0xFF339900) val LightAllGoodColor = Color(0xFF339900)
val DarkAllGoodColor = Color(0xFF99cc33) val DarkAllGoodColor = Color(0xFF99cc33)
@@ -391,9 +391,15 @@ val ColorScheme.overPictureBackground: Color
val ColorScheme.bitcoinColor: Color val ColorScheme.bitcoinColor: Color
get() = if (isLight) BitcoinLight else BitcoinDark get() = if (isLight) BitcoinLight else BitcoinDark
val ColorScheme.redColorOnSecondSurface: Color
get() = if (isLight) LightRedColorOnSecondSurface else DarkRedColorOnSecondSurface
val ColorScheme.warningColor: Color val ColorScheme.warningColor: Color
get() = if (isLight) LightWarningColor else DarkWarningColor get() = if (isLight) LightWarningColor else DarkWarningColor
val ColorScheme.warningColorOnSecondSurface: Color
get() = if (isLight) LightWarningColorOnSecondSurface else DarkWarningColorOnSecondSurface
val ColorScheme.allGoodColor: Color val ColorScheme.allGoodColor: Color
get() = if (isLight) LightAllGoodColor else DarkAllGoodColor get() = if (isLight) LightAllGoodColor else DarkAllGoodColor