Add Bookmark group metadata edit to routes/nav. Make refactors to make use of it.

This commit is contained in:
KotlinGeekDev
2025-11-27 07:19:04 +01:00
parent 0f21c72936
commit cd0a0405a9
7 changed files with 31 additions and 215 deletions
@@ -60,6 +60,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountSwitcherAndLeftDrawe
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.display.BookmarkGroupScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.display.BookmarkGroupScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.ListOfBookmarkGroupsScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.list.metadata.BookmarkGroupMetadataScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.ArticleBookmarkListManagementScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarkgroups.membershipManagement.PostBookmarkListManagementScreen
import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.BookmarkListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.bookmarks.BookmarkListScreen
@@ -145,6 +146,7 @@ fun AppNavigation(
composableFromEnd<Route.BookmarkGroups> { ListOfBookmarkGroupsScreen(accountViewModel, nav) } composableFromEnd<Route.BookmarkGroups> { ListOfBookmarkGroupsScreen(accountViewModel, nav) }
composableFromEndArgs<Route.BookmarkGroupView> { BookmarkGroupScreen(it.dTag, it.bookmarkType, accountViewModel, nav) } composableFromEndArgs<Route.BookmarkGroupView> { BookmarkGroupScreen(it.dTag, it.bookmarkType, accountViewModel, nav) }
composableFromBottomArgs<Route.BookmarkGroupMetadataEdit> { BookmarkGroupMetadataScreen(it.dTag, accountViewModel, nav) }
composableFromBottomArgs<Route.PostBookmarkManagement> { PostBookmarkListManagementScreen(it.postId, accountViewModel, nav) } composableFromBottomArgs<Route.PostBookmarkManagement> { PostBookmarkListManagementScreen(it.postId, accountViewModel, nav) }
composableFromBottomArgs<Route.ArticleBookmarkManagement> { ArticleBookmarkListManagementScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) } composableFromBottomArgs<Route.ArticleBookmarkManagement> { ArticleBookmarkListManagementScreen(Address(it.kind, it.pubKeyHex, it.dTag), accountViewModel, nav) }
@@ -56,6 +56,10 @@ sealed class Route {
val bookmarkType: BookmarkType, val bookmarkType: BookmarkType,
) : Route() ) : Route()
@Serializable data class BookmarkGroupMetadataEdit(
val dTag: String? = null,
) : Route()
@Serializable data class PostBookmarkManagement( @Serializable data class PostBookmarkManagement(
val postId: String, val postId: String,
) : Route() ) : Route()
@@ -51,12 +51,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
@@ -79,8 +76,8 @@ fun BookmarkGroupItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
bookmarkList: LabeledBookmarkList, bookmarkList: LabeledBookmarkList,
onClick: (bookmarkItemType: BookmarkType) -> Unit, onClick: (bookmarkItemType: BookmarkType) -> Unit,
onRename: (String) -> Unit, onRename: () -> Unit,
onDescriptionChange: (String?) -> Unit, onDescriptionChange: () -> Unit,
onClone: (customName: String?, customDescription: String?) -> Unit, onClone: (customName: String?, customDescription: String?) -> Unit,
onDelete: () -> Unit, onDelete: () -> Unit,
) { ) {
@@ -252,8 +249,8 @@ private fun BookmarkGroupOptionsButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
bookmarkGroupName: String, bookmarkGroupName: String,
bookmarkGroupDescription: String?, bookmarkGroupDescription: String?,
onGroupRename: (String) -> Unit, onGroupRename: () -> Unit,
onGroupDescriptionChange: (String?) -> Unit, onGroupDescriptionChange: () -> Unit,
onGroupCloneCreate: (optionalName: String?, optionalDec: String?) -> Unit, onGroupCloneCreate: (optionalName: String?, optionalDec: String?) -> Unit,
onGroupDelete: () -> Unit, onGroupDelete: () -> Unit,
) { ) {
@@ -283,17 +280,12 @@ private fun GroupOptionsMenu(
isExpanded: Boolean, isExpanded: Boolean,
groupName: String, groupName: String,
groupDescription: String?, groupDescription: String?,
onGroupRename: (String) -> Unit, onGroupRename: () -> Unit,
onGroupDescriptionChange: (String?) -> Unit, onGroupDescriptionChange: () -> Unit,
onGroupClone: (optionalNewName: String?, optionalNewDesc: String?) -> Unit, onGroupClone: (optionalNewName: String?, optionalNewDesc: String?) -> Unit,
onDelete: () -> Unit, onDelete: () -> Unit,
onDismiss: () -> Unit, onDismiss: () -> Unit,
) { ) {
val isRenameDialogOpen = remember { mutableStateOf(false) }
val renameString = remember { mutableStateOf("") }
val isDescriptionModDialogOpen = remember { mutableStateOf(false) }
val isCopyDialogOpen = remember { mutableStateOf(false) } val isCopyDialogOpen = remember { mutableStateOf(false) }
val optionalCloneName = remember { mutableStateOf<String?>(null) } val optionalCloneName = remember { mutableStateOf<String?>(null) }
val optionalCloneDescription = remember { mutableStateOf<String?>(null) } val optionalCloneDescription = remember { mutableStateOf<String?>(null) }
@@ -307,7 +299,7 @@ private fun GroupOptionsMenu(
Text(text = stringRes(R.string.follow_set_rename_btn_label)) Text(text = stringRes(R.string.follow_set_rename_btn_label))
}, },
onClick = { onClick = {
isRenameDialogOpen.value = true onGroupRename()
onDismiss() onDismiss()
}, },
) )
@@ -316,7 +308,7 @@ private fun GroupOptionsMenu(
Text(text = stringRes(R.string.follow_set_desc_modify_label)) Text(text = stringRes(R.string.follow_set_desc_modify_label))
}, },
onClick = { onClick = {
isDescriptionModDialogOpen.value = true onGroupDescriptionChange()
onDismiss() onDismiss()
}, },
) )
@@ -339,28 +331,6 @@ private fun GroupOptionsMenu(
) )
} }
if (isRenameDialogOpen.value) {
GroupRenameDialog(
currentName = groupName,
newName = renameString.value,
onStringRenameChange = {
renameString.value = it
},
onDismissDialog = { isRenameDialogOpen.value = false },
onGroupRename = {
onGroupRename(renameString.value)
},
)
}
if (isDescriptionModDialogOpen.value) {
GroupModifyDescriptionDialog(
currentDescription = groupDescription,
onDismissDialog = { isDescriptionModDialogOpen.value = false },
onModifyDescription = onGroupDescriptionChange,
)
}
if (isCopyDialogOpen.value) { if (isCopyDialogOpen.value) {
GroupCloneDialog( GroupCloneDialog(
optionalNewName = optionalCloneName.value, optionalNewName = optionalCloneName.value,
@@ -379,129 +349,6 @@ private fun GroupOptionsMenu(
} }
} }
@Composable
private fun GroupRenameDialog(
modifier: Modifier = Modifier,
currentName: String,
newName: String,
onStringRenameChange: (String) -> Unit,
onDismissDialog: () -> Unit,
onGroupRename: (String) -> Unit,
) {
val renameIndicator =
buildAnnotatedString {
append(stringRes(R.string.follow_set_rename_dialog_indicator_first_part) + " ")
withStyle(
SpanStyle(
fontWeight = FontWeight.Bold,
fontStyle = FontStyle.Normal,
fontSize = 15.sp,
),
) {
append("\"" + currentName + "\"")
}
append(" " + stringRes(R.string.follow_set_rename_dialog_indicator_second_part))
}
AlertDialog(
onDismissRequest = onDismissDialog,
title = {
Text(text = stringRes(R.string.follow_set_rename_btn_label))
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(Size5dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = renameIndicator,
fontSize = 15.sp,
fontWeight = FontWeight.Light,
fontStyle = FontStyle.Italic,
)
TextField(
value = newName,
onValueChange = onStringRenameChange,
)
}
},
confirmButton = {
Button(
onClick = {
onGroupRename(newName)
onDismissDialog()
},
) { Text(text = stringRes(R.string.rename)) }
},
dismissButton = {
Button(onClick = onDismissDialog) { Text(text = stringRes(R.string.cancel)) }
},
)
}
@Composable
private fun GroupModifyDescriptionDialog(
modifier: Modifier = Modifier,
currentDescription: String?,
onDismissDialog: () -> Unit,
onModifyDescription: (String?) -> Unit,
) {
val updatedDescription = remember { mutableStateOf<String?>(null) }
val modifyIndicatorLabel =
if (currentDescription == null) {
stringRes(R.string.follow_set_empty_desc_label)
} else {
buildAnnotatedString {
append(stringRes(R.string.follow_set_current_desc_label) + " ")
withStyle(
SpanStyle(
fontWeight = FontWeight.Bold,
fontStyle = FontStyle.Normal,
fontSize = 15.sp,
),
) {
append("\"" + currentDescription + "\"")
}
}.text
}
AlertDialog(
onDismissRequest = onDismissDialog,
title = {
Text(text = stringRes(R.string.follow_set_desc_modify_label))
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(Size5dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = modifyIndicatorLabel,
fontSize = 15.sp,
fontWeight = FontWeight.Light,
fontStyle = FontStyle.Italic,
)
TextField(
value = updatedDescription.value ?: "",
onValueChange = { updatedDescription.value = it },
)
}
},
confirmButton = {
Button(
onClick = {
onModifyDescription(updatedDescription.value)
onDismissDialog()
},
) { Text(text = stringRes(R.string.follow_set_desc_modify_btn_label)) }
},
dismissButton = {
Button(onClick = onDismissDialog) { Text(text = stringRes(R.string.cancel)) }
},
)
}
@Composable @Composable
private fun GroupCloneDialog( private fun GroupCloneDialog(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -49,8 +49,8 @@ import kotlinx.coroutines.flow.StateFlow
fun ListOfBookmarkGroupsFeedView( fun ListOfBookmarkGroupsFeedView(
groupListFeedSource: StateFlow<List<LabeledBookmarkList>>, groupListFeedSource: StateFlow<List<LabeledBookmarkList>>,
onOpenItem: (String, BookmarkType) -> Unit, onOpenItem: (String, BookmarkType) -> Unit,
onRenameItem: (targetBookmarkGroup: LabeledBookmarkList, newName: String) -> Unit, onRenameItem: (targetBookmarkGroup: LabeledBookmarkList) -> Unit,
onItemDescriptionChange: (bookmarkGroup: LabeledBookmarkList, newDescription: String?) -> Unit, onItemDescriptionChange: (bookmarkGroup: LabeledBookmarkList) -> Unit,
onItemClone: (bookmarkGroup: LabeledBookmarkList, customName: String?, customDesc: String?) -> Unit, onItemClone: (bookmarkGroup: LabeledBookmarkList, customName: String?, customDesc: String?) -> Unit,
onDeleteItem: (bookmarkGroup: LabeledBookmarkList) -> Unit, onDeleteItem: (bookmarkGroup: LabeledBookmarkList) -> Unit,
) { ) {
@@ -71,8 +71,8 @@ fun ListOfBookmarkGroupsFeedView(
modifier = Modifier.fillMaxSize().animateItem(), modifier = Modifier.fillMaxSize().animateItem(),
bookmarkList = groupItem, bookmarkList = groupItem,
onClick = { bookmarkType -> onOpenItem(groupItem.identifier, bookmarkType) }, onClick = { bookmarkType -> onOpenItem(groupItem.identifier, bookmarkType) },
onRename = { onRenameItem(groupItem, it) }, onRename = { onRenameItem(groupItem) },
onDescriptionChange = { onItemDescriptionChange(groupItem, it) }, onDescriptionChange = { onItemDescriptionChange(groupItem) },
onClone = { cloneName, cloneDescription -> onItemClone(groupItem, cloneName, cloneDescription) }, onClone = { cloneName, cloneDescription -> onItemClone(groupItem, cloneName, cloneDescription) },
onDelete = { onDeleteItem(groupItem) }, onDelete = { onDeleteItem(groupItem) },
) )
@@ -32,8 +32,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList import com.vitorpamplona.amethyst.model.nip51Lists.labeledBookmarkLists.LabeledBookmarkList
@@ -52,35 +50,15 @@ fun ListOfBookmarkGroupsScreen(
) { ) {
ListOfBookmarkGroupsFeed( ListOfBookmarkGroupsFeed(
listSource = accountViewModel.account.labeledBookmarkLists.listFeedFlow, listSource = accountViewModel.account.labeledBookmarkLists.listFeedFlow,
addBookmarkGroup = { title, description -> addBookmarkGroup = { nav.nav(Route.BookmarkGroupMetadataEdit()) },
accountViewModel.launchSigner {
accountViewModel.account.labeledBookmarkLists.addLabeledBookmarkList(
listName = title,
listDescription = description,
account = accountViewModel.account,
)
}
},
openBookmarkGroup = { identifier, bookmarkType -> openBookmarkGroup = { identifier, bookmarkType ->
nav.nav(Route.BookmarkGroupView(identifier, bookmarkType)) nav.nav(Route.BookmarkGroupView(identifier, bookmarkType))
}, },
renameBookmarkGroup = { bookmarkGroup, newName -> renameBookmarkGroup = { bookmarkGroup ->
accountViewModel.launchSigner { nav.nav(Route.BookmarkGroupMetadataEdit(bookmarkGroup.identifier))
accountViewModel.account.labeledBookmarkLists.renameBookmarkList(
newName = newName,
bookmarkList = bookmarkGroup,
account = accountViewModel.account,
)
}
}, },
changeBookmarkGroupDescription = { bookmarkGroup, newDescription -> changeBookmarkGroupDescription = { bookmarkGroup ->
accountViewModel.launchSigner { nav.nav(Route.BookmarkGroupMetadataEdit(bookmarkGroup.identifier))
accountViewModel.account.labeledBookmarkLists.modifyListDescription(
newDescription = newDescription,
bookmarkList = bookmarkGroup,
account = accountViewModel.account,
)
}
}, },
cloneBookmarkGroup = { bookmarkGroup, customName, customDesc -> cloneBookmarkGroup = { bookmarkGroup, customName, customDesc ->
accountViewModel.launchSigner { accountViewModel.launchSigner {
@@ -107,10 +85,10 @@ fun ListOfBookmarkGroupsScreen(
@Composable @Composable
fun ListOfBookmarkGroupsFeed( fun ListOfBookmarkGroupsFeed(
listSource: StateFlow<List<LabeledBookmarkList>>, listSource: StateFlow<List<LabeledBookmarkList>>,
addBookmarkGroup: (title: String, description: String?) -> Unit, addBookmarkGroup: () -> Unit,
openBookmarkGroup: (identifier: String, bookmarkType: BookmarkType) -> Unit, openBookmarkGroup: (identifier: String, bookmarkType: BookmarkType) -> Unit,
renameBookmarkGroup: (bookmarkGroup: LabeledBookmarkList, newName: String) -> Unit, renameBookmarkGroup: (bookmarkGroup: LabeledBookmarkList) -> Unit,
changeBookmarkGroupDescription: (bookmarkGroup: LabeledBookmarkList, newDescription: String?) -> Unit, changeBookmarkGroupDescription: (bookmarkGroup: LabeledBookmarkList) -> Unit,
cloneBookmarkGroup: (bookmarkGroup: LabeledBookmarkList, customName: String?, customDesc: String?) -> Unit, cloneBookmarkGroup: (bookmarkGroup: LabeledBookmarkList, customName: String?, customDesc: String?) -> Unit,
deleteBookmarkGroup: (bookmarkGroup: LabeledBookmarkList) -> Unit, deleteBookmarkGroup: (bookmarkGroup: LabeledBookmarkList) -> Unit,
nav: INav, nav: INav,
@@ -120,7 +98,7 @@ fun ListOfBookmarkGroupsFeed(
TopBarWithBackButton(caption = stringRes(R.string.bookmark_lists), nav::popBack) TopBarWithBackButton(caption = stringRes(R.string.bookmark_lists), nav::popBack)
}, },
floatingActionButton = { floatingActionButton = {
BookmarkGroupFabAndMenu(onAddGroup = addBookmarkGroup) BookmarkGroupFab(onAddGroup = addBookmarkGroup)
}, },
) { paddingValues -> ) { paddingValues ->
Column( Column(
@@ -143,9 +121,7 @@ fun ListOfBookmarkGroupsFeed(
} }
@Composable @Composable
fun BookmarkGroupFabAndMenu(onAddGroup: (name: String, description: String?) -> Unit) { fun BookmarkGroupFab(onAddGroup: () -> Unit) {
val isSetAdditionDialogOpen = remember { mutableStateOf(false) }
ExtendedFloatingActionButton( ExtendedFloatingActionButton(
text = { text = {
Text(text = stringRes(R.string.follow_set_create_btn_label)) Text(text = stringRes(R.string.follow_set_create_btn_label))
@@ -156,21 +132,8 @@ fun BookmarkGroupFabAndMenu(onAddGroup: (name: String, description: String?) ->
contentDescription = null, contentDescription = null,
) )
}, },
onClick = { onClick = onAddGroup,
isSetAdditionDialogOpen.value = true
},
shape = CircleShape, shape = CircleShape,
containerColor = MaterialTheme.colorScheme.primary, containerColor = MaterialTheme.colorScheme.primary,
) )
if (isSetAdditionDialogOpen.value) {
NewBookmarkGroupCreationDialog(
onDismiss = {
isSetAdditionDialogOpen.value = false
},
onCreateGroup = { name, description ->
onAddGroup(name, description)
},
)
}
} }
@@ -83,7 +83,7 @@ private fun ListManagementView(
TopBarWithBackButton(caption = stringRes(R.string.article_bookmark_management_title), nav::popBack) TopBarWithBackButton(caption = stringRes(R.string.article_bookmark_management_title), nav::popBack)
}, },
floatingActionButton = { floatingActionButton = {
NewListButton { } NewListButton { nav.nav(Route.BookmarkGroupMetadataEdit()) }
}, },
) { contentPadding -> ) { contentPadding ->
Column( Column(
@@ -82,7 +82,7 @@ private fun ListManagementView(
TopBarWithBackButton(caption = stringRes(R.string.post_bookmark_management_title), nav::popBack) TopBarWithBackButton(caption = stringRes(R.string.post_bookmark_management_title), nav::popBack)
}, },
floatingActionButton = { floatingActionButton = {
NewListButton { } NewListButton { nav.nav(Route.BookmarkGroupMetadataEdit()) }
}, },
) { contentPadding -> ) { contentPadding ->
Column( Column(