Skip to content

Commit

Permalink
Use internal storage for content files
Browse files Browse the repository at this point in the history
  • Loading branch information
jacksonh committed May 20, 2024
1 parent b6c150a commit 4a1b0cb
Show file tree
Hide file tree
Showing 13 changed files with 137 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.omnivore.omnivore.core.data

import android.content.Context
import android.util.Log
import app.omnivore.omnivore.core.data.model.ServerSyncStatus
import app.omnivore.omnivore.core.database.entities.Highlight
Expand All @@ -12,8 +13,8 @@ import app.omnivore.omnivore.core.network.savedItem
import app.omnivore.omnivore.core.network.savedItemUpdates
import app.omnivore.omnivore.core.network.search

suspend fun DataService.librarySearch(cursor: String?, query: String): SearchResult {
val searchResult = networker.search(cursor = cursor, limit = 10, query = query)
suspend fun DataService.librarySearch(context: Context, cursor: String?, query: String): SearchResult {
val searchResult = networker.search(context, cursor = cursor, limit = 10, query = query)

val savedItems = searchResult.items.map {
SavedItemWithLabelsAndHighlights(
Expand All @@ -39,7 +40,7 @@ suspend fun DataService.librarySearch(cursor: String?, query: String): SearchRes
)
}

suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): SavedItemSyncResult {
suspend fun DataService.sync(context: Context, since: String, cursor: String?, limit: Int = 20): SavedItemSyncResult {
val syncResult = networker.savedItemUpdates(cursor = cursor, limit = limit, since = since)
?: return SavedItemSyncResult.errorResult

Expand All @@ -48,7 +49,16 @@ suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): S
}

val savedItems = syncResult.items.map {
saveLibraryItemContentToFile(it.id, it.content)
if (!saveLibraryItemContentToFile(context, it.id, it.content)) {
return SavedItemSyncResult(
hasError = true,
errorString = "Error saving page content",
hasMoreItems = false,
count = 0,
cursor = null,
savedItemSlugs = listOf()
)
}
val savedItem = SavedItem(
savedItemId = it.id,
title = it.title,
Expand Down Expand Up @@ -109,25 +119,27 @@ suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): S

Log.d("sync", "found ${syncResult.items.size} items with sync api. Since: $since")

return SavedItemSyncResult(hasError = false,
return SavedItemSyncResult(
hasError = false,
errorString = null,
hasMoreItems = syncResult.hasMoreItems,
cursor = syncResult.cursor,
count = syncResult.items.size,
savedItemSlugs = syncResult.items.map { it.slug })
savedItemSlugs = syncResult.items.map { it.slug }
)
}

suspend fun DataService.isSavedItemContentStoredInDB(slug: String): Boolean {
suspend fun DataService.isSavedItemContentStoredInDB(context: Context, slug: String): Boolean {
val existingItem = db.savedItemDao().getSavedItemWithLabelsAndHighlights(slug)
existingItem?.savedItem?.savedItemId?.let { savedItemId ->
val htmlContent = loadLibraryItemContent(savedItemId)
val htmlContent = loadLibraryItemContent(context, savedItemId)
return (htmlContent ?: "").length > 10
}
return false
}

suspend fun DataService.fetchSavedItemContent(slug: String) {
val syncResult = networker.savedItem(slug)

suspend fun DataService.fetchSavedItemContent(context: Context, slug: String) {
val syncResult = networker.savedItem(context, slug)
val savedItem = syncResult.item
savedItem?.let {
val item = SavedItemWithLabelsAndHighlights(
Expand All @@ -140,6 +152,7 @@ suspend fun DataService.fetchSavedItemContent(slug: String) {

data class SavedItemSyncResult(
val hasError: Boolean,
val errorString: String?,
val hasMoreItems: Boolean,
val count: Int,
val savedItemSlugs: List<String>,
Expand All @@ -151,6 +164,7 @@ data class SavedItemSyncResult(
hasMoreItems = true,
cursor = null,
count = 0,
errorString = null,
savedItemSlugs = listOf()
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.omnivore.omnivore.core.data.repository

import android.content.Context
import app.omnivore.omnivore.core.data.SavedItemSyncResult
import app.omnivore.omnivore.core.data.SearchResult
import app.omnivore.omnivore.core.data.model.LibraryQuery
Expand All @@ -16,7 +17,7 @@ interface LibraryRepository {

suspend fun getLabels(): List<SavedItemLabel>

suspend fun fetchSavedItemContent(slug: String)
suspend fun fetchSavedItemContent(context: Context, slug: String)

suspend fun insertAllLabels(labels: List<SavedItemLabel>)

Expand All @@ -30,9 +31,9 @@ interface LibraryRepository {

suspend fun createNewSavedItemLabel(labelName: String, hexColorValue: String)

suspend fun librarySearch(cursor: String?, query: String): SearchResult
suspend fun librarySearch(context: Context, cursor: String?, query: String): SearchResult

suspend fun isSavedItemContentStoredInDB(slug: String): Boolean
suspend fun isSavedItemContentStoredInDB(context: Context, slug: String): Boolean

suspend fun deleteSavedItem(itemID: String)

Expand All @@ -44,5 +45,5 @@ interface LibraryRepository {

suspend fun syncHighlightChange(highlightChange: HighlightChange): Boolean

suspend fun sync(since: String, cursor: String?, limit: Int = 20): SavedItemSyncResult
suspend fun sync(context: Context, since: String, cursor: String?, limit: Int = 20): SavedItemSyncResult
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.omnivore.omnivore.core.data.repository.impl

import android.content.Context
import android.util.Log
import app.omnivore.omnivore.core.data.DataService
import app.omnivore.omnivore.core.data.SavedItemSyncResult
Expand Down Expand Up @@ -81,8 +82,8 @@ class LibraryRepositoryImpl @Inject constructor(
savedItemLabelDao.insertAll(labels)
}

override suspend fun fetchSavedItemContent(slug: String) {
val syncResult = networker.savedItem(slug)
override suspend fun fetchSavedItemContent(context: Context, slug: String) {
val syncResult = networker.savedItem(context, slug)

val savedItem = syncResult.item
savedItem?.let {
Expand Down Expand Up @@ -192,9 +193,8 @@ class LibraryRepositoryImpl @Inject constructor(
}
}

override suspend fun librarySearch(cursor: String?, query: String): SearchResult {
val searchResult = networker.search(cursor = cursor, limit = 10, query = query)

override suspend fun librarySearch(context: Context, cursor: String?, query: String): SearchResult {
val searchResult = networker.search(context = context, cursor = cursor, limit = 10, query = query)
val savedItems = searchResult.items.map {
SavedItemWithLabelsAndHighlights(
savedItem = it.item,
Expand All @@ -219,10 +219,10 @@ class LibraryRepositoryImpl @Inject constructor(
)
}

override suspend fun isSavedItemContentStoredInDB(slug: String): Boolean {
override suspend fun isSavedItemContentStoredInDB(context: Context, slug: String): Boolean {
val existingItem = savedItemDao.getSavedItemWithLabelsAndHighlights(slug)
existingItem?.savedItem?.savedItemId?.let { savedItemId ->
val htmlContent = loadLibraryItemContent(savedItemId)
val htmlContent = loadLibraryItemContent(context, savedItemId)
return (htmlContent ?: "").length > 10
}
return false
Expand Down Expand Up @@ -412,7 +412,7 @@ class LibraryRepositoryImpl @Inject constructor(
}
}

override suspend fun sync(since: String, cursor: String?, limit: Int): SavedItemSyncResult {
override suspend fun sync(context: Context, since: String, cursor: String?, limit: Int): SavedItemSyncResult {
val syncResult = networker.savedItemUpdates(cursor = cursor, limit = limit, since = since)
?: return SavedItemSyncResult.errorResult

Expand All @@ -421,7 +421,7 @@ class LibraryRepositoryImpl @Inject constructor(
}

val savedItems = syncResult.items.map {
saveLibraryItemContentToFile(it.id, it.content)
saveLibraryItemContentToFile(context, it.id, it.content)
val savedItem = SavedItem(
savedItemId = it.id,
title = it.title,
Expand Down Expand Up @@ -482,10 +482,13 @@ class LibraryRepositoryImpl @Inject constructor(

Log.d("sync", "found ${syncResult.items.size} items with sync api. Since: $since")

return SavedItemSyncResult(hasError = false,
return SavedItemSyncResult(
hasError = false,
errorString = null,
hasMoreItems = syncResult.hasMoreItems,
cursor = syncResult.cursor,
count = syncResult.items.size,
savedItemSlugs = syncResult.items.map { it.slug })
savedItemSlugs = syncResult.items.map { it.slug }
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.omnivore.omnivore.core.network

import android.content.Context
import android.util.Log
import app.omnivore.omnivore.core.database.entities.Highlight
import app.omnivore.omnivore.core.database.entities.SavedItem
Expand All @@ -24,7 +25,7 @@ data class SavedItemQueryResponse(
}
}

suspend fun Networker.savedItem(slug: String): SavedItemQueryResponse {
suspend fun Networker.savedItem(context: Context, slug: String): SavedItemQueryResponse {
try {
val result = authenticatedApolloClient().query(
GetArticleQuery(slug = slug)
Expand Down Expand Up @@ -80,7 +81,7 @@ suspend fun Networker.savedItem(slug: String): SavedItemQueryResponse {
localPDFPath = localFile.toPath().toString()
}

saveLibraryItemContentToFile(article.articleFields.id, article.articleFields.content)
saveLibraryItemContentToFile(context, article.articleFields.id, article.articleFields.content)

val savedItem = SavedItem(
savedItemId = article.articleFields.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package app.omnivore.omnivore.core.network

import android.os.Environment
import android.widget.Toast
import androidx.core.app.ActivityCompat
import app.omnivore.omnivore.core.data.model.ServerSyncStatus
import app.omnivore.omnivore.core.database.entities.Highlight
import app.omnivore.omnivore.core.database.entities.SavedItem
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
import app.omnivore.omnivore.graphql.generated.SearchQuery
import com.apollographql.apollo3.api.Optional
import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import android.Manifest
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.util.Log
import androidx.compose.ui.platform.LocalContext

data class LibrarySearchQueryResponse(
val cursor: String?, val items: List<LibrarySearchItem>
Expand All @@ -21,6 +27,7 @@ data class LibrarySearchItem(
)

suspend fun Networker.search(
context: Context,
cursor: String? = null, limit: Int = 15, query: String
): LibrarySearchQueryResponse {
try {
Expand All @@ -36,7 +43,7 @@ suspend fun Networker.search(
val itemList = result.data?.search?.onSearchSuccess?.edges ?: listOf()

val searchItems = itemList.map {
saveLibraryItemContentToFile(it.node.id, it.node.content)
saveLibraryItemContentToFile(context, it.node.id, it.node.content)
LibrarySearchItem(item = SavedItem(
savedItemId = it.node.id,
title = it.node.title,
Expand Down Expand Up @@ -95,12 +102,38 @@ suspend fun Networker.search(
}
}

fun saveLibraryItemContentToFile(libraryItemId: String, content: String?): Boolean {
//
private fun writeToInternalStorage(context: Context, content: String, fileName: String) {
try {
context.openFileOutput(fileName, MODE_PRIVATE).use { outputStream ->
outputStream.write(content.toByteArray())
outputStream.flush()
Log.d("FileWrite", "File written successfully to internal storage.")
}
} catch (e: Exception) {
Log.e("FileWrite", "Error writing file", e)
throw e
}
}

private fun readFromInternalStorage(context: Context, fileName: String): String? {
return try {
context.openFileInput(fileName).bufferedReader().useLines { lines ->
lines.fold("") { some, text ->
"$some\n$text"
}
}
} catch (e: Exception) {
Log.e("FileRead", "Error reading file", e)
null
}
}


fun saveLibraryItemContentToFile(context: Context, libraryItemId: String, content: String?): Boolean {
return try {
content?.let { content ->
val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val file = File(directory, "${libraryItemId}.html")
FileOutputStream(file).use { it.write(content.toByteArray()) }
writeToInternalStorage(context, content = content, fileName = "${libraryItemId}.html", )
return false
}
false
Expand All @@ -110,15 +143,9 @@ fun saveLibraryItemContentToFile(libraryItemId: String, content: String?): Boole
}
}

fun loadLibraryItemContent(libraryItemId: String): String? {
fun loadLibraryItemContent(context: Context, libraryItemId: String): String? {
return try {
val directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val file = File(directory, "${libraryItemId}.html")
if (file.exists()) {
return FileInputStream(file).bufferedReader().use { it.readText() }
} else {
null
}
return readFromInternalStorage(context = context, fileName = "${libraryItemId}.html")
} catch (e: Exception) {
e.printStackTrace()
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand Down Expand Up @@ -91,9 +92,10 @@ class FollowingViewModel @Inject constructor(
syncLabels()

viewModelScope.launch {
val context = applicationContext
handleFilterChanges()
for (slug in contentRequestChannel) {
libraryRepository.fetchSavedItemContent(slug)
libraryRepository.fetchSavedItemContent(context, slug)
}
}

Expand Down Expand Up @@ -148,15 +150,17 @@ class FollowingViewModel @Inject constructor(

fun loadUsingSearchAPI() {
viewModelScope.launch {
val context = applicationContext
val result = libraryRepository.librarySearch(
context = context,
cursor = librarySearchCursor,
query = searchQueryString()
)
result.cursor?.let {
librarySearchCursor = it
}
result.savedItems.map {
val isSavedInDB = libraryRepository.isSavedItemContentStoredInDB(it.savedItem.slug)
val isSavedInDB = libraryRepository.isSavedItemContentStoredInDB(context = applicationContext, it.savedItem.slug)

if (!isSavedInDB) {
delay(2000)
Expand Down Expand Up @@ -257,7 +261,7 @@ class FollowingViewModel @Inject constructor(
startTime: String,
) {
libraryRepository.syncOfflineItemsWithServerIfNeeded()
val result = libraryRepository.sync(since = since, cursor = cursor, limit = 20)
val result = libraryRepository.sync(context = this.applicationContext, since = since, cursor = cursor, limit = 20)
val totalCount = count + result.count

if (!result.hasError && result.hasMoreItems && result.cursor != null) {
Expand Down
Loading

0 comments on commit 4a1b0cb

Please sign in to comment.