refactor(ui): remove LOCAL tab and feed relay-picker entry
RelayScreen drops the LOCAL tab and its LocalRelayTab composable. FeedScreen's RelayPickerDialog no longer surfaces a "My Local Relay" row, and its localRelayUrl parameter is removed.
This commit is contained in:
@@ -34,7 +34,6 @@ import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material3.AlertDialog
|
||||
@@ -292,7 +291,6 @@ fun FeedScreen(
|
||||
val newNotesButtonHidden by viewModel.newNotesButtonHidden.collectAsState()
|
||||
val initLoadingState by viewModel.initLoadingState.collectAsState()
|
||||
val relayFeedStatus by viewModel.relayFeedStatus.collectAsState()
|
||||
val localRelayConfig by viewModel.keyRepo.localRelayFlow.collectAsState()
|
||||
val pendingFirstFollow by viewModel.pendingFirstFollow.collectAsState()
|
||||
val firstFollowCheckDone by viewModel.firstFollowCheckDone.collectAsState()
|
||||
val zapInProgress by viewModel.zapInProgress.collectAsState()
|
||||
@@ -466,7 +464,6 @@ fun FeedScreen(
|
||||
favoriteRelays = favoriteRelays,
|
||||
relaySets = ownRelaySets,
|
||||
relayInfoRepo = viewModel.relayInfoRepo,
|
||||
localRelayUrl = localRelayConfig?.let { if (it.enabled) it.url else null },
|
||||
onSelect = { url ->
|
||||
viewModel.setSelectedRelay(url)
|
||||
viewModel.setFeedType(FeedType.RELAY)
|
||||
@@ -1670,7 +1667,6 @@ private fun RelayPickerDialog(
|
||||
favoriteRelays: List<String>,
|
||||
relaySets: List<RelaySet>,
|
||||
relayInfoRepo: RelayInfoRepository,
|
||||
localRelayUrl: String? = null,
|
||||
onSelect: (String) -> Unit,
|
||||
onSelectRelaySet: (RelaySet) -> Unit,
|
||||
onCreateRelaySet: (String) -> Unit,
|
||||
@@ -1751,44 +1747,6 @@ private fun RelayPickerDialog(
|
||||
Spacer(Modifier.size(12.dp))
|
||||
|
||||
LazyColumn(modifier = Modifier.heightIn(max = 400.dp)) {
|
||||
// Local relay — always first when configured
|
||||
if (localRelayUrl != null) {
|
||||
item(key = "local-relay") {
|
||||
Surface(
|
||||
onClick = { onSelect(localRelayUrl) },
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
Icons.Filled.Home,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Column {
|
||||
Text(
|
||||
stringResource(R.string.local_relay_my_relay),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
localRelayUrl.removePrefix("ws://").removePrefix("wss://").removeSuffix("/"),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Favorites section
|
||||
if (favoriteRelays.isNotEmpty()) {
|
||||
item {
|
||||
|
||||
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
@@ -23,35 +22,25 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import android.widget.Toast
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.wisp.app.relay.LocalRelayConfig
|
||||
import com.wisp.app.relay.LocalRelayWritePolicy
|
||||
import com.wisp.app.relay.RelayConfig
|
||||
import com.wisp.app.relay.RelayPool
|
||||
import com.wisp.app.relay.RelaySetType
|
||||
import com.wisp.app.R
|
||||
import com.wisp.app.ui.theme.wispSwitchColors
|
||||
import com.wisp.app.viewmodel.RelayViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -69,7 +58,6 @@ fun RelayScreen(
|
||||
val searchRelays by viewModel.searchRelays.collectAsState()
|
||||
val blockedRelays by viewModel.blockedRelays.collectAsState()
|
||||
val newRelayUrl by viewModel.newRelayUrl.collectAsState()
|
||||
val localRelayConfig by viewModel.localRelay.collectAsState()
|
||||
|
||||
val tabs = RelaySetType.entries
|
||||
|
||||
@@ -108,81 +96,53 @@ fun RelayScreen(
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
if (selectedTab == RelaySetType.LOCAL) {
|
||||
// Local tab: show URL input only when no relay is configured
|
||||
if (localRelayConfig == null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = newRelayUrl,
|
||||
onValueChange = { viewModel.updateNewRelayUrl(it) },
|
||||
label = { Text(stringResource(R.string.local_relay_url_hint)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = { viewModel.addRelay() }) {
|
||||
Icon(Icons.Default.Add, stringResource(R.string.cd_add_relay))
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = newRelayUrl,
|
||||
onValueChange = { viewModel.updateNewRelayUrl(it) },
|
||||
label = { Text(stringResource(R.string.placeholder_relay_url)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = { viewModel.addRelay() }) {
|
||||
Icon(Icons.Default.Add, stringResource(R.string.cd_add_relay))
|
||||
}
|
||||
}
|
||||
|
||||
LocalRelayTab(localRelayConfig, viewModel)
|
||||
} else {
|
||||
// Network relay tabs: URL input + broadcast
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
Spacer(Modifier.height(8.dp))
|
||||
|
||||
if (relayPool != null) {
|
||||
val buttonLabel = when (selectedTab) {
|
||||
RelaySetType.GENERAL -> stringResource(R.string.broadcast_nip65)
|
||||
RelaySetType.DM -> stringResource(R.string.broadcast_dm_relays)
|
||||
RelaySetType.SEARCH -> stringResource(R.string.broadcast_search_relays)
|
||||
RelaySetType.BLOCKED -> stringResource(R.string.broadcast_blocked_relays)
|
||||
}
|
||||
val successMsg = stringResource(R.string.error_relay_broadcast)
|
||||
val failureMsg = stringResource(R.string.error_broadcast_failed)
|
||||
Button(
|
||||
onClick = {
|
||||
val ok = viewModel.publishRelayList(relayPool, signer = signer)
|
||||
val msg = if (ok) successMsg else failureMsg
|
||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = newRelayUrl,
|
||||
onValueChange = { viewModel.updateNewRelayUrl(it) },
|
||||
label = { Text(stringResource(R.string.placeholder_relay_url)) },
|
||||
singleLine = true,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = { viewModel.addRelay() }) {
|
||||
Icon(Icons.Default.Add, stringResource(R.string.cd_add_relay))
|
||||
}
|
||||
Text(buttonLabel)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
if (relayPool != null) {
|
||||
val buttonLabel = when (selectedTab) {
|
||||
RelaySetType.GENERAL -> stringResource(R.string.broadcast_nip65)
|
||||
RelaySetType.DM -> stringResource(R.string.broadcast_dm_relays)
|
||||
RelaySetType.SEARCH -> stringResource(R.string.broadcast_search_relays)
|
||||
RelaySetType.BLOCKED -> stringResource(R.string.broadcast_blocked_relays)
|
||||
RelaySetType.LOCAL -> "" // unreachable
|
||||
}
|
||||
val successMsg = stringResource(R.string.error_relay_broadcast)
|
||||
val failureMsg = stringResource(R.string.error_broadcast_failed)
|
||||
Button(
|
||||
onClick = {
|
||||
val ok = viewModel.publishRelayList(relayPool, signer = signer)
|
||||
val msg = if (ok) successMsg else failureMsg
|
||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(buttonLabel)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
|
||||
when (selectedTab) {
|
||||
RelaySetType.GENERAL -> GeneralRelayList(relays, viewModel)
|
||||
RelaySetType.DM -> SimpleRelayList(dmRelays, viewModel)
|
||||
RelaySetType.SEARCH -> SimpleRelayList(searchRelays, viewModel)
|
||||
RelaySetType.BLOCKED -> SimpleRelayList(blockedRelays, viewModel)
|
||||
RelaySetType.LOCAL -> {} // handled above
|
||||
}
|
||||
when (selectedTab) {
|
||||
RelaySetType.GENERAL -> GeneralRelayList(relays, viewModel)
|
||||
RelaySetType.DM -> SimpleRelayList(dmRelays, viewModel)
|
||||
RelaySetType.SEARCH -> SimpleRelayList(searchRelays, viewModel)
|
||||
RelaySetType.BLOCKED -> SimpleRelayList(blockedRelays, viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,145 +195,6 @@ private fun GeneralRelayList(relays: List<RelayConfig>, viewModel: RelayViewMode
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LocalRelayTab(config: LocalRelayConfig?, viewModel: RelayViewModel) {
|
||||
if (config == null) return
|
||||
|
||||
Column {
|
||||
// URL + enabled toggle
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = config.url,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = config.enabled,
|
||||
onCheckedChange = { viewModel.toggleLocalRelayEnabled() },
|
||||
colors = wispSwitchColors()
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
// Write policy selector
|
||||
Text(
|
||||
text = stringResource(R.string.local_relay_write_policy),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
LocalRelayWritePolicy.entries.forEach { policy ->
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
RadioButton(
|
||||
selected = config.writePolicy == policy,
|
||||
onClick = { viewModel.updateLocalRelayPolicy(policy) }
|
||||
)
|
||||
Text(
|
||||
text = when (policy) {
|
||||
LocalRelayWritePolicy.OWN_NOTES -> stringResource(R.string.local_relay_own_notes)
|
||||
LocalRelayWritePolicy.TAGGED -> stringResource(R.string.local_relay_tagged)
|
||||
LocalRelayWritePolicy.ALL_NOTES -> stringResource(R.string.local_relay_all_notes)
|
||||
},
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(12.dp))
|
||||
|
||||
// Kind chips
|
||||
Text(
|
||||
text = stringResource(R.string.local_relay_kinds),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
FilterChip(
|
||||
selected = 1 in config.kinds,
|
||||
onClick = {
|
||||
val updated = if (1 in config.kinds) config.kinds - 1 else config.kinds + 1
|
||||
viewModel.updateLocalRelayKinds(updated)
|
||||
},
|
||||
label = { Text(stringResource(R.string.local_relay_kind_notes)) }
|
||||
)
|
||||
FilterChip(
|
||||
selected = 1059 in config.kinds,
|
||||
onClick = {
|
||||
val updated = if (1059 in config.kinds) config.kinds - 1059 else config.kinds + 1059
|
||||
viewModel.updateLocalRelayKinds(updated)
|
||||
},
|
||||
label = { Text(stringResource(R.string.local_relay_kind_dms)) }
|
||||
)
|
||||
FilterChip(
|
||||
selected = 9735 in config.kinds,
|
||||
onClick = {
|
||||
val updated = if (9735 in config.kinds) config.kinds - 9735 else config.kinds + 9735
|
||||
viewModel.updateLocalRelayKinds(updated)
|
||||
},
|
||||
label = { Text(stringResource(R.string.local_relay_kind_zaps)) }
|
||||
)
|
||||
}
|
||||
|
||||
// Custom kind input
|
||||
var customKindInput by remember { mutableStateOf("") }
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(top = 4.dp)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = customKindInput,
|
||||
onValueChange = { customKindInput = it.filter { c -> c.isDigit() } },
|
||||
label = { Text(stringResource(R.string.local_relay_add_kind)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = {
|
||||
val kind = customKindInput.toIntOrNull()
|
||||
if (kind != null && kind !in config.kinds) {
|
||||
viewModel.updateLocalRelayKinds(config.kinds + kind)
|
||||
customKindInput = ""
|
||||
}
|
||||
}) {
|
||||
Icon(Icons.Default.Add, stringResource(R.string.cd_add_relay))
|
||||
}
|
||||
}
|
||||
|
||||
// Show custom kinds as removable chips
|
||||
val customKinds = config.kinds - setOf(1, 1059, 9735)
|
||||
if (customKinds.isNotEmpty()) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
customKinds.forEach { kind ->
|
||||
FilterChip(
|
||||
selected = true,
|
||||
onClick = { viewModel.updateLocalRelayKinds(config.kinds - kind) },
|
||||
label = { Text("Kind $kind") }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
TextButton(
|
||||
onClick = { viewModel.removeRelay(config.url) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
stringResource(R.string.local_relay_remove),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SimpleRelayList(urls: List<String>, viewModel: RelayViewModel) {
|
||||
LazyColumn {
|
||||
|
||||
Reference in New Issue
Block a user