detect merge overlaps properly

This commit is contained in:
Satindar Dhillon
2022-11-06 22:02:02 -08:00
parent cb8cecff47
commit 062f98908f
3 changed files with 93 additions and 32 deletions

View File

@ -3,7 +3,7 @@ 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 app.omnivore.omnivore.graphql.generated.type.Highlight
import app.omnivore.omnivore.models.Highlight
import com.apollographql.apollo3.api.Optional
import com.google.gson.Gson
@ -27,14 +27,30 @@ data class CreateHighlightParams(
suspend fun Networker.createWebHighlight(jsonString: String): Boolean {
val input = Gson().fromJson(jsonString, CreateHighlightParams::class.java).asCreateHighlightInput()
return createHighlight(input)
return createHighlight(input) != null
}
suspend fun Networker.createHighlight(input: CreateHighlightInput): Boolean {
suspend fun Networker.createHighlight(input: CreateHighlightInput): Highlight? {
Log.d("Loggo", "created highlight input: $input")
val result = authenticatedApolloClient().mutation(CreateHighlightMutation(input)).execute()
val highlight = result.data?.createHighlight?.onCreateHighlightSuccess?.highlight
return highlight != null
val createdHighlight = result.data?.createHighlight?.onCreateHighlightSuccess?.highlight
if (createdHighlight != null) {
return Highlight(
id = createdHighlight.highlightFields.id,
shortId = createdHighlight.highlightFields.shortId,
quote = createdHighlight.highlightFields.quote,
prefix = createdHighlight.highlightFields.prefix,
suffix = createdHighlight.highlightFields.suffix,
patch = createdHighlight.highlightFields.patch,
annotation = createdHighlight.highlightFields.annotation,
createdAt = null, // TODO: update gql query to get this
updatedAt = createdHighlight.highlightFields.updatedAt,
createdByMe = createdHighlight.highlightFields.createdByMe,
)
} else {
return null
}
}

View File

@ -16,6 +16,7 @@ import app.omnivore.omnivore.R
import app.omnivore.omnivore.models.Highlight
import com.pspdfkit.annotations.Annotation
import com.pspdfkit.annotations.AnnotationProvider
import com.pspdfkit.annotations.HighlightAnnotation
import com.pspdfkit.configuration.PdfConfiguration
import com.pspdfkit.configuration.activity.ThumbnailBarMode
import com.pspdfkit.configuration.page.PageScrollDirection
@ -93,7 +94,8 @@ class PDFReaderActivity: AppCompatActivity(), DocumentListener {
}
override fun onAnnotationUpdated(annotation: Annotation) {
viewModel.updateHighlight(annotation)
val highlightAnnotation = annotation as? HighlightAnnotation ?: return
viewModel.syncUpdatedAnnotationHighlight(highlightAnnotation, articleID = params.item.id)
}
override fun onAnnotationRemoved(annotation: Annotation) {

View File

@ -15,11 +15,15 @@ import app.omnivore.omnivore.networking.*
import com.apollographql.apollo3.api.Optional
import com.google.gson.Gson
import com.pspdfkit.annotations.Annotation
import com.pspdfkit.annotations.HighlightAnnotation
import com.pspdfkit.document.download.DownloadJob
import com.pspdfkit.document.download.DownloadRequest
import com.pspdfkit.document.download.Progress
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.util.*
import javax.inject.Inject
@ -36,7 +40,8 @@ class PDFReaderViewModel @Inject constructor(
private val networker: Networker
): ViewModel() {
val pdfReaderParamsLiveData = MutableLiveData<PDFReaderParams?>(null)
var annotations: List<Annotation> = listOf()
var annotations: List<HighlightAnnotation> = listOf()
var documentHighlights: MutableList<Highlight> = mutableListOf()
fun loadItem(slug: String, context: Context) {
viewModelScope.launch {
@ -56,6 +61,8 @@ class PDFReaderViewModel @Inject constructor(
}
override fun onComplete(output: File) {
documentHighlights.addAll(0, articleQueryResult.highlights)
val articleContent = ArticleContent(
title = article.title,
htmlContent = article.content ?: "",
@ -79,58 +86,94 @@ class PDFReaderViewModel @Inject constructor(
pdfReaderParamsLiveData.postValue(null)
}
fun createHighlight(annotation: Annotation, articleID: String) {
// TODO: Check for overlapping highlights
fun createHighlight(annotation: Annotation, articleID: String, updateDoc: Boolean = true) {
val highlightID = UUID.randomUUID().toString()
val shortID = UUID.randomUUID().toString().replace("-","").substring(0,8)
val quote = annotation.contents ?: ""
val jsonValues = JSONObject()
.put("id", highlightID)
.put("shortId", shortID)
.put("quote", quote)
.put("articleId", articleID)
val omnivoreHighlight = JSONObject()
.put("omnivoreHighlight", jsonValues)
annotation.customData = omnivoreHighlight
val createHighlightInput = CreateHighlightInput(
annotation = Optional.presentIfNotNull(null),
articleId = articleID,
id = UUID.randomUUID().toString(),
id = highlightID,
patch = annotation.toInstantJson(),
quote = annotation.contents ?: "",
shortId = UUID.randomUUID().toString().replace("-","").substring(0,8),
quote = quote,
shortId = shortID,
)
// val ggg = overlappingHighlights(annotation)
// Log.d("annny", "has ${ggg.count()} overlapping highlights")
viewModelScope.launch {
val isHighlightSynced = networker.createHighlight(createHighlightInput)
Log.d("Network", "isHighlightSynced = $isHighlightSynced")
val highlight = networker.createHighlight(createHighlightInput)
if (highlight != null) {
documentHighlights.add(highlight)
}
}
}
fun updateHighlight(annotation: Annotation) {
Log.d("annny", "updated $annotation")
fun syncUpdatedAnnotationHighlight(annotation: HighlightAnnotation, articleID: String) {
val overlapList = overlappingHighlightIDs(annotation)
// TODO: Delete the overlap list
// Calling create highlight creates a loop...
// createHighlight(annotation, articleID)
}
fun deleteHighlight(annotation: Annotation) {
Log.d("annny", "deleted $annotation")
}
private fun overlappingHighlights(annotation: Annotation): List<Highlight> {
var result: MutableList<Highlight> = mutableListOf()
private fun overlappingHighlightIDs(annotation: HighlightAnnotation): List<String> {
val result: MutableList<String> = mutableListOf()
val highlightID = pluckHighlightID(annotation) ?: return listOf()
for (highlight in pdfReaderParamsLiveData.value?.articleContent?.highlights ?: listOf()) {
if (hasOverlappingHighlights(highlight, annotation)) {
result.add(highlight)
val pageHighlights = documentHighlights.filter {
Gson().fromJson(it.patch, HighlightPatch::class.java).pageIndex == annotation.pageIndex
}
for (highlight in pageHighlights) {
if (highlight.id == highlightID) {
continue
}
val rects = Gson().fromJson(highlight.patch, HighlightPatch::class.java).rects
if (hasOverlaps(annotation.rects, rects)) {
result.add(highlight.id)
}
}
result.add(highlightID)
return result
}
private fun hasOverlappingHighlights(highlight: Highlight, annotation: Annotation): Boolean {
val highlightRects = Gson().fromJson(highlight.patch, HighlightRects::class.java).rects
for (rect in highlightRects) {
if (rect.intersect(annotation.boundingBox)) {
return true
private fun hasOverlaps(leftRects: List<RectF>, rightRects: List<List<Double>>): Boolean {
for (leftRect in leftRects) {
for (rightRect in rightRects) {
val transformedRect = RectF(rightRect[0].toFloat(), rightRect[1].toFloat(), rightRect[2].toFloat(), rightRect[3].toFloat())
if (transformedRect.intersect(leftRect)) {
return true
}
}
}
return false
}
private fun pluckHighlightID(annotation: Annotation): String? {
val omnivoreHighlight = annotation.customData?.get("omnivoreHighlight") as? JSONObject
return omnivoreHighlight?.get("id") as? String
}
}
data class HighlightRects(
val rects: List<RectF>
data class HighlightPatch(
val rects: List<List<Double>>,
val pageIndex: Int
)