Add support for copying/cloning follow sets in the UI.

This commit is contained in:
KotlinGeekDev
2025-10-03 16:26:20 +01:00
parent 2df575d4af
commit e418a26f41
4 changed files with 134 additions and 3 deletions

View File

@@ -137,6 +137,14 @@ fun ListsAndSetsScreen(
account = accountViewModel.account,
)
},
cloneItem = { followSet, customName, customDescription ->
followSetsViewModel.cloneFollowSet(
currentFollowSet = followSet,
customCloneName = customName,
customCloneDescription = customDescription,
account = accountViewModel.account,
)
},
deleteItem = { followSet ->
followSetsViewModel.deleteFollowSet(
followSet = followSet,
@@ -155,6 +163,7 @@ fun CustomListsScreen(
addItem: (title: String, description: String?) -> Unit,
openItem: (identifier: String) -> Unit,
renameItem: (followSet: FollowSet, newName: String) -> Unit,
cloneItem: (followSet: FollowSet, customName: String?, customDesc: String?) -> Unit,
deleteItem: (followSet: FollowSet) -> Unit,
accountViewModel: AccountViewModel,
nav: INav,
@@ -213,6 +222,7 @@ fun CustomListsScreen(
onRefresh = refresh,
onOpenItem = openItem,
onRenameItem = renameItem,
onItemClone = cloneItem,
onDeleteItem = deleteItem,
)
@@ -372,6 +382,9 @@ private fun SetItemPreview() {
onFollowSetRename = {
println("Follow set new name: $it")
},
onFollowSetClone = { newName, newDesc ->
println("The follow set has been cloned, and has custom name: $newName, Desc: $newDesc")
},
onFollowSetDelete = {
println(" The follow set ${sampleFollowSet.title} has been deleted.")
},

View File

@@ -57,6 +57,7 @@ import com.vitorpamplona.amethyst.ui.components.ClickableBox
import com.vitorpamplona.amethyst.ui.note.VerticalDotsIcon
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer
import com.vitorpamplona.amethyst.ui.theme.Size5dp
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
@@ -67,6 +68,7 @@ fun CustomSetItem(
followSet: FollowSet,
onFollowSetClick: () -> Unit,
onFollowSetRename: (String) -> Unit,
onFollowSetClone: (customName: String?, customDescription: String?) -> Unit,
onFollowSetDelete: () -> Unit,
) {
val context = LocalContext.current
@@ -122,7 +124,7 @@ fun CustomSetItem(
selected = true,
onClick = {},
label = {
Text(text = "$publicMemberSize $membersLabel")
Text(text = "$publicMemberSize")
},
leadingIcon = {
Icon(
@@ -149,7 +151,7 @@ fun CustomSetItem(
selected = true,
onClick = {},
label = {
Text(text = "$privateMemberSize $membersLabel")
Text(text = "$privateMemberSize")
},
leadingIcon = {
Icon(
@@ -182,6 +184,7 @@ fun CustomSetItem(
SetOptionsButton(
followSetName = followSet.title,
onListRename = onFollowSetRename,
onSetCloneCreate = onFollowSetClone,
onListDelete = onFollowSetDelete,
)
}
@@ -189,10 +192,11 @@ fun CustomSetItem(
}
@Composable
fun SetOptionsButton(
private fun SetOptionsButton(
modifier: Modifier = Modifier,
followSetName: String,
onListRename: (String) -> Unit,
onSetCloneCreate: (optionalName: String?, optionalDec: String?) -> Unit,
onListDelete: () -> Unit,
) {
val isMenuOpen = remember { mutableStateOf(false) }
@@ -207,6 +211,7 @@ fun SetOptionsButton(
isExpanded = isMenuOpen.value,
onDismiss = { isMenuOpen.value = false },
onListRename = onListRename,
onSetClone = onSetCloneCreate,
onDelete = onListDelete,
)
}
@@ -218,12 +223,17 @@ private fun SetOptionsMenu(
isExpanded: Boolean,
listName: String,
onListRename: (String) -> Unit,
onSetClone: (optionalNewName: String?, optionalNewDesc: String?) -> Unit,
onDelete: () -> Unit,
onDismiss: () -> Unit,
) {
val isRenameDialogOpen = remember { mutableStateOf(false) }
val renameString = remember { mutableStateOf("") }
val isCopyDialogOpen = remember { mutableStateOf(false) }
val optionalCloneName = remember { mutableStateOf<String?>(null) }
val optionalCloneDescription = remember { mutableStateOf<String?>(null) }
DropdownMenu(
expanded = isExpanded,
onDismissRequest = onDismiss,
@@ -245,6 +255,15 @@ private fun SetOptionsMenu(
onDismiss()
},
)
DropdownMenuItem(
text = {
Text(text = stringRes(R.string.follow_set_copy_action_btn_label))
},
onClick = {
isCopyDialogOpen.value = true
onDismiss()
},
)
}
if (isRenameDialogOpen.value) {
@@ -260,6 +279,23 @@ private fun SetOptionsMenu(
},
)
}
if (isCopyDialogOpen.value) {
SetCloneDialog(
optionalNewName = optionalCloneName.value,
optionalNewDesc = optionalCloneDescription.value,
onCloneNameChange = {
optionalCloneName.value = it
},
onCloneDescChange = {
optionalCloneDescription.value = it
},
onCloneCreate = { name, description ->
onSetClone(optionalCloneName.value, optionalCloneDescription.value)
},
onDismiss = { isCopyDialogOpen.value = false },
)
}
}
@Composable
@@ -321,3 +357,74 @@ private fun RenameDialog(
},
)
}
@Composable
private fun SetCloneDialog(
modifier: Modifier = Modifier,
optionalNewName: String?,
optionalNewDesc: String?,
onCloneNameChange: (String?) -> Unit,
onCloneDescChange: (String?) -> Unit,
onCloneCreate: (customName: String?, customDescription: String?) -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
onDismissRequest = onDismiss,
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = stringRes(R.string.follow_set_copy_dialog_title),
)
}
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(Size5dp),
) {
Text(
text = stringRes(R.string.follow_set_copy_indicator_description),
fontSize = 15.sp,
fontWeight = FontWeight.Light,
fontStyle = FontStyle.Italic,
)
// For the set clone name
TextField(
value = optionalNewName ?: "",
onValueChange = onCloneNameChange,
label = {
Text(text = stringRes(R.string.follow_set_copy_name_label))
},
)
Spacer(modifier = DoubleVertSpacer)
// For the set clone description
TextField(
value = optionalNewDesc ?: "",
onValueChange = onCloneDescChange,
label = {
Text(text = stringRes(R.string.follow_set_copy_desc_label))
},
)
}
},
confirmButton = {
Button(
onClick = {
onCloneCreate(optionalNewName, optionalNewDesc)
onDismiss()
},
) {
Text(stringRes(R.string.follow_set_copy_action_btn_label))
}
},
dismissButton = {
Button(
onClick = onDismiss,
) {
Text(stringRes(R.string.cancel))
}
},
)
}

View File

@@ -51,6 +51,7 @@ fun FollowSetFeedView(
onRefresh: () -> Unit = {},
onOpenItem: (String) -> Unit = {},
onRenameItem: (targetSet: FollowSet, newName: String) -> Unit,
onItemClone: (followSet: FollowSet, customName: String?, customDesc: String?) -> Unit,
onDeleteItem: (followSet: FollowSet) -> Unit,
) {
when (followSetFeedState) {
@@ -63,6 +64,7 @@ fun FollowSetFeedView(
onRefresh = onRefresh,
onItemClick = onOpenItem,
onItemRename = onRenameItem,
onItemClone = onItemClone,
onItemDelete = onDeleteItem,
)
}
@@ -91,6 +93,7 @@ fun FollowSetLoaded(
onRefresh: () -> Unit = {},
onItemClick: (itemIdentifier: String) -> Unit = {},
onItemRename: (followSet: FollowSet, newName: String) -> Unit,
onItemClone: (followSet: FollowSet, customName: String?, customDesc: String?) -> Unit,
onItemDelete: (followSet: FollowSet) -> Unit,
) {
Log.d("FollowSetComposable", "FollowSetLoaded: Follow Set size: ${loadedFeedState.size}")
@@ -113,6 +116,9 @@ fun FollowSetLoaded(
onFollowSetRename = {
onItemRename(set, it)
},
onFollowSetClone = { cloneName, cloneDescription ->
onItemClone(set, cloneName, cloneDescription)
},
onFollowSetDelete = {
onItemDelete(set)
},

View File

@@ -534,9 +534,14 @@
<string name="follow_set_creation_item_label">New list with %1$s membership</string>
<string name="follow_set_creation_item_description">Creates a new follow set, and adds %1$s as a %2$s member.</string>
<string name="follow_set_creation_dialog_title">New Follow Set</string>
<string name="follow_set_copy_dialog_title">Copy/Clone Follow Set</string>
<string name="follow_set_copy_indicator_description">You can set a custom name/description for this clone set below.</string>
<string name="follow_set_creation_name_label">Set name</string>
<string name="follow_set_copy_name_label">(Original Set name)</string>
<string name="follow_set_creation_desc_label">Set description(optional)</string>
<string name="follow_set_copy_desc_label">(Original Set description)</string>
<string name="follow_set_creation_action_btn_label">Create set</string>
<string name="follow_set_copy_action_btn_label">Copy/Clone set</string>
<string name="follow_set_rename_btn_label">Rename set</string>
<string name="follow_set_rename_dialog_indicator_first_part">You are renaming from </string>
<string name="follow_set_rename_dialog_indicator_second_part"> to..</string>