Merge pull request #2874 from remychantenay/android-highlight-color-palette
Android: Add Highlight color palette for web reader
This commit is contained in:
@ -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 {
|
||||
|
||||
@ -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),
|
||||
)
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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),
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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" -> {
|
||||
|
||||
Reference in New Issue
Block a user