Fixed the issue where the Zim File was not displaying in the ZimHostFragment for custom apps.

* In `ZimHostFragment`, we show Zim files that are saved in the database. These files are typically saved when downloading Zim files. In a custom app, where Zim files are already included within the app and not downloaded separately that's why they are not showing on the `ZimHostFragment`, we have addressed this issue by saving the Zim files in the database to ensure they appear in the `ZimHostFragment`.
* Regarding the `FileDescriptor`, there are no file objects available because we read Zim files using `FileDescriptor`. To address this, we have created a `demo.zim` file to save it in the database so that it will be displayed in the `ZimHostFragment`. We handle this file within the `KiwixServer`. When the current Zim file is `demo.zim`, we create an `Archive` object with the `FileDescriptor` to host the Zim file on the `KiwixServer`.
This commit is contained in:
MohitMali 2023-11-02 17:21:29 +05:30 committed by Kelson
parent 845f19eab6
commit bdb00d7aae
6 changed files with 70 additions and 18 deletions

View File

@ -24,6 +24,7 @@ import org.kiwix.kiwixmobile.core.di.ActivityScope
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.BookmarkItem
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
import javax.inject.Inject
private const val TAG = "MainPresenter"
@ -33,6 +34,7 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour
private var saveHistoryDisposable: Disposable? = null
private var saveBookmarkDisposable: Disposable? = null
private var saveNoteDisposable: Disposable? = null
private var saveBookDisposable: Disposable? = null
private var deleteNoteDisposable: Disposable? = null
fun saveHistory(history: HistoryItem) {
@ -61,10 +63,16 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour
.subscribe({}, { e -> Log.e(TAG, "Unable to delete note", e) })
}
fun saveBook(book: BookOnDisk) {
saveBookDisposable = dataSource.saveBook(book)
.subscribe({}, { e -> Log.e(TAG, "Unable to save book", e) })
}
fun dispose() {
saveHistoryDisposable?.dispose()
saveBookmarkDisposable?.dispose()
saveNoteDisposable?.dispose()
deleteNoteDisposable?.dispose()
saveBookDisposable?.dispose()
}
}

View File

@ -53,7 +53,7 @@ private const val TAG = "ZimFileReader"
class ZimFileReader constructor(
val zimFile: File?,
private val assetFileDescriptor: AssetFileDescriptor? = null,
val assetFileDescriptor: AssetFileDescriptor? = null,
private val jniKiwixReader: Archive,
private val nightModeConfig: NightModeConfig,
private val searcher: SuggestionSearcher = SuggestionSearcher(jniKiwixReader)

View File

@ -29,6 +29,7 @@ import android.provider.DocumentsContract
import android.util.Log
import android.webkit.URLUtil
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.documentfile.provider.DocumentFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -402,4 +403,8 @@ object FileUtils {
null
}
}
@JvmStatic
fun getDemoFilePathForCustomApp(context: Context) =
"${ContextCompat.getExternalFilesDirs(context, null)[0]}/demo.zim"
}

View File

