Merge pull request #4129 from omnivore-app/feat/android-offline-pdf
WIP: download android PDFs for offline to internal storage
This commit is contained in:
@ -49,7 +49,7 @@ suspend fun DataService.sync(context: Context, since: String, cursor: String?, l
|
||||
}
|
||||
|
||||
val savedItems = syncResult.items.map {
|
||||
if (!saveLibraryItemContentToFile(context, it.id, it.content)) {
|
||||
if (!saveLibraryItemContentToFile(context, it.id, it.contentReader, it.content, it.url)) {
|
||||
return SavedItemSyncResult(
|
||||
hasError = true,
|
||||
errorString = "Error saving page content",
|
||||
|
||||
@ -430,7 +430,7 @@ class LibraryRepositoryImpl @Inject constructor(
|
||||
}
|
||||
|
||||
val savedItems = syncResult.items.map {
|
||||
saveLibraryItemContentToFile(context, it.id, it.content)
|
||||
saveLibraryItemContentToFile(context, it.id, it.contentReader, it.content, it.url)
|
||||
val savedItem = SavedItem(
|
||||
savedItemId = it.id,
|
||||
title = it.title,
|
||||
|
||||
@ -7,6 +7,8 @@ import app.omnivore.omnivore.core.database.entities.SavedItem
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.graphql.generated.GetArticleQuery
|
||||
import app.omnivore.omnivore.graphql.generated.type.ContentReader
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
@ -67,21 +69,7 @@ suspend fun Networker.savedItem(context: Context, slug: String): SavedItemQueryR
|
||||
)
|
||||
}
|
||||
|
||||
var localPDFPath: String? = null
|
||||
if (article.articleFields.contentReader == ContentReader.PDF) {
|
||||
// download the PDF and save it locally
|
||||
// article.articleFields.url
|
||||
|
||||
val localFile = File.createTempFile("pdf-" + article.articleFields.id, ".pdf")
|
||||
val url = URL(article.articleFields.url)
|
||||
Log.d("pdf", "creating local file: $localFile")
|
||||
|
||||
url.openStream()
|
||||
.use { Files.copy(it, localFile.toPath(), StandardCopyOption.REPLACE_EXISTING) }
|
||||
localPDFPath = localFile.toPath().toString()
|
||||
}
|
||||
|
||||
saveLibraryItemContentToFile(context, article.articleFields.id, article.articleFields.content)
|
||||
saveLibraryItemContentToFile(context, article.articleFields.id, article.articleFields.contentReader, article.articleFields.content, article.articleFields.url)
|
||||
|
||||
val savedItem = SavedItem(
|
||||
savedItemId = article.articleFields.id,
|
||||
@ -104,7 +92,6 @@ suspend fun Networker.savedItem(context: Context, slug: String): SavedItemQueryR
|
||||
isArchived = article.articleFields.isArchived,
|
||||
contentReader = article.articleFields.contentReader.rawValue,
|
||||
wordsCount = article.articleFields.wordsCount,
|
||||
localPDFPath = localPDFPath
|
||||
)
|
||||
|
||||
return SavedItemQueryResponse(
|
||||
|
||||
@ -15,8 +15,18 @@ import java.io.FileOutputStream
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toUri
|
||||
import app.omnivore.omnivore.graphql.generated.type.ContentReader
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
||||
data class LibrarySearchQueryResponse(
|
||||
val cursor: String?, val items: List<LibrarySearchItem>
|
||||
@ -43,7 +53,7 @@ suspend fun Networker.search(
|
||||
val itemList = result.data?.search?.onSearchSuccess?.edges ?: listOf()
|
||||
|
||||
val searchItems = itemList.map {
|
||||
saveLibraryItemContentToFile(context, it.node.id, it.node.content)
|
||||
saveLibraryItemContentToFile(context, it.node.id, it.node.contentReader, it.node.content, it.node.url)
|
||||
LibrarySearchItem(item = SavedItem(
|
||||
savedItemId = it.node.id,
|
||||
title = it.node.title,
|
||||
@ -129,14 +139,41 @@ private fun readFromInternalStorage(context: Context, fileName: String): String?
|
||||
}
|
||||
}
|
||||
|
||||
fun getUriForInternalFile(context: Context, fileName: String): Uri {
|
||||
val file = File(context.filesDir, fileName)
|
||||
return file.toUri()
|
||||
}
|
||||
|
||||
fun saveLibraryItemContentToFile(context: Context, libraryItemId: String, content: String?): Boolean {
|
||||
|
||||
suspend fun saveLibraryItemContentToFile(context: Context, libraryItemId: String, contentReader: ContentReader, content: String?, contentUrl: String?): Boolean {
|
||||
return try {
|
||||
content?.let { content ->
|
||||
writeToInternalStorage(context, content = content, fileName = "${libraryItemId}.html", )
|
||||
return false
|
||||
var localPDFPath: String? = null
|
||||
if (contentReader == ContentReader.PDF) {
|
||||
val localPDFPath = "${libraryItemId}.pdf"
|
||||
val file = File(context.filesDir, localPDFPath)
|
||||
if (file.exists()) {
|
||||
// TODO: there should really be a checksum check here
|
||||
Log.d("PDF", "SKIPPING DOWNLOAD FOR LOCAL PDF PATH: ${localPDFPath}")
|
||||
return true
|
||||
}
|
||||
withContext(Dispatchers.IO) {
|
||||
val urlStream: InputStream = URL(contentUrl).openStream()
|
||||
context.openFileOutput(localPDFPath, Context.MODE_PRIVATE).use { outputStream ->
|
||||
urlStream.use { inputStream ->
|
||||
inputStream.copyTo(outputStream)
|
||||
}
|
||||
}
|
||||
Log.d("PDF", "File written successfully to internal storage.")
|
||||
}
|
||||
Log.d("PDF", "DOWNLOADING PDF TO LOCAL PDF PATH: ${localPDFPath}")
|
||||
true
|
||||
} else {
|
||||
content?.let { content ->
|
||||
writeToInternalStorage(context, content = content, fileName = "${libraryItemId}.html", )
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
false
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
false
|
||||
|
||||
@ -3,6 +3,8 @@ package app.omnivore.omnivore.feature.reader
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toFile
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@ -20,6 +22,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.core.database.entities.SavedItem
|
||||
import app.omnivore.omnivore.core.network.getUriForInternalFile
|
||||
import com.apollographql.apollo3.api.Optional
|
||||
import com.google.gson.Gson
|
||||
import com.pspdfkit.annotations.Annotation
|
||||
@ -57,17 +60,22 @@ class PDFReaderViewModel @Inject constructor(
|
||||
|
||||
fun loadItem(slug: String, context: Context) {
|
||||
viewModelScope.launch {
|
||||
loadItemFromDB(slug)
|
||||
loadItemFromDB(slug, context)
|
||||
loadItemFromNetwork(slug, context)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadItemFromDB(slug: String) {
|
||||
|
||||
|
||||
private suspend fun loadItemFromDB(slug: String, context: Context) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val persistedItem = dataService.db.savedItemDao().getSavedItemWithLabelsAndHighlights(slug)
|
||||
persistedItem?.let { item ->
|
||||
item.savedItem.localPDF?.let { localPDF ->
|
||||
val localFile = File(localPDF)
|
||||
Log.d("PDF", " - persistedItem?.let { item -> ${item}")
|
||||
Log.d("PDF", " - item.savedItem.localPDF -> ${item.savedItem.localPDF}")
|
||||
|
||||
val localPdf = getUriForInternalFile(context,"${item.savedItem.savedItemId}.pdf")
|
||||
val localFile = localPdf.toFile()
|
||||
|
||||
if (localFile.exists()) {
|
||||
val articleContent = ArticleContent(
|
||||
@ -82,10 +90,9 @@ class PDFReaderViewModel @Inject constructor(
|
||||
PDFReaderParams(
|
||||
item.savedItem,
|
||||
articleContent,
|
||||
Uri.fromFile(localFile)
|
||||
localPdf
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user