mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-22 20:24:03 -04:00
Merge pull request #4333 from kiwix/Fixes#4298
Introduced support of OPDS catalog.
This commit is contained in:
commit
18e3b3d9b6
7
app/proguard-rules.pro
vendored
7
app/proguard-rules.pro
vendored
@ -55,13 +55,6 @@
|
|||||||
<init>(...);
|
<init>(...);
|
||||||
}
|
}
|
||||||
|
|
||||||
## keep everything in LibraryNetworkEntity.kt
|
|
||||||
-keep class org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity { *; }
|
|
||||||
-keep class org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity$* { *; }
|
|
||||||
-keepclassmembers class org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity$* {
|
|
||||||
<init>(...);
|
|
||||||
}
|
|
||||||
|
|
||||||
-keep class javax.xml.stream.** { *; }
|
-keep class javax.xml.stream.** { *; }
|
||||||
-dontwarn javax.xml.stream.Location
|
-dontwarn javax.xml.stream.Location
|
||||||
-dontwarn javax.xml.stream.XMLEventReader
|
-dontwarn javax.xml.stream.XMLEventReader
|
||||||
|
@ -127,7 +127,7 @@ class DownloadRobot : BaseRobot() {
|
|||||||
testFlakyView({
|
testFlakyView({
|
||||||
composeTestRule.apply {
|
composeTestRule.apply {
|
||||||
waitUntilTimeout()
|
waitUntilTimeout()
|
||||||
onAllNodesWithTag(ONLINE_BOOK_ITEM_TESTING_TAG)[0].performClick()
|
onAllNodesWithTag(ONLINE_BOOK_ITEM_TESTING_TAG)[1].performClick()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ import org.kiwix.kiwixmobile.core.di.modules.CALL_TIMEOUT
|
|||||||
import org.kiwix.kiwixmobile.core.di.modules.CONNECTION_TIMEOUT
|
import org.kiwix.kiwixmobile.core.di.modules.CONNECTION_TIMEOUT
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.READ_TIMEOUT
|
import org.kiwix.kiwixmobile.core.di.modules.READ_TIMEOUT
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.USER_AGENT
|
import org.kiwix.kiwixmobile.core.di.modules.USER_AGENT
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.SWIPE_REFRESH_TESTING_TAG
|
import org.kiwix.kiwixmobile.core.ui.components.SWIPE_REFRESH_TESTING_TAG
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.Log
|
import org.kiwix.kiwixmobile.core.utils.files.Log
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -150,7 +150,7 @@ object TestUtils {
|
|||||||
@JvmStatic fun withContent(content: String): Matcher<Any?> {
|
@JvmStatic fun withContent(content: String): Matcher<Any?> {
|
||||||
return object : BoundedMatcher<Any?, Any?>(Any::class.java) {
|
return object : BoundedMatcher<Any?, Any?>(Any::class.java) {
|
||||||
public override fun matchesSafely(myObj: Any?): Boolean {
|
public override fun matchesSafely(myObj: Any?): Boolean {
|
||||||
if (myObj !is LibraryNetworkEntity.Book) {
|
if (myObj !is LibkiwixBook) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return if (myObj.url != null) {
|
return if (myObj.url != null) {
|
||||||
|
@ -35,7 +35,7 @@ import org.junit.Rule
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.utils.TestingUtils.RETRY_RULE_ORDER
|
import org.kiwix.kiwixmobile.core.utils.TestingUtils.RETRY_RULE_ORDER
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.DocumentResolverWrapper
|
import org.kiwix.kiwixmobile.core.utils.files.DocumentResolverWrapper
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
||||||
@ -109,7 +109,7 @@ class FileUtilsInstrumentationTest {
|
|||||||
}
|
}
|
||||||
char1++
|
char1++
|
||||||
}
|
}
|
||||||
val book = LibraryNetworkEntity.Book()
|
val book = LibkiwixBook()
|
||||||
book.file = File(fileName + "bg")
|
book.file = File(fileName + "bg")
|
||||||
val files = getAllZimParts(book)
|
val files = getAllZimParts(book)
|
||||||
|
|
||||||
|
@ -44,7 +44,6 @@ import androidx.compose.ui.semantics.testTag
|
|||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
import org.kiwix.kiwixmobile.core.R.string
|
import org.kiwix.kiwixmobile.core.R.string
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.toPainter
|
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.ProgressBarStyle
|
import org.kiwix.kiwixmobile.core.ui.components.ProgressBarStyle
|
||||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
import org.kiwix.kiwixmobile.core.ui.models.IconItem
|
||||||
@ -104,7 +103,7 @@ private fun DownloadBookContent(
|
|||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
BookIcon(item.favIcon.toPainter())
|
BookIcon(item.favIconUrl, isOnlineLibrary = true)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
|
@ -48,8 +48,6 @@ import androidx.compose.ui.semantics.contentDescription
|
|||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.toPainter
|
|
||||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||||
import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme
|
import org.kiwix.kiwixmobile.core.ui.theme.KiwixTheme
|
||||||
import org.kiwix.kiwixmobile.core.ui.theme.PureGrey
|
import org.kiwix.kiwixmobile.core.ui.theme.PureGrey
|
||||||
@ -58,7 +56,7 @@ import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FIVE_DP
|
|||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.ONLINE_BOOK_DISABLED_COLOR_ALPHA
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.ONLINE_BOOK_DISABLED_COLOR_ALPHA
|
||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.KiloByte
|
import org.kiwix.kiwixmobile.core.zim_manager.Byte
|
||||||
import org.kiwix.kiwixmobile.ui.BookDate
|
import org.kiwix.kiwixmobile.ui.BookDate
|
||||||
import org.kiwix.kiwixmobile.ui.BookDescription
|
import org.kiwix.kiwixmobile.ui.BookDescription
|
||||||
import org.kiwix.kiwixmobile.ui.BookIcon
|
import org.kiwix.kiwixmobile.ui.BookIcon
|
||||||
@ -167,7 +165,7 @@ private fun OnlineBookContent(item: BookItem, bookUtils: BookUtils) {
|
|||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
BookIcon(Base64String(item.book.favicon).toPainter())
|
BookIcon(item.book.favicon, isOnlineLibrary = true)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
@ -207,7 +205,7 @@ private fun BookSizeAndDateRow(item: BookItem) {
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
BookSize(
|
BookSize(
|
||||||
KiloByte(item.book.size).humanReadable,
|
Byte(item.book.size).humanReadable,
|
||||||
modifier = Modifier.weight(1f).testTag(ONLINE_BOOK_SIZE_TEXT_TESTING_TAG)
|
modifier = Modifier.weight(1f).testTag(ONLINE_BOOK_SIZE_TEXT_TESTING_TAG)
|
||||||
)
|
)
|
||||||
BookDate(item.book.date)
|
BookDate(item.book.date)
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.kiwix.kiwixmobile.ui
|
package org.kiwix.kiwixmobile.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -31,18 +32,17 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import coil3.compose.AsyncImage
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.toPainter
|
import org.kiwix.kiwixmobile.core.downloader.model.toPainter
|
||||||
@ -53,7 +53,7 @@ import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FIVE_DP
|
|||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
|
||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.SIXTEEN_DP
|
||||||
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.TWO_DP
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.KiloByte
|
import org.kiwix.kiwixmobile.core.zim_manager.Byte
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.ArticleCount
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.ArticleCount
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode
|
||||||
@ -116,7 +116,7 @@ private fun BookContent(
|
|||||||
if (selectionMode == SelectionMode.MULTI) {
|
if (selectionMode == SelectionMode.MULTI) {
|
||||||
BookCheckbox(bookOnDisk, selectionMode, onMultiSelect, onClick, index)
|
BookCheckbox(bookOnDisk, selectionMode, onMultiSelect, onClick, index)
|
||||||
}
|
}
|
||||||
BookIcon(Base64String(bookOnDisk.book.favicon).toPainter())
|
BookIcon(bookOnDisk.book.favicon, isOnlineLibrary = false)
|
||||||
BookDetails(Modifier.weight(1f), bookOnDisk)
|
BookDetails(Modifier.weight(1f), bookOnDisk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,14 +142,23 @@ private fun BookCheckbox(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BookIcon(painter: Painter) {
|
fun BookIcon(iconSource: String, isOnlineLibrary: Boolean) {
|
||||||
Icon(
|
val modifier = Modifier.size(BOOK_ICON_SIZE)
|
||||||
painter = painter,
|
if (isOnlineLibrary) {
|
||||||
contentDescription = stringResource(R.string.fav_icon),
|
AsyncImage(
|
||||||
modifier = Modifier
|
model = iconSource,
|
||||||
.size(BOOK_ICON_SIZE),
|
contentDescription = stringResource(R.string.fav_icon),
|
||||||
tint = Color.Unspecified
|
modifier = modifier,
|
||||||
)
|
placeholder = painterResource(R.drawable.default_zim_file_icon),
|
||||||
|
error = painterResource(R.drawable.default_zim_file_icon),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Image(
|
||||||
|
painter = Base64String(iconSource).toPainter(),
|
||||||
|
contentDescription = stringResource(R.string.fav_icon),
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -164,7 +173,7 @@ private fun BookDetails(modifier: Modifier, bookOnDisk: BookOnDisk) {
|
|||||||
) {
|
) {
|
||||||
BookDate(bookOnDisk.book.date)
|
BookDate(bookOnDisk.book.date)
|
||||||
Spacer(modifier = Modifier.width(EIGHT_DP))
|
Spacer(modifier = Modifier.width(EIGHT_DP))
|
||||||
BookSize(KiloByte(bookOnDisk.book.size).humanReadable)
|
BookSize(Byte(bookOnDisk.book.size).humanReadable)
|
||||||
Spacer(modifier = Modifier.width(EIGHT_DP))
|
Spacer(modifier = Modifier.width(EIGHT_DP))
|
||||||
BookArticleCount(
|
BookArticleCount(
|
||||||
ArticleCount(bookOnDisk.book.articleCount.orEmpty())
|
ArticleCount(bookOnDisk.book.articleCount.orEmpty())
|
||||||
|
@ -22,18 +22,18 @@ import org.kiwix.kiwixmobile.core.R
|
|||||||
import org.kiwix.kiwixmobile.core.data.remote.OnlineLibraryProgressListener
|
import org.kiwix.kiwixmobile.core.data.remote.OnlineLibraryProgressListener
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
||||||
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.NINE
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||||
|
|
||||||
class AppProgressListenerProvider(
|
class AppProgressListenerProvider(
|
||||||
private val zimManageViewModel: ZimManageViewModel
|
private val zimManageViewModel: ZimManageViewModel
|
||||||
) : OnlineLibraryProgressListener {
|
) : OnlineLibraryProgressListener {
|
||||||
@Suppress("MagicNumber")
|
|
||||||
override fun onProgress(bytesRead: Long, contentLength: Long) {
|
override fun onProgress(bytesRead: Long, contentLength: Long) {
|
||||||
val progress =
|
val progress =
|
||||||
if (contentLength == DEFAULT_INT_VALUE.toLong()) {
|
if (contentLength == DEFAULT_INT_VALUE.toLong()) {
|
||||||
ZERO
|
ZERO
|
||||||
} else {
|
} else {
|
||||||
(bytesRead * 3 * HUNDERED / contentLength).coerceAtMost(HUNDERED.toLong())
|
(bytesRead * NINE * HUNDERED / contentLength).coerceAtMost(HUNDERED.toLong())
|
||||||
}
|
}
|
||||||
zimManageViewModel.downloadProgress.postValue(
|
zimManageViewModel.downloadProgress.postValue(
|
||||||
zimManageViewModel.context.getString(
|
zimManageViewModel.context.getString(
|
||||||
|
@ -70,20 +70,19 @@ import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
|||||||
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
||||||
import org.kiwix.kiwixmobile.core.data.DataSource
|
import org.kiwix.kiwixmobile.core.data.DataSource
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService.Companion.LIBRARY_NETWORK_PATH
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService.Companion.OPDS_LIBRARY_NETWORK_PATH
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.ProgressResponseBody
|
import org.kiwix.kiwixmobile.core.data.remote.ProgressResponseBody
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.UserAgentInterceptor
|
import org.kiwix.kiwixmobile.core.data.remote.UserAgentInterceptor
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.CALL_TIMEOUT
|
import org.kiwix.kiwixmobile.core.di.modules.CALL_TIMEOUT
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.CONNECTION_TIMEOUT
|
import org.kiwix.kiwixmobile.core.di.modules.CONNECTION_TIMEOUT
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.KIWIX_DOWNLOAD_URL
|
import org.kiwix.kiwixmobile.core.di.modules.KIWIX_OPDS_LIBRARY_URL
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.READ_TIMEOUT
|
import org.kiwix.kiwixmobile.core.di.modules.READ_TIMEOUT
|
||||||
import org.kiwix.kiwixmobile.core.di.modules.USER_AGENT
|
import org.kiwix.kiwixmobile.core.di.modules.USER_AGENT
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE
|
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.FIVE
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
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.entity.LibraryNetworkEntity.Book
|
|
||||||
import org.kiwix.kiwixmobile.core.extensions.calculateSearchMatches
|
import org.kiwix.kiwixmobile.core.extensions.calculateSearchMatches
|
||||||
import org.kiwix.kiwixmobile.core.extensions.registerReceiver
|
import org.kiwix.kiwixmobile.core.extensions.registerReceiver
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.ONE
|
import org.kiwix.kiwixmobile.core.ui.components.ONE
|
||||||
@ -97,6 +96,7 @@ import org.kiwix.kiwixmobile.core.zim_manager.ConnectivityBroadcastReceiver
|
|||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState
|
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState.CONNECTED
|
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState.CONNECTED
|
||||||
|
import org.kiwix.kiwixmobile.core.zim_manager.OnlineLibraryManager
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode.MULTI
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode.MULTI
|
||||||
@ -121,7 +121,8 @@ import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
|||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.BookItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.BookItem
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.DividerItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.DividerItem
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.LibraryDownloadItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.LibraryDownloadItem
|
||||||
import java.util.LinkedList
|
import org.kiwix.libkiwix.Library
|
||||||
|
import org.kiwix.libkiwix.Manager
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit.SECONDS
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -132,6 +133,7 @@ const val MAX_PROGRESS = 100
|
|||||||
const val THREE = 3
|
const val THREE = 3
|
||||||
const val FOUR = 4
|
const val FOUR = 4
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
class ZimManageViewModel @Inject constructor(
|
class ZimManageViewModel @Inject constructor(
|
||||||
private val downloadDao: DownloadRoomDao,
|
private val downloadDao: DownloadRoomDao,
|
||||||
private val bookDao: NewBookDao,
|
private val bookDao: NewBookDao,
|
||||||
@ -145,7 +147,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
private val defaultLanguageProvider: DefaultLanguageProvider,
|
private val defaultLanguageProvider: DefaultLanguageProvider,
|
||||||
private val dataSource: DataSource,
|
private val dataSource: DataSource,
|
||||||
private val connectivityManager: ConnectivityManager,
|
private val connectivityManager: ConnectivityManager,
|
||||||
private val sharedPreferenceUtil: SharedPreferenceUtil
|
private val sharedPreferenceUtil: SharedPreferenceUtil,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
sealed class FileSelectActions {
|
sealed class FileSelectActions {
|
||||||
data class RequestNavigateTo(val bookOnDisk: BookOnDisk) : FileSelectActions()
|
data class RequestNavigateTo(val bookOnDisk: BookOnDisk) : FileSelectActions()
|
||||||
@ -158,6 +160,12 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
object UserClickedDownloadBooksButton : FileSelectActions()
|
object UserClickedDownloadBooksButton : FileSelectActions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val library by lazy { Library() }
|
||||||
|
private val manager by lazy { Manager(library) }
|
||||||
|
|
||||||
|
private val onlineLibraryManager by lazy {
|
||||||
|
OnlineLibraryManager(library, manager)
|
||||||
|
}
|
||||||
private var isUnitTestCase: Boolean = false
|
private var isUnitTestCase: Boolean = false
|
||||||
val sideEffects: MutableSharedFlow<SideEffect<*>> = MutableSharedFlow()
|
val sideEffects: MutableSharedFlow<SideEffect<*>> = MutableSharedFlow()
|
||||||
private val _libraryItems = MutableStateFlow<List<LibraryListItem>>(emptyList())
|
private val _libraryItems = MutableStateFlow<List<LibraryListItem>>(emptyList())
|
||||||
@ -168,7 +176,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
val onlineLibraryDownloading = MutableStateFlow(false)
|
val onlineLibraryDownloading = MutableStateFlow(false)
|
||||||
val shouldShowWifiOnlyDialog = MutableLiveData<Boolean>()
|
val shouldShowWifiOnlyDialog = MutableLiveData<Boolean>()
|
||||||
val networkStates = MutableLiveData<NetworkState>()
|
val networkStates = MutableLiveData<NetworkState>()
|
||||||
val networkLibrary = MutableSharedFlow<LibraryNetworkEntity>(replay = 0)
|
val networkLibrary = MutableSharedFlow<List<LibkiwixBook>>(replay = 0)
|
||||||
val requestFileSystemCheck = MutableSharedFlow<Unit>(replay = 0)
|
val requestFileSystemCheck = MutableSharedFlow<Unit>(replay = 0)
|
||||||
val fileSelectActions = MutableSharedFlow<FileSelectActions>()
|
val fileSelectActions = MutableSharedFlow<FileSelectActions>()
|
||||||
private val requestDownloadLibrary = MutableSharedFlow<Unit>(
|
private val requestDownloadLibrary = MutableSharedFlow<Unit>(
|
||||||
@ -238,7 +246,10 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
} ?: originalResponse
|
} ?: originalResponse
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
return KiwixService.ServiceCreator.newHackListService(customOkHttpClient, KIWIX_DOWNLOAD_URL)
|
return KiwixService.ServiceCreator.newHackListService(
|
||||||
|
customOkHttpClient,
|
||||||
|
KIWIX_OPDS_LIBRARY_URL
|
||||||
|
)
|
||||||
.also {
|
.also {
|
||||||
kiwixService = it
|
kiwixService = it
|
||||||
}
|
}
|
||||||
@ -249,7 +260,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
private fun getContentLengthOfLibraryXmlFile(): Long {
|
private fun getContentLengthOfLibraryXmlFile(): Long {
|
||||||
val headRequest =
|
val headRequest =
|
||||||
Request.Builder()
|
Request.Builder()
|
||||||
.url("$KIWIX_DOWNLOAD_URL$LIBRARY_NETWORK_PATH")
|
.url("$KIWIX_OPDS_LIBRARY_URL$OPDS_LIBRARY_NETWORK_PATH")
|
||||||
.head()
|
.head()
|
||||||
.header("Accept-Encoding", "identity")
|
.header("Accept-Encoding", "identity")
|
||||||
.build()
|
.build()
|
||||||
@ -388,7 +399,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
private fun requestsAndConnectivityChangesToLibraryRequests(
|
private fun requestsAndConnectivityChangesToLibraryRequests(
|
||||||
library: MutableSharedFlow<LibraryNetworkEntity>,
|
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) = requestDownloadLibrary.flatMapConcat {
|
) = requestDownloadLibrary.flatMapConcat {
|
||||||
connectivityBroadcastReceiver.networkStates
|
connectivityBroadcastReceiver.networkStates
|
||||||
@ -408,6 +419,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
it.printStackTrace().also {
|
it.printStackTrace().also {
|
||||||
isOnlineLibraryDownloading = false
|
isOnlineLibraryDownloading = false
|
||||||
onlineLibraryDownloading.tryEmit(false)
|
onlineLibraryDownloading.tryEmit(false)
|
||||||
|
library.emit(emptyList())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onEach {
|
.onEach {
|
||||||
@ -439,16 +451,27 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
|
|
||||||
private fun downloadLibraryFlow(
|
private fun downloadLibraryFlow(
|
||||||
kiwixService: KiwixService
|
kiwixService: KiwixService
|
||||||
): Flow<LibraryNetworkEntity?> = flow {
|
): Flow<List<LibkiwixBook>> = flow {
|
||||||
downloadProgress.postValue(context.getString(R.string.starting_downloading_remote_library))
|
downloadProgress.postValue(context.getString(R.string.starting_downloading_remote_library))
|
||||||
val response = kiwixService.getLibrary()
|
val response = kiwixService.getLibrary()
|
||||||
|
val resolvedUrl = response.raw().networkResponse?.request?.url
|
||||||
|
?: response.raw().request.url
|
||||||
|
val baseHostUrl = "${resolvedUrl.scheme}://${resolvedUrl.host}"
|
||||||
downloadProgress.postValue(context.getString(R.string.parsing_remote_library))
|
downloadProgress.postValue(context.getString(R.string.parsing_remote_library))
|
||||||
emit(response)
|
val libraryXml = response.body()
|
||||||
|
val isLibraryParsed = onlineLibraryManager.parseOPDSStream(libraryXml, baseHostUrl)
|
||||||
|
emit(
|
||||||
|
if (isLibraryParsed) {
|
||||||
|
onlineLibraryManager.getOnlineBooks()
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.retry(5)
|
.retry(5)
|
||||||
.catch { e ->
|
.catch { e ->
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
emit(LibraryNetworkEntity().apply { book = LinkedList() })
|
emit(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateNetworkStates() = connectivityBroadcastReceiver.networkStates
|
private fun updateNetworkStates() = connectivityBroadcastReceiver.networkStates
|
||||||
@ -460,7 +483,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
private fun updateLibraryItems(
|
private fun updateLibraryItems(
|
||||||
booksFromDao: Flow<List<BookOnDisk>>,
|
booksFromDao: Flow<List<BookOnDisk>>,
|
||||||
downloads: Flow<List<DownloadModel>>,
|
downloads: Flow<List<DownloadModel>>,
|
||||||
library: MutableSharedFlow<LibraryNetworkEntity>,
|
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||||
languages: Flow<List<Language>>,
|
languages: Flow<List<Language>>,
|
||||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) = viewModelScope.launch(dispatcher) {
|
) = viewModelScope.launch(dispatcher) {
|
||||||
@ -483,14 +506,14 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
val books = args[ZERO] as List<BookOnDisk>
|
val books = args[ZERO] as List<BookOnDisk>
|
||||||
val activeDownloads = args[ONE] as List<DownloadModel>
|
val activeDownloads = args[ONE] as List<DownloadModel>
|
||||||
val languageList = args[TWO] as List<Language>
|
val languageList = args[TWO] as List<Language>
|
||||||
val libraryNetworkEntity = args[THREE] as LibraryNetworkEntity
|
val libraryNetworkEntity = args[THREE] as List<LibkiwixBook>
|
||||||
val filter = args[FOUR] as String
|
val filter = args[FOUR] as String
|
||||||
val fileSystemState = args[FIVE] as FileSystemState
|
val fileSystemState = args[FIVE] as FileSystemState
|
||||||
combineLibrarySources(
|
combineLibrarySources(
|
||||||
booksOnFileSystem = books,
|
booksOnFileSystem = books,
|
||||||
activeDownloads = activeDownloads,
|
activeDownloads = activeDownloads,
|
||||||
allLanguages = languageList,
|
allLanguages = languageList,
|
||||||
libraryNetworkEntity = libraryNetworkEntity,
|
onlineBooks = libraryNetworkEntity,
|
||||||
filter = filter,
|
filter = filter,
|
||||||
fileSystemState = fileSystemState
|
fileSystemState = fileSystemState
|
||||||
)
|
)
|
||||||
@ -505,12 +528,12 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLanguagesInDao(
|
private fun updateLanguagesInDao(
|
||||||
library: MutableSharedFlow<LibraryNetworkEntity>,
|
library: MutableSharedFlow<List<LibkiwixBook>>,
|
||||||
languages: Flow<List<Language>>,
|
languages: Flow<List<Language>>,
|
||||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) =
|
) =
|
||||||
combine(
|
combine(
|
||||||
library.map { it.book }.filterNotNull(),
|
library,
|
||||||
languages
|
languages
|
||||||
) { books, existingLanguages ->
|
) { books, existingLanguages ->
|
||||||
combineToLanguageList(books, existingLanguages)
|
combineToLanguageList(books, existingLanguages)
|
||||||
@ -523,7 +546,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
private fun combineToLanguageList(
|
private fun combineToLanguageList(
|
||||||
booksFromNetwork: List<Book>,
|
booksFromNetwork: List<LibkiwixBook>,
|
||||||
allLanguages: List<Language>
|
allLanguages: List<Language>
|
||||||
) = when {
|
) = when {
|
||||||
booksFromNetwork.isEmpty() -> {
|
booksFromNetwork.isEmpty() -> {
|
||||||
@ -547,8 +570,8 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun networkLanguageCounts(booksFromNetwork: List<Book>) =
|
private fun networkLanguageCounts(booksFromNetwork: List<LibkiwixBook>) =
|
||||||
booksFromNetwork.mapNotNull(Book::language)
|
booksFromNetwork.map { it.language }
|
||||||
.fold(
|
.fold(
|
||||||
mutableMapOf<String, Int>()
|
mutableMapOf<String, Int>()
|
||||||
) { acc, language -> acc.increment(language) }
|
) { acc, language -> acc.increment(language) }
|
||||||
@ -585,14 +608,14 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
booksOnFileSystem: List<BookOnDisk>,
|
booksOnFileSystem: List<BookOnDisk>,
|
||||||
activeDownloads: List<DownloadModel>,
|
activeDownloads: List<DownloadModel>,
|
||||||
allLanguages: List<Language>,
|
allLanguages: List<Language>,
|
||||||
libraryNetworkEntity: LibraryNetworkEntity,
|
onlineBooks: List<LibkiwixBook>,
|
||||||
filter: String,
|
filter: String,
|
||||||
fileSystemState: FileSystemState
|
fileSystemState: FileSystemState
|
||||||
): List<LibraryListItem> {
|
): List<LibraryListItem> {
|
||||||
val activeLanguageCodes =
|
val activeLanguageCodes =
|
||||||
allLanguages.filter(Language::active)
|
allLanguages.filter(Language::active)
|
||||||
.map(Language::languageCode)
|
.map(Language::languageCode)
|
||||||
val allBooks = libraryNetworkEntity.book!! - booksOnFileSystem.map(BookOnDisk::book).toSet()
|
val allBooks = onlineBooks - booksOnFileSystem.map(BookOnDisk::book).toSet()
|
||||||
val downloadingBooks =
|
val downloadingBooks =
|
||||||
activeDownloads.mapNotNull { download ->
|
activeDownloads.mapNotNull { download ->
|
||||||
allBooks.firstOrNull { it.id == download.book.id }
|
allBooks.firstOrNull { it.id == download.book.id }
|
||||||
@ -630,7 +653,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createLibrarySection(
|
private fun createLibrarySection(
|
||||||
books: List<Book>,
|
books: List<LibkiwixBook>,
|
||||||
activeDownloads: List<DownloadModel>,
|
activeDownloads: List<DownloadModel>,
|
||||||
fileSystemState: FileSystemState,
|
fileSystemState: FileSystemState,
|
||||||
sectionStringId: Int,
|
sectionStringId: Int,
|
||||||
@ -644,7 +667,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun applySearchFilter(
|
private fun applySearchFilter(
|
||||||
unDownloadedBooks: List<Book>,
|
unDownloadedBooks: List<LibkiwixBook>,
|
||||||
filter: String
|
filter: String
|
||||||
) = if (filter.isEmpty()) {
|
) = if (filter.isEmpty()) {
|
||||||
unDownloadedBooks
|
unDownloadedBooks
|
||||||
@ -653,7 +676,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
unDownloadedBooks.filter { it.searchMatches > 0 }
|
unDownloadedBooks.filter { it.searchMatches > 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Book>.asLibraryItems(
|
private fun List<LibkiwixBook>.asLibraryItems(
|
||||||
activeDownloads: List<DownloadModel>,
|
activeDownloads: List<DownloadModel>,
|
||||||
fileSystemState: FileSystemState
|
fileSystemState: FileSystemState
|
||||||
) = map { book ->
|
) = map { book ->
|
||||||
|
@ -19,12 +19,11 @@
|
|||||||
package org.kiwix.kiwixmobile.zimManager.libraryView
|
package org.kiwix.kiwixmobile.zimManager.libraryView
|
||||||
|
|
||||||
import eu.mhutti1.utils.storage.Bytes
|
import eu.mhutti1.utils.storage.Bytes
|
||||||
import eu.mhutti1.utils.storage.KB
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
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.core.settings.StorageCalculator
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -42,13 +41,13 @@ class AvailableSpaceCalculator @Inject constructor(
|
|||||||
.map { downloads -> downloads.sumOf(DownloadModel::bytesRemaining) }
|
.map { downloads -> downloads.sumOf(DownloadModel::bytesRemaining) }
|
||||||
.map { bytesToBeDownloaded -> storageCalculator.availableBytes() - bytesToBeDownloaded }
|
.map { bytesToBeDownloaded -> storageCalculator.availableBytes() - bytesToBeDownloaded }
|
||||||
.first()
|
.first()
|
||||||
if (bookItem.book.size.toLong() * KB < trueAvailableBytes) {
|
if (bookItem.book.size.toLong() < trueAvailableBytes) {
|
||||||
successAction.invoke(bookItem)
|
successAction.invoke(bookItem)
|
||||||
} else {
|
} else {
|
||||||
failureAction.invoke(Bytes(trueAvailableBytes).humanReadable)
|
failureAction.invoke(Bytes(trueAvailableBytes).humanReadable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun hasAvailableSpaceForBook(book: Book) =
|
suspend fun hasAvailableSpaceForBook(book: LibkiwixBook) =
|
||||||
book.size.toLong() * KB < storageCalculator.availableBytes()
|
book.size.toLong() < storageCalculator.availableBytes()
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,17 @@ package org.kiwix.kiwixmobile.zimManager.libraryView.adapter
|
|||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Seconds
|
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.core.zim_manager.KiwixTag
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CanWrite4GbFile
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CanWrite4GbFile
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CannotWrite4GbFile
|
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.DetectingFileSystem
|
||||||
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
|
||||||
|
|
||||||
sealed class LibraryListItem {
|
sealed class LibraryListItem {
|
||||||
abstract val id: Long
|
abstract val id: Long
|
||||||
@ -42,7 +41,7 @@ sealed class LibraryListItem {
|
|||||||
) : LibraryListItem()
|
) : LibraryListItem()
|
||||||
|
|
||||||
data class BookItem constructor(
|
data class BookItem constructor(
|
||||||
val book: Book,
|
val book: LibkiwixBook,
|
||||||
val fileSystemState: FileSystemState,
|
val fileSystemState: FileSystemState,
|
||||||
val tags: List<KiwixTag> = KiwixTag.from(book.tags),
|
val tags: List<KiwixTag> = KiwixTag.from(book.tags),
|
||||||
override val id: Long = book.id.hashCode().toLong()
|
override val id: Long = book.id.hashCode().toLong()
|
||||||
@ -54,14 +53,14 @@ sealed class LibraryListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun Book.isLessThan4GB() =
|
private fun LibkiwixBook.isLessThan4GB() =
|
||||||
size.toLongOrNull() ?: 0L < Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES
|
size.toLongOrNull() ?: 0L < Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class LibraryDownloadItem(
|
data class LibraryDownloadItem(
|
||||||
val downloadId: Long,
|
val downloadId: Long,
|
||||||
val favIcon: Base64String,
|
val favIconUrl: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val bytesDownloaded: Long,
|
val bytesDownloaded: Long,
|
||||||
@ -76,7 +75,7 @@ sealed class LibraryListItem {
|
|||||||
|
|
||||||
constructor(downloadModel: DownloadModel) : this(
|
constructor(downloadModel: DownloadModel) : this(
|
||||||
downloadModel.downloadId,
|
downloadModel.downloadId,
|
||||||
Base64String(downloadModel.book.favicon),
|
downloadModel.book.favicon,
|
||||||
downloadModel.book.title,
|
downloadModel.book.title,
|
||||||
downloadModel.book.description,
|
downloadModel.book.description,
|
||||||
downloadModel.bytesDownloaded,
|
downloadModel.bytesDownloaded,
|
||||||
|
@ -28,7 +28,6 @@ import app.cash.turbine.TurbineTestContext
|
|||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.jraska.livedata.test
|
import com.jraska.livedata.test
|
||||||
import io.mockk.clearAllMocks
|
import io.mockk.clearAllMocks
|
||||||
import io.mockk.coEvery
|
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
@ -60,7 +59,7 @@ import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
|||||||
import org.kiwix.kiwixmobile.core.data.DataSource
|
import org.kiwix.kiwixmobile.core.data.DataSource
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
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.utils.BookUtils
|
import org.kiwix.kiwixmobile.core.utils.BookUtils
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
||||||
@ -90,11 +89,10 @@ import org.kiwix.kiwixmobile.zimManager.fileselectView.effects.ShareFiles
|
|||||||
import org.kiwix.kiwixmobile.zimManager.fileselectView.effects.StartMultiSelection
|
import org.kiwix.kiwixmobile.zimManager.fileselectView.effects.StartMultiSelection
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem
|
||||||
import org.kiwix.sharedFunctions.InstantExecutorExtension
|
import org.kiwix.sharedFunctions.InstantExecutorExtension
|
||||||
import org.kiwix.sharedFunctions.book
|
|
||||||
import org.kiwix.sharedFunctions.bookOnDisk
|
import org.kiwix.sharedFunctions.bookOnDisk
|
||||||
import org.kiwix.sharedFunctions.downloadModel
|
import org.kiwix.sharedFunctions.downloadModel
|
||||||
import org.kiwix.sharedFunctions.language
|
import org.kiwix.sharedFunctions.language
|
||||||
import org.kiwix.sharedFunctions.libraryNetworkEntity
|
import org.kiwix.sharedFunctions.libkiwixBook
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@ -191,7 +189,7 @@ class ZimManageViewModelTest {
|
|||||||
setAlertDialogShower(alertDialogShower)
|
setAlertDialogShower(alertDialogShower)
|
||||||
}
|
}
|
||||||
viewModel.fileSelectListStates.value = FileSelectListState(emptyList())
|
viewModel.fileSelectListStates.value = FileSelectListState(emptyList())
|
||||||
runBlocking { viewModel.networkLibrary.emit(libraryNetworkEntity()) }
|
runBlocking { viewModel.networkLibrary.emit(emptyList()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@ -238,8 +236,8 @@ class ZimManageViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `books found on filesystem are filtered by books already in db`() = runTest {
|
fun `books found on filesystem are filtered by books already in db`() = runTest {
|
||||||
every { application.getString(any()) } returns ""
|
every { application.getString(any()) } returns ""
|
||||||
val expectedBook = bookOnDisk(1L, book("1"))
|
val expectedBook = bookOnDisk(1L, libkiwixBook("1"))
|
||||||
val bookToRemove = bookOnDisk(1L, book("2"))
|
val bookToRemove = bookOnDisk(1L, libkiwixBook("2"))
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
viewModel.requestFileSystemCheck.emit(Unit)
|
viewModel.requestFileSystemCheck.emit(Unit)
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
@ -314,9 +312,9 @@ class ZimManageViewModelTest {
|
|||||||
)
|
)
|
||||||
expectNetworkDbAndDefault(
|
expectNetworkDbAndDefault(
|
||||||
listOf(
|
listOf(
|
||||||
book(language = "eng"),
|
libkiwixBook(language = "eng"),
|
||||||
book(language = "eng"),
|
libkiwixBook(language = "eng"),
|
||||||
book(language = "fra")
|
libkiwixBook(language = "fra")
|
||||||
),
|
),
|
||||||
listOf(),
|
listOf(),
|
||||||
defaultLanguage
|
defaultLanguage
|
||||||
@ -352,9 +350,9 @@ class ZimManageViewModelTest {
|
|||||||
)
|
)
|
||||||
expectNetworkDbAndDefault(
|
expectNetworkDbAndDefault(
|
||||||
listOf(
|
listOf(
|
||||||
book(language = "eng"),
|
libkiwixBook(language = "eng"),
|
||||||
book(language = "eng"),
|
libkiwixBook(language = "eng"),
|
||||||
book(language = "fra")
|
libkiwixBook(language = "fra")
|
||||||
),
|
),
|
||||||
listOf(dbLanguage),
|
listOf(dbLanguage),
|
||||||
language(isActive = true, occurencesOfLanguage = 1)
|
language(isActive = true, occurencesOfLanguage = 1)
|
||||||
@ -378,15 +376,14 @@ class ZimManageViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun TestScope.expectNetworkDbAndDefault(
|
private suspend fun TestScope.expectNetworkDbAndDefault(
|
||||||
networkBooks: List<Book>,
|
networkBooks: List<LibkiwixBook>,
|
||||||
dbBooks: List<Language>,
|
dbBooks: List<Language>,
|
||||||
defaultLanguage: Language
|
defaultLanguage: Language
|
||||||
) {
|
) {
|
||||||
every { application.getString(any()) } returns ""
|
every { application.getString(any()) } returns ""
|
||||||
every { application.getString(any(), any()) } returns ""
|
every { application.getString(any(), any()) } returns ""
|
||||||
coEvery { kiwixService.getLibrary() } returns libraryNetworkEntity(networkBooks)
|
|
||||||
every { defaultLanguageProvider.provide() } returns defaultLanguage
|
every { defaultLanguageProvider.provide() } returns defaultLanguage
|
||||||
viewModel.networkLibrary.emit(libraryNetworkEntity(networkBooks))
|
viewModel.networkLibrary.emit(networkBooks)
|
||||||
runCurrent()
|
runCurrent()
|
||||||
languages.value = dbBooks
|
languages.value = dbBooks
|
||||||
runCurrent()
|
runCurrent()
|
||||||
@ -405,10 +402,10 @@ class ZimManageViewModelTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `library update removes from sources and maps to list items`() = runTest {
|
fun `library update removes from sources and maps to list items`() = runTest {
|
||||||
val bookAlreadyOnDisk = book(id = "0", url = "", language = Locale.ENGLISH.language)
|
val bookAlreadyOnDisk = libkiwixBook(id = "0", url = "", language = Locale.ENGLISH.language)
|
||||||
val bookDownloading = book(id = "1", url = "")
|
val bookDownloading = libkiwixBook(id = "1", url = "")
|
||||||
val bookWithActiveLanguage = book(id = "3", language = "activeLanguage", url = "")
|
val bookWithActiveLanguage = libkiwixBook(id = "3", language = "activeLanguage", url = "")
|
||||||
val bookWithInactiveLanguage = book(id = "4", language = "inactiveLanguage", url = "")
|
val bookWithInactiveLanguage = libkiwixBook(id = "4", language = "inactiveLanguage", url = "")
|
||||||
testFlow(
|
testFlow(
|
||||||
flow = viewModel.libraryItems,
|
flow = viewModel.libraryItems,
|
||||||
triggerAction = {
|
triggerAction = {
|
||||||
@ -429,13 +426,11 @@ class ZimManageViewModelTest {
|
|||||||
fileSystemStates.tryEmit(CanWrite4GbFile)
|
fileSystemStates.tryEmit(CanWrite4GbFile)
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
viewModel.networkLibrary.emit(
|
viewModel.networkLibrary.emit(
|
||||||
libraryNetworkEntity(
|
listOf(
|
||||||
listOf(
|
bookAlreadyOnDisk,
|
||||||
bookAlreadyOnDisk,
|
bookDownloading,
|
||||||
bookDownloading,
|
bookWithActiveLanguage,
|
||||||
bookWithActiveLanguage,
|
bookWithInactiveLanguage
|
||||||
bookWithInactiveLanguage
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -458,7 +453,7 @@ class ZimManageViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `library marks files over 4GB as can't download if file system state says to`() = runTest {
|
fun `library marks files over 4GB as can't download if file system state says to`() = runTest {
|
||||||
val bookOver4Gb =
|
val bookOver4Gb =
|
||||||
book(
|
libkiwixBook(
|
||||||
id = "0",
|
id = "0",
|
||||||
url = "",
|
url = "",
|
||||||
size = "${Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES + 1}"
|
size = "${Fat32Checker.FOUR_GIGABYTES_IN_KILOBYTES + 1}"
|
||||||
@ -477,7 +472,7 @@ class ZimManageViewModelTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
fileSystemStates.tryEmit(CannotWrite4GbFile)
|
fileSystemStates.tryEmit(CannotWrite4GbFile)
|
||||||
viewModel.networkLibrary.emit(libraryNetworkEntity(listOf(bookOver4Gb)))
|
viewModel.networkLibrary.emit(listOf(bookOver4Gb))
|
||||||
},
|
},
|
||||||
assert = {
|
assert = {
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
|
@ -24,17 +24,17 @@ import io.mockk.mockk
|
|||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CanWrite4GbFile
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CanWrite4GbFile
|
||||||
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.CannotWrite4GbFile
|
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.DetectingFileSystem
|
||||||
|
import org.kiwix.kiwixmobile.zimManager.Fat32Checker.FileSystemState.NotEnoughSpaceFor4GbFile
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.BookItem
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryListItem.BookItem
|
||||||
|
|
||||||
internal class LibraryListItemTest {
|
internal class LibraryListItemTest {
|
||||||
private val book = mockk<Book>()
|
private val book = mockk<LibkiwixBook>()
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun init() {
|
fun init() {
|
||||||
@ -76,6 +76,6 @@ internal class LibraryListItemTest {
|
|||||||
assertThat(canBeDownloaded(book, NotEnoughSpaceFor4GbFile)).isTrue
|
assertThat(canBeDownloaded(book, NotEnoughSpaceFor4GbFile)).isTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canBeDownloaded(book: Book, fileSystemState: FileSystemState) =
|
private fun canBeDownloaded(book: LibkiwixBook, fileSystemState: FileSystemState) =
|
||||||
BookItem(book, fileSystemState).canBeDownloaded
|
BookItem(book, fileSystemState).canBeDownloaded
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,12 @@ object Libs {
|
|||||||
|
|
||||||
const val tracing: String = "androidx.tracing:tracing:" + Versions.tracing
|
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
|
* https://github.com/square/retrofit
|
||||||
*/
|
*/
|
||||||
@ -363,4 +369,7 @@ object Libs {
|
|||||||
|
|
||||||
const val COMPOSE_LIVE_DATA =
|
const val COMPOSE_LIVE_DATA =
|
||||||
"androidx.compose.runtime:runtime-livedata:${Versions.COMPOSE_VERSION}"
|
"androidx.compose.runtime:runtime-livedata:${Versions.COMPOSE_VERSION}"
|
||||||
|
|
||||||
|
const val COIL3_COMPOSE = "io.coil-kt.coil3:coil-compose:${Versions.COIL_COMPOSE}"
|
||||||
|
const val COIL3_OKHTTP_COMPOSE = "io.coil-kt.coil3:coil-network-okhttp:${Versions.COIL_COMPOSE}"
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,8 @@ object Versions {
|
|||||||
const val COMPOSE_MATERIAL3 = "1.3.1"
|
const val COMPOSE_MATERIAL3 = "1.3.1"
|
||||||
|
|
||||||
const val TURBINE_FLOW_TEST = "1.2.0"
|
const val TURBINE_FLOW_TEST = "1.2.0"
|
||||||
|
|
||||||
|
const val COIL_COMPOSE = "3.2.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,6 +243,8 @@ class AllProjectConfigurer {
|
|||||||
implementation(Libs.ANDROIDX_ACTIVITY_COMPOSE)
|
implementation(Libs.ANDROIDX_ACTIVITY_COMPOSE)
|
||||||
implementation(Libs.COMPOSE_TOOLING_PREVIEW)
|
implementation(Libs.COMPOSE_TOOLING_PREVIEW)
|
||||||
implementation(Libs.COMPOSE_LIVE_DATA)
|
implementation(Libs.COMPOSE_LIVE_DATA)
|
||||||
|
implementation(Libs.COIL3_COMPOSE)
|
||||||
|
implementation(Libs.COIL3_OKHTTP_COMPOSE)
|
||||||
|
|
||||||
// Compose UI test implementation
|
// Compose UI test implementation
|
||||||
androidTestImplementation(Libs.COMPOSE_UI_TEST_JUNIT)
|
androidTestImplementation(Libs.COMPOSE_UI_TEST_JUNIT)
|
||||||
|
@ -47,6 +47,11 @@ dependencies {
|
|||||||
implementation(Libs.select_folder_document_file)
|
implementation(Libs.select_folder_document_file)
|
||||||
|
|
||||||
// Square
|
// 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) {
|
implementation(Libs.converter_simplexml) {
|
||||||
exclude(group = "xpp3", module = "xpp3")
|
exclude(group = "xpp3", module = "xpp3")
|
||||||
exclude(group = "stax", module = "stax-api")
|
exclude(group = "stax", module = "stax-api")
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<ID>MagicNumber:DownloaderModule.kt$DownloaderModule$5</ID>
|
<ID>MagicNumber:DownloaderModule.kt$DownloaderModule$5</ID>
|
||||||
<ID>MagicNumber:FileUtils.kt$FileUtils$3</ID>
|
<ID>MagicNumber:FileUtils.kt$FileUtils$3</ID>
|
||||||
<ID>MagicNumber:JNIInitialiser.kt$JNIInitialiser$1024</ID>
|
<ID>MagicNumber:JNIInitialiser.kt$JNIInitialiser$1024</ID>
|
||||||
<ID>MagicNumber:KiloByte.kt$KiloByte$1024.0</ID>
|
<ID>MagicNumber:Byte.kt$Byte$1024.0</ID>
|
||||||
<ID>MagicNumber:MainMenu.kt$MainMenu$99</ID>
|
<ID>MagicNumber:MainMenu.kt$MainMenu$99</ID>
|
||||||
<ID>MagicNumber:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$100</ID>
|
<ID>MagicNumber:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$100</ID>
|
||||||
<ID>MagicNumber:SearchResultGenerator.kt$ZimSearchResultGenerator$200</ID>
|
<ID>MagicNumber:SearchResultGenerator.kt$ZimSearchResultGenerator$200</ID>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$// Amazingly file.canWrite() does not always return the correct value private fun canWrite(file: File): Boolean</ID>
|
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$// Amazingly file.canWrite() does not always return the correct value private fun canWrite(file: File): Boolean</ID>
|
||||||
<ID>PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
<ID>PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
||||||
<ID>PackageNaming:BooksOnDiskListItem.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
<ID>PackageNaming:BooksOnDiskListItem.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
|
||||||
<ID>PackageNaming:KiloByte.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
<ID>PackageNaming:Byte.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||||
<ID>PackageNaming:KiwixTag.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
<ID>PackageNaming:KiwixTag.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||||
<ID>PackageNaming:Language.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
<ID>PackageNaming:Language.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||||
<ID>PackageNaming:MountPointProducer.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
<ID>PackageNaming:MountPointProducer.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||||
@ -50,6 +50,7 @@
|
|||||||
<ID>PackageNaming:TagsView.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
<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:ConnectivityBroadcastReceiver.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||||
<ID>PackageNaming:NetworkState.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 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 getLocalFilePathByUri( context: Context, uri: Uri ): String?</ID>
|
||||||
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic suspend fun hasPart(file: File): Boolean</ID>
|
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic suspend fun hasPart(file: File): Boolean</ID>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.dao
|
package org.kiwix.kiwixmobile.core.dao
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
@ -25,16 +26,20 @@ import androidx.room.Query
|
|||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.tonyodev.fetch2.Download
|
import com.tonyodev.fetch2.Download
|
||||||
import com.tonyodev.fetch2.Status.COMPLETED
|
import com.tonyodev.fetch2.Status.COMPLETED
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
||||||
import org.kiwix.kiwixmobile.core.downloader.DownloadRequester
|
import org.kiwix.kiwixmobile.core.downloader.DownloadRequester
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadRequest
|
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.reader.ILLUSTRATION_SIZE
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
||||||
|
import org.kiwix.libzim.Archive
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
@ -53,15 +58,37 @@ abstract class DownloadRoomDao {
|
|||||||
|
|
||||||
fun allDownloads() = getAllDownloads().map { it.map(::DownloadModel) }
|
fun allDownloads() = getAllDownloads().map { it.map(::DownloadModel) }
|
||||||
|
|
||||||
private fun moveCompletedToBooksOnDiskDao(downloadEntities: List<DownloadRoomEntity>) {
|
@Suppress("InjectDispatcher")
|
||||||
|
private suspend fun moveCompletedToBooksOnDiskDao(downloadEntities: List<DownloadRoomEntity>) {
|
||||||
downloadEntities.filter { it.status == COMPLETED }
|
downloadEntities.filter { it.status == COMPLETED }
|
||||||
.takeIf(List<DownloadRoomEntity>::isNotEmpty)
|
.takeIf(List<DownloadRoomEntity>::isNotEmpty)
|
||||||
?.let {
|
?.let { completedDownloads ->
|
||||||
deleteDownloadsList(it)
|
deleteDownloadsList(completedDownloads)
|
||||||
newBookDao.insert(it.map(BooksOnDiskListItem::BookOnDisk))
|
// We now use the OPDS stream instead of the custom library.xml handling.
|
||||||
|
// In the OPDS stream, the favicon is a URL instead of a Base64 string.
|
||||||
|
// So when a download is completed, we extract the illustration directly from the archive.
|
||||||
|
val booksOnDisk = completedDownloads.map { download ->
|
||||||
|
val archive = withContext(Dispatchers.IO) {
|
||||||
|
Archive(download.file)
|
||||||
|
}
|
||||||
|
val favicon = getOnlineBookFaviconForOfflineUsages(archive).orEmpty()
|
||||||
|
val updatedEntity = download.copy(favIcon = favicon)
|
||||||
|
BooksOnDiskListItem.BookOnDisk(updatedEntity)
|
||||||
|
}
|
||||||
|
newBookDao.insert(booksOnDisk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getOnlineBookFaviconForOfflineUsages(archive: Archive): String? =
|
||||||
|
if (archive.hasIllustration(ILLUSTRATION_SIZE)) {
|
||||||
|
Base64.encodeToString(
|
||||||
|
archive.getIllustrationItem(ILLUSTRATION_SIZE).data.data,
|
||||||
|
Base64.DEFAULT
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
fun update(download: Download) {
|
fun update(download: Download) {
|
||||||
getEntityForDownloadId(download.id.toLong())?.let { downloadRoomEntity ->
|
getEntityForDownloadId(download.id.toLong())?.let { downloadRoomEntity ->
|
||||||
downloadRoomEntity.updateWith(download)
|
downloadRoomEntity.updateWith(download)
|
||||||
@ -100,7 +127,7 @@ abstract class DownloadRoomDao {
|
|||||||
|
|
||||||
fun addIfDoesNotExist(
|
fun addIfDoesNotExist(
|
||||||
url: String,
|
url: String,
|
||||||
book: LibraryNetworkEntity.Book,
|
book: LibkiwixBook,
|
||||||
downloadRequester: DownloadRequester
|
downloadRequester: DownloadRequester
|
||||||
) {
|
) {
|
||||||
if (doesNotAlreadyExist(book)) {
|
if (doesNotAlreadyExist(book)) {
|
||||||
@ -113,6 +140,6 @@ abstract class DownloadRoomDao {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doesNotAlreadyExist(book: LibraryNetworkEntity.Book) =
|
private fun doesNotAlreadyExist(book: LibkiwixBook) =
|
||||||
count(book.id) == 0
|
count(book.id) == 0
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package org.kiwix.kiwixmobile.core.dao
|
|||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.util.Base64
|
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
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.R
|
||||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
|
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
|
||||||
import org.kiwix.kiwixmobile.core.extensions.deleteFile
|
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.isFileExist
|
||||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||||
import org.kiwix.kiwixmobile.core.page.adapter.Page
|
import org.kiwix.kiwixmobile.core.page.adapter.Page
|
||||||
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
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.ZimFileReader
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||||
@ -205,7 +204,7 @@ class LibkiwixBookmarks @Inject constructor(
|
|||||||
library.addBook(libKiwixBook).also {
|
library.addBook(libKiwixBook).also {
|
||||||
// now library has changed so update our library list.
|
// now library has changed so update our library list.
|
||||||
libraryBooksList = library.booksIds.toList()
|
libraryBooksList = library.booksIds.toList()
|
||||||
Log.d(
|
Log.e(
|
||||||
TAG,
|
TAG,
|
||||||
"Added Book to Library:\n" +
|
"Added Book to Library:\n" +
|
||||||
"ZIM File Path: ${book.path}\n" +
|
"ZIM File Path: ${book.path}\n" +
|
||||||
@ -234,6 +233,7 @@ class LibkiwixBookmarks @Inject constructor(
|
|||||||
CoroutineScope(dispatcher).launch {
|
CoroutineScope(dispatcher).launch {
|
||||||
writeBookMarksAndSaveLibraryToFile()
|
writeBookMarksAndSaveLibraryToFile()
|
||||||
updateFlowBookmarkList()
|
updateFlowBookmarkList()
|
||||||
|
removeBookFromLibraryIfNoRelatedBookmarksAreStored(dispatcher, bookmarks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,6 +242,34 @@ class LibkiwixBookmarks @Inject constructor(
|
|||||||
deleteBookmarks(listOf(LibkiwixBookmarkItem(zimId = bookId, bookmarkUrl = bookmarkUrl)))
|
deleteBookmarks(listOf(LibkiwixBookmarkItem(zimId = bookId, bookmarkUrl = bookmarkUrl)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes books from the library that no longer have any associated bookmarks.
|
||||||
|
*
|
||||||
|
* This function checks if any of the books associated with the given deleted bookmarks
|
||||||
|
* are still referenced by other existing bookmarks. If not, those books are removed from the library.
|
||||||
|
*
|
||||||
|
* @param dispatcher The coroutine dispatcher to run the operation on (typically Dispatchers.IO).
|
||||||
|
* @param deletedBookmarks The list of bookmarks that were just deleted.
|
||||||
|
*/
|
||||||
|
private suspend fun removeBookFromLibraryIfNoRelatedBookmarksAreStored(
|
||||||
|
dispatcher: CoroutineDispatcher,
|
||||||
|
deletedBookmarks: List<LibkiwixBookmarkItem>
|
||||||
|
) {
|
||||||
|
withContext(dispatcher) {
|
||||||
|
val currentBookmarks = getBookmarksList()
|
||||||
|
val deletedZimIds = deletedBookmarks.map { it.zimId }.distinct()
|
||||||
|
|
||||||
|
deletedZimIds.forEach { zimId ->
|
||||||
|
val stillExists = currentBookmarks.any { it.zimId == zimId }
|
||||||
|
if (!stillExists) {
|
||||||
|
library.removeBookById(zimId)
|
||||||
|
Log.d(TAG, "Removed book from library since no bookmarks exist for: $zimId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeBookMarksAndSaveLibraryToFile()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously writes the library and bookmarks data to their respective files in a background thread
|
* Asynchronously writes the library and bookmarks data to their respective files in a background thread
|
||||||
* to prevent potential data loss and ensures that the library holds the updated ZIM file paths and favicons.
|
* to prevent potential data loss and ensures that the library holds the updated ZIM file paths and favicons.
|
||||||
@ -285,10 +313,7 @@ class LibkiwixBookmarks @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the book has an illustration of the specified size and encode it to Base64.
|
// Check if the book has an illustration of the specified size and encode it to Base64.
|
||||||
val favicon =
|
val favicon = book?.getFavicon()
|
||||||
book?.getIllustration(ILLUSTRATION_SIZE)?.data?.let {
|
|
||||||
Base64.encodeToString(it, Base64.DEFAULT)
|
|
||||||
}
|
|
||||||
|
|
||||||
val zimReaderSource = book?.path?.let { ZimReaderSource(File(it)) }
|
val zimReaderSource = book?.path?.let { ZimReaderSource(File(it)) }
|
||||||
// Return the LibkiwixBookmarkItem, filtering out null results.
|
// Return the LibkiwixBookmarkItem, filtering out null results.
|
||||||
|
@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.mapLatest
|
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.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.reader.ZimReaderSource
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -124,7 +124,7 @@ class NewBookDao @Inject constructor(private val box: Box<BookOnDiskEntity>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnsafeCallOnNullableType")
|
@Suppress("UnsafeCallOnNullableType")
|
||||||
fun migrationInsert(books: List<Book>) {
|
fun migrationInsert(books: List<LibkiwixBook>) {
|
||||||
insert(books.map { BookOnDisk(book = it, zimReaderSource = ZimReaderSource(it.file!!)) })
|
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.Entity
|
||||||
import io.objectbox.annotation.Id
|
import io.objectbox.annotation.Id
|
||||||
import io.objectbox.converter.PropertyConverter
|
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
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
@ -70,7 +70,7 @@ data class BookOnDiskEntity(
|
|||||||
bookOnDisk.book.tags
|
bookOnDisk.book.tags
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toBook() = Book().apply {
|
fun toBook() = LibkiwixBook().apply {
|
||||||
id = bookId
|
id = bookId
|
||||||
title = this@BookOnDiskEntity.title
|
title = this@BookOnDiskEntity.title
|
||||||
description = this@BookOnDiskEntity.description
|
description = this@BookOnDiskEntity.description
|
||||||
|
@ -20,12 +20,12 @@ package org.kiwix.kiwixmobile.core.dao.entities
|
|||||||
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import io.objectbox.annotation.Convert
|
|
||||||
import io.objectbox.converter.PropertyConverter
|
|
||||||
import com.tonyodev.fetch2.Download
|
import com.tonyodev.fetch2.Download
|
||||||
import com.tonyodev.fetch2.Error
|
import com.tonyodev.fetch2.Error
|
||||||
import com.tonyodev.fetch2.Status
|
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
|
@Entity
|
||||||
data class DownloadRoomEntity(
|
data class DownloadRoomEntity(
|
||||||
@ -56,7 +56,7 @@ data class DownloadRoomEntity(
|
|||||||
val favIcon: String,
|
val favIcon: String,
|
||||||
val tags: String? = null
|
val tags: String? = null
|
||||||
) {
|
) {
|
||||||
constructor(downloadId: Long, book: Book) : this(
|
constructor(downloadId: Long, book: LibkiwixBook) : this(
|
||||||
downloadId = downloadId,
|
downloadId = downloadId,
|
||||||
bookId = book.id,
|
bookId = book.id,
|
||||||
title = book.title,
|
title = book.title,
|
||||||
@ -75,7 +75,7 @@ data class DownloadRoomEntity(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun toBook() =
|
fun toBook() =
|
||||||
Book().apply {
|
LibkiwixBook().apply {
|
||||||
id = bookId
|
id = bookId
|
||||||
title = this@DownloadRoomEntity.title
|
title = this@DownloadRoomEntity.title
|
||||||
description = this@DownloadRoomEntity.description
|
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
|
// Split languages if there are multiple, otherwise return the single book. Bug fix #3892
|
||||||
if (bookOnDisk.book.language.contains(',')) {
|
if (bookOnDisk.book.language.contains(',')) {
|
||||||
bookOnDisk.book.language.split(',').map { lang ->
|
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 {
|
} else {
|
||||||
listOf(bookOnDisk)
|
listOf(bookOnDisk)
|
||||||
|
@ -20,16 +20,17 @@
|
|||||||
package org.kiwix.kiwixmobile.core.data.remote
|
package org.kiwix.kiwixmobile.core.data.remote
|
||||||
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
|
||||||
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity
|
||||||
|
import retrofit2.Response
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.scalars.ScalarsConverterFactory
|
||||||
import retrofit2.converter.simplexml.SimpleXmlConverterFactory
|
import retrofit2.converter.simplexml.SimpleXmlConverterFactory
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Url
|
import retrofit2.http.Url
|
||||||
|
|
||||||
interface KiwixService {
|
interface KiwixService {
|
||||||
@GET(LIBRARY_NETWORK_PATH)
|
@GET(OPDS_LIBRARY_NETWORK_PATH)
|
||||||
suspend fun getLibrary(): LibraryNetworkEntity?
|
suspend fun getLibrary(): Response<String>
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
suspend fun getMetaLinks(
|
suspend fun getMetaLinks(
|
||||||
@ -43,6 +44,7 @@ interface KiwixService {
|
|||||||
val retrofit = Retrofit.Builder()
|
val retrofit = Retrofit.Builder()
|
||||||
.baseUrl(baseUrl)
|
.baseUrl(baseUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
|
.addConverterFactory(ScalarsConverterFactory.create())
|
||||||
.addConverterFactory(SimpleXmlConverterFactory.create())
|
.addConverterFactory(SimpleXmlConverterFactory.create())
|
||||||
.build()
|
.build()
|
||||||
return retrofit.create(KiwixService::class.java)
|
return retrofit.create(KiwixService::class.java)
|
||||||
@ -50,6 +52,8 @@ interface KiwixService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val LIBRARY_NETWORK_PATH = "/library/library_zim.xml"
|
// 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 = "v2/entries?count=-1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ const val CONNECTION_TIMEOUT = 10L
|
|||||||
const val READ_TIMEOUT = 300L
|
const val READ_TIMEOUT = 300L
|
||||||
const val CALL_TIMEOUT = 300L
|
const val CALL_TIMEOUT = 300L
|
||||||
const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}"
|
const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}"
|
||||||
const val KIWIX_DOWNLOAD_URL = "https://mirror.download.kiwix.org/"
|
const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/"
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class NetworkModule {
|
class NetworkModule {
|
||||||
@ -59,5 +59,5 @@ class NetworkModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides @Singleton fun provideKiwixService(okHttpClient: OkHttpClient): KiwixService =
|
@Provides @Singleton fun provideKiwixService(okHttpClient: OkHttpClient): KiwixService =
|
||||||
ServiceCreator.newHackListService(okHttpClient, KIWIX_DOWNLOAD_URL)
|
ServiceCreator.newHackListService(okHttpClient, KIWIX_OPDS_LIBRARY_URL)
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.kiwix.kiwixmobile.core.downloader
|
package org.kiwix.kiwixmobile.core.downloader
|
||||||
|
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
|
|
||||||
interface Downloader {
|
interface Downloader {
|
||||||
fun download(book: LibraryNetworkEntity.Book)
|
fun download(book: LibkiwixBook)
|
||||||
fun cancelDownload(downloadId: Long)
|
fun cancelDownload(downloadId: Long)
|
||||||
fun retryDownload(downloadId: Long)
|
fun retryDownload(downloadId: Long)
|
||||||
fun pauseResumeDownload(downloadId: Long, isPause: Boolean)
|
fun pauseResumeDownload(downloadId: Long, isPause: Boolean)
|
||||||
|
@ -23,8 +23,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DownloaderImpl @Inject constructor(
|
class DownloaderImpl @Inject constructor(
|
||||||
@ -33,7 +32,7 @@ class DownloaderImpl @Inject constructor(
|
|||||||
private val kiwixService: KiwixService
|
private val kiwixService: KiwixService
|
||||||
) : Downloader {
|
) : Downloader {
|
||||||
@Suppress("InjectDispatcher")
|
@Suppress("InjectDispatcher")
|
||||||
override fun download(book: LibraryNetworkEntity.Book) {
|
override fun download(book: LibkiwixBook) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
urlProvider(book)?.let {
|
urlProvider(book)?.let {
|
||||||
@ -46,7 +45,7 @@ class DownloaderImpl @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnsafeCallOnNullableType")
|
@Suppress("UnsafeCallOnNullableType")
|
||||||
private suspend fun urlProvider(book: Book): String? =
|
private suspend fun urlProvider(book: LibkiwixBook): String? =
|
||||||
if (book.url?.endsWith("meta4") == true) {
|
if (book.url?.endsWith("meta4") == true) {
|
||||||
kiwixService.getMetaLinks(book.url!!)?.relevantUrl?.value
|
kiwixService.getMetaLinks(book.url!!)?.relevantUrl?.value
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,6 +37,7 @@ import javax.inject.Inject
|
|||||||
const val ZERO = 0
|
const val ZERO = 0
|
||||||
const val FIVE = 5
|
const val FIVE = 5
|
||||||
const val SIX = 6
|
const val SIX = 6
|
||||||
|
const val NINE = 9
|
||||||
const val HUNDERED = 100
|
const val HUNDERED = 100
|
||||||
const val DEFAULT_INT_VALUE = -1
|
const val DEFAULT_INT_VALUE = -1
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ value class Base64String(private val encodedString: String?) {
|
|||||||
BitmapFactory.decodeByteArray(it, 0, it.size)
|
BitmapFactory.decodeByteArray(it, 0, it.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (illegalArgumentException: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ import org.kiwix.kiwixmobile.core.R
|
|||||||
|
|
||||||
data class DownloadItem(
|
data class DownloadItem(
|
||||||
val downloadId: Long,
|
val downloadId: Long,
|
||||||
val favIcon: Base64String,
|
val favIconUrl: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val bytesDownloaded: Long,
|
val bytesDownloaded: Long,
|
||||||
@ -47,7 +47,7 @@ data class DownloadItem(
|
|||||||
|
|
||||||
constructor(downloadModel: DownloadModel) : this(
|
constructor(downloadModel: DownloadModel) : this(
|
||||||
downloadModel.downloadId,
|
downloadModel.downloadId,
|
||||||
Base64String(downloadModel.book.favicon),
|
downloadModel.book.favicon,
|
||||||
downloadModel.book.title,
|
downloadModel.book.title,
|
||||||
downloadModel.book.description,
|
downloadModel.book.description,
|
||||||
downloadModel.bytesDownloaded,
|
downloadModel.bytesDownloaded,
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.kiwix.kiwixmobile.core.downloader.model
|
package org.kiwix.kiwixmobile.core.downloader.model
|
||||||
|
|
||||||
import com.tonyodev.fetch2.Status
|
|
||||||
import com.tonyodev.fetch2.Error
|
import com.tonyodev.fetch2.Error
|
||||||
|
import com.tonyodev.fetch2.Status
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
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
|
import org.kiwix.kiwixmobile.core.utils.StorageUtils
|
||||||
|
|
||||||
data class DownloadModel(
|
data class DownloadModel(
|
||||||
@ -33,7 +33,7 @@ data class DownloadModel(
|
|||||||
val state: Status,
|
val state: Status,
|
||||||
val error: Error,
|
val error: Error,
|
||||||
val progress: Int,
|
val progress: Int,
|
||||||
val book: Book
|
val book: LibkiwixBook
|
||||||
) {
|
) {
|
||||||
val bytesRemaining: Long by lazy { totalSizeOfDownload - bytesDownloaded }
|
val bytesRemaining: Long by lazy { totalSizeOfDownload - bytesDownloaded }
|
||||||
val fileNameFromUrl: String by lazy { StorageUtils.getFileNameFromUrl(book.url) }
|
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()
|
||||||
|
}
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2019 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.simpleframework.xml.Attribute
|
|
||||||
import org.simpleframework.xml.ElementList
|
|
||||||
import org.simpleframework.xml.Root
|
|
||||||
import java.io.File
|
|
||||||
import java.io.Serializable
|
|
||||||
import java.util.LinkedList
|
|
||||||
|
|
||||||
@Root(name = "library")
|
|
||||||
class LibraryNetworkEntity {
|
|
||||||
@field:ElementList(name = "book", inline = true, required = false)
|
|
||||||
var book: LinkedList<Book>? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "version", required = false)
|
|
||||||
var version: String? = null
|
|
||||||
|
|
||||||
@Root(name = "book", strict = false)
|
|
||||||
class Book : Serializable {
|
|
||||||
@field:Attribute(name = "id", required = false)
|
|
||||||
var id: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "title", required = false)
|
|
||||||
var title: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "description", required = false)
|
|
||||||
var description: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "language", required = false)
|
|
||||||
var language: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "creator", required = false)
|
|
||||||
var creator: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "publisher", required = false)
|
|
||||||
var publisher: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "favicon", required = false)
|
|
||||||
var favicon: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "faviconMimeType", required = false)
|
|
||||||
var faviconMimeType: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "date", required = false)
|
|
||||||
var date: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "url", required = false)
|
|
||||||
var url: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "articleCount", required = false)
|
|
||||||
var articleCount: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "mediaCount", required = false)
|
|
||||||
var mediaCount: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "size", required = false)
|
|
||||||
var size: String = ""
|
|
||||||
|
|
||||||
@field:Attribute(name = "name", required = false)
|
|
||||||
var bookName: String? = null
|
|
||||||
|
|
||||||
@field:Attribute(name = "tags", required = false)
|
|
||||||
var tags: String? = null
|
|
||||||
var searchMatches = 0
|
|
||||||
|
|
||||||
var file: File? = null
|
|
||||||
|
|
||||||
// Two books are equal if their ids match
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (other is Book) {
|
|
||||||
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()
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
fun copy(
|
|
||||||
language: String = this.language,
|
|
||||||
title: String = this.title,
|
|
||||||
description: String? = this.description,
|
|
||||||
creator: String = this.creator,
|
|
||||||
publisher: String = this.publisher,
|
|
||||||
favicon: String = this.favicon,
|
|
||||||
faviconMimeType: String? = this.faviconMimeType,
|
|
||||||
date: String = this.date,
|
|
||||||
url: String? = this.url,
|
|
||||||
articleCount: String? = this.articleCount,
|
|
||||||
mediaCount: String? = this.mediaCount,
|
|
||||||
size: String = this.size,
|
|
||||||
bookName: String? = this.bookName,
|
|
||||||
tags: String? = this.tags
|
|
||||||
): Book {
|
|
||||||
return Book().apply {
|
|
||||||
this.id = this@Book.id
|
|
||||||
this.title = title
|
|
||||||
this.description = description
|
|
||||||
this.language = language
|
|
||||||
this.creator = creator
|
|
||||||
this.publisher = publisher
|
|
||||||
this.favicon = favicon
|
|
||||||
this.faviconMimeType = faviconMimeType
|
|
||||||
this.date = date
|
|
||||||
this.url = url
|
|
||||||
this.articleCount = articleCount
|
|
||||||
this.mediaCount = mediaCount
|
|
||||||
this.size = size
|
|
||||||
this.bookName = bookName
|
|
||||||
this.tags = tags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,30 +18,33 @@
|
|||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.extensions
|
package org.kiwix.kiwixmobile.core.extensions
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import android.util.Log
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
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.BookUtils
|
||||||
import org.kiwix.kiwixmobile.core.utils.NetworkUtils
|
import org.kiwix.kiwixmobile.core.utils.NetworkUtils
|
||||||
|
import org.kiwix.libkiwix.Book
|
||||||
|
|
||||||
fun Book.calculateSearchMatches(
|
fun LibkiwixBook.calculateSearchMatches(
|
||||||
filter: String,
|
filter: String,
|
||||||
bookUtils: BookUtils
|
bookUtils: BookUtils
|
||||||
) {
|
) {
|
||||||
val searchableText = buildSearchableText(bookUtils)
|
val searchableText = buildSearchableText(bookUtils)
|
||||||
searchMatches = filter.split("\\s+")
|
searchMatches = filter.split("\\s+")
|
||||||
.foldRight(
|
.foldRight(
|
||||||
0,
|
0
|
||||||
{ filterWord, acc ->
|
) { filterWord, acc ->
|
||||||
if (searchableText.contains(filterWord, true)) {
|
if (searchableText.contains(filterWord, true)) {
|
||||||
acc + 1
|
acc + 1
|
||||||
} else {
|
} else {
|
||||||
acc
|
acc
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Book.buildSearchableText(bookUtils: BookUtils): String =
|
fun LibkiwixBook.buildSearchableText(bookUtils: BookUtils): String =
|
||||||
StringBuilder().apply {
|
StringBuilder().apply {
|
||||||
append(title)
|
append(title)
|
||||||
append("|")
|
append("|")
|
||||||
@ -54,3 +57,21 @@ fun Book.buildSearchableText(bookUtils: BookUtils): String =
|
|||||||
append("|")
|
append("|")
|
||||||
}
|
}
|
||||||
}.toString()
|
}.toString()
|
||||||
|
|
||||||
|
fun Book?.getFavicon(): String? =
|
||||||
|
runCatching {
|
||||||
|
val illustration = this?.getIllustration(ILLUSTRATION_SIZE)
|
||||||
|
illustration?.url()?.ifBlank {
|
||||||
|
illustration.data?.let {
|
||||||
|
Base64.encodeToString(it, Base64.DEFAULT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.getOrElse {
|
||||||
|
it.printStackTrace().also {
|
||||||
|
this?.illustrations?.forEach { illustration ->
|
||||||
|
Log.e("BOOK", "getFavicon: ${illustration.data} and ${illustration.url()}")
|
||||||
|
}
|
||||||
|
Log.e("BOOK", "getFavicon: ${this?.title}")
|
||||||
|
}
|
||||||
|
""
|
||||||
|
}
|
||||||
|
@ -24,20 +24,6 @@ import androidx.annotation.ColorInt
|
|||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.widget.ImageViewCompat
|
import androidx.core.widget.ImageViewCompat
|
||||||
import org.kiwix.kiwixmobile.core.R
|
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
|
||||||
|
|
||||||
fun ImageView.setBitmap(base64String: Base64String) {
|
|
||||||
base64String.toBitmap()
|
|
||||||
?.let(::setImageBitmap)
|
|
||||||
?: kotlin.run { setImageDrawableCompat(R.drawable.default_zim_file_icon) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// methods that accept inline classes as parameters are not allowed to be called from java
|
|
||||||
// hence this facade
|
|
||||||
fun ImageView.setBitmapFromString(string: String?) {
|
|
||||||
setBitmap(Base64String(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ImageView.setImageDrawableCompat(
|
fun ImageView.setImageDrawableCompat(
|
||||||
@DrawableRes id: Int
|
@DrawableRes id: Int
|
||||||
|
@ -340,6 +340,7 @@ abstract class CoreReaderFragment :
|
|||||||
private val navigationHistoryList: MutableList<NavigationHistoryListItem> = ArrayList()
|
private val navigationHistoryList: MutableList<NavigationHistoryListItem> = ArrayList()
|
||||||
private var isReadSelection = false
|
private var isReadSelection = false
|
||||||
private var isReadAloudServiceRunning = false
|
private var isReadAloudServiceRunning = false
|
||||||
|
private var libkiwixBook: Book? = null
|
||||||
private var readerLifeCycleScope: CoroutineScope? = null
|
private var readerLifeCycleScope: CoroutineScope? = null
|
||||||
|
|
||||||
val coreReaderLifeCycleScope: CoroutineScope?
|
val coreReaderLifeCycleScope: CoroutineScope?
|
||||||
@ -2038,9 +2039,7 @@ abstract class CoreReaderFragment :
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
getCurrentWebView()?.url?.let { articleUrl ->
|
getCurrentWebView()?.url?.let { articleUrl ->
|
||||||
zimReaderContainer?.zimFileReader?.let { zimFileReader ->
|
zimReaderContainer?.zimFileReader?.let { zimFileReader ->
|
||||||
val libKiwixBook = Book().apply {
|
val libKiwixBook = getLibkiwixBook(zimFileReader)
|
||||||
update(zimFileReader.jniKiwixReader)
|
|
||||||
}
|
|
||||||
if (isBookmarked) {
|
if (isBookmarked) {
|
||||||
repositoryActions?.deleteBookmark(libKiwixBook.id, articleUrl)
|
repositoryActions?.deleteBookmark(libKiwixBook.id, articleUrl)
|
||||||
snackBarRoot?.snack(R.string.bookmark_removed)
|
snackBarRoot?.snack(R.string.bookmark_removed)
|
||||||
@ -2071,6 +2070,19 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the libkiwix book evertime when user saves or remove the bookmark.
|
||||||
|
* the object will be created once to avoid creating it multiple times.
|
||||||
|
*/
|
||||||
|
private fun getLibkiwixBook(zimFileReader: ZimFileReader): Book {
|
||||||
|
libkiwixBook?.let { return it }
|
||||||
|
val book = Book().apply {
|
||||||
|
update(zimFileReader.jniKiwixReader)
|
||||||
|
}
|
||||||
|
libkiwixBook = book
|
||||||
|
return book
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
updateBottomToolbarVisibility()
|
updateBottomToolbarVisibility()
|
||||||
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
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.UNINITIALISER_ADDRESS
|
||||||
import org.kiwix.kiwixmobile.core.main.UNINITIALISE_HTML
|
import org.kiwix.kiwixmobile.core.main.UNINITIALISE_HTML
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
|
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
|
||||||
@ -377,7 +377,7 @@ class ZimFileReader constructor(
|
|||||||
|
|
||||||
@Suppress("ExplicitThis") // this@ZimFileReader.name is required
|
@Suppress("ExplicitThis") // this@ZimFileReader.name is required
|
||||||
fun toBook() =
|
fun toBook() =
|
||||||
Book().apply {
|
LibkiwixBook().apply {
|
||||||
title = this@ZimFileReader.title
|
title = this@ZimFileReader.title
|
||||||
id = this@ZimFileReader.id
|
id = this@ZimFileReader.id
|
||||||
size = "$fileSize"
|
size = "$fileSize"
|
||||||
|
@ -42,7 +42,7 @@ import kotlinx.coroutines.sync.withLock
|
|||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.downloader.ChunkUtils
|
import org.kiwix.kiwixmobile.core.downloader.ChunkUtils
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.extensions.deleteFile
|
import org.kiwix.kiwixmobile.core.extensions.deleteFile
|
||||||
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
import org.kiwix.kiwixmobile.core.extensions.isFileExist
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||||
@ -494,7 +494,7 @@ object FileUtils {
|
|||||||
|
|
||||||
@Suppress("NestedBlockDepth")
|
@Suppress("NestedBlockDepth")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
suspend fun getAllZimParts(book: Book): List<File> {
|
suspend fun getAllZimParts(book: LibkiwixBook): List<File> {
|
||||||
val files = ArrayList<File>()
|
val files = ArrayList<File>()
|
||||||
book.file?.let {
|
book.file?.let {
|
||||||
if (it.path.endsWith(".zim") || it.path.endsWith(".zim.part")) {
|
if (it.path.endsWith(".zim") || it.path.endsWith(".zim.part")) {
|
||||||
|
@ -23,10 +23,10 @@ import kotlin.math.log10
|
|||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class KiloByte(private val kilobyteString: String?) {
|
value class Byte(private val byteString: String?) {
|
||||||
val humanReadable
|
val humanReadable
|
||||||
get() = kilobyteString?.toLongOrNull()?.let {
|
get() = byteString?.toLongOrNull()?.let {
|
||||||
val units = arrayOf("KB", "MB", "GB", "TB")
|
val units = arrayOf("B", "KB", "MB", "GB", "TB")
|
||||||
val conversion = (log10(it.toDouble()) / log10(1024.0)).toInt()
|
val conversion = (log10(it.toDouble()) / log10(1024.0)).toInt()
|
||||||
DecimalFormat("#,##0.#")
|
DecimalFormat("#,##0.#")
|
||||||
.format(it / 1024.0.pow(conversion.toDouble())) +
|
.format(it / 1024.0.pow(conversion.toDouble())) +
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.zim_manager
|
||||||
|
|
||||||
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
|
import org.kiwix.libkiwix.Library
|
||||||
|
import org.kiwix.libkiwix.Manager
|
||||||
|
|
||||||
|
class OnlineLibraryManager(val library: Library, val manager: Manager) {
|
||||||
|
suspend fun parseOPDSStream(content: String?, urlHost: String): Boolean =
|
||||||
|
runCatching {
|
||||||
|
manager.readOpds(content, urlHost)
|
||||||
|
}.onFailure {
|
||||||
|
it.printStackTrace()
|
||||||
|
}.isSuccess
|
||||||
|
|
||||||
|
suspend fun getOnlineBooks(): List<LibkiwixBook> {
|
||||||
|
val onlineBooksList = arrayListOf<LibkiwixBook>()
|
||||||
|
runCatching {
|
||||||
|
library.booksIds.forEach { bookId ->
|
||||||
|
val book = library.getBookById(bookId)
|
||||||
|
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.compat.CompatHelper.Companion.convertToLocal
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
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.ZimFileReader
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.KiwixTag
|
import org.kiwix.kiwixmobile.core.zim_manager.KiwixTag
|
||||||
@ -44,7 +44,7 @@ sealed class BooksOnDiskListItem {
|
|||||||
|
|
||||||
data class BookOnDisk constructor(
|
data class BookOnDisk constructor(
|
||||||
val databaseId: Long = 0L,
|
val databaseId: Long = 0L,
|
||||||
val book: LibraryNetworkEntity.Book,
|
val book: LibkiwixBook,
|
||||||
val file: File = File(""),
|
val file: File = File(""),
|
||||||
val zimReaderSource: ZimReaderSource,
|
val zimReaderSource: ZimReaderSource,
|
||||||
val tags: List<KiwixTag> = KiwixTag.Companion.from(book.tags),
|
val tags: List<KiwixTag> = KiwixTag.Companion.from(book.tags),
|
||||||
|
@ -22,14 +22,12 @@ import com.tonyodev.fetch2.Status
|
|||||||
import com.tonyodev.fetch2.Status.NONE
|
import com.tonyodev.fetch2.Status.NONE
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Base64String
|
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Pending
|
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Pending
|
||||||
import org.kiwix.kiwixmobile.core.downloader.model.Seconds
|
import org.kiwix.kiwixmobile.core.downloader.model.Seconds
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
|
||||||
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity
|
||||||
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity.FileElement
|
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity.FileElement
|
||||||
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity.Pieces
|
import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity.Pieces
|
||||||
@ -38,11 +36,10 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
|||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.LinkedList
|
|
||||||
|
|
||||||
fun bookOnDisk(
|
fun bookOnDisk(
|
||||||
databaseId: Long = 0L,
|
databaseId: Long = 0L,
|
||||||
book: Book = book(),
|
book: LibkiwixBook = libkiwixBook(),
|
||||||
zimReaderSource: ZimReaderSource = ZimReaderSource(File(""))
|
zimReaderSource: ZimReaderSource = ZimReaderSource(File(""))
|
||||||
) = BookOnDisk(databaseId, book, File(""), zimReaderSource)
|
) = BookOnDisk(databaseId, book, File(""), zimReaderSource)
|
||||||
|
|
||||||
@ -56,7 +53,7 @@ fun downloadModel(
|
|||||||
status: Status = NONE,
|
status: Status = NONE,
|
||||||
error: Error = Error.NONE,
|
error: Error = Error.NONE,
|
||||||
progress: Int = 1,
|
progress: Int = 1,
|
||||||
book: Book = book()
|
book: LibkiwixBook = libkiwixBook()
|
||||||
) = DownloadModel(
|
) = DownloadModel(
|
||||||
databaseId, downloadId, file, etaInMilliSeconds, bytesDownloaded, totalSizeOfDownload,
|
databaseId, downloadId, file, etaInMilliSeconds, bytesDownloaded, totalSizeOfDownload,
|
||||||
status, error, progress, book
|
status, error, progress, book
|
||||||
@ -64,7 +61,7 @@ fun downloadModel(
|
|||||||
|
|
||||||
fun downloadItem(
|
fun downloadItem(
|
||||||
downloadId: Long = 1L,
|
downloadId: Long = 1L,
|
||||||
favIcon: Base64String = Base64String("favIcon"),
|
favIcon: String = "favIcon",
|
||||||
title: String = "title",
|
title: String = "title",
|
||||||
description: String = "description",
|
description: String = "description",
|
||||||
bytesDownloaded: Long = 1L,
|
bytesDownloaded: Long = 1L,
|
||||||
@ -135,7 +132,7 @@ fun url(
|
|||||||
this.value = value
|
this.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun book(
|
fun libkiwixBook(
|
||||||
id: String = "id",
|
id: String = "id",
|
||||||
title: String = "title",
|
title: String = "title",
|
||||||
description: String = "description",
|
description: String = "description",
|
||||||
@ -150,7 +147,7 @@ fun book(
|
|||||||
name: String = "name",
|
name: String = "name",
|
||||||
favIcon: String = "favIcon",
|
favIcon: String = "favIcon",
|
||||||
file: File = File("")
|
file: File = File("")
|
||||||
) = Book().apply {
|
) = LibkiwixBook().apply {
|
||||||
this.id = id
|
this.id = id
|
||||||
this.title = title
|
this.title = title
|
||||||
this.description = description
|
this.description = description
|
||||||
@ -167,11 +164,6 @@ fun book(
|
|||||||
favicon = favIcon
|
favicon = favIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
fun libraryNetworkEntity(books: List<Book> = emptyList()) =
|
|
||||||
LibraryNetworkEntity().apply {
|
|
||||||
book = LinkedList(books)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun recentSearchEntity(
|
fun recentSearchEntity(
|
||||||
id: Long = 0L,
|
id: Long = 0L,
|
||||||
searchTerm: String = "",
|
searchTerm: String = "",
|
||||||
|
@ -40,7 +40,7 @@ import org.kiwix.kiwixmobile.core.utils.files.FileSearch
|
|||||||
import org.kiwix.kiwixmobile.core.utils.files.ScanningProgressListener
|
import org.kiwix.kiwixmobile.core.utils.files.ScanningProgressListener
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.testFlow
|
import org.kiwix.kiwixmobile.core.utils.files.testFlow
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.sharedFunctions.book
|
import org.kiwix.sharedFunctions.libkiwixBook
|
||||||
import org.kiwix.sharedFunctions.bookOnDisk
|
import org.kiwix.sharedFunctions.bookOnDisk
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class StorageObserverTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `zim files are read by the file reader`() = runTest {
|
fun `zim files are read by the file reader`() = runTest {
|
||||||
val expectedBook =
|
val expectedBook =
|
||||||
book(
|
libkiwixBook(
|
||||||
"id", "title", "1", "favicon", "creator", "publisher", "date",
|
"id", "title", "1", "favicon", "creator", "publisher", "date",
|
||||||
"description", "language"
|
"description", "language"
|
||||||
)
|
)
|
||||||
|
@ -40,13 +40,13 @@ import org.junit.jupiter.api.Nested
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity_
|
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity_
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||||
import org.kiwix.kiwixmobile.core.utils.files.testFlow
|
import org.kiwix.kiwixmobile.core.utils.files.testFlow
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.sharedFunctions.book
|
|
||||||
import org.kiwix.sharedFunctions.bookOnDisk
|
import org.kiwix.sharedFunctions.bookOnDisk
|
||||||
import org.kiwix.sharedFunctions.bookOnDiskEntity
|
import org.kiwix.sharedFunctions.bookOnDiskEntity
|
||||||
|
import org.kiwix.sharedFunctions.libkiwixBook
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
@ -131,9 +131,9 @@ internal class NewBookDaoTest {
|
|||||||
fun `insert transaction adds books to the box that have distinct ids`() {
|
fun `insert transaction adds books to the box that have distinct ids`() {
|
||||||
val slot: CapturingSlot<Callable<Unit>> = slot()
|
val slot: CapturingSlot<Callable<Unit>> = slot()
|
||||||
every { box.store.callInTx(capture(slot)) } returns Unit
|
every { box.store.callInTx(capture(slot)) } returns Unit
|
||||||
val distinctBook: BookOnDisk = bookOnDisk(databaseId = 0, book = book(id = "same"))
|
val distinctBook: BookOnDisk = bookOnDisk(databaseId = 0, book = libkiwixBook(id = "same"))
|
||||||
newBookDao.insert(
|
newBookDao.insert(
|
||||||
listOf(distinctBook, bookOnDisk(databaseId = 1, book = book(id = "same")))
|
listOf(distinctBook, bookOnDisk(databaseId = 1, book = libkiwixBook(id = "same")))
|
||||||
)
|
)
|
||||||
val queryBuilder: QueryBuilder<BookOnDiskEntity> = mockk(relaxed = true)
|
val queryBuilder: QueryBuilder<BookOnDiskEntity> = mockk(relaxed = true)
|
||||||
every { box.query() } returns queryBuilder
|
every { box.query() } returns queryBuilder
|
||||||
@ -216,7 +216,7 @@ internal class NewBookDaoTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun migrationInsert() {
|
fun migrationInsert() {
|
||||||
val book: LibraryNetworkEntity.Book = book()
|
val book: LibkiwixBook = libkiwixBook()
|
||||||
val slot: CapturingSlot<Callable<Unit>> = slot()
|
val slot: CapturingSlot<Callable<Unit>> = slot()
|
||||||
every { box.store.callInTx(capture(slot)) } returns Unit
|
every { box.store.callInTx(capture(slot)) } returns Unit
|
||||||
newBookDao.migrationInsert(listOf(book))
|
newBookDao.migrationInsert(listOf(book))
|
||||||
|
@ -22,16 +22,16 @@ import io.mockk.clearMocks
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class FileUtilsTest {
|
class FileUtilsTest {
|
||||||
private val mockFile: File = mockk()
|
private val mockFile: File = mockk()
|
||||||
private val testBook = Book().apply { file = mockFile }
|
private val testBook = LibkiwixBook().apply { file = mockFile }
|
||||||
private val testId = "8ce5775a-10a9-bbf3-178a-9df69f23263c"
|
private val testId = "8ce5775a-10a9-bbf3-178a-9df69f23263c"
|
||||||
private val fileName = "/data/user/0/org.kiwix.kiwixmobile/files${File.separator}$testId"
|
private val fileName = "/data/user/0/org.kiwix.kiwixmobile/files${File.separator}$testId"
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ package org.kiwix.kiwixmobile.custom.download.effects
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||||
import org.kiwix.kiwixmobile.core.downloader.Downloader
|
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 org.kiwix.kiwixmobile.custom.BuildConfig
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ data class DownloadCustom @Inject constructor(val downloader: Downloader) : Side
|
|||||||
name: String = "",
|
name: String = "",
|
||||||
favIcon: String = ""
|
favIcon: String = ""
|
||||||
) =
|
) =
|
||||||
Book().apply {
|
LibkiwixBook().apply {
|
||||||
this.id = id
|
this.id = id
|
||||||
this.title = title
|
this.title = title
|
||||||
this.description = description
|
this.description = description
|
||||||
|
@ -22,7 +22,7 @@ import io.mockk.coVerify
|
|||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.kiwix.kiwixmobile.core.downloader.Downloader
|
import org.kiwix.kiwixmobile.core.downloader.Downloader
|
||||||
import org.kiwix.sharedFunctions.book
|
import org.kiwix.sharedFunctions.libkiwixBook
|
||||||
|
|
||||||
internal class DownloadCustomTest {
|
internal class DownloadCustomTest {
|
||||||
@Test
|
@Test
|
||||||
@ -35,7 +35,7 @@ internal class DownloadCustomTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun expectedBook() =
|
private fun expectedBook() =
|
||||||
book(
|
libkiwixBook(
|
||||||
"custom",
|
"custom",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user