add a save annotation view
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
package app.omnivore.omnivore.networking
|
||||
|
||||
import android.util.Log
|
||||
import app.omnivore.omnivore.graphql.generated.CreateHighlightMutation
|
||||
import app.omnivore.omnivore.graphql.generated.type.CreateHighlightInput
|
||||
import com.apollographql.apollo3.api.Optional
|
||||
@ -23,10 +24,13 @@ data class CreateHighlightParams(
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun Networker.createHighlight(jsonString: String) {
|
||||
suspend fun Networker.createHighlight(jsonString: String): Boolean {
|
||||
val input = Gson().fromJson(jsonString, CreateHighlightParams::class.java).asCreateHighlightInput()
|
||||
|
||||
authenticatedApolloClient().mutation(
|
||||
CreateHighlightMutation(input)
|
||||
).execute()
|
||||
Log.d("Loggo", "created highlight input: $input")
|
||||
|
||||
val result = authenticatedApolloClient().mutation(CreateHighlightMutation(input)).execute()
|
||||
|
||||
val highlight = result.data?.createHighlight?.onCreateHighlightSuccess?.highlight
|
||||
return highlight != null
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
package app.omnivore.omnivore.ui.reader
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
// TODO: better layout and styling for this view
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AnnotationEditView(
|
||||
initialAnnotation: String,
|
||||
onSave: (String) -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
) {
|
||||
val annotation = remember { mutableStateOf(initialAnnotation) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.padding(8.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
) {
|
||||
Text(text = "Note")
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TextField(
|
||||
value = annotation.value,
|
||||
onValueChange = { annotation.value = it }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.align(Alignment.End)
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
onCancel()
|
||||
}
|
||||
) {
|
||||
Text("Cancel")
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
onSave(annotation.value)
|
||||
}
|
||||
) {
|
||||
Text("Save")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,7 @@ import android.view.*
|
||||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -28,7 +29,7 @@ fun WebReaderLoadingContainer(slug: String, webReaderViewModel: WebReaderViewMod
|
||||
if (webReaderParams != null) {
|
||||
WebReader(webReaderParams!!, webReaderViewModel)
|
||||
} else {
|
||||
// TODO: add a proper loading viewhandleIncomingWebMessage
|
||||
// TODO: add a proper loading view
|
||||
Text("Loading...")
|
||||
}
|
||||
}
|
||||
@ -36,6 +37,8 @@ fun WebReaderLoadingContainer(slug: String, webReaderViewModel: WebReaderViewMod
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Composable
|
||||
fun WebReader(params: WebReaderParams, webReaderViewModel: WebReaderViewModel) {
|
||||
val annotation: String? by webReaderViewModel.annotationLiveData.observeAsState(null)
|
||||
|
||||
WebView.setWebContentsDebuggingEnabled(true)
|
||||
|
||||
val webReaderContent = WebReaderContent(
|
||||
@ -51,32 +54,57 @@ fun WebReader(params: WebReaderParams, webReaderViewModel: WebReaderViewModel) {
|
||||
|
||||
val styledContent = webReaderContent.styledContent()
|
||||
|
||||
AndroidView(factory = {
|
||||
OmnivoreWebView(it).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
Box {
|
||||
AndroidView(factory = {
|
||||
OmnivoreWebView(it).apply {
|
||||
layoutParams = ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
settings.javaScriptEnabled = true
|
||||
settings.allowContentAccess = true
|
||||
settings.allowFileAccess = true
|
||||
settings.domStorageEnabled = true
|
||||
|
||||
webViewClient = object : WebViewClient() {
|
||||
}
|
||||
|
||||
val javascriptInterface = AndroidWebKitMessenger { actionID, json ->
|
||||
webReaderViewModel.handleIncomingWebMessage(actionID, json)
|
||||
}
|
||||
|
||||
addJavascriptInterface(javascriptInterface, "AndroidWebKitMessenger")
|
||||
loadDataWithBaseURL(
|
||||
"file:///android_asset/",
|
||||
styledContent,
|
||||
"text/html; charset=utf-8",
|
||||
"utf-8",
|
||||
null
|
||||
);
|
||||
|
||||
}
|
||||
}, update = {
|
||||
it.loadDataWithBaseURL(
|
||||
"file:///android_asset/",
|
||||
styledContent,
|
||||
"text/html; charset=utf-8",
|
||||
"utf-8",
|
||||
null
|
||||
);
|
||||
})
|
||||
|
||||
if (annotation != null) {
|
||||
AnnotationEditView(
|
||||
initialAnnotation = annotation!!,
|
||||
onSave = { Log.d("Loggo", "Saving annotation: $it") },
|
||||
onCancel = {
|
||||
Log.d("Loggo", "Cancelling annotation")
|
||||
webReaderViewModel.cancelAnnotationEdit()
|
||||
}
|
||||
)
|
||||
|
||||
settings.javaScriptEnabled = true
|
||||
settings.allowContentAccess = true
|
||||
settings.allowFileAccess = true
|
||||
settings.domStorageEnabled = true
|
||||
|
||||
webViewClient = object : WebViewClient() {
|
||||
}
|
||||
|
||||
val javascriptInterface = AndroidWebKitMessenger { actionID, json ->
|
||||
webReaderViewModel.handleIncomingWebMessage(actionID, json)
|
||||
}
|
||||
|
||||
addJavascriptInterface(javascriptInterface, "AndroidWebKitMessenger")
|
||||
loadDataWithBaseURL("file:///android_asset/", styledContent, "text/html; charset=utf-8", "utf-8", null);
|
||||
|
||||
}
|
||||
}, update = {
|
||||
it.loadDataWithBaseURL("file:///android_asset/", styledContent, "text/html; charset=utf-8", "utf-8", null);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class OmnivoreWebView(context: Context) : WebView(context) {
|
||||
@ -97,7 +125,9 @@ class OmnivoreWebView(context: Context) : WebView(context) {
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.annotate -> {
|
||||
Log.d("Loggo", "Annotate action selected")
|
||||
val script = "var event = new Event('annotate');document.dispatchEvent(event);"
|
||||
evaluateJavascript(script, null) // Maybe this one isn't needed?
|
||||
// TODO: open note modal
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.DatastoreRepository
|
||||
import app.omnivore.omnivore.models.LinkedItem
|
||||
import app.omnivore.omnivore.networking.CreateHighlightParams
|
||||
import app.omnivore.omnivore.networking.Networker
|
||||
import app.omnivore.omnivore.networking.createHighlight
|
||||
import app.omnivore.omnivore.networking.linkedItem
|
||||
@ -20,12 +21,17 @@ data class WebReaderParams(
|
||||
val articleContent: ArticleContent
|
||||
)
|
||||
|
||||
data class AnnotationWebViewMessage(
|
||||
val annotation: String?
|
||||
)
|
||||
|
||||
@HiltViewModel
|
||||
class WebReaderViewModel @Inject constructor(
|
||||
private val datastoreRepo: DatastoreRepository,
|
||||
private val networker: Networker
|
||||
): ViewModel() {
|
||||
val webReaderParamsLiveData = MutableLiveData<WebReaderParams?>(null)
|
||||
val annotationLiveData = MutableLiveData<String?>(null)
|
||||
|
||||
fun loadItem(slug: String) {
|
||||
viewModelScope.launch {
|
||||
@ -50,7 +56,8 @@ class WebReaderViewModel @Inject constructor(
|
||||
when (actionID) {
|
||||
"createHighlight" -> {
|
||||
viewModelScope.launch {
|
||||
networker.createHighlight(jsonString)
|
||||
val isHighlightSynced = networker.createHighlight(jsonString)
|
||||
Log.d("Network", "isHighlightSynced = $isHighlightSynced")
|
||||
}
|
||||
}
|
||||
"deleteHighlight" -> {
|
||||
@ -64,7 +71,12 @@ class WebReaderViewModel @Inject constructor(
|
||||
Log.d("Loggo", "received article reading progress action: $jsonString")
|
||||
}
|
||||
"annotate" -> {
|
||||
Log.d("Loggo", "received annotate action: $jsonString")
|
||||
viewModelScope.launch {
|
||||
val annotation = Gson()
|
||||
.fromJson(jsonString, AnnotationWebViewMessage::class.java)
|
||||
.annotation ?: ""
|
||||
annotationLiveData.value = annotation
|
||||
}
|
||||
}
|
||||
"existingHighlightTap" -> {
|
||||
Log.d("Loggo", "receive existing highlight tap action: $jsonString")
|
||||
@ -80,5 +92,10 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun reset() {
|
||||
webReaderParamsLiveData.value = null
|
||||
annotationLiveData.value = null
|
||||
}
|
||||
|
||||
fun cancelAnnotationEdit() {
|
||||
annotationLiveData.value = null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user