Write down implementation for FollowSetScreen. Introduce functions(hacks, really) for making sure of the UI/UX design.
- Implement dialog for creating a new list.
This commit is contained in:
+183
-13
@@ -30,15 +30,21 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.TabRow
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -58,12 +64,12 @@ import com.vitorpamplona.amethyst.ui.navigation.TopBarWithBackButton
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.NostrUserListFeedViewModel
|
import com.vitorpamplona.amethyst.ui.screen.NostrUserListFeedViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.DisappearingScaffold
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.followsets.FollowSetScreen
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||||
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
import com.vitorpamplona.amethyst.ui.theme.TabRowHeight
|
||||||
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
|
||||||
import com.vitorpamplona.quartz.nip51Lists.PeopleListEvent
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -95,21 +101,43 @@ fun ListsScreen(
|
|||||||
|
|
||||||
val followSetsFlow by followSetsViewModel.feedContent.collectAsStateWithLifecycle()
|
val followSetsFlow by followSetsViewModel.feedContent.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
val followSets by produceState<FollowSetState>(initialValue = FollowSetState.Loading) {
|
||||||
|
followSetsViewModel.feedContent.collectLatest { value = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Replace this with nav-based solution.
|
||||||
|
val isFollowSetSelected = remember { mutableStateOf(false) }
|
||||||
|
val selectedFollowListWithIndex = remember { mutableStateOf<Pair<Int, FollowSet>?>(null) }
|
||||||
|
|
||||||
CustomListsScreen(
|
CustomListsScreen(
|
||||||
followSetsFlow,
|
followSets,
|
||||||
refresh = {
|
refresh = {
|
||||||
followSetsViewModel.invalidateData()
|
followSetsViewModel.invalidateData()
|
||||||
},
|
},
|
||||||
|
addItem = { title: String, description: String?, listType: ListVisibility ->
|
||||||
|
followSetsViewModel.addFollowSet(
|
||||||
|
setName = title,
|
||||||
|
setDescription = description,
|
||||||
|
setType = listType,
|
||||||
|
)
|
||||||
|
},
|
||||||
openItem = {
|
openItem = {
|
||||||
currentCoroutineScope.launch(Dispatchers.IO) {
|
val selectedFollowSet = followSetsViewModel.findFollowSet(identifier = it)
|
||||||
val note = followSetsViewModel.getFollowSetAddressable(it, accountViewModel.account)
|
if (selectedFollowSet != null) {
|
||||||
if (note != null) {
|
selectedFollowListWithIndex.value = selectedFollowSet
|
||||||
val event = note.event as PeopleListEvent
|
isFollowSetSelected.value = true
|
||||||
println("Found list, with title: ${event.nameOrTitle()}")
|
} else {
|
||||||
} else {
|
println("This list has not been found. Could it not have been added/deleted properly?")
|
||||||
println("No corresponding note found for this list.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// currentCoroutineScope.launch(Dispatchers.IO) {
|
||||||
|
// val note = followSetsViewModel.getFollowSetAddressable(it, accountViewModel.account)
|
||||||
|
// if (note != null) {
|
||||||
|
// val event = note.event as PeopleListEvent
|
||||||
|
// println("Found list, with title: ${event.nameOrTitle()}")
|
||||||
|
// } else {
|
||||||
|
// println("No corresponding note found for this list.")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
renameItem = { index, newValue ->
|
renameItem = { index, newValue ->
|
||||||
followSetsViewModel.renameFollowSet(newName = newValue, setIndex = index)
|
followSetsViewModel.renameFollowSet(newName = newValue, setIndex = index)
|
||||||
@@ -120,12 +148,41 @@ fun ListsScreen(
|
|||||||
accountViewModel,
|
accountViewModel,
|
||||||
nav,
|
nav,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: Replace this with nav-based solution.
|
||||||
|
if (isFollowSetSelected.value && selectedFollowListWithIndex.value != null) {
|
||||||
|
val leFollowSetIndex = selectedFollowListWithIndex.value!!.first
|
||||||
|
FollowSetScreen(
|
||||||
|
onClose = {
|
||||||
|
isFollowSetSelected.value = false
|
||||||
|
selectedFollowListWithIndex.value = null
|
||||||
|
},
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
navigator = nav,
|
||||||
|
selectedSet = selectedFollowListWithIndex.value!!.second,
|
||||||
|
onProfileRemove = {
|
||||||
|
val newSet = followSetsViewModel.removeUserFromSet(it, leFollowSetIndex)
|
||||||
|
selectedFollowListWithIndex.value = Pair(leFollowSetIndex, newSet)
|
||||||
|
},
|
||||||
|
onListSave = {
|
||||||
|
accountViewModel.toastManager.toast("List Changes", "Changes already saved.")
|
||||||
|
},
|
||||||
|
onListBroadcast = {
|
||||||
|
accountViewModel.toastManager.toast("List Status", "List has been broadcast.")
|
||||||
|
},
|
||||||
|
onListDelete = {
|
||||||
|
isFollowSetSelected.value = false
|
||||||
|
followSetsViewModel.deleteFollowSet(leFollowSetIndex)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CustomListsScreen(
|
fun CustomListsScreen(
|
||||||
followSetState: FollowSetState,
|
followSetState: FollowSetState,
|
||||||
refresh: () -> Unit,
|
refresh: () -> Unit,
|
||||||
|
addItem: (title: String, description: String?, listType: ListVisibility) -> Unit,
|
||||||
openItem: (identifier: String) -> Unit,
|
openItem: (identifier: String) -> Unit,
|
||||||
renameItem: (Int, String) -> Unit,
|
renameItem: (Int, String) -> Unit,
|
||||||
deleteItem: (Int) -> Unit,
|
deleteItem: (Int) -> Unit,
|
||||||
@@ -168,7 +225,14 @@ fun CustomListsScreen(
|
|||||||
},
|
},
|
||||||
floatingButton = {
|
floatingButton = {
|
||||||
// TODO: Show components based on current tab
|
// TODO: Show components based on current tab
|
||||||
FollowSetFabsAndMenu()
|
FollowSetFabsAndMenu(
|
||||||
|
onAddPrivateList = { name: String, description: String? ->
|
||||||
|
addItem(name, description, ListVisibility.Private)
|
||||||
|
},
|
||||||
|
onAddPublicList = { name: String, description: String? ->
|
||||||
|
addItem(name, description, ListVisibility.Public)
|
||||||
|
},
|
||||||
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
@@ -196,13 +260,22 @@ fun CustomListsScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FollowSetFabsAndMenu(modifier: Modifier = Modifier) {
|
fun FollowSetFabsAndMenu(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onAddPrivateList: (name: String, description: String?) -> Unit,
|
||||||
|
onAddPublicList: (name: String, description: String?) -> Unit,
|
||||||
|
) {
|
||||||
|
val isListAdditionDialogOpen = remember { mutableStateOf(false) }
|
||||||
|
val isPrivateOptionTapped = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
) {
|
) {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
println("The private list addition...")
|
println("The private list addition...")
|
||||||
|
isPrivateOptionTapped.value = true
|
||||||
|
isListAdditionDialogOpen.value = true
|
||||||
},
|
},
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
@@ -216,6 +289,7 @@ fun FollowSetFabsAndMenu(modifier: Modifier = Modifier) {
|
|||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
println("The public list creation...")
|
println("The public list creation...")
|
||||||
|
isListAdditionDialogOpen.value = true
|
||||||
},
|
},
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
@@ -227,6 +301,102 @@ fun FollowSetFabsAndMenu(modifier: Modifier = Modifier) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isListAdditionDialogOpen.value) {
|
||||||
|
NewListCreationDialog(
|
||||||
|
onDismiss = {
|
||||||
|
isListAdditionDialogOpen.value = false
|
||||||
|
isPrivateOptionTapped.value = false
|
||||||
|
},
|
||||||
|
shouldBePrivate = isPrivateOptionTapped.value,
|
||||||
|
onCreateList = { name, description ->
|
||||||
|
if (isPrivateOptionTapped.value) {
|
||||||
|
onAddPrivateList(name, description)
|
||||||
|
} else {
|
||||||
|
onAddPublicList(name, description)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun NewListCreationDialog(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
shouldBePrivate: Boolean,
|
||||||
|
onCreateList: (name: String, description: String?) -> Unit,
|
||||||
|
) {
|
||||||
|
val newListName = remember { mutableStateOf("") }
|
||||||
|
val newListDescription = remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
|
val listTypeText =
|
||||||
|
when (shouldBePrivate) {
|
||||||
|
true -> "Private"
|
||||||
|
false -> "Public"
|
||||||
|
}
|
||||||
|
|
||||||
|
val listTypeIcon =
|
||||||
|
when (shouldBePrivate) {
|
||||||
|
true -> R.drawable.lock
|
||||||
|
false -> R.drawable.ic_public
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismiss,
|
||||||
|
title = {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(listTypeIcon),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "New $listTypeText List",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
// For the new list name
|
||||||
|
TextField(
|
||||||
|
value = newListName.value,
|
||||||
|
onValueChange = { newListName.value = it },
|
||||||
|
label = {
|
||||||
|
Text("List name")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Spacer(modifier = StdVertSpacer)
|
||||||
|
// For the list description
|
||||||
|
TextField(
|
||||||
|
value =
|
||||||
|
(
|
||||||
|
if (newListDescription.value != null) newListDescription.value else ""
|
||||||
|
).toString(),
|
||||||
|
onValueChange = { newListDescription.value = it },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onCreateList(newListName.value, newListDescription.value)
|
||||||
|
onDismiss()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Text("Create list")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
Button(
|
||||||
|
onClick = onDismiss,
|
||||||
|
) {
|
||||||
|
Text("Cancel")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
+226
-1
@@ -20,8 +20,233 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.followsets
|
package com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.followsets
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.vitorpamplona.amethyst.R
|
||||||
|
import com.vitorpamplona.amethyst.model.User
|
||||||
|
import com.vitorpamplona.amethyst.ui.components.ClickableBox
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.INav
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||||
|
import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.FollowSet
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.lists.ListVisibility
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.qrcode.BackButton
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.UserMetadata
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun FollowSetScreen(
|
||||||
|
onClose: () -> Unit,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
navigator: INav,
|
||||||
|
selectedSet: FollowSet,
|
||||||
|
onProfileRemove: (String) -> Unit,
|
||||||
|
onListSave: () -> Unit,
|
||||||
|
onListBroadcast: () -> Unit,
|
||||||
|
onListDelete: () -> Unit,
|
||||||
|
) {
|
||||||
|
BackHandler { onClose() }
|
||||||
|
|
||||||
|
// TODO: Remove this line and the function it calls, as they are hacks.
|
||||||
|
val users = selectedSet.profileList.mapToUsers()
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = selectedSet.title,
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
painter =
|
||||||
|
painterResource(
|
||||||
|
when (selectedSet.listVisibility) {
|
||||||
|
ListVisibility.Public -> R.drawable.ic_public
|
||||||
|
ListVisibility.Private -> R.drawable.lock
|
||||||
|
ListVisibility.Mixed -> R.drawable.format_list_bulleted_type
|
||||||
|
},
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
BackButton(
|
||||||
|
onPress = onClose,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
ListActionsMenuButton(
|
||||||
|
onSaveList = onListSave,
|
||||||
|
onBroadcastList = onListBroadcast,
|
||||||
|
onDeleteList = onListDelete,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
colors =
|
||||||
|
TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { padding ->
|
||||||
|
FollowSetListView(
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(
|
||||||
|
start = 10.dp,
|
||||||
|
end = 10.dp,
|
||||||
|
top = padding.calculateTopPadding(),
|
||||||
|
bottom = padding.calculateBottomPadding(),
|
||||||
|
).consumeWindowInsets(padding)
|
||||||
|
.imePadding(),
|
||||||
|
followSetList = users,
|
||||||
|
onDeleteUser = { onProfileRemove(it) },
|
||||||
|
accountViewModel = accountViewModel,
|
||||||
|
nav = navigator,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Set<String>.mapToUsers(): List<User> =
|
||||||
|
map {
|
||||||
|
User(Random.nextBytes(32).toHexKey()).apply {
|
||||||
|
info = UserMetadata().apply { name = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FollowSetScreen() {
|
private fun FollowSetListView(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
followSetList: List<User>,
|
||||||
|
onDeleteUser: (String) -> Unit,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: INav,
|
||||||
|
) {
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier,
|
||||||
|
contentPadding = FeedPadding,
|
||||||
|
state = listState,
|
||||||
|
) {
|
||||||
|
itemsIndexed(followSetList, key = { _, item -> item.pubkeyHex }) { _, item ->
|
||||||
|
Row {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
onDeleteUser(item.info?.name.toString())
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Delete,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
UserCompose(item, accountViewModel = accountViewModel, nav = nav)
|
||||||
|
HorizontalDivider(
|
||||||
|
thickness = DividerThickness,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ListActionsMenuButton(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onSaveList: () -> Unit,
|
||||||
|
onBroadcastList: () -> Unit,
|
||||||
|
onDeleteList: () -> Unit,
|
||||||
|
) {
|
||||||
|
val isActionListOpen = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
ClickableBox(
|
||||||
|
onClick = { isActionListOpen.value = true },
|
||||||
|
) {
|
||||||
|
VerticalDotsIcon()
|
||||||
|
ListActionsMenu(
|
||||||
|
onCloseMenu = { isActionListOpen.value = false },
|
||||||
|
isOpen = isActionListOpen.value,
|
||||||
|
onSaveList = onSaveList,
|
||||||
|
onBroadcastList = onBroadcastList,
|
||||||
|
onDeleteList = onDeleteList,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ListActionsMenu(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onCloseMenu: () -> Unit,
|
||||||
|
isOpen: Boolean,
|
||||||
|
onSaveList: () -> Unit,
|
||||||
|
onBroadcastList: () -> Unit,
|
||||||
|
onDeleteList: () -> Unit,
|
||||||
|
) {
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = isOpen,
|
||||||
|
onDismissRequest = onCloseMenu,
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text("Save Changes")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onSaveList()
|
||||||
|
onCloseMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text("Broadcast List")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onBroadcastList()
|
||||||
|
onCloseMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text("Delete List")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onDeleteList()
|
||||||
|
onCloseMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user