Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ import org.kiwix.kiwixmobile.core.utils.SimpleRecyclerViewScrollListener.Compani
import org.kiwix.kiwixmobile.core.utils.SimpleRecyclerViewScrollListener.Companion.SCROLL_UP
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BookOnDiskDelegate
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskAdapter
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
Expand All @@ -90,7 +89,6 @@ import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions.Req
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions.RequestNavigateTo
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel.FileSelectActions.RequestSelect
import org.kiwix.kiwixmobile.zimManager.fileselectView.FileSelectListState
import java.io.File
import javax.inject.Inject

private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE"
Expand Down Expand Up @@ -245,7 +243,7 @@ class LocalLibraryFragment : BaseFragment() {
offerAction(FileSelectActions.UserClickedDownloadBooksButton)
}
}
hideFilePickerButton()
setUpFilePickerButton()

fragmentDestinationLibraryBinding?.zimfilelist?.addOnScrollListener(
SimpleRecyclerViewScrollListener { _, newState ->
Expand Down Expand Up @@ -303,19 +301,9 @@ class LocalLibraryFragment : BaseFragment() {
}
}

private fun hideFilePickerButton() {
if (sharedPreferenceUtil.isPlayStoreBuild) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
fragmentDestinationLibraryBinding?.selectFile?.visibility = View.GONE
}
}

private fun setUpFilePickerButton() {
fragmentDestinationLibraryBinding?.selectFile?.setOnClickListener {
if (!requireActivity().isManageExternalStoragePermissionGranted(sharedPreferenceUtil)) {
showManageExternalStoragePermissionDialog()
} else {
showFileChooser()
}
showFileChooser()
}
}

