Start creating a separate sync queue for android highlight changes

This commit is contained in:
Jackson Harper
2024-01-08 22:27:48 +08:00
parent 8f9f8bb43b
commit cb48c755f1
18 changed files with 175 additions and 43 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,12 +1,17 @@
package app.omnivore.omnivore.dataService
import android.util.Log
import app.omnivore.omnivore.graphql.generated.type.HighlightType
import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.persistence.entities.Highlight
import app.omnivore.omnivore.persistence.entities.SavedItemAndHighlightCrossRef
import app.omnivore.omnivore.persistence.entities.saveHighlightChange
import com.apollographql.apollo3.api.Optional
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.withContext
import java.util.*
@ -33,6 +38,8 @@ suspend fun DataService.createWebHighlight(jsonString: String, colorName: String
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_CREATION.rawValue
saveHighlightChange(db.highlightChangesDao(), createHighlightInput.articleId, highlight)
val crossRef = SavedItemAndHighlightCrossRef(
highlightId = createHighlightInput.id,
savedItemId = createHighlightInput.articleId
@ -73,6 +80,8 @@ suspend fun DataService.createNoteHighlight(savedItemId: String, note: String):
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_CREATION.rawValue
saveHighlightChange(db.highlightChangesDao(), savedItemId, highlight)
val crossRef = SavedItemAndHighlightCrossRef(
highlightId = createHighlightId,
savedItemId = savedItemId
@ -103,18 +112,33 @@ suspend fun DataService.createNoteHighlight(savedItemId: String, note: String):
suspend fun DataService.mergeWebHighlights(jsonString: String) {
val mergeHighlightInput = Gson().fromJson(jsonString, MergeHighlightsParams::class.java).asMergeHighlightInput()
Log.d("sync", "mergeHighlightInput: " + mergeHighlightInput.id + ": " + mergeHighlightInput)
withContext(Dispatchers.IO) {
val highlight = db.highlightDao().findById(highlightId = mergeHighlightInput.id) ?: return@withContext
highlight.shortId = mergeHighlightInput.shortId
highlight.quote = mergeHighlightInput.quote
highlight.patch = mergeHighlightInput.patch
highlight.prefix = mergeHighlightInput.prefix.getOrNull()
highlight.annotation = mergeHighlightInput.annotation.getOrNull()
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
val highlight = Highlight(
type = "HIGHLIGHT",
highlightId = mergeHighlightInput.id,
shortId = mergeHighlightInput.shortId,
quote = mergeHighlightInput.quote,
prefix = null,
suffix = null,
patch = mergeHighlightInput.patch,
annotation = mergeHighlightInput.annotation.getOrNull(),
createdAt = null,
updatedAt = null,
createdByMe = false,
color = mergeHighlightInput.color.getOrNull(),
highlightPositionPercent = mergeHighlightInput.highlightPositionPercent.getOrNull() ?: 0.0,
highlightPositionAnchorIndex = mergeHighlightInput.highlightPositionAnchorIndex.getOrNull() ?: 0
)
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_CREATION.rawValue
saveHighlightChange(db.highlightChangesDao(), mergeHighlightInput.articleId, highlight)
Log.d("sync", "overlapHighlightIdList: " + mergeHighlightInput.overlapHighlightIdList)
for (highlightID in mergeHighlightInput.overlapHighlightIdList) {
deleteHighlight(highlightID)
deleteHighlight(mergeHighlightInput.articleId, highlightID)
}
val crossRef = SavedItemAndHighlightCrossRef(
@ -122,11 +146,10 @@ suspend fun DataService.mergeWebHighlights(jsonString: String) {
savedItemId = mergeHighlightInput.articleId
)
db.highlightDao().insertAll(listOf(highlight))
db.savedItemAndHighlightCrossRefDao().insertAll(listOf(crossRef))
db.highlightDao().update(highlight)
val isUpdatedOnServer = networker.mergeHighlights(mergeHighlightInput)
if (isUpdatedOnServer) {
highlight.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
db.highlightDao().update(highlight)
@ -135,16 +158,22 @@ suspend fun DataService.mergeWebHighlights(jsonString: String) {
}
suspend fun DataService.updateWebHighlight(jsonString: String) {
val updateHighlightParams = Gson().fromJson(jsonString, UpdateHighlightParams::class.java).asUpdateHighlightInput()
val updateHighlightParams = Gson().fromJson(jsonString, UpdateHighlightParams::class.java)
if (updateHighlightParams.highlightId == null || updateHighlightParams.libraryItemId == null) {
Log.d("error","ERROR INVALID HIGHLIGHT DATA")
}
withContext(Dispatchers.IO) {
val highlight = db.highlightDao().findById(highlightId = updateHighlightParams.highlightId) ?: return@withContext
val highlight = db.highlightDao().findById(highlightId = updateHighlightParams.highlightId ?: "") ?: return@withContext
highlight.annotation = updateHighlightParams.annotation.getOrNull()
highlight.annotation = updateHighlightParams.annotation
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
db.highlightDao().update(highlight)
val isUpdatedOnServer = networker.updateHighlight(updateHighlightParams)
saveHighlightChange(db.highlightChangesDao(), updateHighlightParams.libraryItemId ?: "", highlight)
val isUpdatedOnServer = networker.updateHighlight(updateHighlightParams.asUpdateHighlightInput())
if (isUpdatedOnServer) {
highlight.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
@ -153,24 +182,31 @@ suspend fun DataService.updateWebHighlight(jsonString: String) {
}
}
suspend fun DataService.deleteHighlights(jsonString: String) {
val highlightIDs = Gson().fromJson(jsonString, DeleteHighlightParams::class.java).asIdList()
for (highlightID in highlightIDs) {
deleteHighlight(highlightID)
}
suspend fun DataService.deleteHighlightFromJSON(jsonString: String) {
Log.d("sync", "DELETION STRING: " + jsonString)
val deleteHighlightParams = Gson().fromJson(jsonString, DeleteHighlightParams::class.java)
deleteHighlight(deleteHighlightParams.libraryItemId, deleteHighlightParams.highlightId)
}
private suspend fun DataService.deleteHighlight(highlightID: String) {
private suspend fun DataService.deleteHighlight(savedItemId: String, highlightID: String) {
withContext(Dispatchers.IO) {
val highlight = db.highlightDao().findById(highlightId = highlightID) ?: return@withContext
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_DELETION.rawValue
db.highlightDao().update(highlight)
val highlight = db.highlightDao().findById(highlightId = highlightID)
val isUpdatedOnServer = networker.deleteHighlights(listOf(highlightID))
highlight?.let {
highlight.serverSyncStatus = ServerSyncStatus.NEEDS_DELETION.rawValue
db.highlightDao().update(highlight)
if (isUpdatedOnServer) {
db.highlightDao().deleteById(highlightId = highlightID)
saveHighlightChange(db.highlightChangesDao(), savedItemId, highlight)
val isUpdatedOnServer = networker.deleteHighlights(listOf(highlightID))
Log.d("sync","DELETING HIGHLIGHT" + highlightID)
if (isUpdatedOnServer) {
Log.d("sync","DELETED HIGHLIGHT" + highlightID)
db.highlightDao().deleteById(highlightId = highlightID)
}
} ?: run {
Log.d("sync","Could not find highlight for deletion" + savedItemId + "," + highlightID)
}
}
}

View File

@ -1,5 +1,6 @@
package app.omnivore.omnivore.dataService
import android.util.Log
import app.omnivore.omnivore.graphql.generated.type.CreateHighlightInput
import app.omnivore.omnivore.graphql.generated.type.UpdateHighlightInput
import app.omnivore.omnivore.models.ServerSyncStatus
@ -8,8 +9,10 @@ import app.omnivore.omnivore.persistence.entities.Highlight
import app.omnivore.omnivore.persistence.entities.SavedItem
import com.apollographql.apollo3.api.Optional
import kotlinx.coroutines.delay
import kotlin.math.log
suspend fun DataService.startSyncChannels() {
Log.d("sync", "Starting sync channels")
for (savedItem in savedItemSyncChannel) {
syncSavedItem(savedItem)
}
@ -21,7 +24,8 @@ suspend fun DataService.startSyncChannels() {
suspend fun DataService.syncOfflineItemsWithServerIfNeeded() {
val unSyncedSavedItems = db.savedItemDao().getUnSynced()
val unSyncedHighlights = db.highlightDao().getUnSynced()
val unSyncedHighlights = db.highlightChangesDao().getUnSynced()
Log.d("sync","UNSYNC CHANGES: " + unSyncedHighlights)
for (savedItem in unSyncedSavedItems) {
delay(250)
@ -30,7 +34,7 @@ suspend fun DataService.syncOfflineItemsWithServerIfNeeded() {
for (highlight in unSyncedHighlights) {
delay(250)
highlightSyncChannel.send(highlight)
// highlightSyncChannel.send(highlight)
}
}

View File

@ -39,6 +39,7 @@ data class CreateHighlightParams(
data class UpdateHighlightParams(
val highlightId: String?,
val libraryItemId: String?,
val `annotation`: String?,
val sharedAt: String?,
) {
@ -73,9 +74,10 @@ data class MergeHighlightsParams(
}
data class DeleteHighlightParams(
val highlightId: String?
val highlightId: String,
val libraryItemId: String
) {
fun asIdList() = listOf(highlightId ?: "")
fun asIdList() = listOf(highlightId)
}
suspend fun Networker.deleteHighlight(jsonString: String): Boolean {

View File

@ -10,15 +10,17 @@ import app.omnivore.omnivore.persistence.entities.*
SavedItem::class,
SavedItemLabel::class,
Highlight::class,
HighlightChange::class,
SavedItemAndSavedItemLabelCrossRef::class,
SavedItemAndHighlightCrossRef::class
],
version = 15
version = 20
)
abstract class AppDatabase : RoomDatabase() {
abstract fun viewerDao(): ViewerDao
abstract fun savedItemDao(): SavedItemDao
abstract fun highlightDao(): HighlightDao
abstract fun highlightChangesDao(): HighlightChangesDao
abstract fun savedItemLabelDao(): SavedItemLabelDao
abstract fun savedItemWithLabelsAndHighlightsDao(): SavedItemWithLabelsAndHighlightsDao
abstract fun savedItemAndSavedItemLabelCrossRefDao(): SavedItemAndSavedItemLabelCrossRefDao

View File

@ -0,0 +1,70 @@
package app.omnivore.omnivore.persistence.entities
import android.util.Log
import androidx.room.Dao
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey
import androidx.room.Query
import app.omnivore.omnivore.models.ServerSyncStatus
import com.google.gson.annotations.SerializedName
@Entity
data class HighlightChange(
@PrimaryKey val highlightId: String,
val savedItemId: String,
val type: String,
var annotation: String?,
val createdAt: String?,
val createdByMe: Boolean = true,
val markedForDeletion: Boolean = false,
var patch: String?,
var prefix: String?,
var quote: String?,
var serverSyncStatus: Int = ServerSyncStatus.IS_SYNCED.rawValue,
var shortId: String,
val suffix: String?,
val updatedAt: String?,
val color: String?,
val highlightPositionPercent: Double?,
val highlightPositionAnchorIndex: Int?
)
fun saveHighlightChange(dao: HighlightChangesDao, savedItemId: String, highlight: Highlight): HighlightChange {
Log.d("sync", "saving highlight change: " + savedItemId + ", " + highlight)
val change = HighlightChange(
savedItemId = savedItemId,
highlightId = highlight.highlightId,
type = highlight.type,
shortId = highlight.shortId,
quote = highlight.quote,
prefix = highlight.prefix,
suffix = highlight.suffix,
patch = highlight.patch,
annotation = highlight.annotation,
createdAt = highlight.createdAt,
updatedAt = highlight.updatedAt,
createdByMe = highlight.createdByMe,
color =highlight.color,
highlightPositionPercent = highlight.highlightPositionPercent,
highlightPositionAnchorIndex = highlight.highlightPositionAnchorIndex,
serverSyncStatus = highlight.serverSyncStatus
)
dao.insertAll(listOf(change))
return change
}
@Dao
interface HighlightChangesDao {
@Query("SELECT * FROM highlightChange WHERE serverSyncStatus != 0 ORDER BY updatedAt ASC")
fun getUnSynced(): List<HighlightChange>
@Query("DELETE FROM highlightChange WHERE highlightId = :highlightId")
fun deleteById(highlightId: String)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(items: List<HighlightChange>)
}

View File

@ -333,7 +333,7 @@ class WebReaderViewModel @Inject constructor(
"deleteHighlight" -> {
Log.d("Loggo", "receive delete highlight action: $jsonString")
viewModelScope.launch {
dataService.deleteHighlights(jsonString)
dataService.deleteHighlightFromJSON(jsonString)
}
}
"updateHighlight" -> {