refactor: keep lazy itemsIndexed for relay drag-and-drop

Replace the single-item Column approach with RelayDragState that works
within itemsIndexed. Each relay item remains a separate lazy item for
better performance with large lists. The drag handle icon on each row
captures drag gestures while the item modifier applies visual feedback
(elevation, scale, translation).

https://claude.ai/code/session_01RVM5kEJGrCaJTaP3GmVHDd
This commit is contained in:
Claude
2026-04-06 15:29:19 +00:00
parent ce11edc352
commit 5b95a47e0e
15 changed files with 465 additions and 332 deletions
@@ -68,6 +68,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayExporter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayListCollection import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayListCollection
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayZipExporter import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayZipExporter
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.ConnectedRelayListViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.ConnectedRelayListViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.renderConnectedItems import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.connected.renderConnectedItems
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.dm.DMRelayListViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.dm.DMRelayListViewModel
@@ -201,6 +202,67 @@ fun MappedAllRelayListView(
val indexerCounts by indexerViewModel.countResults.collectAsStateWithLifecycle() val indexerCounts by indexerViewModel.countResults.collectAsStateWithLifecycle()
val searchCounts by searchViewModel.countResults.collectAsStateWithLifecycle() val searchCounts by searchViewModel.countResults.collectAsStateWithLifecycle()
val homeDragState =
rememberRelayDragState(
onMove = { from, to -> nip65ViewModel.moveHomeRelay(from, to) },
itemCount = { homeFeedState.size },
)
val notifDragState =
rememberRelayDragState(
onMove = { from, to -> nip65ViewModel.moveNotifRelay(from, to) },
itemCount = { notifFeedState.size },
)
val dmDragState =
rememberRelayDragState(
onMove = { from, to -> dmViewModel.moveRelay(from, to) },
itemCount = { dmFeedState.size },
)
val privateOutboxDragState =
rememberRelayDragState(
onMove = { from, to -> privateOutboxViewModel.moveRelay(from, to) },
itemCount = { privateOutboxFeedState.size },
)
val proxyDragState =
rememberRelayDragState(
onMove = { from, to -> proxyViewModel.moveRelay(from, to) },
itemCount = { proxyRelays.size },
)
val broadcastDragState =
rememberRelayDragState(
onMove = { from, to -> broadcastViewModel.moveRelay(from, to) },
itemCount = { broadcastRelays.size },
)
val indexerDragState =
rememberRelayDragState(
onMove = { from, to -> indexerViewModel.moveRelay(from, to) },
itemCount = { indexerRelays.size },
)
val searchDragState =
rememberRelayDragState(
onMove = { from, to -> searchViewModel.moveRelay(from, to) },
itemCount = { searchFeedState.size },
)
val localDragState =
rememberRelayDragState(
onMove = { from, to -> localViewModel.moveRelay(from, to) },
itemCount = { localFeedState.size },
)
val trustedDragState =
rememberRelayDragState(
onMove = { from, to -> trustedViewModel.moveRelay(from, to) },
itemCount = { trustedFeedState.size },
)
val feedsDragState =
rememberRelayDragState(
onMove = { from, to -> relayFeedsViewModel.moveRelay(from, to) },
itemCount = { relayFeedsFeedState.size },
)
val blockedDragState =
rememberRelayDragState(
onMove = { from, to -> blockedViewModel.moveRelay(from, to) },
itemCount = { blockedFeedState.size },
)
Scaffold( Scaffold(
topBar = { topBar = {
SavingTopBar( SavingTopBar(
@@ -274,7 +336,7 @@ fun MappedAllRelayListView(
SettingsCategoryFirstModifier, SettingsCategoryFirstModifier,
) )
} }
renderNip65HomeItems(homeFeedState, nip65ViewModel, accountViewModel, nav, outboxCounts) renderNip65HomeItems(homeFeedState, nip65ViewModel, accountViewModel, nav, outboxCounts, homeDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -283,7 +345,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderNip65NotifItems(notifFeedState, nip65ViewModel, accountViewModel, nav, inboxCounts) renderNip65NotifItems(notifFeedState, nip65ViewModel, accountViewModel, nav, inboxCounts, notifDragState)
item { item {
SettingsCategoryWithButton( SettingsCategoryWithButton(
@@ -295,7 +357,7 @@ fun MappedAllRelayListView(
}, },
) )
} }
renderDMItems(dmFeedState, dmViewModel, accountViewModel, nav, dmCounts) renderDMItems(dmFeedState, dmViewModel, accountViewModel, nav, dmCounts, dmDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -304,7 +366,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderPrivateOutboxItems(privateOutboxFeedState, privateOutboxViewModel, accountViewModel, nav, privateHomeCounts) renderPrivateOutboxItems(privateOutboxFeedState, privateOutboxViewModel, accountViewModel, nav, privateHomeCounts, privateOutboxDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -313,7 +375,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderProxyItems(proxyRelays, proxyViewModel, accountViewModel, nav, proxyCounts) renderProxyItems(proxyRelays, proxyViewModel, accountViewModel, nav, proxyCounts, proxyDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -322,7 +384,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderBroadcastItems(broadcastRelays, broadcastViewModel, accountViewModel, nav) renderBroadcastItems(broadcastRelays, broadcastViewModel, accountViewModel, nav, broadcastDragState)
item { item {
SettingsCategoryWithButton( SettingsCategoryWithButton(
@@ -333,7 +395,7 @@ fun MappedAllRelayListView(
ResetIndexerRelays(indexerViewModel) ResetIndexerRelays(indexerViewModel)
} }
} }
renderIndexerItems(indexerRelays, indexerViewModel, accountViewModel, nav, indexerCounts) renderIndexerItems(indexerRelays, indexerViewModel, accountViewModel, nav, indexerCounts, indexerDragState)
item { item {
SettingsCategoryWithButton( SettingsCategoryWithButton(
@@ -344,7 +406,7 @@ fun MappedAllRelayListView(
ResetSearchRelays(searchViewModel) ResetSearchRelays(searchViewModel)
} }
} }
renderSearchItems(searchFeedState, searchViewModel, accountViewModel, nav, searchCounts) renderSearchItems(searchFeedState, searchViewModel, accountViewModel, nav, searchCounts, searchDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -371,7 +433,7 @@ fun MappedAllRelayListView(
) )
} }
} }
renderLocalItems(localFeedState, localViewModel, accountViewModel, nav) renderLocalItems(localFeedState, localViewModel, accountViewModel, nav, localDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -380,7 +442,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderTrustedItems(trustedFeedState, trustedViewModel, accountViewModel, nav) renderTrustedItems(trustedFeedState, trustedViewModel, accountViewModel, nav, trustedDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -389,7 +451,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderRelayFeedsItems(relayFeedsFeedState, relayFeedsViewModel, accountViewModel, nav) renderRelayFeedsItems(relayFeedsFeedState, relayFeedsViewModel, accountViewModel, nav, feedsDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -398,7 +460,7 @@ fun MappedAllRelayListView(
SettingsCategorySpacingModifier, SettingsCategorySpacingModifier,
) )
} }
renderBlockedItems(blockedFeedState, blockedViewModel, accountViewModel, nav) renderBlockedItems(blockedFeedState, blockedViewModel, accountViewModel, nav, blockedDragState)
item { item {
SettingsCategory( SettingsCategory(
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,9 +35,10 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -48,14 +50,18 @@ fun BlockedRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderBlockedItems(feedState, postViewModel, accountViewModel, newNav) renderBlockedItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -65,21 +71,18 @@ fun LazyListScope.renderBlockedItems(
postViewModel: BlockedRelayListViewModel, postViewModel: BlockedRelayListViewModel,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
dragState: RelayDragState? = null,
) { ) {
item(key = "Blocked_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Blocked" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( index = index,
item, dragState = dragState,
onDelete = { postViewModel.deleteRelay(item) }, accountViewModel = accountViewModel,
nip11CachedRetriever = Amethyst.instance.nip11Cache, nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,9 +35,10 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -48,14 +50,18 @@ fun BroadcastRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderBroadcastItems(feedState, postViewModel, accountViewModel, newNav) renderBroadcastItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -65,21 +71,18 @@ fun LazyListScope.renderBroadcastItems(
postViewModel: BroadcastRelayListViewModel, postViewModel: BroadcastRelayListViewModel,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
dragState: RelayDragState? = null,
) { ) {
item(key = "Broadcast_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Broadcast" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( index = index,
item, dragState = dragState,
onDelete = { postViewModel.deleteRelay(item) }, accountViewModel = accountViewModel,
nip11CachedRetriever = Amethyst.instance.nip11Cache, nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -71,36 +71,54 @@ fun BasicRelaySetupInfoClickableRow(
onClick: () -> Unit, onClick: () -> Unit,
nip11CachedRetriever: Nip11CachedRetriever, nip11CachedRetriever: Nip11CachedRetriever,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
dragModifier: Modifier = Modifier, index: Int = -1,
dragState: RelayDragState? = null,
countResult: RelayCountResult? = null, countResult: RelayCountResult? = null,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
) { ) {
val clipboardManager = LocalClipboard.current val clipboardManager = LocalClipboard.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
Column(
Modifier val itemModifier =
.fillMaxWidth() if (dragState != null && index >= 0) {
.combinedClickable( Modifier
onClick = onClick, .fillMaxWidth()
onLongClick = { .draggableRelayItem(index, dragState)
scope.launch { .combinedClickable(
clipboardManager.setText(item.relay.url) onClick = onClick,
} onLongClick = {
}, scope.launch {
), clipboardManager.setText(item.relay.url)
) { }
},
)
} else {
Modifier
.fillMaxWidth()
.combinedClickable(
onClick = onClick,
onLongClick = {
scope.launch {
clipboardManager.setText(item.relay.url)
}
},
)
}
Column(itemModifier) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = modifier, modifier = modifier,
) { ) {
if (dragModifier != Modifier) { if (dragState != null && index >= 0) {
Icon( Icon(
Icons.Default.DragIndicator, Icons.Default.DragIndicator,
contentDescription = stringRes(R.string.relay_reorder), contentDescription = stringRes(R.string.relay_reorder),
modifier = modifier =
dragModifier Modifier
.size(24.dp), .size(24.dp)
.relayDragHandle(index, dragState),
tint = MaterialTheme.colorScheme.onSurfaceVariant, tint = MaterialTheme.colorScheme.onSurfaceVariant,
) )
} }
@@ -21,7 +21,6 @@
package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.vitorpamplona.amethyst.model.nip11RelayInfo.Nip11CachedRetriever import com.vitorpamplona.amethyst.model.nip11RelayInfo.Nip11CachedRetriever
import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route import com.vitorpamplona.amethyst.ui.navigation.routes.Route
@@ -34,7 +33,8 @@ fun BasicRelaySetupInfoDialog(
nip11CachedRetriever: Nip11CachedRetriever, nip11CachedRetriever: Nip11CachedRetriever,
onDelete: ((BasicRelaySetupInfo) -> Unit)?, onDelete: ((BasicRelaySetupInfo) -> Unit)?,
countResult: RelayCountResult? = null, countResult: RelayCountResult? = null,
dragModifier: Modifier = Modifier, index: Int = -1,
dragState: RelayDragState? = null,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
) { ) {
@@ -46,7 +46,8 @@ fun BasicRelaySetupInfoDialog(
onClick = { nav.nav(Route.RelayInfo(item.relay.url)) }, onClick = { nav.nav(Route.RelayInfo(item.relay.url)) },
nip11CachedRetriever = nip11CachedRetriever, nip11CachedRetriever = nip11CachedRetriever,
modifier = HalfVertPadding, modifier = HalfVertPadding,
dragModifier = dragModifier, index = index,
dragState = dragState,
countResult = countResult, countResult = countResult,
accountViewModel = accountViewModel, accountViewModel = accountViewModel,
nav = nav, nav = nav,
@@ -22,10 +22,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@@ -38,106 +36,112 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
@Composable @Stable
fun DraggableRelayList( class RelayDragState(
items: List<BasicRelaySetupInfo>, val onMove: (from: Int, to: Int) -> Unit,
onMove: (from: Int, to: Int) -> Unit, val itemCount: () -> Int,
modifier: Modifier = Modifier,
content: @Composable (
index: Int,
item: BasicRelaySetupInfo,
dragModifier: Modifier,
) -> Unit,
) { ) {
var draggedItemIndex by remember { mutableIntStateOf(-1) } var draggedItemIndex by mutableIntStateOf(-1)
var dragOffset by remember { mutableFloatStateOf(0f) } var dragOffset by mutableFloatStateOf(0f)
val itemHeights = remember { mutableStateMapOf<Int, Float>() } val itemHeights = mutableStateMapOf<Int, Float>()
Column(modifier = modifier.fillMaxWidth()) { fun onDragStart(index: Int) {
items.forEachIndexed { index, item -> draggedItemIndex = index
val isDragging = draggedItemIndex == index dragOffset = 0f
val targetElevation = if (isDragging) 8f else 0f }
val animatedElevation by animateFloatAsState(
targetValue = targetElevation,
label = "dragElevation",
)
Box( fun onDrag(dragAmount: Float) {
modifier = dragOffset += dragAmount
Modifier
.zIndex(if (isDragging) 1f else 0f)
.onGloballyPositioned { coordinates ->
itemHeights[index] = coordinates.size.height.toFloat()
}.graphicsLayer {
translationY = if (isDragging) dragOffset else 0f
shadowElevation = animatedElevation
if (isDragging) {
scaleX = 1.02f
scaleY = 1.02f
}
},
) {
val dragModifier =
Modifier.pointerInput(Unit) {
detectDragGestures(
onDragStart = {
draggedItemIndex = index
dragOffset = 0f
},
onDrag = { change, dragAmount ->
change.consume()
dragOffset += dragAmount.y
val currentIndex = draggedItemIndex val currentIndex = draggedItemIndex
if (currentIndex < 0) return@detectDragGestures if (currentIndex < 0) return
// Check if we should swap with the item above // Check if we should swap with the item above
if (dragOffset < 0 && currentIndex > 0) { if (dragOffset < 0 && currentIndex > 0) {
val aboveHeight = itemHeights[currentIndex - 1] ?: 0f val aboveHeight = itemHeights[currentIndex - 1] ?: 0f
if (-dragOffset > aboveHeight / 2f) { if (-dragOffset > aboveHeight / 2f) {
onMove(currentIndex, currentIndex - 1) onMove(currentIndex, currentIndex - 1)
// Transfer heights val h1 = itemHeights[currentIndex]
val h1 = itemHeights[currentIndex] val h2 = itemHeights[currentIndex - 1]
val h2 = itemHeights[currentIndex - 1] if (h1 != null) itemHeights[currentIndex - 1] = h1
if (h1 != null) itemHeights[currentIndex - 1] = h1 if (h2 != null) itemHeights[currentIndex] = h2
if (h2 != null) itemHeights[currentIndex] = h2
dragOffset += aboveHeight dragOffset += aboveHeight
draggedItemIndex = currentIndex - 1 draggedItemIndex = currentIndex - 1
} }
} }
// Check if we should swap with the item below // Check if we should swap with the item below
if (dragOffset > 0 && currentIndex < items.lastIndex) { if (dragOffset > 0 && currentIndex < itemCount() - 1) {
val belowHeight = itemHeights[currentIndex + 1] ?: 0f val belowHeight = itemHeights[currentIndex + 1] ?: 0f
if (dragOffset > belowHeight / 2f) { if (dragOffset > belowHeight / 2f) {
onMove(currentIndex, currentIndex + 1) onMove(currentIndex, currentIndex + 1)
// Transfer heights val h1 = itemHeights[currentIndex]
val h1 = itemHeights[currentIndex] val h2 = itemHeights[currentIndex + 1]
val h2 = itemHeights[currentIndex + 1] if (h1 != null) itemHeights[currentIndex + 1] = h1
if (h1 != null) itemHeights[currentIndex + 1] = h1 if (h2 != null) itemHeights[currentIndex] = h2
if (h2 != null) itemHeights[currentIndex] = h2
dragOffset -= belowHeight dragOffset -= belowHeight
draggedItemIndex = currentIndex + 1 draggedItemIndex = currentIndex + 1
}
}
},
onDragEnd = {
draggedItemIndex = -1
dragOffset = 0f
},
onDragCancel = {
draggedItemIndex = -1
dragOffset = 0f
},
)
}
content(index, item, dragModifier)
} }
} }
} }
fun onDragEnd() {
draggedItemIndex = -1
dragOffset = 0f
}
} }
@Composable
fun rememberRelayDragState(
onMove: (from: Int, to: Int) -> Unit,
itemCount: () -> Int,
): RelayDragState =
remember(onMove, itemCount) {
RelayDragState(onMove, itemCount)
}
@Composable
fun Modifier.draggableRelayItem(
index: Int,
dragState: RelayDragState,
): Modifier {
val isDragging = dragState.draggedItemIndex == index
val targetElevation = if (isDragging) 8f else 0f
val animatedElevation by animateFloatAsState(
targetValue = targetElevation,
label = "dragElevation",
)
return this
.zIndex(if (isDragging) 1f else 0f)
.onGloballyPositioned { coordinates ->
dragState.itemHeights[index] = coordinates.size.height.toFloat()
}.graphicsLayer {
translationY = if (isDragging) dragState.dragOffset else 0f
shadowElevation = animatedElevation
if (isDragging) {
scaleX = 1.02f
scaleY = 1.02f
}
}
}
fun Modifier.relayDragHandle(
index: Int,
dragState: RelayDragState,
): Modifier =
this.pointerInput(index) {
detectDragGestures(
onDragStart = { dragState.onDragStart(index) },
onDrag = { change, dragAmount ->
change.consume()
dragState.onDrag(dragAmount.y)
},
onDragEnd = { dragState.onDragEnd() },
onDragCancel = { dragState.onDragEnd() },
)
}
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -51,12 +53,17 @@ fun DMRelayList(
) { ) {
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderDMItems(feedState, postViewModel, accountViewModel, newNav) renderDMItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -67,22 +74,19 @@ fun LazyListScope.renderDMItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "DM_draggable_list") { itemsIndexed(feedState, key = { _, item -> "DM" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,9 +35,10 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -48,14 +50,18 @@ fun RelayFeedsList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderRelayFeedsItems(feedState, postViewModel, accountViewModel, newNav) renderRelayFeedsItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -65,21 +71,18 @@ fun LazyListScope.renderRelayFeedsItems(
postViewModel: RelayFeedsListViewModel, postViewModel: RelayFeedsListViewModel,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
dragState: RelayDragState? = null,
) { ) {
item(key = "RelayFeeds_draggable_list") { itemsIndexed(feedState, key = { _, item -> "RelayFeeds" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( index = index,
item, dragState = dragState,
onDelete = { postViewModel.deleteRelay(item) }, accountViewModel = accountViewModel,
nip11CachedRetriever = Amethyst.instance.nip11Cache, nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -50,14 +52,18 @@ fun IndexerRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderIndexerItems(feedState, postViewModel, accountViewModel, newNav) renderIndexerItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -68,22 +74,19 @@ fun LazyListScope.renderIndexerItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Indexer_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Indexer" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,9 +35,10 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -49,12 +51,17 @@ fun LocalRelayList(
) { ) {
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderLocalItems(feedState, postViewModel, accountViewModel, newNav) renderLocalItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -64,21 +71,18 @@ fun LazyListScope.renderLocalItems(
postViewModel: LocalRelayListViewModel, postViewModel: LocalRelayListViewModel,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
dragState: RelayDragState? = null,
) { ) {
item(key = "Local_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Local" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( index = index,
item, dragState = dragState,
onDelete = { postViewModel.deleteRelay(item) }, accountViewModel = accountViewModel,
nip11CachedRetriever = Amethyst.instance.nip11Cache, nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -51,12 +53,17 @@ fun PrivateOutboxRelayList(
) { ) {
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderPrivateOutboxItems(feedState, postViewModel, accountViewModel, newNav) renderPrivateOutboxItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -67,22 +74,19 @@ fun LazyListScope.renderPrivateOutboxItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Outbox_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Outbox" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -54,12 +56,23 @@ fun Nip65RelayList(
val homeFeedState by postViewModel.homeRelays.collectAsStateWithLifecycle() val homeFeedState by postViewModel.homeRelays.collectAsStateWithLifecycle()
val notifFeedState by postViewModel.notificationRelays.collectAsStateWithLifecycle() val notifFeedState by postViewModel.notificationRelays.collectAsStateWithLifecycle()
val homeDragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveHomeRelay(from, to) },
itemCount = { homeFeedState.size },
)
val notifDragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveNotifRelay(from, to) },
itemCount = { notifFeedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderNip65HomeItems(homeFeedState, postViewModel, accountViewModel, newNav) renderNip65HomeItems(homeFeedState, postViewModel, accountViewModel, newNav, dragState = homeDragState)
renderNip65NotifItems(notifFeedState, postViewModel, accountViewModel, newNav) renderNip65NotifItems(notifFeedState, postViewModel, accountViewModel, newNav, dragState = notifDragState)
} }
} }
} }
@@ -72,14 +85,18 @@ fun Nip65InboxRelayList(
nav: INav, nav: INav,
) { ) {
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val notifFeedState by postViewModel.notificationRelays.collectAsStateWithLifecycle() val notifFeedState by postViewModel.notificationRelays.collectAsStateWithLifecycle()
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveNotifRelay(from, to) },
itemCount = { notifFeedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderNip65NotifItems(notifFeedState, postViewModel, accountViewModel, newNav) renderNip65NotifItems(notifFeedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -92,14 +109,18 @@ fun Nip65OutboxRelayList(
nav: INav, nav: INav,
) { ) {
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val homeFeedState by postViewModel.homeRelays.collectAsStateWithLifecycle() val homeFeedState by postViewModel.homeRelays.collectAsStateWithLifecycle()
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveHomeRelay(from, to) },
itemCount = { homeFeedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderNip65HomeItems(homeFeedState, postViewModel, accountViewModel, newNav) renderNip65HomeItems(homeFeedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -110,22 +131,19 @@ fun LazyListScope.renderNip65HomeItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Nip65Home_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Nip65Home" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveHomeRelay(from, to) }, onDelete = { postViewModel.deleteHomeRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteHomeRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -144,22 +162,19 @@ fun LazyListScope.renderNip65NotifItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Nip65Notif_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Nip65Notif" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveNotifRelay(from, to) }, onDelete = { postViewModel.deleteNotifRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteNotifRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -50,14 +52,18 @@ fun ProxyRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderProxyItems(feedState, postViewModel, accountViewModel, newNav) renderProxyItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -68,22 +74,19 @@ fun LazyListScope.renderProxyItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Proxy_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Proxy" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,10 +35,11 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayCountResult
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
@@ -50,14 +52,18 @@ fun SearchRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderSearchItems(feedState, postViewModel, accountViewModel, newNav) renderSearchItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -68,22 +74,19 @@ fun LazyListScope.renderSearchItems(
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(), countResults: Map<NormalizedRelayUrl, RelayCountResult> = emptyMap(),
dragState: RelayDragState? = null,
) { ) {
item(key = "Search_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Search" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( countResult = countResults[item.relay],
item, index = index,
onDelete = { postViewModel.deleteRelay(item) }, dragState = dragState,
nip11CachedRetriever = Amethyst.instance.nip11Cache, accountViewModel = accountViewModel,
countResult = countResults[item.relay], nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {
@@ -24,6 +24,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
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
@@ -34,9 +35,10 @@ import com.vitorpamplona.amethyst.ui.navigation.navs.rememberExtendedNav
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.BasicRelaySetupInfoDialog
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.DraggableRelayList import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayDragState
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.RelayUrlEditField
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.relaySetupInfoBuilder
import com.vitorpamplona.amethyst.ui.screen.loggedIn.relays.common.rememberRelayDragState
import com.vitorpamplona.amethyst.ui.theme.FeedPadding import com.vitorpamplona.amethyst.ui.theme.FeedPadding
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -48,14 +50,18 @@ fun TrustedRelayList(
nav: INav, nav: INav,
) { ) {
val feedState by postViewModel.relays.collectAsStateWithLifecycle() val feedState by postViewModel.relays.collectAsStateWithLifecycle()
val newNav = rememberExtendedNav(nav, onClose) val newNav = rememberExtendedNav(nav, onClose)
val dragState =
rememberRelayDragState(
onMove = { from, to -> postViewModel.moveRelay(from, to) },
itemCount = { feedState.size },
)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
LazyColumn( LazyColumn(
contentPadding = FeedPadding, contentPadding = FeedPadding,
) { ) {
renderTrustedItems(feedState, postViewModel, accountViewModel, newNav) renderTrustedItems(feedState, postViewModel, accountViewModel, newNav, dragState = dragState)
} }
} }
} }
@@ -65,21 +71,18 @@ fun LazyListScope.renderTrustedItems(
postViewModel: TrustedRelayListViewModel, postViewModel: TrustedRelayListViewModel,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
nav: INav, nav: INav,
dragState: RelayDragState? = null,
) { ) {
item(key = "Trusted_draggable_list") { itemsIndexed(feedState, key = { _, item -> "Trusted" + item.relay.url }) { index, item ->
DraggableRelayList( BasicRelaySetupInfoDialog(
items = feedState, item,
onMove = { from, to -> postViewModel.moveRelay(from, to) }, onDelete = { postViewModel.deleteRelay(item) },
) { _, item, dragModifier -> nip11CachedRetriever = Amethyst.instance.nip11Cache,
BasicRelaySetupInfoDialog( index = index,
item, dragState = dragState,
onDelete = { postViewModel.deleteRelay(item) }, accountViewModel = accountViewModel,
nip11CachedRetriever = Amethyst.instance.nip11Cache, nav = nav,
dragModifier = dragModifier, )
accountViewModel = accountViewModel,
nav = nav,
)
}
} }
item { item {