Expand All @@ -335,40 +323,24 @@ class LocalLibraryFragment : BaseFragment() {
private val fileSelectLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK) {
result.data?.data?.let { uri ->
getZimFileFromUri(uri)?.let(::navigateToReaderFragment)
result.data?.data?.let {
// Taking `takePersistableUriPermission` for uris that user try to open via file picker.
// Since we need access of this uri to open the same file again,
// if user tries to open notes, history etc.
requireActivity().contentResolver.takePersistableUriPermission(
it,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
navigateToReaderFragment(it)
}
}
}

private fun getZimFileFromUri(
uri: Uri
): File? {
val filePath = FileUtils.getLocalFilePathByUri(
requireActivity().applicationContext, uri
private fun navigateToReaderFragment(uri: Uri) {
activity?.navigate(
LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader()
.apply { zimFileUri = "$uri" }
)
if (filePath == null || !File(filePath).exists()) {
activity.toast(R.string.error_file_not_found)
return null
}
val file = File(filePath)
return if (!FileUtils.isValidZimFile(file.path)) {
activity.toast(R.string.error_file_invalid)
null
} else {
file
}
}

private fun navigateToReaderFragment(file: File) {
if (!file.canRead()) {
activity.toast(R.string.unable_to_read_zim_file)
} else {
activity?.navigate(
LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader()
.apply { zimFileUri = file.toUri().toString() }
)
}
}

override fun onResume() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package org.kiwix.kiwixmobile.nav.destination.reader

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
Expand All @@ -33,6 +32,7 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toFile
import androidx.core.net.toUri
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.bottomnavigation.BottomNavigationView
import org.kiwix.kiwixmobile.R
Expand All @@ -43,7 +43,6 @@ import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldCall
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.setupDrawerToggle
import org.kiwix.kiwixmobile.core.extensions.coreMainActivity
import org.kiwix.kiwixmobile.core.extensions.isFileExist
import org.kiwix.kiwixmobile.core.extensions.setBottomMarginToFragmentContainerView
import org.kiwix.kiwixmobile.core.extensions.setImageDrawableCompat
import org.kiwix.kiwixmobile.core.extensions.snack
Expand All @@ -55,9 +54,7 @@ import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
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.FileUtils.getAssetFileDescriptorFromUri
import java.io.File

private const val HIDE_TAB_SWITCHER_DELAY: Long = 300

Expand Down Expand Up @@ -108,15 +105,20 @@ class KiwixReaderFragment : CoreReaderFragment() {
}

private fun tryOpeningZimFile(zimFileUri: String) {
val filePath = FileUtils.getLocalFilePathByUri(
requireActivity().applicationContext, Uri.parse(zimFileUri)
)

if (filePath == null || !File(filePath).isFileExist()) {
activity.toast(R.string.error_file_not_found)
return
getAssetFileDescriptorFromUri(
requireActivity(),
zimFileUri.toUri()
)?.let { assetFileDescriptor ->
openZimFile(
null,
assetFileDescriptor = assetFileDescriptor,
assetFileDescriptorPath = zimFileUri
)
} ?: kotlin.run {
// exit the previous if any loaded
exitBook()
activity.toast(R.string.cannot_open_file)
}
openZimFile(File(filePath))
}

override fun loadDrawerViews() {
Expand All @@ -134,7 +136,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
}

private fun closeZimBook() {
zimReaderContainer?.setZimFile(null)
zimReaderContainer?.setZimFileOrFileDescriptor(null, null, null)
}

override fun openHomeScreen() {
Expand Down Expand Up @@ -205,9 +207,7 @@ class KiwixReaderFragment : CoreReaderFragment() {

override fun onResume() {
super.onResume()
if (zimReaderContainer?.zimFile == null &&
zimReaderContainer?.zimFileReader?.assetFileDescriptor == null
) {
if (zimReaderContainer?.isValidZimFileReader == false) {
exitBook()
}
if (isFullScreenVideo) {
Expand All @@ -226,15 +226,28 @@ class KiwixReaderFragment : CoreReaderFragment() {
currentTab: Int
) {
val settings = requireActivity().getSharedPreferences(SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0)
val zimFile = settings.getString(TAG_CURRENT_FILE, null)

if (zimFile != null && File(zimFile).isFileExist()) {
if (zimReaderContainer?.zimFile == null) {
openZimFile(File(zimFile))
Log.d(
TAG_KIWIX,
"Kiwix normal start, Opened last used zimFile: -> $zimFile"
)
val zimFileUri = settings.getString(TAG_CURRENT_FILE, null)

if (zimFileUri != null &&
getAssetFileDescriptorFromUri(requireActivity(), zimFileUri.toUri()) != null
) {
if (zimReaderContainer?.assetFileDescriptor == null) {
getAssetFileDescriptorFromUri(
requireActivity(),
zimFileUri.toUri()
)?.let { assetFileDescriptor ->
openZimFile(
null,
assetFileDescriptor = assetFileDescriptor,
assetFileDescriptorPath = zimFileUri
)
Log.d(
TAG_KIWIX,
"Kiwix normal start, Opened last used zimFile: -> $zimFileUri"
)
} ?: kotlin.run {
activity.toast(R.string.cannot_open_file)
}
} else {
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
}
Expand Down Expand Up @@ -299,7 +312,11 @@ class KiwixReaderFragment : CoreReaderFragment() {
// pass this uri to zimFileReader, which is necessary for saving
// notes, bookmarks, history, and reopening the same ZIM file after the app closes.
getAssetFileDescriptorFromUri(activity, it)?.let { assetFileDescriptor ->
openZimFile(null, assetFileDescriptor = assetFileDescriptor, filePath = "$it")
openZimFile(
null,
assetFileDescriptor = assetFileDescriptor,
assetFileDescriptorPath = "$it"
)
} ?: kotlin.run {
activity.toast(R.string.cannot_open_file)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ data class DeleteFiles(private val booksOnDiskListItems: List<BookOnDisk>) :
return fold(true) { acc, book ->
acc && deleteSpecificZimFile(book).also {
if (it && book.file.canonicalPath == zimReaderContainer.zimCanonicalPath) {
zimReaderContainer.setZimFile(null)
zimReaderContainer.setZimFileOrFileDescriptor(null)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,7 @@ abstract class CoreReaderFragment :
reopenBook()
}
tempWebViewForUndo?.let {
zimReaderContainer?.setZimFile(tempZimFileForUndo)
zimReaderContainer?.setZimFileOrFileDescriptor(tempZimFileForUndo)
webViewList.add(index, it)
tabsAdapter?.notifyDataSetChanged()
snackBarRoot?.let { root ->
Expand Down Expand Up @@ -1479,17 +1479,11 @@ abstract class CoreReaderFragment :
file: File?,
isCustomApp: Boolean = false,
assetFileDescriptor: AssetFileDescriptor? = null,
filePath: String? = null
assetFileDescriptorPath: String? = null
) {
if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || isCustomApp) {
if (file?.isFileExist() == true) {
openAndSetInContainer(file = file)
updateTitle()
} else if (assetFileDescriptor != null) {
openAndSetInContainer(
assetFileDescriptor = assetFileDescriptor,
filePath = filePath
)
if (file?.isFileExist() == true || assetFileDescriptor != null) {
openAndSetInContainer(file = file, assetFileDescriptor, assetFileDescriptorPath)
updateTitle()
} else {
Log.w(TAG_KIWIX, "ZIM file doesn't exist at " + file?.absolutePath)
Expand Down Expand Up @@ -1522,24 +1516,23 @@ abstract class CoreReaderFragment :
private fun openAndSetInContainer(
file: File? = null,
assetFileDescriptor: AssetFileDescriptor? = null,
filePath: String? = null
assetFileDescriptorPath: String? = null
) {
try {
if (isNotPreviouslyOpenZim(file?.canonicalPath)) {
if (isNotPreviouslyOpenZim(file?.canonicalPath) &&
isNotPreviouslyOpenZim(assetFileDescriptorPath)
) {
webViewList.clear()
}
} catch (e: IOException) {
e.printStackTrace()
}
zimReaderContainer?.let { zimReaderContainer ->
if (assetFileDescriptor != null) {
zimReaderContainer.setZimFileDescriptor(
assetFileDescriptor,
filePath = filePath
)
} else {
zimReaderContainer.setZimFile(file)
}
zimReaderContainer.setZimFileOrFileDescriptor(
file,
assetFileDescriptor,
assetFileDescriptorPath
)

val zimFileReader = zimReaderContainer.zimFileReader
zimFileReader?.let { zimFileReader ->
Expand Down Expand Up @@ -1632,7 +1625,7 @@ abstract class CoreReaderFragment :

private fun restoreDeletedTabs() {
if (tempWebViewListForUndo.isNotEmpty()) {
zimReaderContainer?.setZimFile(tempZimFileForUndo)
zimReaderContainer?.setZimFileOrFileDescriptor(tempZimFileForUndo)
webViewList.addAll(tempWebViewListForUndo)
tabsAdapter?.notifyDataSetChanged()
snackBarRoot?.let { root ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ data class BookmarkItem(
) : this(
zimId = zimFileReader.id,
zimName = zimFileReader.name,
zimFilePath = zimFileReader.zimFile?.canonicalPath ?: zimFileReader.assetDescriptorFilePath,
zimFilePath = zimFileReader.zimCanonicalPath,
bookmarkUrl = url,
title = title,
favicon = zimFileReader.favicon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ sealed class HistoryListItem : PageRelated {
) : this(
zimId = zimFileReader.id,
zimName = zimFileReader.name,
zimFilePath = zimFileReader.zimFile?.canonicalPath
?: zimFileReader.assetDescriptorFilePath
?: "",
zimFilePath = zimFileReader.zimCanonicalPath ?: "",
favicon = zimFileReader.favicon,
historyUrl = url,
title = title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ data class NoteListItem(
) : this(
zimId = zimFileReader.id,
title = title,
zimFilePath = zimFileReader.zimFile?.canonicalPath ?: zimFileReader.assetDescriptorFilePath,
zimFilePath = zimFileReader.zimCanonicalPath,
zimUrl = url,
favicon = zimFileReader.favicon,
noteFilePath = noteFilePath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.kiwix.kiwixmobile.core.page.notes.viewmodel.effects

import androidx.appcompat.app.AppCompatActivity
import androidx.core.net.toUri
import io.reactivex.processors.PublishProcessor
import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent
Expand All @@ -29,7 +30,7 @@ import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenPage
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.ShowNoteDialog
import java.io.File
import org.kiwix.kiwixmobile.core.utils.files.FileUtils.getAssetFileDescriptorFromUri
import javax.inject.Inject

data class ShowOpenNoteDialog(
Expand All @@ -49,8 +50,19 @@ data class ShowOpenNoteDialog(
// 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 file = File(it)
zimReaderContainer.setZimFile(file)
// Obtain the asset file descriptor for the provided URI.
// Given that we now exclusively use the fileDescriptor for all our functionalities,
// we have modified this method to assign the fileDescriptor instead of the file
// to address the crash triggered when clicking the 'OPEN NOTE' button.
getAssetFileDescriptorFromUri(
activity,
it.toUri()
)?.let { assetFileDescriptor ->
zimReaderContainer.setZimFileOrFileDescriptor(
assetFileDescriptor = assetFileDescriptor,
assetDescriptorFilePath = it
)
}
}
effects.offer(OpenNote(item.noteFilePath, item.zimUrl, item.title))
}
Expand Down
Loading