diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsSelectionSheet.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsSelectionSheet.kt new file mode 100644 index 000000000..28af4a225 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelsSelectionSheet.kt @@ -0,0 +1,124 @@ +package app.omnivore.omnivore.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import app.omnivore.omnivore.persistence.entities.SavedItemLabel +import app.omnivore.omnivore.ui.library.LibraryViewModel + +@Composable +fun LabelsSelectionSheet(viewModel: LibraryViewModel) { + val isActive: Boolean by viewModel.showLabelsSelectionSheetLiveData.observeAsState(false) + + if (isActive) { + Dialog(onDismissRequest = { viewModel.showLabelsSelectionSheetLiveData.value = false } ) { + LabelsSelectionSheetContent(viewModel = viewModel, initialSelectedLabels = viewModel.activeLabelsLiveData.value ?: listOf()) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun LabelsSelectionSheetContent(viewModel: LibraryViewModel, initialSelectedLabels: List) { + val listState = rememberLazyListState() + val labels: List by viewModel.savedItemLabelsLiveData.observeAsState(listOf()) + val selectedLabels = remember { mutableStateOf(initialSelectedLabels) } + + Surface( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background), + shape = RoundedCornerShape(16.dp) + ) { + LazyColumn( + state = listState, + verticalArrangement = Arrangement.Top, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 6.dp) + ) { + item { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + ) { + TextButton(onClick = { viewModel.showLabelsSelectionSheetLiveData.value = false }) { + Text(text = "Cancel") + } + + Text("Filter by Label", fontWeight = FontWeight.ExtraBold) + + TextButton( + onClick = { + selectedLabels.value?.let { + viewModel.updateAppliedLabels(it) + } + viewModel.showLabelsSelectionSheetLiveData.value = false + } + ) { + Text(text = "Done") + } + } + } + items(labels) { label -> + val isLabelSelected = (selectedLabels.value ?: listOf()).contains(label) + + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .clickable { + if (isLabelSelected) { + selectedLabels.value = (selectedLabels.value + ?: listOf()).filter { it.savedItemLabelId != label.savedItemLabelId } + } else { + selectedLabels.value = (selectedLabels.value ?: listOf()) + listOf(label) + } + } + .padding(horizontal = 6.dp) + ) { + val chipColors = LabelChipColors.fromHex(label.color) + + SuggestionChip( + onClick = {}, + label = { Text(label.name) }, + border = null, + colors = SuggestionChipDefaults.elevatedSuggestionChipColors( + containerColor = chipColors.containerColor, + labelColor = chipColors.textColor, + iconContentColor = chipColors.textColor + ) + ) + if (isLabelSelected) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = null + ) + } + } + Divider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp) + } + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryView.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryView.kt index c1e89f1e9..a14260f6d 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryView.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryView.kt @@ -30,6 +30,7 @@ import app.omnivore.omnivore.Routes import app.omnivore.omnivore.persistence.entities.SavedItemCardDataWithLabels import app.omnivore.omnivore.persistence.entities.SavedItemLabel import app.omnivore.omnivore.ui.components.LabelChipColors +import app.omnivore.omnivore.ui.components.LabelsSelectionSheet import app.omnivore.omnivore.ui.savedItemViews.SavedItemCard import app.omnivore.omnivore.ui.reader.PDFReaderActivity import app.omnivore.omnivore.ui.reader.WebReaderLoadingContainerActivity @@ -153,103 +154,3 @@ fun InfiniteListHandler( } } } - -@Composable -fun LabelsSelectionSheet(viewModel: LibraryViewModel) { - val isActive: Boolean by viewModel.showLabelsSelectionSheetLiveData.observeAsState(false) - - if (isActive) { - Dialog(onDismissRequest = { viewModel.showLabelsSelectionSheetLiveData.value = false } ) { - LabelsSelectionSheetContent(viewModel = viewModel, initialSelectedLabels = viewModel.activeLabelsLiveData.value ?: listOf()) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun LabelsSelectionSheetContent(viewModel: LibraryViewModel, initialSelectedLabels: List) { - val listState = rememberLazyListState() - val labels: List by viewModel.savedItemLabelsLiveData.observeAsState(listOf()) - val selectedLabels = remember { mutableStateOf(initialSelectedLabels) } - - Surface( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background), - shape = RoundedCornerShape(16.dp) - ) { - LazyColumn( - state = listState, - verticalArrangement = Arrangement.Top, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 6.dp) - ) { - item { - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - ) { - TextButton(onClick = { viewModel.showLabelsSelectionSheetLiveData.value = false }) { - Text(text = "Cancel") - } - - Text("Filter by Label", fontWeight = FontWeight.ExtraBold) - - TextButton( - onClick = { - selectedLabels.value?.let { - viewModel.updateAppliedLabels(it) - } - viewModel.showLabelsSelectionSheetLiveData.value = false - } - ) { - Text(text = "Done") - } - } - } - items(labels) { label -> - val isLabelSelected = (selectedLabels.value ?: listOf()).contains(label) - - Row( - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .fillMaxWidth() - .clickable { - if (isLabelSelected) { - selectedLabels.value = (selectedLabels.value - ?: listOf()).filter { it.savedItemLabelId != label.savedItemLabelId } - } else { - selectedLabels.value = (selectedLabels.value ?: listOf()) + listOf(label) - } - } - .padding(horizontal = 6.dp) - ) { - val chipColors = LabelChipColors.fromHex(label.color) - - SuggestionChip( - onClick = {}, - label = { Text(label.name) }, - border = null, - colors = SuggestionChipDefaults.elevatedSuggestionChipColors( - containerColor = chipColors.containerColor, - labelColor = chipColors.textColor, - iconContentColor = chipColors.textColor - ) - ) - if (isLabelSelected) { - Icon( - imageVector = Icons.Default.Check, - contentDescription = null - ) - } - } - Divider(color = MaterialTheme.colorScheme.outlineVariant, thickness = 1.dp) - } - } - } -} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt index ca67daabd..5808462fb 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/library/LibraryViewModel.kt @@ -260,6 +260,9 @@ class LibraryViewModel @Inject constructor( dataService.unarchiveSavedItem(itemID) } } + SavedItemAction.EditLabels -> { + Log.d("label", "itemID") + } } } @@ -283,5 +286,6 @@ class LibraryViewModel @Inject constructor( enum class SavedItemAction { Delete, Archive, - Unarchive + Unarchive, + EditLabels } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt index 612d45af4..d3de2c1aa 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderViewModel.kt @@ -157,6 +157,9 @@ class WebReaderViewModel @Inject constructor( popToLibraryView() } } + SavedItemAction.EditLabels -> { + Log.d("label", "itemID") + } } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemContextMenu.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemContextMenu.kt index 7725d62d7..450b3e767 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemContextMenu.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemContextMenu.kt @@ -1,6 +1,7 @@ package app.omnivore.omnivore.ui.savedItemViews import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.CheckCircle import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.List import androidx.compose.material3.DropdownMenu @@ -21,6 +22,19 @@ fun SavedItemContextMenu( expanded = isExpanded, onDismissRequest = onDismiss ) { + DropdownMenuItem( + text = { Text("Edit Labels") }, + onClick = { + actionHandler(SavedItemAction.EditLabels) + onDismiss() + }, + leadingIcon = { + Icon( + Icons.Outlined.CheckCircle, // TODO: use more appropriate icon + contentDescription = null + ) + } + ) DropdownMenuItem( text = { Text(if (isArchived) "Unarchive" else "Archive") }, onClick = {