Refactored the whole code to use ZimReaderSource

This commit is contained in:
MohitMaliFtechiz 2024-08-24 16:03:44 +05:30
parent da51cfc02d
commit 811e37bf70
22 changed files with 173 additions and 121 deletions

View File

@ -43,6 +43,7 @@ import org.kiwix.kiwixmobile.core.dao.entities.BookmarkEntity
import org.kiwix.kiwixmobile.core.data.remote.ObjectBoxToLibkiwixMigrator
import org.kiwix.kiwixmobile.core.di.modules.DatabaseModule
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.handleLocaleChange
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.main.KiwixMainActivity
@ -74,6 +75,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedZimId,
expectedZimName,
expectedZimFilePath,
ZimReaderSource(File(expectedZimFilePath)),
expectedBookmarkUrl,
expectedTitle,
expectedFavicon
@ -156,7 +158,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
assertEquals(1, actualDataAfterMigration.size)
assertEquals(actualDataAfterMigration[0].zimFilePath, expectedZimFilePath)
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), expectedZimFilePath)
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
assertEquals(actualDataAfterMigration[0].title, expectedTitle)
assertEquals(actualDataAfterMigration[0].url, expectedBookmarkUrl)
@ -185,6 +187,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedZimId,
expectedZimName,
expectedZimFilePath,
ZimReaderSource(File(expectedZimFilePath)),
existingBookmarkUrl,
existingTitle,
expectedFavicon
@ -226,6 +229,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedZimId,
expectedZimName,
expectedZimFilePath,
ZimReaderSource(File(expectedZimFilePath)),
"https://alpine_linux/search_$i",
"title_$i",
expectedFavicon
@ -250,6 +254,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedZimId,
expectedZimName,
null,
null,
expectedBookmarkUrl,
expectedTitle,
expectedFavicon
@ -261,7 +266,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
assertEquals(1, actualDataAfterMigration.size)
assertEquals(actualDataAfterMigration[0].zimFilePath, null)
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), null)
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
assertEquals(actualDataAfterMigration[0].title, expectedTitle)
assertEquals(actualDataAfterMigration[0].url, expectedBookmarkUrl)
@ -278,6 +283,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedZimId,
expectedZimName,
nonExistingPath,
ZimReaderSource(File(nonExistingPath)),
expectedBookmarkUrl,
expectedTitle,
expectedFavicon
@ -289,7 +295,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
assertEquals(1, actualDataAfterMigration.size)
assertEquals(actualDataAfterMigration[0].zimFilePath, null)
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), null)
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
assertEquals(actualDataAfterMigration[0].title, expectedTitle)
assertEquals(actualDataAfterMigration[0].url, expectedBookmarkUrl)

View File

@ -31,11 +31,11 @@ import org.junit.Test
import org.kiwix.kiwixmobile.BaseActivityTest
import org.kiwix.kiwixmobile.core.DarkModeConfig
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.main.KiwixMainActivity
import org.kiwix.kiwixmobile.testutils.TestUtils.closeSystemDialogs
import org.kiwix.kiwixmobile.testutils.TestUtils.isSystemUINotRespondingDialogVisible
import org.kiwix.libzim.Archive
import org.kiwix.libzim.SuggestionSearcher
import java.io.File
import java.io.FileOutputStream
@ -81,12 +81,11 @@ class MimeTypeTest : BaseActivityTest() {
}
}
}
val archive = Archive(zimFile.canonicalPath)
val zimSource = ZimReaderSource(zimFile)
val archive = zimSource.createArchive()
val zimFileReader = ZimFileReader(
zimFile,
emptyList(),
null,
archive,
zimSource,
archive!!,
DarkModeConfig(SharedPreferenceUtil(context), context),
SuggestionSearcher(archive)
)

View File

@ -31,11 +31,11 @@ import org.junit.Test
import org.kiwix.kiwixmobile.BaseActivityTest
import org.kiwix.kiwixmobile.core.DarkModeConfig
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.handleLocaleChange
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.main.KiwixMainActivity
import org.kiwix.kiwixmobile.testutils.TestUtils
import org.kiwix.libzim.Archive
import org.kiwix.libzim.SuggestionSearcher
import java.io.File
import java.io.FileOutputStream
@ -89,12 +89,11 @@ class EncodedUrlTest : BaseActivityTest() {
}
}
}
val archive = Archive(zimFile.canonicalPath)
val zimReaderSource = ZimReaderSource(zimFile)
val archive = zimReaderSource.createArchive()
val zimFileReader = ZimFileReader(
zimFile,
emptyList(),
null,
archive,
zimReaderSource,
archive!!,
DarkModeConfig(SharedPreferenceUtil(context), context),
SuggestionSearcher(archive)
)