@ -18,7 +18,10 @@
package org.kiwix.kiwixmobile.core.webserver
import android.content.Context
import android.util.Log
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.files.FileUtils.getDemoFilePathForCustomApp
import org.kiwix.libkiwix.Book
import org.kiwix.libkiwix.JNIKiwixException
import org.kiwix.libkiwix.Library
@ -36,13 +39,32 @@ class KiwixServer @Inject constructor(
private val jniKiwixServer: Server
) {
class Factory @Inject constructor() {
class Factory @Inject constructor(
private val context: Context,
private val zimReaderContainer: ZimReaderContainer
) {
@Suppress("NestedBlockDepth")
fun createKiwixServer(selectedBooksPath: ArrayList<String>): KiwixServer {
val kiwixLibrary = Library()
selectedBooksPath.forEach { path ->
try {
val book = Book().apply {
update(Archive(path))
// Determine whether to create an Archive from an asset or a file path
val archive = if (path == getDemoFilePathForCustomApp(context)) {
// For custom apps using a demo file, create an Archive with FileDescriptor
val assetFileDescriptor = zimReaderContainer.zimFileReader?.assetFileDescriptor
val startOffset = assetFileDescriptor?.startOffset ?: 0L
val size = assetFileDescriptor?.length ?: 0L
Archive(
assetFileDescriptor?.parcelFileDescriptor?.dup()?.fileDescriptor,
startOffset,
size
)
} else {
// For regular files, create an Archive from the file path
Archive(path)
}
update(archive)
}
kiwixLibrary.addBook(book)
} catch (e: JNIKiwixException) {

View File

@ -53,6 +53,7 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.requestNotificat
import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.navigateToAppSettings
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.ConnectivityReporter
import org.kiwix.kiwixmobile.core.utils.REQUEST_POST_NOTIFICATION_PERMISSION
import org.kiwix.kiwixmobile.core.utils.ServerUtils
@ -60,15 +61,15 @@ import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.StartServer
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_CHECK_IP_ADDRESS
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_START_SERVER
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_STOP_SERVER
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.SelectionMode
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
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_CHECK_IP_ADDRESS
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_START_SERVER
import org.kiwix.kiwixmobile.core.webserver.wifi_hotspot.HotspotService.Companion.ACTION_STOP_SERVER
import javax.inject.Inject
class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View {
@ -87,6 +88,9 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View {
@Inject
lateinit var zimReaderFactory: ZimFileReader.Factory
@Inject
lateinit var zimReaderContainer: ZimReaderContainer
private lateinit var booksAdapter: BooksOnDiskAdapter
private lateinit var bookDelegate: BookOnDiskDelegate.BookDelegate
private var hotspotService: HotspotService? = null
@ -485,18 +489,13 @@ class ZimHostFragment : BaseFragment(), ZimHostCallbacks, ZimHostContract.View {
val updatedBooksList: MutableList<BooksOnDiskListItem> = arrayListOf()
books.forEach {
if (it is BookOnDisk) {
zimReaderFactory.create(it.file)?.let { zimFileReader ->
zimReaderContainer.zimFileReader?.let { zimFileReader ->
val booksOnDiskListItem =
zimFileReader.zimFile?.let { file ->
(BookOnDisk(file, zimFileReader) as BooksOnDiskListItem)
.apply {
isSelected = true
}
}
if (booksOnDiskListItem != null) {
updatedBooksList.add(booksOnDiskListItem)
}
zimFileReader.dispose()
(BookOnDisk(it.file, zimFileReader) as BooksOnDiskListItem)
.apply {
isSelected = true
}
updatedBooksList.add(booksOnDiskListItem)
}
} else {
updatedBooksList.add(it)

View File

@ -32,6 +32,7 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.observeNavigationResult
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.setupDrawerToggle
import org.kiwix.kiwixmobile.core.extensions.isFileExist
import org.kiwix.kiwixmobile.core.main.CoreReaderFragment
import org.kiwix.kiwixmobile.core.main.FIND_IN_PAGE_SEARCH_STRING
import org.kiwix.kiwixmobile.core.main.MainMenu
@ -39,11 +40,14 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchItemToOpen
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
import org.kiwix.kiwixmobile.core.utils.files.FileUtils.getDemoFilePathForCustomApp
import org.kiwix.kiwixmobile.core.utils.titleToUrl
import org.kiwix.kiwixmobile.core.utils.urlSuffixToParsableUrl
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
import org.kiwix.kiwixmobile.custom.BuildConfig
import org.kiwix.kiwixmobile.custom.R
import org.kiwix.kiwixmobile.custom.customActivityComponent
import java.io.File
import java.util.Locale
import javax.inject.Inject
@ -149,6 +153,15 @@ class CustomReaderFragment : CoreReaderFragment() {
} else {
openZimFile(it.file, true)
}
// Save book in the database to display it in `ZimHostFragment`.
zimReaderContainer?.zimFileReader?.let { zimFileReader ->
// Check if the file is not null. If the file is null,
// it means we have created zimFileReader with a fileDescriptor,
// so we create a demo file to save it in the database for display on the `ZimHostFragment`.
val file = it.file ?: createDemoFile()
val bookOnDisk = BookOnDisk(file, zimFileReader)
repositoryActions?.saveBook(bookOnDisk)
}
}
is ValidationState.HasBothFiles -> {
it.zimFile.delete()
@ -163,6 +176,11 @@ class CustomReaderFragment : CoreReaderFragment() {
)
}
private fun createDemoFile() =
File(getDemoFilePathForCustomApp(requireActivity())).also {
if (!it.isFileExist()) it.createNewFile()
}
@Suppress("DEPRECATION")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)