diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/dataService/HighlightActionHandlers.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/dataService/HighlightActionHandlers.kt index cb6ac4393..d92975f89 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/dataService/HighlightActionHandlers.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/dataService/HighlightActionHandlers.kt @@ -12,7 +12,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.util.* -suspend fun DataService.createWebHighlight(jsonString: String) { +suspend fun DataService.createWebHighlight(jsonString: String, colorName: String?) { val createHighlightInput = Gson().fromJson(jsonString, CreateHighlightParams::class.java).asCreateHighlightInput() withContext(Dispatchers.IO) { @@ -28,7 +28,7 @@ suspend fun DataService.createWebHighlight(jsonString: String) { createdAt = null, updatedAt = null, createdByMe = false, - color = null, + color = colorName ?: createHighlightInput.color.getOrNull(), ) highlight.serverSyncStatus = ServerSyncStatus.NEEDS_CREATION.rawValue @@ -80,13 +80,13 @@ suspend fun DataService.createNoteHighlight(savedItemId: String, note: String): db.savedItemAndHighlightCrossRefDao().insertAll(listOf(crossRef)) val newHighlight = networker.createHighlight(input = CreateHighlightParams( - type = HighlightType.NOTE, - articleId = savedItemId, - id = createHighlightId, - shortId = shortId, - quote = null, - patch = null, - annotation = note, + type = HighlightType.NOTE, + articleId = savedItemId, + id = createHighlightId, + shortId = shortId, + quote = null, + patch = null, + annotation = note, ).asCreateHighlightInput()) newHighlight?.let { diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColor.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColor.kt new file mode 100644 index 000000000..666489828 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColor.kt @@ -0,0 +1,8 @@ +package app.omnivore.omnivore.ui.components + +import androidx.compose.ui.graphics.Color + +data class HighlightColor( + val name: String = "yellow", + val color: Color = Color(0xFFFFD234), +) diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPalette.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPalette.kt new file mode 100644 index 000000000..c8bf10ba5 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPalette.kt @@ -0,0 +1,48 @@ +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import app.omnivore.omnivore.ui.components.HighlightColor +import app.omnivore.omnivore.ui.components.HighlightColorPaletteMode + +@Composable +fun HighlightColorPalette( + mode: HighlightColorPaletteMode = HighlightColorPaletteMode.Light, + selectedColorName: String, + onColorSelected: (color: HighlightColor) -> Unit, + modifier: Modifier = Modifier, +) { + Surface( + modifier = modifier, + shape = RoundedCornerShape(8.dp), + color = mode.backgroundColor, + shadowElevation = 9.dp + ) { + Row(modifier = Modifier.padding(8.dp, 2.dp, 8.dp, 2.dp)) { + HighlightColorPaletteItem( + color = HighlightColor(name = "yellow", Color(0xFFFFD234)), + isSelected = "yellow" == selectedColorName, + onClick = onColorSelected + ) + HighlightColorPaletteItem( + color = HighlightColor(name = "red", Color(0xFFFB9A9A)), + isSelected = "red" == selectedColorName, + onClick = onColorSelected + ) + HighlightColorPaletteItem( + color = HighlightColor(name = "green", Color(0xFF55C689)), + isSelected = "green" == selectedColorName, + onClick = onColorSelected + ) + HighlightColorPaletteItem( + color = HighlightColor(name = "blue", Color(0xFF6AB1FF)), + isSelected = "blue" == selectedColorName, + onClick = onColorSelected + ) + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteItem.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteItem.kt new file mode 100644 index 000000000..24fe75435 --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteItem.kt @@ -0,0 +1,47 @@ +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +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.unit.dp +import app.omnivore.omnivore.ui.components.HighlightColor + +@Composable +fun HighlightColorPaletteItem( + color: HighlightColor, + isSelected: Boolean, + onClick: (color: HighlightColor) -> Unit, + modifier: Modifier = Modifier.padding(6.dp) +) { + Column ( + modifier = modifier, + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(color.color) + .clickable { onClick(color) } + ) + { + if (isSelected) { + Icon( + Icons.Rounded.Check, + contentDescription = "checkIcon", + tint = Color.DarkGray, + modifier = Modifier.align(Alignment.Center) + ) + } + } + } +} diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteMode.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteMode.kt new file mode 100644 index 000000000..29eca575d --- /dev/null +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/ui/components/HighlightColorPaletteMode.kt @@ -0,0 +1,7 @@ +package app.omnivore.omnivore.ui.components + +import androidx.compose.ui.graphics.Color +enum class HighlightColorPaletteMode(val backgroundColor: Color) { + Light(Color.White), + Dark(Color.Black), +} 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 078c85b3a..8a1372802 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 @@ -1,5 +1,6 @@ package app.omnivore.omnivore.ui.reader +import HighlightColorPalette import android.annotation.SuppressLint import android.content.ClipData import android.content.ClipboardManager @@ -18,8 +19,12 @@ import androidx.compose.foundation.layout.* 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.unit.dp import androidx.compose.ui.viewinterop.AndroidView import app.omnivore.omnivore.R +import app.omnivore.omnivore.ui.components.HighlightColorPaletteMode import com.google.gson.Gson import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -40,6 +45,9 @@ fun WebReader( WebView.setWebContentsDebuggingEnabled(true) + val showHighlightColorPalette = webReaderViewModel.showHighlightColorPalette.observeAsState() + val highlightColor = webReaderViewModel.highlightColor.observeAsState() + Box { AndroidView(factory = { OmnivoreWebView(it).apply { @@ -144,6 +152,18 @@ fun WebReader( webReaderViewModel.resetJavascriptDispatchQueue() } }) + if (showHighlightColorPalette.value == true) { + HighlightColorPalette( + mode = if (isDarkMode) HighlightColorPaletteMode.Dark else HighlightColorPaletteMode.Light, + selectedColorName = highlightColor.value?.name ?: "yellow", + onColorSelected = { + webReaderViewModel.setHighlightColor(it) + }, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(12.dp, 12.dp, 12.dp, 36.dp) + ) + } } } @@ -164,6 +184,7 @@ class OmnivoreWebView(context: Context) : WebView(context), OnScrollChangeListen Log.d("wv", "inflating existing highlight menu") mode.menuInflater.inflate(R.menu.highlight_selection_menu, menu) } else { + viewModel?.showHighlightColorPalette() mode.menuInflater.inflate(R.menu.text_selection_menu, menu) } return true @@ -233,6 +254,7 @@ class OmnivoreWebView(context: Context) : WebView(context), OnScrollChangeListen override fun onDestroyActionMode(mode: ActionMode) { Log.d("wv", "destroying menu: $mode") viewModel?.hasTappedExistingHighlight = false + viewModel?.hideHighlightColorPalette() actionMode = null } 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 0f80b5689..50c01c788 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 @@ -21,6 +21,7 @@ import app.omnivore.omnivore.networking.* import app.omnivore.omnivore.persistence.entities.SavedItem import app.omnivore.omnivore.persistence.entities.SavedItemAndSavedItemLabelCrossRef import app.omnivore.omnivore.persistence.entities.SavedItemLabel +import app.omnivore.omnivore.ui.components.HighlightColor import app.omnivore.omnivore.ui.library.SavedItemAction import com.apollographql.apollo3.api.Optional import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull @@ -77,7 +78,10 @@ class WebReaderViewModel @Inject constructor( var lastTapCoordinates: TapCoordinates? = null private var isLoading = false private var slug: String? = null - + + val showHighlightColorPalette = MutableLiveData(false) + val highlightColor = MutableLiveData(HighlightColor()) + fun loadItem(slug: String?, requestID: String?) { this.slug = slug if (isLoading || webReaderParamsLiveData.value != null) { return } @@ -297,11 +301,30 @@ class WebReaderViewModel @Inject constructor( } } + + fun showHighlightColorPalette() { + CoroutineScope(Dispatchers.Main).launch { + showHighlightColorPalette.postValue(true) + } + } + + fun hideHighlightColorPalette() { + CoroutineScope(Dispatchers.Main).launch { + showHighlightColorPalette.postValue(false) + } + } + + fun setHighlightColor(color: HighlightColor) { + CoroutineScope(Dispatchers.Main).launch { + highlightColor.postValue(color) + } + } + fun handleIncomingWebMessage(actionID: String, jsonString: String) { when (actionID) { "createHighlight" -> { viewModelScope.launch { - dataService.createWebHighlight(jsonString) + dataService.createWebHighlight(jsonString, highlightColor.value?.name) } } "deleteHighlight" -> {