View File

@ -220,7 +220,7 @@ class KiwixMainActivity : CoreMainActivity() {
{
intent.getStringExtra(DOWNLOAD_NOTIFICATION_TITLE)?.let {
newBookDao.bookMatching(it)?.let { bookOnDiskEntity ->
openZimFromFilePath(bookOnDiskEntity.file.path)
openZimFromFilePath(bookOnDiskEntity.zimReaderSource.toDatabase())
}
}
},

View File

@ -75,6 +75,7 @@ import org.kiwix.kiwixmobile.core.main.MainRepositoryActions
import org.kiwix.kiwixmobile.core.navigateToAppSettings
import org.kiwix.kiwixmobile.core.navigateToSettings
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.SimpleRecyclerViewScrollListener
@ -405,9 +406,9 @@ class LocalLibraryFragment : BaseFragment() {
// we can directly add it to the database.
// See https://github.com/kiwix/kiwix-android/issues/3650
runBlocking {
zimReaderFactory.create(file)
zimReaderFactory.create(ZimReaderSource(file))
?.let { zimFileReader ->
BookOnDisk(file, zimFileReader).also {
BookOnDisk(zimFileReader).also {
mainRepositoryActions.saveBook(it)
zimFileReader.dispose()
}

View File

@ -54,11 +54,14 @@ import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.main.CoreReaderFragment
import org.kiwix.kiwixmobile.core.main.CoreWebViewClient
import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
import org.kiwix.kiwixmobile.core.utils.files.Log
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
import java.io.File
private const val HIDE_TAB_SWITCHER_DELAY: Long = 300
@ -124,7 +127,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
activity.toast(string.error_file_not_found)
return
}
openZimFile(File(filePath))
openZimFile(ZimReaderSource(File(filePath)))
}
override fun loadDrawerViews() {
@ -200,9 +203,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
override fun onResume() {
super.onResume()
if (zimReaderContainer?.zimFile == null &&
zimReaderContainer?.zimFileReader?.assetFileDescriptorList?.isEmpty() == true
) {
if (zimReaderContainer?.zimReaderSource == null) {
exitBook()
}
if (isFullScreenVideo || isInFullScreenMode()) {
@ -221,14 +222,14 @@ class KiwixReaderFragment : CoreReaderFragment() {
currentTab: Int
) {
val settings = requireActivity().getSharedPreferences(SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0)
val zimFile = settings.getString(TAG_CURRENT_FILE, null)
val zimReaderSource = fromDatabaseValue(settings.getString(TAG_CURRENT_FILE, null))
if (zimFile != null && File(zimFile).isFileExist()) {
if (zimReaderContainer?.zimFile == null) {
openZimFile(File(zimFile))
if (zimReaderSource != null && zimReaderSource.canOpenInLibkiwix()) {
if (zimReaderContainer?.zimReaderSource == null) {
openZimFile(zimReaderSource)
Log.d(
TAG_KIWIX,
"Kiwix normal start, Opened last used zimFile: -> $zimFile"
"Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}"
)
} else {
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
@ -305,21 +306,13 @@ class KiwixReaderFragment : CoreReaderFragment() {
when (it.scheme) {
"file" -> {
Handler(Looper.getMainLooper()).postDelayed({
openZimFile(it.toFile()).also {
// if used once then clear it to avoid affecting any other functionality
// of the application.
requireActivity().intent.action = null
}
openAndSaveZimFileInLocalLibrary(it.toFile())
}, 300)
}
"content" -> {
Handler(Looper.getMainLooper()).postDelayed({
getZimFileFromUri(it)?.let { zimFile ->
openZimFile(zimFile)
}.also {
requireActivity().intent.action = null
}
getZimFileFromUri(it)?.let(::openAndSaveZimFileInLocalLibrary)
}, 300)
}
@ -329,6 +322,29 @@ class KiwixReaderFragment : CoreReaderFragment() {
return ShouldCall
}
private fun openAndSaveZimFileInLocalLibrary(file: File) {
val zimReaderSource = ZimReaderSource(file)
if (zimReaderSource.canOpenInLibkiwix()) {
zimReaderContainer?.let { zimReaderContainer ->
zimReaderContainer.setZimReaderSource(zimReaderSource)
zimReaderContainer.zimFileReader?.let { zimFileReader ->
BooksOnDiskListItem.BookOnDisk(zimFileReader).also { bookOnDisk ->
// save the book in the library
repositoryActions?.saveBook(bookOnDisk)
zimFileReader.dispose()
}
}
}
openZimFile(ZimReaderSource(file))
} else {
activity.toast(R.string.cannot_open_file)
}
// if used once then clear it to avoid affecting any other functionality
// of the application.
requireActivity().intent.action = null
}
private fun getZimFileFromUri(
uri: Uri
): File? {

View File

@ -59,17 +59,20 @@ data class DeleteFiles(private val booksOnDiskListItems: List<BookOnDisk>) :
private fun List<BookOnDisk>.deleteAll(): Boolean {
return fold(true) { acc, book ->
acc && deleteSpecificZimFile(book).also {
if (it && book.file.canonicalPath == zimReaderContainer.zimCanonicalPath) {
zimReaderContainer.setZimFile(null)
if (it && book.zimReaderSource == zimReaderContainer.zimReaderSource) {
zimReaderContainer.setZimReaderSource(null)
}
}
}
}
private fun deleteSpecificZimFile(book: BookOnDisk): Boolean {
val file = book.file
FileUtils.deleteZimFile(file.path)
if (file.isFileExist()) {
val file = book.zimReaderSource.file
file?.let {
@Suppress("UnreachableCode")
FileUtils.deleteZimFile(it.path)
}
if (file?.isFileExist() == true) {
return false
}
newBookDao.delete(book.databaseId)

View File

@ -19,11 +19,9 @@
package org.kiwix.kiwixmobile.zimManager.fileselectView.effects
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.navigate
import org.kiwix.kiwixmobile.core.extensions.canReadFile
import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
import org.kiwix.kiwixmobile.nav.destination.library.LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader
@ -32,12 +30,14 @@ data class OpenFileWithNavigation(private val bookOnDisk: BooksOnDiskListItem.Bo
SideEffect<Unit> {
override fun invokeWith(activity: AppCompatActivity) {
val file = bookOnDisk.file
if (!file.canReadFile()) {
val zimReaderSource = bookOnDisk.zimReaderSource
if (!zimReaderSource.canOpenInLibkiwix()) {
activity.toast(R.string.error_file_not_found)
} else {
activity.navigate(
actionNavigationLibraryToNavigationReader().apply { zimFileUri = file.toUri().toString() }
actionNavigationLibraryToNavigationReader().apply {
zimFileUri = zimReaderSource.toDatabase()
}
)
}
}

View File

@ -19,7 +19,6 @@
package org.kiwix.kiwixmobile.zimManager.fileselectView.effects
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.core.os.bundleOf
import org.kiwix.kiwixmobile.R
import org.kiwix.kiwixmobile.core.base.SideEffect
@ -31,11 +30,7 @@ data class ShareFiles(private val selectedBooks: List<BookOnDisk>) :
SideEffect<Unit> {
override fun invokeWith(activity: AppCompatActivity) {
val selectedFileContentURIs = selectedBooks.mapNotNull {
FileProvider.getUriForFile(
activity,
activity.packageName + ".fileprovider",
it.file
)
it.zimReaderSource.getUri(activity)
}
activity.navigate(
R.id.localFileTransferFragment,

View File

@ -26,6 +26,7 @@ import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.files.FileSearch
import org.kiwix.kiwixmobile.core.utils.files.ScanningProgressListener
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
@ -57,9 +58,9 @@ class StorageObserver @Inject constructor(
downloads.firstOrNull { file.absolutePath.endsWith(it.fileNameFromUrl) } == null
private fun convertToBookOnDisk(file: File) = runBlocking {
zimReaderFactory.create(file)
zimReaderFactory.create(ZimReaderSource(file))
?.let { zimFileReader ->
BookOnDisk(file, zimFileReader).also {
BookOnDisk(zimFileReader).also {
// add the book to libkiwix library to validate the imported bookmarks
libkiwixBookmarks.addBookToLibrary(archive = zimFileReader.jniKiwixReader)
zimFileReader.dispose()

View File

@ -36,7 +36,6 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
import org.kiwix.kiwixmobile.core.extensions.isFileExist
import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.BookmarkItem
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
import org.kiwix.kiwixmobile.core.reader.ILLUSTRATION_SIZE
import org.kiwix.kiwixmobile.core.reader.ZimFileReader

View File

@ -149,7 +149,7 @@ open class ErrorActivity : BaseActivity() {
}
return """
Current Zim File:
${zimReaderContainer.zimCanonicalPath}
${zimReaderContainer.zimReaderSource?.toDatabase()}
All Zim Files in DB:
$allZimFiles

View File

@ -119,7 +119,7 @@ class AddNoteDialog : DialogFragment() {
.inject(this)
// Returns name of the form ".../Kiwix/granbluefantasy_en_all_all_nopic_2018-10.zim"
zimFileName = zimReaderContainer.zimCanonicalPath ?: zimReaderContainer.name
zimFileName = zimReaderContainer.zimReaderSource?.toDatabase() ?: zimReaderContainer.name
if (zimFileName != null) { // No zim file currently opened
zimFileTitle = zimReaderContainer.zimFileTitle
zimId = zimReaderContainer.id.orEmpty()

View File

@ -57,6 +57,7 @@ import org.kiwix.kiwixmobile.core.extensions.getToolbarNavigationIcon
import org.kiwix.kiwixmobile.core.extensions.registerReceiver
import org.kiwix.kiwixmobile.core.extensions.setToolTipWithContentDescription
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.search.NAV_ARG_SEARCH_STRING
import org.kiwix.kiwixmobile.core.utils.EXTRA_IS_WIDGET_VOICE
import org.kiwix.kiwixmobile.core.utils.ExternalLinkOpener
@ -372,12 +373,20 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider {
)
}
fun openPage(pageUrl: String, zimFilePath: String = "", shouldOpenInNewTab: Boolean = false) {
fun openPage(
pageUrl: String,
zimReaderSource: ZimReaderSource? = null,
shouldOpenInNewTab: Boolean = false
) {
var zimFileUri = ""
if (zimReaderSource != null) {
zimFileUri = zimReaderSource.toDatabase()
}
navigate(
readerFragmentResId,
bundleOf(
PAGE_URL_KEY to pageUrl,
ZIM_FILE_URI_KEY to zimFilePath,
ZIM_FILE_URI_KEY to zimFileUri,
SHOULD_OPEN_IN_NEW_TAB to shouldOpenInNewTab
)
)

View File

@ -26,7 +26,6 @@ import android.content.Intent
import android.content.ServiceConnection
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.AssetFileDescriptor
import android.content.res.Configuration
import android.graphics.Canvas
import android.media.AudioManager
@ -107,7 +106,6 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.requestNotificat
import org.kiwix.kiwixmobile.core.extensions.ViewGroupExtensions.findFirstTextView
import org.kiwix.kiwixmobile.core.extensions.closeFullScreenMode
import org.kiwix.kiwixmobile.core.extensions.getToolbarNavigationIcon
import org.kiwix.kiwixmobile.core.extensions.isFileExist
import org.kiwix.kiwixmobile.core.extensions.setToolTipWithContentDescription
import org.kiwix.kiwixmobile.core.extensions.showFullScreenMode
import org.kiwix.kiwixmobile.core.extensions.snack
@ -131,6 +129,7 @@ import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudService.Companion.ACTION_S
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchItemToOpen
import org.kiwix.kiwixmobile.core.utils.AnimationUtils.rotate
import org.kiwix.kiwixmobile.core.utils.DimenUtils.getToolbarHeight
@ -159,7 +158,6 @@ import org.kiwix.kiwixmobile.core.utils.files.Log
import org.kiwix.kiwixmobile.core.utils.titleToUrl
import org.kiwix.kiwixmobile.core.utils.urlSuffixToParsableUrl
import org.kiwix.libkiwix.Book
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
@ -286,11 +284,11 @@ abstract class CoreReaderFragment :
private var tts: KiwixTextToSpeech? = null
private var compatCallback: CompatFindActionModeCallback? = null
private var tabsAdapter: TabsAdapter? = null
private var file: File? = null
private var zimReaderSource: ZimReaderSource? = null
private var actionMode: ActionMode? = null
private var tempWebViewForUndo: KiwixWebView? = null
private var tempWebViewListForUndo: MutableList<KiwixWebView> = ArrayList()
private var tempZimFileForUndo: File? = null
private var tempZimSourceForUndo: ZimReaderSource? = null
private var isFirstRun = false
private var tableDrawerAdapter: TableDrawerAdapter? = null
private var tableDrawerRight: RecyclerView? = null
@ -1323,7 +1321,7 @@ abstract class CoreReaderFragment :
// Address those issues when the user frequently clicks on the close icon of the same tab.
// See https://github.com/kiwix/kiwix-android/issues/3790 for more details.
if (index == RecyclerView.NO_POSITION) return
tempZimFileForUndo = zimReaderContainer?.zimFile
tempZimSourceForUndo = zimReaderContainer?.zimReaderSource
tempWebViewForUndo = webViewList[index]
webViewList.removeAt(index)
if (index <= currentWebViewIndex && currentWebViewIndex > 0) {
@ -1360,7 +1358,7 @@ abstract class CoreReaderFragment :
}
private fun closeZimBook() {
zimReaderContainer?.setZimFile(null)
zimReaderContainer?.setZimReaderSource(null)
}
private fun restoreDeletedTab(index: Int) {
@ -1378,7 +1376,7 @@ abstract class CoreReaderFragment :
LinearLayout.LayoutParams.MATCH_PARENT
)
}
zimReaderContainer?.setZimFile(tempZimFileForUndo)
zimReaderContainer?.setZimReaderSource(tempZimSourceForUndo)
webViewList.add(index, it)
tabsAdapter?.notifyDataSetChanged()
snackBarRoot?.let { root ->
@ -1617,33 +1615,21 @@ abstract class CoreReaderFragment :
unsupportedMimeTypeHandler?.showSaveOrOpenUnsupportedFilesDialog(url, documentType)
}
fun openZimFile(
file: File?,
isCustomApp: Boolean = false,
assetFileDescriptorList: List<AssetFileDescriptor> = emptyList(),
filePath: String? = null
) {
fun openZimFile(zimReaderSource: ZimReaderSource, isCustomApp: Boolean = false) {
if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || isCustomApp) {
if (file?.isFileExist() == true) {
if (zimReaderSource.canOpenInLibkiwix()) {
// Show content if there is `Open Library` button showing
// and we are opening the ZIM file
reopenBook()
openAndSetInContainer(file = file)
updateTitle()
} else if (assetFileDescriptorList.isNotEmpty()) {
reopenBook()
openAndSetInContainer(
assetFileDescriptorList = assetFileDescriptorList,
filePath = filePath
)
openAndSetInContainer(zimReaderSource)
updateTitle()
} else {
exitBook()
Log.w(TAG_KIWIX, "ZIM file doesn't exist at " + file?.absolutePath)
Log.w(TAG_KIWIX, "ZIM file doesn't exist at " + zimReaderSource.toDatabase())
requireActivity().toast(R.string.error_file_not_found, Toast.LENGTH_LONG)
}
} else {
this.file = file
this.zimReaderSource = zimReaderSource
requestExternalStoragePermission()
}
}
@ -1666,27 +1652,16 @@ abstract class CoreReaderFragment :
)
}
private fun openAndSetInContainer(
file: File? = null,
assetFileDescriptorList: List<AssetFileDescriptor> = emptyList(),
filePath: String? = null
) {
private fun openAndSetInContainer(zimReaderSource: ZimReaderSource) {
try {
if (isNotPreviouslyOpenZim(file?.canonicalPath)) {
if (isNotPreviouslyOpenZim(zimReaderSource)) {
webViewList.clear()
}
} catch (e: IOException) {
e.printStackTrace()
}
zimReaderContainer?.let { zimReaderContainer ->
if (assetFileDescriptorList.isNotEmpty()) {
zimReaderContainer.setZimFileDescriptor(
assetFileDescriptorList,
filePath = filePath
)
} else {
zimReaderContainer.setZimFile(file)
}
zimReaderContainer.setZimReaderSource(zimReaderSource)
val zimFileReader = zimReaderContainer.zimFileReader
zimFileReader?.let { zimFileReader ->
@ -1721,8 +1696,8 @@ abstract class CoreReaderFragment :
bookmarkingDisposable?.dispose()
}
private fun isNotPreviouslyOpenZim(canonicalPath: String?): Boolean =
canonicalPath != null && canonicalPath != zimReaderContainer?.zimCanonicalPath
private fun isNotPreviouslyOpenZim(zimReaderSource: ZimReaderSource?): Boolean =
zimReaderSource != null && zimReaderSource != zimReaderContainer?.zimReaderSource
override fun onRequestPermissionsResult(
requestCode: Int,
@ -1732,7 +1707,7 @@ abstract class CoreReaderFragment :
when (requestCode) {
REQUEST_STORAGE_PERMISSION -> {
if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
file?.let(::openZimFile)
zimReaderSource?.let(::openZimFile)
} else {
snackBarRoot?.let { snackBarRoot ->
Snackbar.make(snackBarRoot, R.string.request_storage, Snackbar.LENGTH_LONG)
@ -1761,7 +1736,7 @@ abstract class CoreReaderFragment :
rotate()
setIsCloseAllTabButtonClickable(false)
}
tempZimFileForUndo = zimReaderContainer?.zimFile
tempZimSourceForUndo = zimReaderContainer?.zimReaderSource
tempWebViewListForUndo.apply {
clear()
addAll(webViewList)
@ -1788,7 +1763,7 @@ abstract class CoreReaderFragment :
private fun restoreDeletedTabs() {
if (tempWebViewListForUndo.isNotEmpty()) {
zimReaderContainer?.setZimFile(tempZimFileForUndo)
zimReaderContainer?.setZimReaderSource(tempZimSourceForUndo)
webViewList.addAll(tempWebViewListForUndo)
tabsAdapter?.notifyDataSetChanged()
snackBarRoot?.let { root ->
@ -2131,7 +2106,7 @@ abstract class CoreReaderFragment :
urls.put(view.url)
positions.put(view.scrollY)
}
editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimCanonicalPath)
editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase())
editor.putString(TAG_CURRENT_ARTICLES, "$urls")
editor.putString(TAG_CURRENT_POSITIONS, "$positions")
editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex)
@ -2143,7 +2118,8 @@ abstract class CoreReaderFragment :
saveTabStates()
Log.d(
TAG_KIWIX,
"onPause Save current zim file to preferences: " + zimReaderContainer?.zimCanonicalPath
"onPause Save current zim file to preferences: " +
"${zimReaderContainer?.zimReaderSource?.toDatabase()}"
)
}

View File

@ -30,7 +30,7 @@ sealed class HistoryListItem : PageRelated {
val databaseId: Long = 0L,
override val zimId: String,
val zimName: String,
override val zimReaderSource: ZimReaderSource,
override val zimReaderSource: ZimReaderSource?,
override val favicon: String?,
val historyUrl: String,
override val title: String,

View File

@ -23,6 +23,7 @@ import io.reactivex.processors.PublishProcessor
import org.json.JSONArray
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp
import org.kiwix.kiwixmobile.core.page.adapter.Page
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenNote
@ -36,7 +37,6 @@ import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_POSITIONS
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_TAB
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.ShowNoteDialog
import java.io.File
import javax.inject.Inject
data class ShowOpenNoteDialog(
@ -52,14 +52,15 @@ data class ShowOpenNoteDialog(
{ effects.offer(OpenPage(page, zimReaderContainer)) },
{
val item = page as NoteListItem
// Check if zimFilePath is not null, and then set it in zimReaderContainer.
// Check if toDatabase is not null, and then set it in zimReaderContainer.
// For custom apps, we are currently using fileDescriptor, and they only have a single file in them,
// which is already set in zimReaderContainer, so there's no need to set it again.
item.zimFilePath?.let {
val currentZimFilePath = zimReaderContainer.zimCanonicalPath
val file = File(it)
zimReaderContainer.setZimFile(file)
if (zimReaderContainer.zimCanonicalPath != currentZimFilePath) {
item.zimReaderSource?.toDatabase().let {
if (!activity.isCustomApp()) {
zimReaderContainer.setZimReaderSource(item.zimReaderSource)
}
val currentZimReaderSource = zimReaderContainer.zimReaderSource
if (zimReaderContainer.zimReaderSource != currentZimReaderSource) {
// if current zim file is not the same set the main page of that zim file
// so that when we go back it properly loads the article, and do nothing if the
// zim file is same because there might be multiple tabs opened.
@ -72,7 +73,7 @@ data class ShowOpenNoteDialog(
val positions = JSONArray()
urls.put(CONTENT_PREFIX + zimReaderContainer.mainPage)
positions.put(0)
editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimCanonicalPath)
editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimReaderSource?.toDatabase())
editor.putString(TAG_CURRENT_ARTICLES, "$urls")
editor.putString(TAG_CURRENT_POSITIONS, "$positions")
editor.putInt(TAG_CURRENT_TAB, 0)

View File

@ -32,8 +32,8 @@ data class OpenPage(
override fun invokeWith(activity: AppCompatActivity) {
activity as CoreMainActivity
activity.popNavigationBackstack()
if (page.zimFilePath != zimReaderContainer.zimCanonicalPath) {
page.zimFilePath?.let { activity.openPage(page.url, it) }
if (page.zimReaderSource != zimReaderContainer.zimReaderSource) {
page.zimReaderSource?.let { activity.openPage(page.url, it) }
} else {
activity.openPage(page.url)
}

View File

@ -35,7 +35,7 @@ import java.io.File
class ZimReaderSource(
val file: File? = null,
val uri: Uri? = null,
private val assetFileDescriptorList: List<AssetFileDescriptor>? = null
val assetFileDescriptorList: List<AssetFileDescriptor>? = null
) {
constructor(uri: Uri) : this(
uri = uri,

View File

@ -22,6 +22,7 @@ import android.app.Activity
import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.content.res.AssetFileDescriptor
import android.net.Uri
import android.os.Build
import android.os.Environment
@ -44,6 +45,8 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import java.io.BufferedReader
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
import java.io.IOException
object FileUtils {
@ -476,4 +479,48 @@ object FileUtils {
@JvmStatic
fun getDemoFilePathForCustomApp(context: Context) =
"${ContextCompat.getExternalFilesDirs(context, null)[0]}/demo.zim"
@SuppressLint("Recycle")
@JvmStatic
fun getAssetFileDescriptorFromUri(
context: Context,
uri: Uri
): List<AssetFileDescriptor>? {
return try {
val assetFileDescriptor = context.contentResolver.openAssetFileDescriptor(uri, "r")
// Verify whether libkiwix can successfully open this file descriptor or not.
return if (
isFileDescriptorCanOpenWithLibkiwix(assetFileDescriptor?.parcelFileDescriptor?.fd)
) {
assetFileDescriptor?.let(::listOf)
} else {
null
}
} catch (ignore: FileNotFoundException) {
null
} catch (ignore: Exception) {
// It may throw a SecurityException in the Play Store variant
// since we have limited access to storage and URIs in the Play Store variant.
// If the user opens the ZIM file via app linking and closes the application,
// the next time they try to open that ZIM file, we won't have access to this URI.
null
}
}
@JvmStatic
fun isFileDescriptorCanOpenWithLibkiwix(fdNumber: Int?): Boolean {
return try {
// Attempt to create a FileInputStream object using the specified path.
// Since libkiwix utilizes this path to create the archive object internally,
// it is crucial to verify if we can successfully read the file descriptor (fd)
// via the given file path before passing it to libkiwix.
// This precaution helps prevent runtime crashes.
// For more details, refer to https://github.com/kiwix/kiwix-android/pull/3636.
FileInputStream("dev/fd/$fdNumber")
true
} catch (ignore: Exception) {
ignore.printStackTrace()
false
}
}
}

View File

@ -52,7 +52,7 @@ class KiwixServer @Inject constructor(
val archive = if (path == getDemoFilePathForCustomApp(context)) {
// For custom apps using a demo file, create an Archive with FileDescriptor
val assetFileDescriptor =
zimReaderContainer.zimFileReader?.assetFileDescriptorList?.get(0)
zimReaderContainer.zimReaderSource?.assetFileDescriptorList?.get(0)
val startOffset = assetFileDescriptor?.startOffset ?: 0L
val size = assetFileDescriptor?.length ?: 0L
Archive(

View File

@ -117,7 +117,7 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View {
.filter(BooksOnDiskListItem::isSelected)
.filterIsInstance<BookOnDisk>()
.map {
it.file.absolutePath
it.zimReaderSource.toDatabase()
}
.onEach { path ->
Log.v(tag, "ZIM PATH : $path")
@ -487,7 +487,7 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View {
if (it is BookOnDisk) {
zimReaderContainer.zimFileReader?.let { zimFileReader ->
val booksOnDiskListItem =
(BookOnDisk(it.file, zimFileReader) as BooksOnDiskListItem)
(BookOnDisk(zimFileReader) as BooksOnDiskListItem)
.apply {
isSelected = true
}