From ebbe1b988964a141cce072b98edbe4dfe6ac3740 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Thu, 5 Jun 2025 23:49:02 +0530 Subject: [PATCH] Fixed: Downloading was not working. * Fixed: `Online Books` were showing incorrect book sizes. The OPDS stream now provides sizes in bytes instead of kilobytes, so the code has been updated accordingly. * Added the `io.coil-kt.coil3:coil-compose` library to load favicons for online books, as OPDS now returns favicon URLs instead of Base64-encoded strings. * Since favicons are no longer provided in Base64 format when downloading ZIM files, we now extract the favicon from the Archive using libkiwix after the download completes. This allows us to display it locally on various screens such as the library, Wi-Fi hotspot, notes, history, and more. * Cached the `LibkiwixBook` instance to avoid recreating it multiple times when adding or removing bookmarks. --- .../library/online/DownloadBookItem.kt | 3 +- .../library/online/OnlineBookItem.kt | 8 ++-- .../java/org/kiwix/kiwixmobile/ui/BookItem.kt | 37 ++++++++++++------- .../zimManager/ZimManageViewModel.kt | 18 ++++++--- .../libraryView/AvailableSpaceCalculator.kt | 5 +-- .../libraryView/adapter/LibraryListItem.kt | 5 +-- buildSrc/src/main/kotlin/Libs.kt | 3 ++ buildSrc/src/main/kotlin/Versions.kt | 2 + .../kotlin/plugin/AllProjectConfigurer.kt | 2 + core/detekt_baseline.xml | 4 +- .../kiwixmobile/core/dao/DownloadRoomDao.kt | 35 ++++++++++++++++-- .../kiwixmobile/core/dao/LibkiwixBookmarks.kt | 1 + .../core/data/remote/KiwixService.kt | 8 ++-- .../core/di/modules/NetworkModule.kt | 2 +- .../core/downloader/model/Base64String.kt | 2 +- .../core/downloader/model/DownloadItem.kt | 4 +- .../core/extensions/BookExtensions.kt | 21 +++++++++-- .../core/extensions/ImageViewExtensions.kt | 14 ------- .../core/main/CoreReaderFragment.kt | 18 +++++++-- .../core/zim_manager/{KiloByte.kt => Byte.kt} | 6 +-- 20 files changed, 129 insertions(+), 69 deletions(-) rename core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/{KiloByte.kt => Byte.kt} (87%) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/DownloadBookItem.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/DownloadBookItem.kt index 655fcb6fe..af3f2284f 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/DownloadBookItem.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/DownloadBookItem.kt @@ -44,7 +44,6 @@ import androidx.compose.ui.semantics.testTag import com.tonyodev.fetch2.Status import org.kiwix.kiwixmobile.R 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.ProgressBarStyle import org.kiwix.kiwixmobile.core.ui.models.IconItem @@ -104,7 +103,7 @@ private fun DownloadBookContent( .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - BookIcon(item.favIcon.toPainter()) + BookIcon(item.favIconUrl, isOnlineLibrary = true) Column( modifier = Modifier .weight(1f) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineBookItem.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineBookItem.kt index d4c113940..10523668c 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineBookItem.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/online/OnlineBookItem.kt @@ -48,8 +48,6 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.zIndex 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.ui.theme.KiwixTheme 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.SIXTEEN_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.BookDescription import org.kiwix.kiwixmobile.ui.BookIcon @@ -167,7 +165,7 @@ private fun OnlineBookContent(item: BookItem, bookUtils: BookUtils) { .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - BookIcon(Base64String(item.book.favicon).toPainter()) + BookIcon(item.book.favicon, isOnlineLibrary = true) Column( modifier = Modifier .weight(1f) @@ -207,7 +205,7 @@ private fun BookSizeAndDateRow(item: BookItem) { verticalAlignment = Alignment.CenterVertically ) { BookSize( - KiloByte(item.book.size).humanReadable, + Byte(item.book.size).humanReadable, modifier = Modifier.weight(1f).testTag(ONLINE_BOOK_SIZE_TEXT_TESTING_TAG) ) BookDate(item.book.date) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt b/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt index c8539a813..df8615ea2 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/ui/BookItem.kt @@ -19,6 +19,7 @@ package org.kiwix.kiwixmobile.ui import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Column 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.CardDefaults import androidx.compose.material3.Checkbox -import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment 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.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow +import coil3.compose.AsyncImage import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.downloader.model.Base64String 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.SIXTEEN_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.BooksOnDiskListItem.BookOnDisk import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode @@ -116,7 +116,7 @@ private fun BookContent( if (selectionMode == SelectionMode.MULTI) { BookCheckbox(bookOnDisk, selectionMode, onMultiSelect, onClick, index) } - BookIcon(Base64String(bookOnDisk.book.favicon).toPainter()) + BookIcon(bookOnDisk.book.favicon, isOnlineLibrary = false) BookDetails(Modifier.weight(1f), bookOnDisk) } } @@ -142,14 +142,23 @@ private fun BookCheckbox( } @Composable -fun BookIcon(painter: Painter) { - Icon( - painter = painter, - contentDescription = stringResource(R.string.fav_icon), - modifier = Modifier - .size(BOOK_ICON_SIZE), - tint = Color.Unspecified - ) +fun BookIcon(iconSource: String, isOnlineLibrary: Boolean) { + val modifier = Modifier.size(BOOK_ICON_SIZE) + if (isOnlineLibrary) { + AsyncImage( + model = iconSource, + contentDescription = stringResource(R.string.fav_icon), + 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 @@ -164,7 +173,7 @@ private fun BookDetails(modifier: Modifier, bookOnDisk: BookOnDisk) { ) { BookDate(bookOnDisk.book.date) Spacer(modifier = Modifier.width(EIGHT_DP)) - BookSize(KiloByte(bookOnDisk.book.size).humanReadable) + BookSize(Byte(bookOnDisk.book.size).humanReadable) Spacer(modifier = Modifier.width(EIGHT_DP)) BookArticleCount( ArticleCount(bookOnDisk.book.articleCount.orEmpty()) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt index ce6df49de..83dcb24a3 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt @@ -446,13 +446,19 @@ class ZimManageViewModel @Inject constructor( ): Flow> = flow { downloadProgress.postValue(context.getString(R.string.starting_downloading_remote_library)) 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)) - val isLibraryParsed = onlineLibraryManager.parseOPDSStream(response, KIWIX_OPDS_LIBRARY_URL) - if (isLibraryParsed) { - emit(onlineLibraryManager.getOnlineBooks()) - } else { - emit(emptyList()) - } + val libraryXml = response.body() + val isLibraryParsed = onlineLibraryManager.parseOPDSStream(libraryXml, baseHostUrl) + emit( + if (isLibraryParsed) { + onlineLibraryManager.getOnlineBooks() + } else { + emptyList() + } + ) } .retry(5) .catch { e -> diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/AvailableSpaceCalculator.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/AvailableSpaceCalculator.kt index 7b1193251..73c5fda7a 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/AvailableSpaceCalculator.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/AvailableSpaceCalculator.kt @@ -19,7 +19,6 @@ package org.kiwix.kiwixmobile.zimManager.libraryView import eu.mhutti1.utils.storage.Bytes -import eu.mhutti1.utils.storage.KB import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao @@ -42,7 +41,7 @@ class AvailableSpaceCalculator @Inject constructor( .map { downloads -> downloads.sumOf(DownloadModel::bytesRemaining) } .map { bytesToBeDownloaded -> storageCalculator.availableBytes() - bytesToBeDownloaded } .first() - if (bookItem.book.size.toLong() * KB < trueAvailableBytes) { + if (bookItem.book.size.toLong() < trueAvailableBytes) { successAction.invoke(bookItem) } else { failureAction.invoke(Bytes(trueAvailableBytes).humanReadable) @@ -50,5 +49,5 @@ class AvailableSpaceCalculator @Inject constructor( } suspend fun hasAvailableSpaceForBook(book: LibkiwixBook) = - book.size.toLong() * KB < storageCalculator.availableBytes() + book.size.toLong() < storageCalculator.availableBytes() } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/adapter/LibraryListItem.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/adapter/LibraryListItem.kt index 95b813789..d33ecee0e 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/adapter/LibraryListItem.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/libraryView/adapter/LibraryListItem.kt @@ -20,7 +20,6 @@ package org.kiwix.kiwixmobile.zimManager.libraryView.adapter import androidx.annotation.StringRes 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.DownloadState import org.kiwix.kiwixmobile.core.downloader.model.Seconds @@ -61,7 +60,7 @@ sealed class LibraryListItem { data class LibraryDownloadItem( val downloadId: Long, - val favIcon: Base64String, + val favIconUrl: String, val title: String, val description: String?, val bytesDownloaded: Long, @@ -76,7 +75,7 @@ sealed class LibraryListItem { constructor(downloadModel: DownloadModel) : this( downloadModel.downloadId, - Base64String(downloadModel.book.favicon), + downloadModel.book.favicon, downloadModel.book.title, downloadModel.book.description, downloadModel.bytesDownloaded, diff --git a/buildSrc/src/main/kotlin/Libs.kt b/buildSrc/src/main/kotlin/Libs.kt index ce38398e7..09f10679e 100644 --- a/buildSrc/src/main/kotlin/Libs.kt +++ b/buildSrc/src/main/kotlin/Libs.kt @@ -369,4 +369,7 @@ object Libs { const val COMPOSE_LIVE_DATA = "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}" } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 72dd1badc..d39d9fd84 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -115,6 +115,8 @@ object Versions { const val COMPOSE_MATERIAL3 = "1.3.1" const val TURBINE_FLOW_TEST = "1.2.0" + + const val COIL_COMPOSE = "3.2.0" } /** diff --git a/buildSrc/src/main/kotlin/plugin/AllProjectConfigurer.kt b/buildSrc/src/main/kotlin/plugin/AllProjectConfigurer.kt index dd2df6691..4c1458ea7 100644 --- a/buildSrc/src/main/kotlin/plugin/AllProjectConfigurer.kt +++ b/buildSrc/src/main/kotlin/plugin/AllProjectConfigurer.kt @@ -243,6 +243,8 @@ class AllProjectConfigurer { implementation(Libs.ANDROIDX_ACTIVITY_COMPOSE) implementation(Libs.COMPOSE_TOOLING_PREVIEW) implementation(Libs.COMPOSE_LIVE_DATA) + implementation(Libs.COIL3_COMPOSE) + implementation(Libs.COIL3_OKHTTP_COMPOSE) // Compose UI test implementation androidTestImplementation(Libs.COMPOSE_UI_TEST_JUNIT) diff --git a/core/detekt_baseline.xml b/core/detekt_baseline.xml index 876ea7fd3..93e357e6b 100644 --- a/core/detekt_baseline.xml +++ b/core/detekt_baseline.xml @@ -21,7 +21,7 @@ MagicNumber:DownloaderModule.kt$DownloaderModule$5 MagicNumber:FileUtils.kt$FileUtils$3 MagicNumber:JNIInitialiser.kt$JNIInitialiser$1024 - MagicNumber:KiloByte.kt$KiloByte$1024.0 + MagicNumber:Byte.kt$Byte$1024.0 MagicNumber:MainMenu.kt$MainMenu$99 MagicNumber:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$100 MagicNumber:SearchResultGenerator.kt$ZimSearchResultGenerator$200 @@ -42,7 +42,7 @@ NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$// Amazingly file.canWrite() does not always return the correct value private fun canWrite(file: File): Boolean PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view PackageNaming:BooksOnDiskListItem.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view - PackageNaming:KiloByte.kt$package org.kiwix.kiwixmobile.core.zim_manager + PackageNaming:Byte.kt$package org.kiwix.kiwixmobile.core.zim_manager PackageNaming:KiwixTag.kt$package org.kiwix.kiwixmobile.core.zim_manager PackageNaming:Language.kt$package org.kiwix.kiwixmobile.core.zim_manager PackageNaming:MountPointProducer.kt$package org.kiwix.kiwixmobile.core.zim_manager diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt index e1d84a3e9..3186a7663 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/DownloadRoomDao.kt @@ -18,6 +18,7 @@ package org.kiwix.kiwixmobile.core.dao +import android.util.Base64 import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert @@ -25,16 +26,20 @@ import androidx.room.Query import androidx.room.Update import com.tonyodev.fetch2.Download import com.tonyodev.fetch2.Status.COMPLETED +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.withContext import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity import org.kiwix.kiwixmobile.core.downloader.DownloadRequester import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel import org.kiwix.kiwixmobile.core.downloader.model.DownloadRequest import org.kiwix.kiwixmobile.core.entity.LibkiwixBook +import org.kiwix.kiwixmobile.core.reader.ILLUSTRATION_SIZE import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem +import org.kiwix.libzim.Archive import javax.inject.Inject @Dao @@ -53,15 +58,37 @@ abstract class DownloadRoomDao { fun allDownloads() = getAllDownloads().map { it.map(::DownloadModel) } - private fun moveCompletedToBooksOnDiskDao(downloadEntities: List) { + @Suppress("InjectDispatcher") + private suspend fun moveCompletedToBooksOnDiskDao(downloadEntities: List) { downloadEntities.filter { it.status == COMPLETED } .takeIf(List::isNotEmpty) - ?.let { - deleteDownloadsList(it) - newBookDao.insert(it.map(BooksOnDiskListItem::BookOnDisk)) + ?.let { completedDownloads -> + deleteDownloadsList(completedDownloads) + // 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) { getEntityForDownloadId(download.id.toLong())?.let { downloadRoomEntity -> downloadRoomEntity.updateWith(download) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LibkiwixBookmarks.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LibkiwixBookmarks.kt index 991c7ee7b..d1e86c9b0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LibkiwixBookmarks.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LibkiwixBookmarks.kt @@ -285,6 +285,7 @@ class LibkiwixBookmarks @Inject constructor( // Check if the book has an illustration of the specified size and encode it to Base64. val favicon = book?.getFavicon() + Log.e(TAG, "getBookmarksList: $favicon") val zimReaderSource = book?.path?.let { ZimReaderSource(File(it)) } // Return the LibkiwixBookmarkItem, filtering out null results. diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/KiwixService.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/KiwixService.kt index 5f549dceb..1ef98b7e6 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/KiwixService.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/KiwixService.kt @@ -21,14 +21,16 @@ package org.kiwix.kiwixmobile.core.data.remote import okhttp3.OkHttpClient import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity +import retrofit2.Response import retrofit2.Retrofit import retrofit2.converter.scalars.ScalarsConverterFactory +import retrofit2.converter.simplexml.SimpleXmlConverterFactory import retrofit2.http.GET import retrofit2.http.Url interface KiwixService { @GET(OPDS_LIBRARY_NETWORK_PATH) - suspend fun getLibrary(): String? + suspend fun getLibrary(): Response @GET suspend fun getMetaLinks( @@ -43,7 +45,7 @@ interface KiwixService { .baseUrl(baseUrl) .client(okHttpClient) .addConverterFactory(ScalarsConverterFactory.create()) - // .addConverterFactory(SimpleXmlConverterFactory.create()) + .addConverterFactory(SimpleXmlConverterFactory.create()) .build() return retrofit.create(KiwixService::class.java) } @@ -52,6 +54,6 @@ interface KiwixService { companion object { // To fetch the full OPDS catalog. // TODO we will change this to pagination later once we migrate to OPDS properly. - const val OPDS_LIBRARY_NETWORK_PATH = "entries?count=-1" + const val OPDS_LIBRARY_NETWORK_PATH = "v2/entries?count=-1" } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt index 18e6d450a..e0d5a816e 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt @@ -38,7 +38,7 @@ const val CONNECTION_TIMEOUT = 10L const val READ_TIMEOUT = 300L const val CALL_TIMEOUT = 300L const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}" -const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/v2/" +const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/" @Module class NetworkModule { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/Base64String.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/Base64String.kt index df06f6980..849cb7f34 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/Base64String.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/Base64String.kt @@ -38,7 +38,7 @@ value class Base64String(private val encodedString: String?) { BitmapFactory.decodeByteArray(it, 0, it.size) } } - } catch (illegalArgumentException: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { null } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/DownloadItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/DownloadItem.kt index b0cf08251..7af29cc8b 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/DownloadItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/downloader/model/DownloadItem.kt @@ -34,7 +34,7 @@ import org.kiwix.kiwixmobile.core.R data class DownloadItem( val downloadId: Long, - val favIcon: Base64String, + val favIconUrl: String, val title: String, val description: String?, val bytesDownloaded: Long, @@ -47,7 +47,7 @@ data class DownloadItem( constructor(downloadModel: DownloadModel) : this( downloadModel.downloadId, - Base64String(downloadModel.book.favicon), + downloadModel.book.favicon, downloadModel.book.title, downloadModel.book.description, downloadModel.bytesDownloaded, diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/BookExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/BookExtensions.kt index 7b9b82e09..cbc73a0a1 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/BookExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/BookExtensions.kt @@ -19,6 +19,7 @@ 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.entity.LibkiwixBook import org.kiwix.kiwixmobile.core.reader.ILLUSTRATION_SIZE @@ -57,6 +58,20 @@ fun LibkiwixBook.buildSearchableText(bookUtils: BookUtils): String = } }.toString() -fun Book.getFavicon(): String? = getIllustration(ILLUSTRATION_SIZE)?.data?.let { - Base64.encodeToString(it, Base64.DEFAULT) -} +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}") + } + "" + } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ImageViewExtensions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ImageViewExtensions.kt index a046dc6f2..ac38ec97a 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ImageViewExtensions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/extensions/ImageViewExtensions.kt @@ -24,20 +24,6 @@ import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.core.content.ContextCompat 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( @DrawableRes id: Int diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index c19977ec8..a71785914 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -340,6 +340,7 @@ abstract class CoreReaderFragment : private val navigationHistoryList: MutableList = ArrayList() private var isReadSelection = false private var isReadAloudServiceRunning = false + private var libkiwixBook: Book? = null private var readerLifeCycleScope: CoroutineScope? = null val coreReaderLifeCycleScope: CoroutineScope? @@ -2038,9 +2039,7 @@ abstract class CoreReaderFragment : lifecycleScope.launch { getCurrentWebView()?.url?.let { articleUrl -> zimReaderContainer?.zimFileReader?.let { zimFileReader -> - val libKiwixBook = Book().apply { - update(zimFileReader.jniKiwixReader) - } + val libKiwixBook = getLibkiwixBook(zimFileReader) if (isBookmarked) { repositoryActions?.deleteBookmark(libKiwixBook.id, articleUrl) 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() { super.onResume() updateBottomToolbarVisibility() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/KiloByte.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/Byte.kt similarity index 87% rename from core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/KiloByte.kt rename to core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/Byte.kt index 906a317ff..129e17528 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/KiloByte.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/zim_manager/Byte.kt @@ -23,10 +23,10 @@ import kotlin.math.log10 import kotlin.math.pow @JvmInline -value class KiloByte(private val kilobyteString: String?) { +value class Byte(private val byteString: String?) { val humanReadable - get() = kilobyteString?.toLongOrNull()?.let { - val units = arrayOf("KB", "MB", "GB", "TB") + get() = byteString?.toLongOrNull()?.let { + val units = arrayOf("B", "KB", "MB", "GB", "TB") val conversion = (log10(it.toDouble()) / log10(1024.0)).toInt() DecimalFormat("#,##0.#") .format(it / 1024.0.pow(conversion.toDouble())) +