update apollo and rename package

This commit is contained in:
Stefano Sansone
2024-02-01 13:16:59 +00:00
parent c3276fdaf1
commit 55ef6a6543
32 changed files with 418 additions and 411 deletions

View File

@ -3,10 +3,10 @@ plugins {
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
id 'com.apollographql.apollo3' version '3.7.2'
id("com.apollographql.apollo3") version "3.8.2"
}
def keystorePropertiesFile = rootProject.file("app/external/keystore.properties");
def keystorePropertiesFile = rootProject.file("app/external/keystore.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
@ -135,7 +135,7 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-compiler:$hilt_version"
implementation 'com.apollographql.apollo3:apollo-runtime:3.7.2'
implementation("com.apollographql.apollo3:apollo-runtime:3.8.2")
implementation 'androidx.compose.material3:material3:1.1.2'
implementation 'androidx.compose.material3:material3-window-size-class:1.1.2'
@ -163,7 +163,7 @@ dependencies {
}
apollo {
packageName.set 'app.omnivore.omnivore.graphql.generated'
packageName.set "app.omnivore.omnivore.graphql.generated"
}
task printVersion {

View File

@ -2,7 +2,7 @@ package app.omnivore.omnivore
import android.content.Context
import app.omnivore.omnivore.dataService.DataService
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.network.Networker
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn

View File

@ -1,6 +1,6 @@
package app.omnivore.omnivore
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.network.Networker
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

View File

@ -2,7 +2,7 @@ package app.omnivore.omnivore.dataService
import android.content.Context
import androidx.room.Room
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.AppDatabase
import app.omnivore.omnivore.persistence.entities.Highlight
import app.omnivore.omnivore.persistence.entities.SavedItem

View File

@ -1,17 +1,13 @@
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.network.*
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.*

View File

@ -2,7 +2,7 @@ package app.omnivore.omnivore.dataService
import android.util.Log
import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.entities.*
suspend fun DataService.librarySearch(cursor: String?, query: String): SearchResult {

View File

@ -1,8 +1,8 @@
package app.omnivore.omnivore.dataService
import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.ReadingProgressParams
import app.omnivore.omnivore.networking.updateReadingProgress
import app.omnivore.omnivore.network.ReadingProgressParams
import app.omnivore.omnivore.network.updateReadingProgress
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

View File

@ -1,6 +1,6 @@
package app.omnivore.omnivore.dataService
import app.omnivore.omnivore.networking.savedItemLabels
import app.omnivore.omnivore.network.savedItemLabels
suspend fun DataService.syncLabels() {
val fetchedLabels = networker.savedItemLabels()

View File

@ -1,56 +1,56 @@
package app.omnivore.omnivore.dataService
import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.archiveSavedItem
import app.omnivore.omnivore.networking.deleteSavedItem
import app.omnivore.omnivore.networking.unarchiveSavedItem
import app.omnivore.omnivore.network.archiveSavedItem
import app.omnivore.omnivore.network.deleteSavedItem
import app.omnivore.omnivore.network.unarchiveSavedItem
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
suspend fun DataService.deleteSavedItem(itemID: String) {
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_DELETION.rawValue
db.savedItemDao().update(savedItem)
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_DELETION.rawValue
db.savedItemDao().update(savedItem)
val isUpdatedOnServer = networker.deleteSavedItem(itemID)
val isUpdatedOnServer = networker.deleteSavedItem(itemID)
if (isUpdatedOnServer) {
db.savedItemDao().deleteById(itemID)
if (isUpdatedOnServer) {
db.savedItemDao().deleteById(itemID)
}
}
}
}
suspend fun DataService.archiveSavedItem(itemID: String) {
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
savedItem.isArchived = true
db.savedItemDao().update(savedItem)
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
savedItem.isArchived = true
db.savedItemDao().update(savedItem)
val isUpdatedOnServer = networker.archiveSavedItem(itemID)
val isUpdatedOnServer = networker.archiveSavedItem(itemID)
if (isUpdatedOnServer) {
savedItem.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
db.savedItemDao().update(savedItem)
if (isUpdatedOnServer) {
savedItem.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
db.savedItemDao().update(savedItem)
}
}
}
}
suspend fun DataService.unarchiveSavedItem(itemID: String) {
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
withContext(Dispatchers.IO) {
val savedItem = db.savedItemDao().findById(itemID = itemID) ?: return@withContext
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
savedItem.isArchived = false
db.savedItemDao().update(savedItem)
savedItem.serverSyncStatus = ServerSyncStatus.NEEDS_UPDATE.rawValue
savedItem.isArchived = false
db.savedItemDao().update(savedItem)
val isUpdatedOnServer = networker.unarchiveSavedItem(itemID)
val isUpdatedOnServer = networker.unarchiveSavedItem(itemID)
if (isUpdatedOnServer) {
savedItem.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
db.savedItemDao().update(savedItem)
if (isUpdatedOnServer) {
savedItem.serverSyncStatus = ServerSyncStatus.IS_SYNCED.rawValue
db.savedItemDao().update(savedItem)
}
}
}
}

View File

@ -1,21 +1,17 @@
package app.omnivore.omnivore.dataService
import android.util.Log
import androidx.room.PrimaryKey
import app.omnivore.omnivore.graphql.generated.type.CreateHighlightInput
import app.omnivore.omnivore.graphql.generated.type.HighlightType
import app.omnivore.omnivore.graphql.generated.type.MergeHighlightInput
import app.omnivore.omnivore.graphql.generated.type.UpdateHighlightInput
import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.persistence.entities.Highlight
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.entities.HighlightChange
import app.omnivore.omnivore.persistence.entities.SavedItem
import app.omnivore.omnivore.persistence.entities.highlightChangeToHighlight
import app.omnivore.omnivore.persistence.entities.saveHighlightChange
import com.apollographql.apollo3.api.Optional
import kotlinx.coroutines.delay
import kotlin.math.log
suspend fun DataService.startSyncChannels() {
Log.d("sync", "Starting sync channels")

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import android.util.Log
import app.omnivore.omnivore.graphql.generated.CreateHighlightMutation

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.Constants
import app.omnivore.omnivore.DatastoreKeys

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.SaveArticleReadingProgressMutation
import app.omnivore.omnivore.graphql.generated.type.SaveArticleReadingProgressInput

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.CreateLabelMutation
import app.omnivore.omnivore.graphql.generated.SetLabelsMutation

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.GetLabelsQuery
import app.omnivore.omnivore.persistence.entities.SavedItemLabel

View File

@ -0,0 +1,65 @@
package app.omnivore.omnivore.network
import android.net.Uri
import androidx.compose.ui.text.intl.Locale
import app.omnivore.omnivore.graphql.generated.SaveUrlMutation
import app.omnivore.omnivore.graphql.generated.SetBookmarkArticleMutation
import app.omnivore.omnivore.graphql.generated.SetLinkArchivedMutation
import app.omnivore.omnivore.graphql.generated.type.ArchiveLinkInput
import app.omnivore.omnivore.graphql.generated.type.SaveUrlInput
import app.omnivore.omnivore.graphql.generated.type.SetBookmarkArticleInput
import com.apollographql.apollo3.api.Optional
import java.util.TimeZone
import java.util.UUID
suspend fun Networker.deleteSavedItem(itemID: String): Boolean {
return try {
val input = SetBookmarkArticleInput(itemID, false)
val result =
authenticatedApolloClient().mutation(SetBookmarkArticleMutation(input)).execute()
result.data?.setBookmarkArticle?.onSetBookmarkArticleSuccess?.bookmarkedArticle?.id != null
} catch (e: java.lang.Exception) {
false
}
}
suspend fun Networker.archiveSavedItem(itemID: String): Boolean {
return updateArchiveStatusSavedItem(itemID, true)
}
suspend fun Networker.unarchiveSavedItem(itemID: String): Boolean {
return updateArchiveStatusSavedItem(itemID, false)
}
suspend fun Networker.updateArchiveStatusSavedItem(
itemID: String,
setAsArchived: Boolean
): Boolean {
return try {
val input = ArchiveLinkInput(setAsArchived, itemID)
val result = authenticatedApolloClient().mutation(SetLinkArchivedMutation(input)).execute()
result.data?.setLinkArchived?.onArchiveLinkSuccess?.linkId != null
} catch (e: java.lang.Exception) {
false
}
}
suspend fun Networker.saveUrl(url: Uri): Boolean {
return try {
val clientRequestId = UUID.randomUUID().toString()
// get locale and timezone from device
val timezone = TimeZone.getDefault().id
val locale = Locale.current.toLanguageTag()
val input = SaveUrlInput(
url = url.toString(),
clientRequestId = clientRequestId,
source = "android",
timezone = Optional.present(timezone),
locale = Optional.present(locale)
)
val result = authenticatedApolloClient().mutation(SaveUrlMutation(input)).execute()
result.data?.saveUrl?.onSaveSuccess?.url != null
} catch (e: java.lang.Exception) {
false
}
}

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import android.util.Log
import app.omnivore.omnivore.graphql.generated.GetArticleQuery

View File

@ -1,8 +1,7 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.UpdatesSinceQuery
import app.omnivore.omnivore.graphql.generated.type.UpdateReason
import app.omnivore.omnivore.persistence.entities.SavedItem
import com.apollographql.apollo3.api.Optional
data class SavedItemUpdatesQueryResponse(

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.SearchQuery
import app.omnivore.omnivore.models.ServerSyncStatus

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.TypeaheadSearchQuery
import app.omnivore.omnivore.persistence.entities.TypeaheadCardData

View File

@ -1,4 +1,4 @@
package app.omnivore.omnivore.networking
package app.omnivore.omnivore.network
import app.omnivore.omnivore.graphql.generated.ViewerQuery
import app.omnivore.omnivore.persistence.entities.Viewer

View File

@ -1,68 +0,0 @@
package app.omnivore.omnivore.networking
import android.content.ContentValues
import android.net.Uri
import android.util.Log
import androidx.compose.ui.text.intl.Locale
import androidx.lifecycle.viewModelScope
import app.omnivore.omnivore.Constants
import app.omnivore.omnivore.graphql.generated.SaveUrlMutation
import app.omnivore.omnivore.graphql.generated.SetBookmarkArticleMutation
import app.omnivore.omnivore.graphql.generated.SetLinkArchivedMutation
import app.omnivore.omnivore.graphql.generated.type.*
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.Optional
import kotlinx.coroutines.launch
import java.util.*
suspend fun Networker.deleteSavedItem(itemID: String): Boolean {
return try {
val input = SetBookmarkArticleInput(itemID, false)
val result =
authenticatedApolloClient().mutation(SetBookmarkArticleMutation(input)).execute()
result.data?.setBookmarkArticle?.onSetBookmarkArticleSuccess?.bookmarkedArticle?.id != null
} catch (e: java.lang.Exception) {
false
}
}
suspend fun Networker.archiveSavedItem(itemID: String): Boolean {
return updateArchiveStatusSavedItem(itemID, true)
}
suspend fun Networker.unarchiveSavedItem(itemID: String): Boolean {
return updateArchiveStatusSavedItem(itemID, false)
}
suspend fun Networker.updateArchiveStatusSavedItem(
itemID: String,
setAsArchived: Boolean
): Boolean {
return try {
val input = ArchiveLinkInput(setAsArchived, itemID)
val result = authenticatedApolloClient().mutation(SetLinkArchivedMutation(input)).execute()
result.data?.setLinkArchived?.onArchiveLinkSuccess?.linkId != null
} catch (e: java.lang.Exception) {
false
}
}
suspend fun Networker.saveUrl(url: Uri): Boolean {
return try {
val clientRequestId = UUID.randomUUID().toString()
// get locale and timezone from device
val timezone = TimeZone.getDefault().id
val locale = Locale.current.toLanguageTag()
val input = SaveUrlInput(
url = url.toString(),
clientRequestId = clientRequestId,
source = "android",
timezone = Optional.present(timezone),
locale = Optional.present(locale)
)
val result = authenticatedApolloClient().mutation(SaveUrlMutation(input)).execute()
result.data?.saveUrl?.onSaveSuccess?.url != null
} catch (e: java.lang.Exception) {
false
}
}

View File

@ -1,254 +1,269 @@
package app.omnivore.omnivore.persistence.entities
import android.util.Log
import androidx.core.net.toUri
import androidx.lifecycle.LiveData
import androidx.room.*
import app.omnivore.omnivore.models.ServerSyncStatus
import java.util.*
@Entity
data class SavedItem(
@PrimaryKey val savedItemId: String,
val title: String,
val createdAt: String,
val savedAt: String,
val readAt: String?,
val updatedAt: String?,
var readingProgress: Double,
var readingProgressAnchor: Int,
val imageURLString: String?,
val pageURLString: String,
val descriptionText: String?,
val publisherURLString: String?,
val siteName: String?,
val author: String?,
val publishDate: String?,
val slug: String,
var isArchived: Boolean,
val contentReader: String? = null,
val content: String? = null,
val createdId: String? = null,
val htmlContent: String? = null,
val language: String? = null,
val listenPositionIndex: Int? = null,
val listenPositionOffset: Double? = null,
val listenPositionTime: Double? = null,
val localPDF: String? = null,
val onDeviceImageURLString: String? = null,
val originalHtml: String? = null,
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) val pdfData: ByteArray? = null,
var serverSyncStatus: Int = 0,
val tempPDFURL: String? = null,
val wordsCount: Int? = null,
val localPDFPath: String? = null
@PrimaryKey val savedItemId: String,
val title: String,
val createdAt: String,
val savedAt: String,
val readAt: String?,
val updatedAt: String?,
var readingProgress: Double,
var readingProgressAnchor: Int,
val imageURLString: String?,
val pageURLString: String,
val descriptionText: String?,
val publisherURLString: String?,
val siteName: String?,
val author: String?,
val publishDate: String?,
val slug: String,
var isArchived: Boolean,
val contentReader: String? = null,
val content: String? = null,
val createdId: String? = null,
val htmlContent: String? = null,
val language: String? = null,
val listenPositionIndex: Int? = null,
val listenPositionOffset: Double? = null,
val listenPositionTime: Double? = null,
val localPDF: String? = null,
val onDeviceImageURLString: String? = null,
val originalHtml: String? = null,
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) val pdfData: ByteArray? = null,
var serverSyncStatus: Int = 0,
val tempPDFURL: String? = null,
val wordsCount: Int? = null,
val localPDFPath: String? = null
// hasMany highlights
// hasMany labels
// has Many recommendations (rec has one savedItem)
) {
fun publisherDisplayName(): String? {
return publisherURLString?.toUri()?.host
}
fun publisherDisplayName(): String? {
return publisherURLString?.toUri()?.host
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as SavedItem
other as SavedItem
if (savedItemId != other.savedItemId) return false
return savedItemId == other.savedItemId
}
return true
}
override fun hashCode(): Int {
return savedItemId.hashCode()
}
override fun hashCode(): Int {
return savedItemId.hashCode()
}
}
data class TypeaheadCardData(
val savedItemId: String,
val slug: String,
val title: String,
val isArchived: Boolean,
val savedItemId: String,
val slug: String,
val title: String,
val isArchived: Boolean,
)
@Dao
abstract class SavedItemWithLabelsAndHighlightsDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertSavedItems(items: List<SavedItem>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertSavedItems(items: List<SavedItem>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertLabelCrossRefs(items: List<SavedItemAndSavedItemLabelCrossRef>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertLabelCrossRefs(items: List<SavedItemAndSavedItemLabelCrossRef>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertLabels(items: List<SavedItemLabel>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertLabels(items: List<SavedItemLabel>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertHighlights(items: List<Highlight>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertHighlights(items: List<Highlight>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertHighlightCrossRefs(items: List<SavedItemAndHighlightCrossRef>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
abstract fun insertHighlightCrossRefs(items: List<SavedItemAndHighlightCrossRef>)
@Transaction
open fun insertAll(savedItems: List<SavedItemWithLabelsAndHighlights>) {
insertSavedItems(savedItems.map { it.savedItem })
@Transaction
open fun insertAll(savedItems: List<SavedItemWithLabelsAndHighlights>) {
insertSavedItems(savedItems.map { it.savedItem })
val labels: MutableList<SavedItemLabel> = mutableListOf()
val highlights: MutableList<Highlight> = mutableListOf()
val labels: MutableList<SavedItemLabel> = mutableListOf()
val highlights: MutableList<Highlight> = mutableListOf()
val labelCrossRefs: MutableList<SavedItemAndSavedItemLabelCrossRef> = mutableListOf()
val highlightCrossRefs: MutableList<SavedItemAndHighlightCrossRef> = mutableListOf()
val labelCrossRefs: MutableList<SavedItemAndSavedItemLabelCrossRef> = mutableListOf()
val highlightCrossRefs: MutableList<SavedItemAndHighlightCrossRef> = mutableListOf()
for (searchItem in savedItems) {
labels.addAll(searchItem.labels)
highlights.addAll(searchItem.highlights)
for (searchItem in savedItems) {
labels.addAll(searchItem.labels)
highlights.addAll(searchItem.highlights)
val newLabelCrossRefs = searchItem.labels.map {
SavedItemAndSavedItemLabelCrossRef(savedItemLabelId = it.savedItemLabelId, savedItemId = searchItem.savedItem.savedItemId)
}
val newLabelCrossRefs = searchItem.labels.map {
SavedItemAndSavedItemLabelCrossRef(
savedItemLabelId = it.savedItemLabelId,
savedItemId = searchItem.savedItem.savedItemId
)
}
val newHighlightCrossRefs = searchItem.highlights.map {
SavedItemAndHighlightCrossRef(highlightId = it.highlightId, savedItemId = searchItem.savedItem.savedItemId)
}
val newHighlightCrossRefs = searchItem.highlights.map {
SavedItemAndHighlightCrossRef(
highlightId = it.highlightId,
savedItemId = searchItem.savedItem.savedItemId
)
}
labelCrossRefs.addAll(newLabelCrossRefs)
highlightCrossRefs.addAll(newHighlightCrossRefs)
labelCrossRefs.addAll(newLabelCrossRefs)
highlightCrossRefs.addAll(newHighlightCrossRefs)
}
insertLabels(labels)
insertLabelCrossRefs(labelCrossRefs)
insertHighlights(highlights)
insertHighlightCrossRefs(highlightCrossRefs)
}
insertLabels(labels)
insertLabelCrossRefs(labelCrossRefs)
insertHighlights(highlights)
insertHighlightCrossRefs(highlightCrossRefs)
}
}
@Dao
interface SavedItemDao {
@Query("SELECT * FROM savedItem")
fun getAll(): List<SavedItem>
@Query("SELECT * FROM savedItem")
fun getAll(): List<SavedItem>
@Query("SELECT * FROM savedItem WHERE savedItemId = :itemID")
fun findById(itemID: String): SavedItem?
@Query("SELECT * FROM savedItem WHERE savedItemId = :itemID")
fun findById(itemID: String): SavedItem?
@Query("SELECT * FROM savedItem WHERE serverSyncStatus != 0")
fun getUnSynced(): List<SavedItem>
@Query("SELECT * FROM savedItem WHERE serverSyncStatus != 0")
fun getUnSynced(): List<SavedItem>
@Query("SELECT * FROM savedItem WHERE slug = :slug")
fun getSavedItemWithLabelsAndHighlights(slug: String): SavedItemWithLabelsAndHighlights?
@Query("SELECT * FROM savedItem WHERE slug = :slug")
fun getSavedItemWithLabelsAndHighlights(slug: String): SavedItemWithLabelsAndHighlights?
@Query("DELETE FROM savedItem WHERE savedItemId = :itemID")
fun deleteById(itemID: String)
@Query("DELETE FROM savedItem WHERE savedItemId = :itemID")
fun deleteById(itemID: String)
@Query("DELETE FROM savedItem WHERE savedItemId in (:itemIDs)")
fun deleteByIds(itemIDs: List<String>)
@Query("DELETE FROM savedItem WHERE savedItemId in (:itemIDs)")
fun deleteByIds(itemIDs: List<String>)
@Update
fun update(savedItem: SavedItem)
@Update
fun update(savedItem: SavedItem)
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.savedItemId = :savedItemId " +
"WHERE SavedItem.savedItemId = :savedItemId " +
"GROUP BY SavedItem.savedItemId "
)
fun getLibraryItemById(savedItemId: String): LiveData<SavedItemWithLabelsAndHighlights>
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.savedItemId = :savedItemId " +
"GROUP BY SavedItem.savedItemId "
)
suspend fun getById(savedItemId: String): SavedItemWithLabelsAndHighlights?
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.serverSyncStatus != 2 " +
"AND SavedItem.isArchived IN (:allowedArchiveStates) " +
"AND SavedItem.contentReader IN (:allowedContentReaders) " +
"AND CASE WHEN :hasRequiredLabels THEN SavedItemLabel.name in (:requiredLabels) ELSE 1 END " +
"AND CASE WHEN :hasExcludedLabels THEN SavedItemLabel.name is NULL OR SavedItemLabel.name not in (:excludedLabels) ELSE 1 END " +
"GROUP BY SavedItem.savedItemId " +
"ORDER BY \n" +
"CASE WHEN :sortKey = 'newest' THEN SavedItem.savedAt END DESC,\n" +
"CASE WHEN :sortKey = 'oldest' THEN SavedItem.savedAt END ASC,\n" +
"CASE WHEN :sortKey = 'recentlyRead' THEN SavedItem.readAt END DESC,\n" +
"CASE WHEN :sortKey = 'recentlyPublished' THEN SavedItem.publishDate END DESC"
)
fun _filteredLibraryData(allowedArchiveStates: List<Int>, sortKey: String, hasRequiredLabels: Int, hasExcludedLabels: Int, requiredLabels: List<String>, excludedLabels: List<String>, allowedContentReaders: List<String>): LiveData<List<SavedItemWithLabelsAndHighlights>>
fun filteredLibraryData(allowedArchiveStates: List<Int>, sortKey: String, requiredLabels: List<String>, excludedLabels: List<String>, allowedContentReaders: List<String>): LiveData<List<SavedItemWithLabelsAndHighlights>> {
val result = _filteredLibraryData(
allowedArchiveStates = allowedArchiveStates,
sortKey = sortKey,
hasRequiredLabels = requiredLabels.size,
hasExcludedLabels = excludedLabels.size,
requiredLabels = requiredLabels,
excludedLabels = excludedLabels,
allowedContentReaders = allowedContentReaders
"GROUP BY SavedItem.savedItemId "
)
return result
}
fun getLibraryItemById(savedItemId: String): LiveData<SavedItemWithLabelsAndHighlights>
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.savedItemId = :savedItemId " +
"GROUP BY SavedItem.savedItemId "
)
suspend fun getById(savedItemId: String): SavedItemWithLabelsAndHighlights?
@Transaction
@Query(
"SELECT ${SavedItemQueryConstants.libraryColumns} " +
"FROM SavedItem " +
"LEFT OUTER JOIN SavedItemAndSavedItemLabelCrossRef on SavedItem.savedItemId = SavedItemAndSavedItemLabelCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemAndHighlightCrossRef on SavedItem.savedItemId = SavedItemAndHighlightCrossRef.savedItemId " +
"LEFT OUTER JOIN SavedItemLabel on SavedItemLabel.savedItemLabelId = SavedItemAndSavedItemLabelCrossRef.savedItemLabelId " +
"LEFT OUTER JOIN Highlight on highlight.highlightId = SavedItemAndHighlightCrossRef.highlightId " +
"WHERE SavedItem.serverSyncStatus != 2 " +
"AND SavedItem.isArchived IN (:allowedArchiveStates) " +
"AND SavedItem.contentReader IN (:allowedContentReaders) " +
"AND CASE WHEN :hasRequiredLabels THEN SavedItemLabel.name in (:requiredLabels) ELSE 1 END " +
"AND CASE WHEN :hasExcludedLabels THEN SavedItemLabel.name is NULL OR SavedItemLabel.name not in (:excludedLabels) ELSE 1 END " +
"GROUP BY SavedItem.savedItemId " +
"ORDER BY \n" +
"CASE WHEN :sortKey = 'newest' THEN SavedItem.savedAt END DESC,\n" +
"CASE WHEN :sortKey = 'oldest' THEN SavedItem.savedAt END ASC,\n" +
"CASE WHEN :sortKey = 'recentlyRead' THEN SavedItem.readAt END DESC,\n" +
"CASE WHEN :sortKey = 'recentlyPublished' THEN SavedItem.publishDate END DESC"
)
fun _filteredLibraryData(
allowedArchiveStates: List<Int>,
sortKey: String,
hasRequiredLabels: Int,
hasExcludedLabels: Int,
requiredLabels: List<String>,
excludedLabels: List<String>,
allowedContentReaders: List<String>
): LiveData<List<SavedItemWithLabelsAndHighlights>>
fun filteredLibraryData(
allowedArchiveStates: List<Int>,
sortKey: String,
requiredLabels: List<String>,
excludedLabels: List<String>,
allowedContentReaders: List<String>
): LiveData<List<SavedItemWithLabelsAndHighlights>> {
val result = _filteredLibraryData(
allowedArchiveStates = allowedArchiveStates,
sortKey = sortKey,
hasRequiredLabels = requiredLabels.size,
hasExcludedLabels = excludedLabels.size,
requiredLabels = requiredLabels,
excludedLabels = excludedLabels,
allowedContentReaders = allowedContentReaders
)
return result
}
}
object SavedItemQueryConstants {
const val columns = "savedItemId, slug, publisherURLString, title, author, descriptionText, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount"
const val libraryColumns = "SavedItem.savedItemId, " +
"SavedItem.slug, " +
"SavedItem.createdAt, " +
const val columns =
"savedItemId, slug, publisherURLString, title, author, descriptionText, imageURLString, isArchived, pageURLString, contentReader, savedAt, readingProgress, wordsCount"
const val libraryColumns = "SavedItem.savedItemId, " +
"SavedItem.slug, " +
"SavedItem.createdAt, " +
"SavedItem.publisherURLString, " +
"SavedItem.title, " +
"SavedItem.author, " +
"SavedItem.descriptionText, " +
"SavedItem.imageURLString, " +
"SavedItem.isArchived, " +
"SavedItem.pageURLString, " +
"SavedItem.contentReader, " +
"SavedItem.savedAt, " +
"SavedItem.readingProgress, " +
"SavedItem.readingProgressAnchor, " +
"SavedItem.serverSyncStatus, " +
"SavedItem.publisherURLString, " +
"SavedItem.title, " +
"SavedItem.author, " +
"SavedItem.descriptionText, " +
"SavedItem.imageURLString, " +
"SavedItem.isArchived, " +
"SavedItem.pageURLString, " +
"SavedItem.contentReader, " +
"SavedItem.savedAt, " +
"SavedItem.readingProgress, " +
"SavedItem.readingProgressAnchor, " +
"SavedItem.serverSyncStatus, " +
"SavedItem.wordsCount, " +
"SavedItemLabel.savedItemLabelId, " +
"SavedItemLabel.name, " +
"SavedItemLabel.color, " +
"Highlight.highlightId, " +
"Highlight.shortId, " +
"Highlight.createdByMe "
"SavedItem.wordsCount, " +
"SavedItemLabel.savedItemLabelId, " +
"SavedItemLabel.name, " +
"SavedItemLabel.color, " +
"Highlight.highlightId, " +
"Highlight.shortId, " +
"Highlight.createdByMe "
}

View File

@ -3,8 +3,8 @@ package app.omnivore.omnivore.ui
import app.omnivore.omnivore.dataService.DataService
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
import app.omnivore.omnivore.graphql.generated.type.SetLabelsInput
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.networking.updateLabelsForSavedItem
import app.omnivore.omnivore.network.Networker
import app.omnivore.omnivore.network.updateLabelsForSavedItem
import app.omnivore.omnivore.persistence.entities.SavedItemAndSavedItemLabelCrossRef
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
import com.apollographql.apollo3.api.Optional

View File

@ -9,8 +9,8 @@ import androidx.lifecycle.*
import app.omnivore.omnivore.*
import app.omnivore.omnivore.dataService.DataService
import app.omnivore.omnivore.graphql.generated.ValidateUsernameQuery
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.networking.viewer
import app.omnivore.omnivore.network.Networker
import app.omnivore.omnivore.network.viewer
import app.omnivore.omnivore.ui.ResourceProvider
import com.apollographql.apollo3.ApolloClient
import com.google.android.gms.auth.api.signin.GoogleSignInAccount

View File

@ -7,7 +7,7 @@ import androidx.lifecycle.*
import app.omnivore.omnivore.*
import app.omnivore.omnivore.dataService.*
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.entities.*
import app.omnivore.omnivore.ui.ResourceProvider
import app.omnivore.omnivore.ui.setSavedItemLabels

View File

@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.omnivore.omnivore.*
import app.omnivore.omnivore.dataService.*
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.entities.*
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*

View File

@ -4,8 +4,8 @@ import androidx.lifecycle.*
import app.omnivore.omnivore.dataService.DataService
import app.omnivore.omnivore.dataService.createNoteHighlight
import app.omnivore.omnivore.graphql.generated.type.UpdateHighlightInput
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.networking.updateHighlight
import app.omnivore.omnivore.network.Networker
import app.omnivore.omnivore.network.updateHighlight
import app.omnivore.omnivore.persistence.entities.Highlight
import app.omnivore.omnivore.persistence.entities.SavedItemWithLabelsAndHighlights
import com.apollographql.apollo3.api.Optional

View File

@ -12,7 +12,7 @@ import app.omnivore.omnivore.graphql.generated.type.CreateHighlightInput
import app.omnivore.omnivore.graphql.generated.type.MergeHighlightInput
import app.omnivore.omnivore.graphql.generated.type.UpdateHighlightInput
import app.omnivore.omnivore.persistence.entities.SavedItem
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import com.apollographql.apollo3.api.Optional
import com.google.gson.Gson
import com.pspdfkit.annotations.Annotation

View File

@ -15,7 +15,7 @@ import app.omnivore.omnivore.EventTracker
import app.omnivore.omnivore.R
import app.omnivore.omnivore.dataService.*
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.network.*
import app.omnivore.omnivore.persistence.entities.SavedItem
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
import app.omnivore.omnivore.ui.components.HighlightColor

View File

@ -18,84 +18,88 @@ import app.omnivore.omnivore.ui.reader.WebReaderViewModel
@Composable
fun SavedItemContextMenu(
isExpanded: Boolean,
isArchived: Boolean,
context: Context,
webReaderViewModel: WebReaderViewModel,
onDismiss: () -> Unit,
actionHandler: (SavedItemAction) -> Unit
isExpanded: Boolean,
isArchived: Boolean,
context: Context,
webReaderViewModel: WebReaderViewModel,
onDismiss: () -> Unit,
actionHandler: (SavedItemAction) -> Unit
) {
DropdownMenu(
expanded = isExpanded,
onDismissRequest = onDismiss
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_info)) },
onClick = {
actionHandler(SavedItemAction.EditInfo)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Info,
contentDescription = null
DropdownMenu(
expanded = isExpanded,
onDismissRequest = onDismiss
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_info)) },
onClick = {
actionHandler(SavedItemAction.EditInfo)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Info,
contentDescription = null
)
}
)
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_labels)) },
onClick = {
actionHandler(SavedItemAction.EditLabels)
onDismiss()
},
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.tag),
contentDescription = null
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_edit_labels)) },
onClick = {
actionHandler(SavedItemAction.EditLabels)
onDismiss()
},
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.tag),
contentDescription = null
)
}
)
}
)
DropdownMenuItem(
text = { Text(if (isArchived)
stringResource(R.string.saved_item_context_menu_action_unarchive) else
stringResource(R.string.saved_item_context_menu_action_archive)) },
onClick = {
val action = if (isArchived) SavedItemAction.Unarchive else SavedItemAction.Archive
actionHandler(action)
onDismiss()
},
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.archive_outline),
contentDescription = null
DropdownMenuItem(
text = {
Text(
if (isArchived)
stringResource(R.string.saved_item_context_menu_action_unarchive) else
stringResource(R.string.saved_item_context_menu_action_archive)
)
},
onClick = {
val action = if (isArchived) SavedItemAction.Unarchive else SavedItemAction.Archive
actionHandler(action)
onDismiss()
},
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.archive_outline),
contentDescription = null
)
}
)
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_share_original)) },
onClick = {
webReaderViewModel.showShareLinkSheet(context)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Share,
contentDescription = null
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_share_original)) },
onClick = {
webReaderViewModel.showShareLinkSheet(context)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Share,
contentDescription = null
)
}
)
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_remove_item)) },
onClick = {
actionHandler(SavedItemAction.Delete)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Delete,
contentDescription = null
DropdownMenuItem(
text = { Text(stringResource(R.string.saved_item_context_menu_action_remove_item)) },
onClick = {
actionHandler(SavedItemAction.Delete)
onDismiss()
},
leadingIcon = {
Icon(
Icons.Outlined.Delete,
contentDescription = null
)
}
)
}
)
}
}
}

View File

@ -5,8 +5,8 @@ import androidx.lifecycle.viewModelScope
import app.omnivore.omnivore.DatastoreKeys
import app.omnivore.omnivore.DatastoreRepository
import app.omnivore.omnivore.dataService.DataService
import app.omnivore.omnivore.networking.Networker
import app.omnivore.omnivore.networking.viewer
import app.omnivore.omnivore.network.Networker
import app.omnivore.omnivore.network.viewer
import dagger.hilt.android.lifecycle.HiltViewModel
import io.intercom.android.sdk.Intercom
import io.intercom.android.sdk.IntercomSpace