mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 02:36:24 -04:00
Added the com.squareup.retrofit2:converter-scalars
converter to Retrofit
to parse OPDS
network responses.
* Created `LibkiwixBook` to wrap the `Book` class from `libkiwix`, allowing us to set custom values from the database and manage books received from the `OPDS` stream. This wrapper is necessary because the original Book class does not provide setters. We'll use `LibkiwixBook` throughout the codebase. * Refactored the codebase to replace `LibraryNetworkEntity.Book` with `LibkiwixBook`.
This commit is contained in:
parent
20722fe15b
commit
7a10528d19
@ -82,7 +82,7 @@ import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.FIVE
|
||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.extensions.calculateSearchMatches
|
||||
import org.kiwix.kiwixmobile.core.extensions.registerReceiver
|
||||
import org.kiwix.kiwixmobile.core.ui.components.ONE
|
||||
@ -131,6 +131,7 @@ const val MAX_PROGRESS = 100
|
||||
const val THREE = 3
|
||||
const val FOUR = 4
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
class ZimManageViewModel @Inject constructor(
|
||||
private val downloadDao: DownloadRoomDao,
|
||||
private val bookDao: NewBookDao,
|
||||
@ -168,7 +169,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
val onlineLibraryDownloading = MutableStateFlow(false)
|
||||
val shouldShowWifiOnlyDialog = MutableLiveData<Boolean>()
|
||||
val networkStates = MutableLiveData<NetworkState>()
|
||||
val networkLibrary = MutableSharedFlow<List<org.kiwix.libkiwix.Book>>(replay = 0)
|
||||
val networkLibrary = MutableSharedFlow<List<LibkiwixBook>>(replay = 0)
|
||||
val requestFileSystemCheck = MutableSharedFlow<Unit>(replay = 0)
|
||||
val fileSelectActions = MutableSharedFlow<FileSelectActions>()
|
||||
private val requestDownloadLibrary = MutableSharedFlow<Unit>(
|
||||
@ -391,7 +392,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun requestsAndConnectivityChangesToLibraryRequests(
|
||||
library: MutableSharedFlow<List<org.kiwix.libkiwix.Book>>,
|
||||
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) = requestDownloadLibrary.flatMapConcat {
|
||||
connectivityBroadcastReceiver.networkStates
|
||||
@ -442,12 +443,16 @@ class ZimManageViewModel @Inject constructor(
|
||||
|
||||
private fun downloadLibraryFlow(
|
||||
kiwixService: KiwixService
|
||||
): Flow<List<org.kiwix.libkiwix.Book>> = flow {
|
||||
): Flow<List<LibkiwixBook>> = flow {
|
||||
downloadProgress.postValue(context.getString(R.string.starting_downloading_remote_library))
|
||||
val response = kiwixService.getLibrary()
|
||||
downloadProgress.postValue(context.getString(R.string.parsing_remote_library))
|
||||
onlineLibraryManager.parseOPDSStream(response, KIWIX_OPDS_LIBRARY_URL)
|
||||
emit(onlineLibraryManager.getOnlineBooks())
|
||||
val isLibraryParsed = onlineLibraryManager.parseOPDSStream(response, KIWIX_OPDS_LIBRARY_URL)
|
||||
if (isLibraryParsed) {
|
||||
emit(onlineLibraryManager.getOnlineBooks())
|
||||
} else {
|
||||
emit(emptyList())
|
||||
}
|
||||
}
|
||||
.retry(5)
|
||||
.catch { e ->
|
||||
@ -464,7 +469,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
private fun updateLibraryItems(
|
||||
booksFromDao: Flow<List<BookOnDisk>>,
|
||||
downloads: Flow<List<DownloadModel>>,
|
||||
library: MutableSharedFlow<List<org.kiwix.libkiwix.Book>>,
|
||||
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||
languages: Flow<List<Language>>,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) = viewModelScope.launch(dispatcher) {
|
||||
@ -487,14 +492,14 @@ class ZimManageViewModel @Inject constructor(
|
||||
val books = args[ZERO] as List<BookOnDisk>
|
||||
val activeDownloads = args[ONE] as List<DownloadModel>
|
||||
val languageList = args[TWO] as List<Language>
|
||||
val libraryNetworkEntity = args[THREE] as List<org.kiwix.libkiwix.Book>
|
||||
val libraryNetworkEntity = args[THREE] as List<LibkiwixBook>
|
||||
val filter = args[FOUR] as String
|
||||
val fileSystemState = args[FIVE] as FileSystemState
|
||||
combineLibrarySources(
|
||||
booksOnFileSystem = books,
|
||||
activeDownloads = activeDownloads,
|
||||
allLanguages = languageList,
|
||||
libraryNetworkEntity = libraryNetworkEntity,
|
||||
onlineBooks = libraryNetworkEntity,
|
||||
filter = filter,
|
||||
fileSystemState = fileSystemState
|
||||
)
|
||||
@ -509,7 +514,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun updateLanguagesInDao(
|
||||
library: MutableSharedFlow<List<org.kiwix.libkiwix.Book>>,
|
||||
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||
languages: Flow<List<Language>>,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
) =
|
||||
@ -527,7 +532,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
private fun combineToLanguageList(
|
||||
booksFromNetwork: List<org.kiwix.libkiwix.Book>,
|
||||
booksFromNetwork: List<LibkiwixBook>,
|
||||
allLanguages: List<Language>
|
||||
) = when {
|
||||
booksFromNetwork.isEmpty() -> {
|
||||
@ -551,8 +556,8 @@ class ZimManageViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun networkLanguageCounts(booksFromNetwork: List<org.kiwix.libkiwix.Book>) =
|
||||
booksFromNetwork.mapNotNull { it.language }
|
||||
private fun networkLanguageCounts(booksFromNetwork: List<LibkiwixBook>) =
|
||||
booksFromNetwork.map { it.language }
|
||||
.fold(
|
||||
mutableMapOf<String, Int>()
|
||||
) { acc, language -> acc.increment(language) }
|
||||
@ -589,7 +594,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
booksOnFileSystem: List<BookOnDisk>,
|
||||
activeDownloads: List<DownloadModel>,
|
||||
allLanguages: List<Language>,
|
||||
onlineBooks: List<org.kiwix.libkiwix.Book>,
|
||||
onlineBooks: List<LibkiwixBook>,
|
||||
filter: String,
|
||||
fileSystemState: FileSystemState
|
||||
): List<LibraryListItem> {
|
||||
@ -634,7 +639,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun createLibrarySection(
|
||||
books: List<Book>,
|
||||
books: List<LibkiwixBook>,
|
||||
activeDownloads: List<DownloadModel>,
|
||||
fileSystemState: FileSystemState,
|
||||
sectionStringId: Int,
|
||||
@ -648,7 +653,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun applySearchFilter(
|
||||
unDownloadedBooks: List<Book>,
|
||||
unDownloadedBooks: List<LibkiwixBook>,
|
||||
filter: String
|
||||
) = if (filter.isEmpty()) {
|
||||
unDownloadedBooks
|
||||
@ -657,7 +662,7 @@ class ZimManageViewModel @Inject constructor(
|
||||
unDownloadedBooks.filter { it.searchMatches > 0 }
|
||||
}
|
||||
|
||||
private fun List<Book>.asLibraryItems(
|
||||
private fun List<LibkiwixBook>.asLibraryItems(
|
||||
activeDownloads: List<DownloadModel>,
|
||||
fileSystemState: FileSystemState
|
||||
) = map { book ->
|
||||
|
@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.settings.StorageCalculator
|
||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
||||
import javax.inject.Inject
|
||||
@ -49,6 +49,6 @@ class AvailableSpaceCalculator @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun hasAvailableSpaceForBook(book: Book) =
|
||||
suspend fun hasAvailableSpaceForBook(book: LibkiwixBook) =
|
||||
book.size.toLong() * KB < storageCalculator.availableBytes()
|
||||
}
|
||||
|
@ -24,14 +24,14 @@ import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.Seconds
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.KiwixTag
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CanWrite4GbFile
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CannotWrite4GbFile
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.DetectingFileSystem
|
||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
|
||||
|
||||
sealed class LibraryListItem {
|
||||
abstract val id: Long
|
||||
@ -42,7 +42,7 @@ sealed class LibraryListItem {
|
||||
) : LibraryListItem()
|
||||
|
||||
data class BookItem constructor(
|
||||
val book: Book,
|
||||
val book: LibkiwixBook,
|
||||
val fileSystemState: FileSystemState,
|
||||
val tags: List<KiwixTag> = KiwixTag.from(book.tags),
|
||||
override val id: Long = book.id.hashCode().toLong()
|
||||
@ -54,7 +54,7 @@ sealed class LibraryListItem {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun Book.isLessThan4GB() =
|
||||
private fun LibkiwixBook.isLessThan4GB() =
|
||||
size.toLongOrNull() ?: 0L < Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,12 @@ object Libs {
|
||||
|
||||
const val tracing: String = "androidx.tracing:tracing:" + Versions.tracing
|
||||
|
||||
/**
|
||||
* https://github.com/square/retrofit
|
||||
*/
|
||||
const val converter_scalars: String = "com.squareup.retrofit2:converter-scalars:" +
|
||||
Versions.com_squareup_retrofit2
|
||||
|
||||
/**
|
||||
* https://github.com/square/retrofit
|
||||
*/
|
||||
|
@ -47,6 +47,11 @@ dependencies {
|
||||
implementation(Libs.select_folder_document_file)
|
||||
|
||||
// Square
|
||||
implementation(Libs.converter_scalars) {
|
||||
exclude(group = "xpp3", module = "xpp3")
|
||||
exclude(group = "stax", module = "stax-api")
|
||||
exclude(group = "stax", module = "stax")
|
||||
}
|
||||
implementation(Libs.converter_simplexml) {
|
||||
exclude(group = "xpp3", module = "xpp3")
|
||||
exclude(group = "stax", module = "stax-api")
|
||||
|
@ -50,6 +50,7 @@
|
||||
<ID>PackageNaming:TagsView.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
<ID>PackageNaming:ConnectivityBroadcastReceiver.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
<ID>PackageNaming:NetworkState.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
<ID>PackageNaming:OnlineLibraryManager.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun getAllZimParts(book: Book): List<File></ID>
|
||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic suspend fun getLocalFilePathByUri( context: Context, uri: Uri ): String?</ID>
|
||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic suspend fun hasPart(file: File): Boolean</ID>
|
||||
|
@ -33,7 +33,7 @@ import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
||||
import org.kiwix.kiwixmobile.core.downloader.DownloadRequester
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadRequest
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -100,7 +100,7 @@ abstract class DownloadRoomDao {
|
||||
|
||||
fun addIfDoesNotExist(
|
||||
url: String,
|
||||
book: LibraryNetworkEntity.Book,
|
||||
book: LibkiwixBook,
|
||||
downloadRequester: DownloadRequester
|
||||
) {
|
||||
if (doesNotAlreadyExist(book)) {
|
||||
@ -113,6 +113,6 @@ abstract class DownloadRoomDao {
|
||||
}
|
||||
}
|
||||
|
||||
private fun doesNotAlreadyExist(book: LibraryNetworkEntity.Book) =
|
||||
private fun doesNotAlreadyExist(book: LibkiwixBook) =
|
||||
count(book.id) == 0
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ package org.kiwix.kiwixmobile.core.dao
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.util.Base64
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -36,11 +35,11 @@ import org.kiwix.kiwixmobile.core.DarkModeConfig
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
|
||||
import org.kiwix.kiwixmobile.core.extensions.deleteFile
|
||||
import org.kiwix.kiwixmobile.core.extensions.getFavicon
|
||||
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.page.adapter.Page
|
||||
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
||||
import org.kiwix.kiwixmobile.core.reader.ILLUSTRATION_SIZE
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
@ -285,10 +284,7 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
}
|
||||
|
||||
// Check if the book has an illustration of the specified size and encode it to Base64.
|
||||
val favicon =
|
||||
book?.getIllustration(ILLUSTRATION_SIZE)?.data?.let {
|
||||
Base64.encodeToString(it, Base64.DEFAULT)
|
||||
}
|
||||
val favicon = book?.getFavicon()
|
||||
|
||||
val zimReaderSource = book?.path?.let { ZimReaderSource(File(it)) }
|
||||
// Return the LibkiwixBookmarkItem, filtering out null results.
|
||||
|
@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity_
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||
import javax.inject.Inject
|
||||
@ -124,7 +124,7 @@ class NewBookDao @Inject constructor(private val box: Box<BookOnDiskEntity>) {
|
||||
}
|
||||
|
||||
@Suppress("UnsafeCallOnNullableType")
|
||||
fun migrationInsert(books: List<Book>) {
|
||||
fun migrationInsert(books: List<LibkiwixBook>) {
|
||||
insert(books.map { BookOnDisk(book = it, zimReaderSource = ZimReaderSource(it.file!!)) })
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ import io.objectbox.annotation.Convert
|
||||
import io.objectbox.annotation.Entity
|
||||
import io.objectbox.annotation.Id
|
||||
import io.objectbox.converter.PropertyConverter
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||
@ -70,7 +70,7 @@ data class BookOnDiskEntity(
|
||||
bookOnDisk.book.tags
|
||||
)
|
||||
|
||||
fun toBook() = Book().apply {
|
||||
fun toBook() = LibkiwixBook().apply {
|
||||
id = bookId
|
||||
title = this@BookOnDiskEntity.title
|
||||
description = this@BookOnDiskEntity.description
|
||||
|
@ -20,12 +20,12 @@ package org.kiwix.kiwixmobile.core.dao.entities
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import io.objectbox.annotation.Convert
|
||||
import io.objectbox.converter.PropertyConverter
|
||||
import com.tonyodev.fetch2.Download
|
||||
import com.tonyodev.fetch2.Error
|
||||
import com.tonyodev.fetch2.Status
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import io.objectbox.annotation.Convert
|
||||
import io.objectbox.converter.PropertyConverter
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
|
||||
@Entity
|
||||
data class DownloadRoomEntity(
|
||||
@ -56,7 +56,7 @@ data class DownloadRoomEntity(
|
||||
val favIcon: String,
|
||||
val tags: String? = null
|
||||
) {
|
||||
constructor(downloadId: Long, book: Book) : this(
|
||||
constructor(downloadId: Long, book: LibkiwixBook) : this(
|
||||
downloadId = downloadId,
|
||||
bookId = book.id,
|
||||
title = book.title,
|
||||
@ -75,7 +75,7 @@ data class DownloadRoomEntity(
|
||||
)
|
||||
|
||||
fun toBook() =
|
||||
Book().apply {
|
||||
LibkiwixBook().apply {
|
||||
id = bookId
|
||||
title = this@DownloadRoomEntity.title
|
||||
description = this@DownloadRoomEntity.description
|
||||
|
@ -71,7 +71,7 @@ class Repository @Inject internal constructor(
|
||||
// Split languages if there are multiple, otherwise return the single book. Bug fix #3892
|
||||
if (bookOnDisk.book.language.contains(',')) {
|
||||
bookOnDisk.book.language.split(',').map { lang ->
|
||||
bookOnDisk.copy(book = bookOnDisk.book.copy(language = lang.trim()))
|
||||
bookOnDisk.copy(book = bookOnDisk.book.copy(_language = lang.trim()))
|
||||
}
|
||||
} else {
|
||||
listOf(bookOnDisk)
|
||||
|
@ -22,6 +22,7 @@ package org.kiwix.kiwixmobile.core.data.remote
|
||||
import okhttp3.OkHttpClient
|
||||
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.scalars.ScalarsConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Url
|
||||
|
||||
@ -41,6 +42,8 @@ interface KiwixService {
|
||||
val retrofit = Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(ScalarsConverterFactory.create())
|
||||
// .addConverterFactory(SimpleXmlConverterFactory.create())
|
||||
.build()
|
||||
return retrofit.create(KiwixService::class.java)
|
||||
}
|
||||
@ -49,6 +52,6 @@ interface KiwixService {
|
||||
companion object {
|
||||
// To fetch the full OPDS catalog.
|
||||
// TODO we will change this to pagination later once we migrate to OPDS properly.
|
||||
const val OPDS_LIBRARY_NETWORK_PATH = "/entries?count=-1"
|
||||
const val OPDS_LIBRARY_NETWORK_PATH = "entries?count=-1"
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchResultGenerator
|
||||
import org.kiwix.kiwixmobile.core.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.OnlineLibraryManager
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@ -99,6 +100,7 @@ interface CoreComponent {
|
||||
fun connectivityManager(): ConnectivityManager
|
||||
fun objectBoxToLibkiwixMigrator(): ObjectBoxToLibkiwixMigrator
|
||||
fun libkiwixBookmarks(): LibkiwixBookmarks
|
||||
fun onlineLibraryManager(): OnlineLibraryManager
|
||||
fun recentSearchRoomDao(): RecentSearchRoomDao
|
||||
fun historyRoomDao(): HistoryRoomDao
|
||||
fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
|
||||
|
@ -28,7 +28,6 @@ import org.kiwix.kiwixmobile.core.zim_manager.OnlineLibraryManager
|
||||
import org.kiwix.libkiwix.JNIKiwix
|
||||
import org.kiwix.libkiwix.Library
|
||||
import org.kiwix.libkiwix.Manager
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@ -38,39 +37,27 @@ class JNIModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("bookmarks")
|
||||
fun provideLibrary(): Library = Library()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("bookmarks")
|
||||
fun providesManager(library: Library): Manager = Manager(library)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesLibkiwixBookmarks(
|
||||
@Named("bookmarks") library: Library,
|
||||
@Named("bookmarks") manager: Manager,
|
||||
library: Library,
|
||||
manager: Manager,
|
||||
sharedPreferenceUtil: SharedPreferenceUtil,
|
||||
bookDao: NewBookDao,
|
||||
zimReaderContainer: ZimReaderContainer
|
||||
): LibkiwixBookmarks =
|
||||
LibkiwixBookmarks(library, manager, sharedPreferenceUtil, bookDao, zimReaderContainer)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("onlineLibrary")
|
||||
fun provideOnlineLibrary(): Library = Library()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("onlineLibrary")
|
||||
fun providesOnlineManager(library: Library): Manager = Manager(library)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnlineLibraryParser(
|
||||
@Named("onlineLibrary") library: Library,
|
||||
@Named("onlineLibrary") manager: Manager
|
||||
) = OnlineLibraryManager(library, manager)
|
||||
library: Library,
|
||||
manager: Manager
|
||||
): OnlineLibraryManager = OnlineLibraryManager(library, manager)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ const val CONNECTION_TIMEOUT = 10L
|
||||
const val READ_TIMEOUT = 300L
|
||||
const val CALL_TIMEOUT = 300L
|
||||
const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}"
|
||||
const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/v2"
|
||||
const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/v2/"
|
||||
|
||||
@Module
|
||||
class NetworkModule {
|
||||
|
@ -17,10 +17,10 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.core.downloader
|
||||
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
|
||||
interface Downloader {
|
||||
fun download(book: LibraryNetworkEntity.Book)
|
||||
fun download(book: LibkiwixBook)
|
||||
fun cancelDownload(downloadId: Long)
|
||||
fun retryDownload(downloadId: Long)
|
||||
fun pauseResumeDownload(downloadId: Long, isPause: Boolean)
|
||||
|
@ -23,8 +23,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import javax.inject.Inject
|
||||
|
||||
class DownloaderImpl @Inject constructor(
|
||||
@ -33,7 +32,7 @@ class DownloaderImpl @Inject constructor(
|
||||
private val kiwixService: KiwixService
|
||||
) : Downloader {
|
||||
@Suppress("InjectDispatcher")
|
||||
override fun download(book: LibraryNetworkEntity.Book) {
|
||||
override fun download(book: LibkiwixBook) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
runCatching {
|
||||
urlProvider(book)?.let {
|
||||
@ -46,7 +45,7 @@ class DownloaderImpl @Inject constructor(
|
||||
}
|
||||
|
||||
@Suppress("UnsafeCallOnNullableType")
|
||||
private suspend fun urlProvider(book: Book): String? =
|
||||
private suspend fun urlProvider(book: LibkiwixBook): String? =
|
||||
if (book.url?.endsWith("meta4") == true) {
|
||||
kiwixService.getMetaLinks(book.url!!)?.relevantUrl?.value
|
||||
} else {
|
||||
|
@ -17,10 +17,10 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.core.downloader.model
|
||||
|
||||
import com.tonyodev.fetch2.Status
|
||||
import com.tonyodev.fetch2.Error
|
||||
import com.tonyodev.fetch2.Status
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.utils.StorageUtils
|
||||
|
||||
data class DownloadModel(
|
||||
@ -33,7 +33,7 @@ data class DownloadModel(
|
||||
val state: Status,
|
||||
val error: Error,
|
||||
val progress: Int,
|
||||
val book: Book
|
||||
val book: LibkiwixBook
|
||||
) {
|
||||
val bytesRemaining: Long by lazy { totalSizeOfDownload - bytesDownloaded }
|
||||
val fileNameFromUrl: String by lazy { StorageUtils.getFileNameFromUrl(book.url) }
|
||||
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.core.entity
|
||||
|
||||
import org.kiwix.kiwixmobile.core.extensions.getFavicon
|
||||
import org.kiwix.libkiwix.Book
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Wrapper around libkiwix's [Book] that allows setting custom values (e.g. from DB or UI),
|
||||
* while still falling back to the original [nativeBook]'s properties when not provided.
|
||||
*/
|
||||
@Suppress("ConstructorParameterNaming")
|
||||
data class LibkiwixBook(
|
||||
private val nativeBook: Book? = null,
|
||||
private var _id: String = "",
|
||||
private var _title: String = "",
|
||||
private var _description: String? = null,
|
||||
private var _language: String = "",
|
||||
private var _creator: String = "",
|
||||
private var _publisher: String = "",
|
||||
private var _date: String = "",
|
||||
private var _url: String? = null,
|
||||
private var _articleCount: String? = null,
|
||||
private var _mediaCount: String? = null,
|
||||
private var _size: String = "",
|
||||
private var _bookName: String? = null,
|
||||
private var _favicon: String = "",
|
||||
private var _tags: String? = null,
|
||||
var searchMatches: Int = 0,
|
||||
var file: File? = null
|
||||
) {
|
||||
var id: String
|
||||
get() = _id.ifEmpty { nativeBook?.id.orEmpty() }
|
||||
set(id) {
|
||||
_id = id
|
||||
}
|
||||
|
||||
var title: String
|
||||
get() = _title.ifEmpty { nativeBook?.title.orEmpty() }
|
||||
set(title) {
|
||||
_title = title
|
||||
}
|
||||
|
||||
var description: String?
|
||||
get() = _description ?: nativeBook?.description
|
||||
set(description) {
|
||||
_description = description
|
||||
}
|
||||
|
||||
var language: String
|
||||
get() = _language.ifEmpty { nativeBook?.language.orEmpty() }
|
||||
set(language) {
|
||||
_language = language
|
||||
}
|
||||
|
||||
var creator: String
|
||||
get() = _creator.ifEmpty { nativeBook?.creator.orEmpty() }
|
||||
set(creator) {
|
||||
_creator = creator
|
||||
}
|
||||
|
||||
var publisher: String
|
||||
get() = _publisher.ifEmpty { nativeBook?.publisher.orEmpty() }
|
||||
set(publisher) {
|
||||
_publisher = publisher
|
||||
}
|
||||
|
||||
var date: String
|
||||
get() = _date.ifEmpty { nativeBook?.date.orEmpty() }
|
||||
set(date) {
|
||||
_date = date
|
||||
}
|
||||
|
||||
var url: String?
|
||||
get() = _url ?: nativeBook?.url
|
||||
set(url) {
|
||||
_url = url
|
||||
}
|
||||
|
||||
var articleCount: String?
|
||||
get() = _articleCount ?: nativeBook?.articleCount?.toString()
|
||||
set(articleCount) {
|
||||
_articleCount = articleCount
|
||||
}
|
||||
|
||||
var mediaCount: String?
|
||||
get() = _mediaCount ?: nativeBook?.mediaCount?.toString()
|
||||
set(mediaCount) {
|
||||
_mediaCount = mediaCount
|
||||
}
|
||||
|
||||
var size: String
|
||||
get() = _size.ifEmpty { nativeBook?.size?.toString().orEmpty() }
|
||||
set(size) {
|
||||
_size = size
|
||||
}
|
||||
|
||||
var bookName: String?
|
||||
get() = _bookName ?: nativeBook?.name
|
||||
set(bookName) {
|
||||
_bookName = bookName
|
||||
}
|
||||
|
||||
var favicon: String
|
||||
get() = _favicon.ifEmpty { nativeBook?.getFavicon().orEmpty() }
|
||||
set(favicon) {
|
||||
_favicon = favicon
|
||||
}
|
||||
|
||||
var tags: String?
|
||||
get() = _tags ?: nativeBook?.tags
|
||||
set(tags) {
|
||||
_tags = tags
|
||||
}
|
||||
|
||||
// Two books are equal if their ids match
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is LibkiwixBook) {
|
||||
if (other.id == id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Only use the book's id to generate a hash code
|
||||
override fun hashCode(): Int = id.hashCode()
|
||||
}
|
@ -18,30 +18,32 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.extensions
|
||||
|
||||
import android.util.Base64
|
||||
import org.kiwix.kiwixmobile.core.CoreApp
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.reader.ILLUSTRATION_SIZE
|
||||
import org.kiwix.kiwixmobile.core.utils.BookUtils
|
||||
import org.kiwix.kiwixmobile.core.utils.NetworkUtils
|
||||
import org.kiwix.libkiwix.Book
|
||||
|
||||
fun Book.calculateSearchMatches(
|
||||
fun LibkiwixBook.calculateSearchMatches(
|
||||
filter: String,
|
||||
bookUtils: BookUtils
|
||||
) {
|
||||
val searchableText = buildSearchableText(bookUtils)
|
||||
searchMatches = filter.split("\\s+")
|
||||
.foldRight(
|
||||
0,
|
||||
{ filterWord, acc ->
|
||||
if (searchableText.contains(filterWord, true)) {
|
||||
acc + 1
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
0
|
||||
) { filterWord, acc ->
|
||||
if (searchableText.contains(filterWord, true)) {
|
||||
acc + 1
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun Book.buildSearchableText(bookUtils: BookUtils): String =
|
||||
fun LibkiwixBook.buildSearchableText(bookUtils: BookUtils): String =
|
||||
StringBuilder().apply {
|
||||
append(title)
|
||||
append("|")
|
||||
@ -54,3 +56,7 @@ fun Book.buildSearchableText(bookUtils: BookUtils): String =
|
||||
append("|")
|
||||
}
|
||||
}.toString()
|
||||
|
||||
fun Book.getFavicon(): String? = getIllustration(ILLUSTRATION_SIZE)?.data?.let {
|
||||
Base64.encodeToString(it, Base64.DEFAULT)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kiwix.kiwixmobile.core.CoreApp
|
||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.main.UNINITIALISER_ADDRESS
|
||||
import org.kiwix.kiwixmobile.core.main.UNINITIALISE_HTML
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
|
||||
@ -377,7 +377,7 @@ class ZimFileReader constructor(
|
||||
|
||||
@Suppress("ExplicitThis") // this@ZimFileReader.name is required
|
||||
fun toBook() =
|
||||
Book().apply {
|
||||
LibkiwixBook().apply {
|
||||
title = this@ZimFileReader.title
|
||||
id = this@ZimFileReader.id
|
||||
size = "$fileSize"
|
||||
|
@ -18,11 +18,12 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.zim_manager
|
||||
|
||||
import org.kiwix.libkiwix.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.libkiwix.Library
|
||||
import org.kiwix.libkiwix.Manager
|
||||
import javax.inject.Inject
|
||||
|
||||
class OnlineLibraryManager(
|
||||
class OnlineLibraryManager @Inject constructor(
|
||||
val library: Library,
|
||||
val manager: Manager
|
||||
) {
|
||||
@ -33,12 +34,12 @@ class OnlineLibraryManager(
|
||||
it.printStackTrace()
|
||||
}.isSuccess
|
||||
|
||||
suspend fun getOnlineBooks(): List<Book> {
|
||||
val onlineBooksList = arrayListOf<Book>()
|
||||
suspend fun getOnlineBooks(): List<LibkiwixBook> {
|
||||
val onlineBooksList = arrayListOf<LibkiwixBook>()
|
||||
runCatching {
|
||||
library.booksIds.forEach { bookId ->
|
||||
val book = library.getBookById(bookId)
|
||||
onlineBooksList.add(book)
|
||||
onlineBooksList.add(LibkiwixBook(book))
|
||||
}
|
||||
}.onFailure { it.printStackTrace() }
|
||||
return onlineBooksList
|
||||
|
@ -21,7 +21,7 @@ package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view
|
||||
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.convertToLocal
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.KiwixTag
|
||||
@ -44,7 +44,7 @@ sealed class BooksOnDiskListItem {
|
||||
|
||||
data class BookOnDisk constructor(
|
||||
val databaseId: Long = 0L,
|
||||
val book: LibraryNetworkEntity.Book,
|
||||
val book: LibkiwixBook,
|
||||
val file: File = File(""),
|
||||
val zimReaderSource: ZimReaderSource,
|
||||
val tags: List<KiwixTag> = KiwixTag.Companion.from(book.tags),
|
||||
|
@ -21,7 +21,7 @@ package org.kiwix.kiwixmobile.custom.download.effects
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.downloader.Downloader
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||
import org.kiwix.kiwixmobile.custom.BuildConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -45,7 +45,7 @@ data class DownloadCustom @Inject constructor(val downloader: Downloader) : Side
|
||||
name: String = "",
|
||||
favIcon: String = ""
|
||||
) =
|
||||
Book().apply {
|
||||
LibkiwixBook().apply {
|
||||
this.id = id
|
||||
this.title = title
|
||||
this.description = description
|
||||
|
Loading…
x
Reference in New Issue
Block a user