add a save annotation view

This commit is contained in:
Satindar Dhillon
2022-09-27 09:30:20 -07:00
parent aac794949c
commit f6376b929f
4 changed files with 151 additions and 32 deletions

View File

@ -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
}

View File

@ -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")
}
}
}
}

View File

@ -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
}

View File

@ -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
}
}