From 4e87d55b2724c58486fc6abf1263e998fb411fd8 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Thu, 27 Apr 2023 17:11:43 +0800 Subject: [PATCH] New Label chips, show label selector in a bottom sheet --- android/Omnivore/app/build.gradle | 4 +- .../omnivore/ui/components/LabelChip.kt | 33 ++++ .../ui/components/LabelsSelectionSheet.kt | 183 +++++++++++------- .../omnivore/omnivore/ui/reader/WebReader.kt | 6 - .../ui/reader/WebReaderLoadingContainer.kt | 19 +- .../ui/savedItemViews/SavedItemCard.kt | 18 +- 6 files changed, 161 insertions(+), 102 deletions(-) create mode 100644 android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelChip.kt diff --git a/android/Omnivore/app/build.gradle b/android/Omnivore/app/build.gradle index b3c8f5ed1..e59527202 100644 --- a/android/Omnivore/app/build.gradle +++ b/android/Omnivore/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "app.omnivore.omnivore" minSdk 26 targetSdk 33 - versionCode 46 - versionName "0.0.46" + versionCode 49 + versionName "0.0.49" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelChip.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelChip.kt new file mode 100644 index 000000000..5f56c3c23 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/LabelChip.kt @@ -0,0 +1,33 @@ +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.toggleable +import androidx.compose.material.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import app.omnivore.omnivore.ui.components.LabelChipColors + +@Composable +fun LabelChip( + name: String, + colors: LabelChipColors, + onSelectionChanged: (String) -> Unit = {}, +) { + Surface( + modifier = Modifier.padding(4.dp), + shape = MaterialTheme.shapes.medium, + color = colors.containerColor + ) { + Row(modifier = Modifier + ) { + Text( + text = name, + color = colors.textColor, + style = MaterialTheme.typography.subtitle2, + modifier = Modifier.padding(vertical = 3.dp, horizontal = 5.dp) + ) + } + } +} 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 index f441e0172..9d4a05d41 100644 --- 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 @@ -1,20 +1,31 @@ +@file:OptIn(ExperimentalMaterialApi::class) + package app.omnivore.omnivore.ui.components +import LabelChip 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.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.ModalBottomSheetLayout +import androidx.compose.material.ModalBottomSheetValue import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AddCircle import androidx.compose.material.icons.filled.Check +import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog @@ -29,28 +40,37 @@ fun WebReaderLabelsSelectionSheet(viewModel: WebReaderViewModel) { val labels: List by viewModel.savedItemLabelsLiveData.observeAsState(listOf()) val webReaderParams: WebReaderParams? by viewModel.webReaderParamsLiveData.observeAsState(null) + val modalBottomSheetState = rememberModalBottomSheetState( + ModalBottomSheetValue.HalfExpanded, + confirmStateChange = { false } + ) + if (isActive) { - Dialog(onDismissRequest = { - viewModel.showLabelsSelectionSheetLiveData.value = false - } ) { - LabelsSelectionSheetContent( - labels = labels, - initialSelectedLabels = webReaderParams?.labels ?: listOf(), - onCancel = { - viewModel.showLabelsSelectionSheetLiveData.value = false - }, - isLibraryMode = false, - onSave = { - if (it != labels) { - viewModel.updateSavedItemLabels(savedItemID = webReaderParams?.item?.savedItemId ?: "", labels = it) - } - viewModel.showLabelsSelectionSheetLiveData.value = false - }, - onCreateLabel = { newLabelName, labelHexValue -> - viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) + ModalBottomSheetLayout( + sheetBackgroundColor = Color.Transparent, + sheetState = modalBottomSheetState, + sheetContent = { + BottomSheetUI { + LabelsSelectionSheetContent( + labels = labels, + initialSelectedLabels = webReaderParams?.labels ?: listOf(), + onCancel = { + viewModel.showLabelsSelectionSheetLiveData.value = false + }, + isLibraryMode = false, + onSave = { + if (it != labels) { + viewModel.updateSavedItemLabels(savedItemID = webReaderParams?.item?.savedItemId ?: "", labels = it) + } + viewModel.showLabelsSelectionSheetLiveData.value = false + }, + onCreateLabel = { newLabelName, labelHexValue -> + viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) + } + ) } - ) - } + } + ) {} } } @@ -60,48 +80,59 @@ fun LabelsSelectionSheet(viewModel: LibraryViewModel) { val labels: List by viewModel.savedItemLabelsLiveData.observeAsState(listOf()) val currentSavedItemData = viewModel.currentSavedItemUnderEdit() + val modalBottomSheetState = rememberModalBottomSheetState( + ModalBottomSheetValue.HalfExpanded, + confirmStateChange = { it != ModalBottomSheetValue.Hidden } + ) + if (isActive) { - Dialog(onDismissRequest = { - viewModel.labelsSelectionCurrentItemLiveData.value = null - viewModel.showLabelsSelectionSheetLiveData.value = false - } ) { - if (currentSavedItemData != null) { - LabelsSelectionSheetContent( - labels = labels, - initialSelectedLabels = currentSavedItemData.labels, - onCancel = { - viewModel.showLabelsSelectionSheetLiveData.value = false - viewModel.labelsSelectionCurrentItemLiveData.value = null - }, - isLibraryMode = false, - onSave = { - if (it != labels) { - viewModel.updateSavedItemLabels(savedItemID = currentSavedItemData.savedItem.savedItemId, labels = it) - } - viewModel.labelsSelectionCurrentItemLiveData.value = null - viewModel.showLabelsSelectionSheetLiveData.value = false - }, - onCreateLabel = { newLabelName, labelHexValue -> - viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) + ModalBottomSheetLayout( + sheetBackgroundColor = Color.Transparent, + sheetState = modalBottomSheetState, + sheetContent = { + BottomSheetUI { + if (currentSavedItemData != null) { + LabelsSelectionSheetContent( + labels = labels, + initialSelectedLabels = currentSavedItemData.labels, + onCancel = { + viewModel.showLabelsSelectionSheetLiveData.value = false + viewModel.labelsSelectionCurrentItemLiveData.value = null + }, + isLibraryMode = false, + onSave = { + if (it != labels) { + viewModel.updateSavedItemLabels( + savedItemID = currentSavedItemData.savedItem.savedItemId, + labels = it + ) + } + viewModel.labelsSelectionCurrentItemLiveData.value = null + viewModel.showLabelsSelectionSheetLiveData.value = false + }, + onCreateLabel = { newLabelName, labelHexValue -> + viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) + } + ) + } else { // Is used in library mode + LabelsSelectionSheetContent( + labels = labels, + initialSelectedLabels = viewModel.activeLabelsLiveData.value ?: listOf(), + onCancel = { viewModel.showLabelsSelectionSheetLiveData.value = false }, + isLibraryMode = true, + onSave = { + viewModel.updateAppliedLabels(it) + viewModel.labelsSelectionCurrentItemLiveData.value = null + viewModel.showLabelsSelectionSheetLiveData.value = false + }, + onCreateLabel = { newLabelName, labelHexValue -> + viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) + } + ) } - ) - } else { // Is used in library mode - LabelsSelectionSheetContent( - labels = labels, - initialSelectedLabels = viewModel.activeLabelsLiveData.value ?: listOf(), - onCancel = { viewModel.showLabelsSelectionSheetLiveData.value = false }, - isLibraryMode = true, - onSave = { - viewModel.updateAppliedLabels(it) - viewModel.labelsSelectionCurrentItemLiveData.value = null - viewModel.showLabelsSelectionSheetLiveData.value = false - }, - onCreateLabel = { newLabelName, labelHexValue -> - viewModel.createNewSavedItemLabel(newLabelName, labelHexValue) - } - ) + } } - } + ) {} } } @@ -125,7 +156,6 @@ fun LabelsSelectionSheetContent( modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background), - shape = RoundedCornerShape(16.dp) ) { if (showCreateLabelDialog) { @@ -142,8 +172,9 @@ fun LabelsSelectionSheetContent( verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier + // .verticalScroll(rememberScrollState()) .fillMaxSize() - .padding(horizontal = 6.dp) + .padding(horizontal = 0.dp) ) { Row( horizontalArrangement = Arrangement.SpaceBetween, @@ -158,7 +189,7 @@ fun LabelsSelectionSheetContent( Text(titleText, fontWeight = FontWeight.ExtraBold) TextButton(onClick = { onSave(selectedLabels.value) }) { - Text(text = "Done") + Text(text = "Save") } } LazyColumn( @@ -184,19 +215,13 @@ fun LabelsSelectionSheetContent( selectedLabels.value = selectedLabels.value + listOf(label) } } - .padding(horizontal = 6.dp) + .padding(horizontal = 10.dp, vertical = 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 - ) + LabelChip( + name = label.name, + colors = chipColors ) if (isLabelSelected) { Icon( @@ -233,3 +258,17 @@ fun LabelsSelectionSheetContent( } } } + +@Composable +private fun BottomSheetUI(content: @Composable () -> Unit) { + Box( + modifier = Modifier + .wrapContentHeight() + .fillMaxWidth() + .clip(RoundedCornerShape(topEnd = 20.dp, topStart = 20.dp)) + .background(Color.White) + .statusBarsPadding() + ) { + content() + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt index 3c1294c1b..c4576e921 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReader.kt @@ -39,16 +39,10 @@ fun WebReader( .observeAsState(UUID.randomUUID()) WebView.setWebContentsDebuggingEnabled(true) - val isInDarkMode = preferences.themeKey == "Dark" || preferences.themeKey == "Black" Box { AndroidView(factory = { OmnivoreWebView(it).apply { - if (isInDarkMode) { - setBackgroundColor(Color.Transparent.hashCode()) - } else { - setBackgroundColor(Color.White.hashCode()) - } viewModel = webReaderViewModel layoutParams = ViewGroup.LayoutParams( diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt index a73c3e2ca..5230b381e 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/reader/WebReaderLoadingContainer.kt @@ -122,17 +122,14 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null, o webReaderViewModel.maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() } webReaderViewModel.loadItem(slug = slug, requestID = requestID) - val styledContent = - if (webReaderParams != null) { - val webReaderContent = WebReaderContent( - preferences = webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()), - item = webReaderParams!!.item, - articleContent = webReaderParams!!.articleContent, - ) - webReaderContent.styledContent() - } else { - null - } + val styledContent = webReaderParams?.let { + val webReaderContent = WebReaderContent( + preferences = webReaderViewModel.storedWebPreferences(isSystemInDarkTheme()), + item = it.item, + articleContent = it.articleContent, + ) + webReaderContent.styledContent() + } ?: null Box( modifier = Modifier diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt index 2cfc42db2..1144ced03 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/savedItemViews/SavedItemCard.kt @@ -1,5 +1,6 @@ package app.omnivore.omnivore.ui.savedItemViews +import LabelChip import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow @@ -102,21 +103,16 @@ fun SavedItemCard(savedItemViewModel: SavedItemViewModel, savedItem: SavedItemWi horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.CenterVertically, modifier = Modifier - .padding(start = 10.dp, bottom = 5.dp, end = 10.dp) + .padding(start = 5.dp, bottom = 5.dp, end = 10.dp) ) { items(savedItem.labels.sortedBy { it.name }) { label -> val chipColors = LabelChipColors.fromHex(label.color) - SuggestionChip( - onClick = onClickHandler, - label = { Text(label.name) }, - border = null, - colors = elevatedSuggestionChipColors( - containerColor = chipColors.containerColor, - labelColor = chipColors.textColor, - iconContentColor = chipColors.textColor - ), - modifier = Modifier.padding(end = 5.dp) + LabelChip( + // onClick = onClickHandler, + name = label.name, + colors = chipColors, + // modifier = Modifier.padding(end = 5.dp) ) }