mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 10:46:53 -04:00
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.
This commit is contained in:
parent
7a10528d19
commit
ebbe1b9889
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
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
|
||||
.size(BOOK_ICON_SIZE),
|
||||
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
|
||||
@ -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())
|
||||
|
@ -446,13 +446,19 @@ class ZimManageViewModel @Inject constructor(
|
||||
): Flow<List<LibkiwixBook>> = 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)
|
||||
val libraryXml = response.body()
|
||||
val isLibraryParsed = onlineLibraryManager.parseOPDSStream(libraryXml, baseHostUrl)
|
||||
emit(
|
||||
if (isLibraryParsed) {
|
||||
emit(onlineLibraryManager.getOnlineBooks())
|
||||
onlineLibraryManager.getOnlineBooks()
|
||||
} else {
|
||||
emit(emptyList())
|
||||
emptyList()
|
||||
}
|
||||
)
|
||||
}
|
||||
.retry(5)
|
||||
.catch { e ->
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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}"
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -21,7 +21,7 @@
|
||||
<ID>MagicNumber:DownloaderModule.kt$DownloaderModule$5</ID>
|
||||
<ID>MagicNumber:FileUtils.kt$FileUtils$3</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:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$100</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>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: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:Language.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
<ID>PackageNaming:MountPointProducer.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
|
||||
|
@ -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,13 +58,35 @@ abstract class DownloadRoomDao {
|
||||
|
||||
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 }
|
||||
.takeIf(List<DownloadRoomEntity>::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) {
|
||||
|
@ -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.
|
||||
|
@ -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<String>
|
||||
|
||||
@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"
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -38,7 +38,7 @@ value class Base64String(private val encodedString: String?) {
|
||||
BitmapFactory.decodeByteArray(it, 0, it.size)
|
||||
}
|
||||
}
|
||||
} catch (illegalArgumentException: IllegalArgumentException) {
|
||||
} catch (_: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
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.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
|
||||
|
@ -340,6 +340,7 @@ abstract class CoreReaderFragment :
|
||||
private val navigationHistoryList: MutableList<NavigationHistoryListItem> = 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()
|
||||
|
@ -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())) +
|
Loading…
x
Reference in New Issue
Block a user