mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-13 17:38:42 -04:00
Fixed: Restore web view history in Kiwix app.
* Improved restoration of web view history after opening a searched article. * Refactored `restoreViewStateOnValidJSON` and `restoreViewStateOnInvalidJSON` methods to save and retrieve web view history from the Room database. * Added detailed comments to methods for better understanding, including guidance for developers to check subclass implementations before making modifications. * Fixed the `static analysis` errors.
This commit is contained in:
parent
ee50417154
commit
2fb1896cea
@ -58,6 +58,7 @@ import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
|
|||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
|
||||||
|
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchItemToOpen
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE
|
import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE
|
||||||
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
||||||
@ -69,6 +70,7 @@ private const val HIDE_TAB_SWITCHER_DELAY: Long = 300
|
|||||||
|
|
||||||
class KiwixReaderFragment : CoreReaderFragment() {
|
class KiwixReaderFragment : CoreReaderFragment() {
|
||||||
private var isFullScreenVideo: Boolean = false
|
private var isFullScreenVideo: Boolean = false
|
||||||
|
private var searchItemToOpen: SearchItemToOpen? = null
|
||||||
|
|
||||||
override fun inject(baseActivity: BaseActivity) {
|
override fun inject(baseActivity: BaseActivity) {
|
||||||
baseActivity.cachedComponent.inject(this)
|
baseActivity.cachedComponent.inject(this)
|
||||||
@ -111,7 +113,16 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
} else {
|
} else {
|
||||||
val restoreOrigin =
|
val restoreOrigin =
|
||||||
if (args.searchItemTitle.isNotEmpty()) FromSearchScreen else FromExternalLaunch
|
if (args.searchItemTitle.isNotEmpty()) FromSearchScreen else FromExternalLaunch
|
||||||
manageExternalLaunchAndRestoringViewState(restoreOrigin)
|
manageExternalLaunchAndRestoringViewState(restoreOrigin) {
|
||||||
|
// This lambda function is invoked after restoring the tabs. It checks if there is a
|
||||||
|
// search item to open. If `searchItemToOpen` is not null, it will call the superclass
|
||||||
|
// method to open the specified search item. After opening, it sets `searchItemToOpen`
|
||||||
|
// to null to prevent any unexpected behavior on subsequent calls.
|
||||||
|
searchItemToOpen?.let {
|
||||||
|
super.openSearchItem(it)
|
||||||
|
}
|
||||||
|
searchItemToOpen = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requireArguments().clear()
|
requireArguments().clear()
|
||||||
@ -151,6 +162,18 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
openZimFile(zimReaderSource)
|
openZimFile(zimReaderSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the specified search item to be opened later.
|
||||||
|
*
|
||||||
|
* This method saves the provided `SearchItemToOpen` object, which will be used to
|
||||||
|
* open the searched item after the tabs have been restored.
|
||||||
|
*
|
||||||
|
* @param item The search item to be opened after restoring the tabs.
|
||||||
|
*/
|
||||||
|
override fun openSearchItem(item: SearchItemToOpen) {
|
||||||
|
searchItemToOpen = item
|
||||||
|
}
|
||||||
|
|
||||||
override fun loadDrawerViews() {
|
override fun loadDrawerViews() {
|
||||||
drawerLayout = requireActivity().findViewById(R.id.navigation_container)
|
drawerLayout = requireActivity().findViewById(R.id.navigation_container)
|
||||||
tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view)
|
tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view)
|
||||||
@ -243,7 +266,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun restoreViewStateOnInvalidJSON() {
|
override fun restoreViewStateOnInvalidWebViewHistory() {
|
||||||
Log.d(TAG_KIWIX, "Kiwix normal start, no zimFile loaded last time -> display home page")
|
Log.d(TAG_KIWIX, "Kiwix normal start, no zimFile loaded last time -> display home page")
|
||||||
exitBook()
|
exitBook()
|
||||||
}
|
}
|
||||||
@ -256,15 +279,16 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
* as the ZIM file is already set in the reader. The method handles setting up the ZIM file and bookmarks,
|
* as the ZIM file is already set in the reader. The method handles setting up the ZIM file and bookmarks,
|
||||||
* and restores the tabs and positions from the provided data.
|
* and restores the tabs and positions from the provided data.
|
||||||
*
|
*
|
||||||
* @param webViewHistoryItemList JSON string representing the list of articles to be restored.
|
* @param webViewHistoryItemList WebViewHistoryItem list representing the list of articles to be restored.
|
||||||
* @param currentTab Index of the tab to be restored as the currently active one.
|
* @param currentTab Index of the tab to be restored as the currently active one.
|
||||||
* @param restoreOrigin Indicates whether the restoration is triggered from an external launch or the search screen.
|
* @param restoreOrigin Indicates whether the restoration is triggered from an external launch or the search screen.
|
||||||
|
* @param onComplete Callback to be invoked upon completion of the restoration process.
|
||||||
*/
|
*/
|
||||||
|
override fun restoreViewStateOnValidWebViewHistory(
|
||||||
override fun restoreViewStateOnValidJSON(
|
|
||||||
webViewHistoryItemList: List<WebViewHistoryItem>,
|
webViewHistoryItemList: List<WebViewHistoryItem>,
|
||||||
currentTab: Int,
|
currentTab: Int,
|
||||||
restoreOrigin: RestoreOrigin
|
restoreOrigin: RestoreOrigin,
|
||||||
|
onComplete: () -> Unit
|
||||||
) {
|
) {
|
||||||
when (restoreOrigin) {
|
when (restoreOrigin) {
|
||||||
FromExternalLaunch -> {
|
FromExternalLaunch -> {
|
||||||
@ -274,7 +298,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
val zimReaderSource = fromDatabaseValue(settings.getString(TAG_CURRENT_FILE, null))
|
val zimReaderSource = fromDatabaseValue(settings.getString(TAG_CURRENT_FILE, null))
|
||||||
if (zimReaderSource?.canOpenInLibkiwix() == true) {
|
if (zimReaderSource?.canOpenInLibkiwix() == true) {
|
||||||
if (zimReaderContainer?.zimReaderSource == null) {
|
if (zimReaderContainer?.zimReaderSource == null) {
|
||||||
openZimFile(zimReaderSource)
|
openZimFile(zimReaderSource, isFromManageExternalLaunch = true)
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG_KIWIX,
|
TAG_KIWIX,
|
||||||
"Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}"
|
"Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}"
|
||||||
@ -282,7 +306,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
} else {
|
} else {
|
||||||
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
|
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
|
||||||
}
|
}
|
||||||
restoreTabs(webViewHistoryItemList, currentTab)
|
restoreTabs(webViewHistoryItemList, currentTab, onComplete)
|
||||||
} else {
|
} else {
|
||||||
getCurrentWebView()?.snack(string.zim_not_opened)
|
getCurrentWebView()?.snack(string.zim_not_opened)
|
||||||
exitBook() // hide the options for zim file to avoid unexpected UI behavior
|
exitBook() // hide the options for zim file to avoid unexpected UI behavior
|
||||||
@ -291,7 +315,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FromSearchScreen -> {
|
FromSearchScreen -> {
|
||||||
restoreTabs(webViewHistoryItemList, currentTab)
|
restoreTabs(webViewHistoryItemList, currentTab, onComplete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
|||||||
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
|
|
||||||
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
||||||
|
@ -28,8 +28,8 @@ import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
|||||||
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
||||||
|
import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
||||||
import org.kiwix.kiwixmobile.core.di.qualifiers.IO
|
import org.kiwix.kiwixmobile.core.di.qualifiers.IO
|
||||||
import org.kiwix.kiwixmobile.core.di.qualifiers.MainThread
|
import org.kiwix.kiwixmobile.core.di.qualifiers.MainThread
|
||||||
@ -37,7 +37,6 @@ import org.kiwix.kiwixmobile.core.extensions.HeaderizableList
|
|||||||
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
|
|
||||||
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
@ -148,7 +147,9 @@ class Repository @Inject internal constructor(
|
|||||||
Completable.fromAction { notesRoomDao.deleteNotes(noteList) }
|
Completable.fromAction { notesRoomDao.deleteNotes(noteList) }
|
||||||
.subscribeOn(ioThread)
|
.subscribeOn(ioThread)
|
||||||
|
|
||||||
override suspend fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List<WebViewHistoryEntity>) {
|
override suspend fun insertWebViewPageHistoryItems(
|
||||||
|
webViewHistoryEntityList: List<WebViewHistoryEntity>
|
||||||
|
) {
|
||||||
webViewHistoryRoomDao.insertWebViewPageHistoryItems(webViewHistoryEntityList)
|
webViewHistoryRoomDao.insertWebViewPageHistoryItems(webViewHistoryEntityList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ class Repository @Inject internal constructor(
|
|||||||
.observeOn(mainThread)
|
.observeOn(mainThread)
|
||||||
|
|
||||||
override suspend fun clearWebViewPagesHistory() {
|
override suspend fun clearWebViewPagesHistory() {
|
||||||
webViewHistoryRoomDao.clearPageHistoryWithPrimaryKey()
|
webViewHistoryRoomDao.clearWebViewPagesHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteNote(noteTitle: String): Completable =
|
override fun deleteNote(noteTitle: String): Completable =
|
||||||
|
@ -100,8 +100,8 @@ import kotlinx.coroutines.SupervisorJob
|
|||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.json.JSONException
|
|
||||||
import org.kiwix.kiwixmobile.core.BuildConfig
|
import org.kiwix.kiwixmobile.core.BuildConfig
|
||||||
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.StorageObserver
|
import org.kiwix.kiwixmobile.core.StorageObserver
|
||||||
@ -286,6 +286,7 @@ abstract class CoreReaderFragment :
|
|||||||
|
|
||||||
private var isFirstTimeMainPageLoaded = true
|
private var isFirstTimeMainPageLoaded = true
|
||||||
private var isFromManageExternalLaunch = false
|
private var isFromManageExternalLaunch = false
|
||||||
|
private var shouldSaveTabsOnPause = true
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@Inject
|
@Inject
|
||||||
@ -421,6 +422,9 @@ abstract class CoreReaderFragment :
|
|||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
) {
|
) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
// Set this to true to enable saving the tab history
|
||||||
|
// when the fragment goes into the paused state.
|
||||||
|
shouldSaveTabsOnPause = true
|
||||||
setupMenu()
|
setupMenu()
|
||||||
donationDialogHandler?.setDonationDialogCallBack(this)
|
donationDialogHandler?.setDonationDialogCallBack(this)
|
||||||
val activity = requireActivity() as AppCompatActivity?
|
val activity = requireActivity() as AppCompatActivity?
|
||||||
@ -1306,6 +1310,15 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of `KiwixWebView` with the specified URL.
|
||||||
|
*
|
||||||
|
* @param url The URL to load in the web view. This is ignored if `shouldLoadUrl` is false.
|
||||||
|
* @param shouldLoadUrl A flag indicating whether to load the specified URL in the web view.
|
||||||
|
* When restoring tabs, this should be set to false to avoid loading
|
||||||
|
* an extra page, as the previous web view history will be restored directly.
|
||||||
|
* @return The initialized `KiwixWebView` instance, or null if initialization fails.
|
||||||
|
*/
|
||||||
private fun initalizeWebView(url: String, shouldLoadUrl: Boolean = true): KiwixWebView? {
|
private fun initalizeWebView(url: String, shouldLoadUrl: Boolean = true): KiwixWebView? {
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
val attrs = requireActivity().getAttributes(R.xml.webview)
|
val attrs = requireActivity().getAttributes(R.xml.webview)
|
||||||
@ -1354,6 +1367,17 @@ abstract class CoreReaderFragment :
|
|||||||
newTab(url, false)
|
newTab(url, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of `KiwixWebView` and adds it to the list of web views.
|
||||||
|
*
|
||||||
|
* @param url The URL to load in the newly created web view.
|
||||||
|
* @param selectTab A flag indicating whether to select the newly created tab immediately.
|
||||||
|
* Defaults to true, which means the new tab will be selected.
|
||||||
|
* @param shouldLoadUrl A flag indicating whether to load the specified URL in the web view.
|
||||||
|
* If set to false, the web view will be created without loading the URL,
|
||||||
|
* which is useful when restoring tabs.
|
||||||
|
* @return The newly created `KiwixWebView` instance, or null if the initialization fails.
|
||||||
|
*/
|
||||||
private fun newTab(
|
private fun newTab(
|
||||||
url: String,
|
url: String,
|
||||||
selectTab: Boolean = true,
|
selectTab: Boolean = true,
|
||||||
@ -1529,6 +1553,17 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSearchMenuClickedMenuClicked() {
|
||||||
|
// Set this to false to prevent saving the tab history in onPause
|
||||||
|
// when opening the search fragment.
|
||||||
|
shouldSaveTabsOnPause = false
|
||||||
|
saveTabStates {
|
||||||
|
// Pass this function to saveTabStates so that after saving
|
||||||
|
// the tab state in the database, it will open the search fragment.
|
||||||
|
openSearch("", isOpenedFromTabView = isInTabSwitcher, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("NestedBlockDepth")
|
@Suppress("NestedBlockDepth")
|
||||||
override fun onReadAloudMenuClicked() {
|
override fun onReadAloudMenuClicked() {
|
||||||
if (requireActivity().hasNotificationPermission(sharedPreferenceUtil)) {
|
if (requireActivity().hasNotificationPermission(sharedPreferenceUtil)) {
|
||||||
@ -2103,7 +2138,21 @@ abstract class CoreReaderFragment :
|
|||||||
openSearch("", isOpenedFromTabView = false, isVoice)
|
openSearch("", isOpenedFromTabView = false, isVoice)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openSearchItem(item: SearchItemToOpen) {
|
/**
|
||||||
|
* Opens a search item based on its properties.
|
||||||
|
*
|
||||||
|
* If the item should open in a new tab, a new tab is created.
|
||||||
|
*
|
||||||
|
* The method attempts to load the page URL directly. If the page URL is not available,
|
||||||
|
* it attempts to convert the page title to a URL using the ZIM reader container. The
|
||||||
|
* resulting URL is then loaded in the current web view.
|
||||||
|
*
|
||||||
|
* Note: This method is overridden in the `KiwixReaderFragment` class to store the
|
||||||
|
* `SearchItemToOpen` object for later use. If modifications are made to this method,
|
||||||
|
* please check the overridden version to understand how it interacts with the fragment's
|
||||||
|
* navigation logic.
|
||||||
|
*/
|
||||||
|
open fun openSearchItem(item: SearchItemToOpen) {
|
||||||
if (item.shouldOpenInNewTab) {
|
if (item.shouldOpenInNewTab) {
|
||||||
createNewTab()
|
createNewTab()
|
||||||
}
|
}
|
||||||
@ -2360,13 +2409,42 @@ abstract class CoreReaderFragment :
|
|||||||
updateNightMode()
|
updateNightMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveTabStates() {
|
/**
|
||||||
|
* Saves the current state of tabs and web view history to persistent storage.
|
||||||
|
*
|
||||||
|
* This method is designed to be called when the fragment is about to pause,
|
||||||
|
* ensuring that the current tab states are preserved. It performs the following steps:
|
||||||
|
*
|
||||||
|
* 1. Clears any previous web view page history stored in the database.
|
||||||
|
* 2. Retrieves the current activity's shared preferences to store the tab states.
|
||||||
|
* 3. Iterates over the currently opened web views, creating a list of
|
||||||
|
* `WebViewHistoryEntity` objects based on their URLs.
|
||||||
|
* 4. Saves the collected web view history entities to the database.
|
||||||
|
* 5. Updates the shared preferences with the current ZIM file and tab index.
|
||||||
|
* 6. Logs the current ZIM file being saved for debugging purposes.
|
||||||
|
* 7. Calls the provided `onComplete` callback function once all operations are finished.
|
||||||
|
*
|
||||||
|
* Note: This method runs on the main thread and performs database operations
|
||||||
|
* in a background thread to avoid blocking the UI.
|
||||||
|
*
|
||||||
|
* @param onComplete A lambda function to be executed after the tab states have
|
||||||
|
* been successfully saved. This is optional and defaults to
|
||||||
|
* an empty function.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* ```
|
||||||
|
* saveTabStates {
|
||||||
|
* openSearch("", isOpenedFromTabView = isInTabSwitcher, false)
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
private fun saveTabStates(onComplete: () -> Unit = {}) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
// clear the previous history saved in database
|
// clear the previous history saved in database
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
repositoryActions?.clearWebViewPageHistory()
|
repositoryActions?.clearWebViewPageHistory()
|
||||||
}
|
}
|
||||||
val settings = requireActivity().getSharedPreferences(
|
val coreApp = sharedPreferenceUtil?.context as CoreApp
|
||||||
|
val settings = coreApp.getMainActivity().getSharedPreferences(
|
||||||
SharedPreferenceUtil.PREF_KIWIX_MOBILE,
|
SharedPreferenceUtil.PREF_KIWIX_MOBILE,
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
@ -2382,10 +2460,43 @@ abstract class CoreReaderFragment :
|
|||||||
editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase())
|
editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase())
|
||||||
editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex)
|
editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex)
|
||||||
editor.apply()
|
editor.apply()
|
||||||
|
Log.d(
|
||||||
|
TAG_KIWIX,
|
||||||
|
"Save current zim file to preferences: " +
|
||||||
|
"${zimReaderContainer?.zimReaderSource?.toDatabase()}"
|
||||||
|
)
|
||||||
|
onComplete.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getWebViewHistoryEntity(
|
/**
|
||||||
|
* Retrieves a `WebViewHistoryEntity` from the given `KiwixWebView` instance.
|
||||||
|
*
|
||||||
|
* This method captures the current state of the specified web view, including its
|
||||||
|
* scroll position and back-forward list, and creates a `WebViewHistoryEntity`
|
||||||
|
* if the necessary conditions are met. The steps involved are as follows:
|
||||||
|
*
|
||||||
|
* 1. Initializes a `Bundle` to store the state of the web view.
|
||||||
|
* 2. Calls `saveState` on the provided `webView`, which populates the bundle
|
||||||
|
* with the current state of the web view's back-forward list.
|
||||||
|
* 3. Retrieves the ID of the currently loaded ZIM file from the `zimReaderContainer`.
|
||||||
|
* 4. Checks if the ZIM ID is not null and if the web back-forward list contains any entries:
|
||||||
|
* - If both conditions are satisfied, it creates and returns a `WebViewHistoryEntity`
|
||||||
|
* containing a `WebViewHistoryItem` with the following data:
|
||||||
|
* - `zimId`: The ID of the current ZIM file.
|
||||||
|
* - `webViewIndex`: The index of the web view in the list of opened views.
|
||||||
|
* - `webViewPosition`: The current vertical scroll position of the web view.
|
||||||
|
* - `webViewBackForwardList`: The bundle containing the saved state of the
|
||||||
|
* web view's back-forward list.
|
||||||
|
* 5. If the ZIM ID is null or the web back-forward list is empty, the method returns null.
|
||||||
|
*
|
||||||
|
* @param webView The `KiwixWebView` instance from which to retrieve the history entity.
|
||||||
|
* @param webViewIndex The index of the web view in the list of opened web views,
|
||||||
|
* used to identify the position of this web view in the history.
|
||||||
|
* @return A `WebViewHistoryEntity` containing the state information of the web view,
|
||||||
|
* or null if the necessary conditions for creating the entity are not met.
|
||||||
|
*/
|
||||||
|
private suspend fun getWebViewHistoryEntity(
|
||||||
webView: KiwixWebView,
|
webView: KiwixWebView,
|
||||||
webViewIndex: Int
|
webViewIndex: Int
|
||||||
): WebViewHistoryEntity? {
|
): WebViewHistoryEntity? {
|
||||||
@ -2406,14 +2517,14 @@ abstract class CoreReaderFragment :
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see shouldSaveTabsOnPause
|
||||||
|
*/
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
saveTabStates()
|
if (shouldSaveTabsOnPause) {
|
||||||
Log.d(
|
saveTabStates()
|
||||||
TAG_KIWIX,
|
}
|
||||||
"onPause Save current zim file to preferences: " +
|
|
||||||
"${zimReaderContainer?.zimReaderSource?.toDatabase()}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun webViewUrlLoading() {
|
override fun webViewUrlLoading() {
|
||||||
@ -2597,7 +2708,8 @@ abstract class CoreReaderFragment :
|
|||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
protected fun manageExternalLaunchAndRestoringViewState(
|
protected fun manageExternalLaunchAndRestoringViewState(
|
||||||
restoreOrigin: RestoreOrigin = FromExternalLaunch
|
restoreOrigin: RestoreOrigin = FromExternalLaunch,
|
||||||
|
onComplete: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val settings = requireActivity().getSharedPreferences(
|
val settings = requireActivity().getSharedPreferences(
|
||||||
SharedPreferenceUtil.PREF_KIWIX_MOBILE,
|
SharedPreferenceUtil.PREF_KIWIX_MOBILE,
|
||||||
@ -2606,29 +2718,49 @@ abstract class CoreReaderFragment :
|
|||||||
val currentTab = safelyGetCurrentTab(settings)
|
val currentTab = safelyGetCurrentTab(settings)
|
||||||
repositoryActions?.loadWebViewPagesHistory()
|
repositoryActions?.loadWebViewPagesHistory()
|
||||||
?.subscribe({ webViewHistoryItemList ->
|
?.subscribe({ webViewHistoryItemList ->
|
||||||
Log.e(
|
|
||||||
"VALID_DATA",
|
|
||||||
"manageExternalLaunchAndRestoringViewState: ${webViewHistoryItemList.size}"
|
|
||||||
)
|
|
||||||
if (webViewHistoryItemList.isEmpty()) {
|
if (webViewHistoryItemList.isEmpty()) {
|
||||||
restoreViewStateOnInvalidJSON()
|
restoreViewStateOnInvalidWebViewHistory()
|
||||||
return@subscribe
|
return@subscribe
|
||||||
}
|
}
|
||||||
restoreViewStateOnValidJSON(webViewHistoryItemList, currentTab, restoreOrigin)
|
restoreViewStateOnValidWebViewHistory(
|
||||||
|
webViewHistoryItemList,
|
||||||
|
currentTab,
|
||||||
|
restoreOrigin,
|
||||||
|
onComplete
|
||||||
|
)
|
||||||
}, {
|
}, {
|
||||||
Log.e("INVALID_DATA", "manageExternalLaunchAndRestoringViewState: $it")
|
restoreViewStateOnInvalidWebViewHistory()
|
||||||
restoreViewStateOnInvalidJSON()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun safelyGetCurrentTab(settings: SharedPreferences): Int =
|
private fun safelyGetCurrentTab(settings: SharedPreferences): Int =
|
||||||
max(settings.getInt(TAG_CURRENT_TAB, 0), 0)
|
max(settings.getInt(TAG_CURRENT_TAB, 0), 0)
|
||||||
|
|
||||||
/* This method restores tabs state in new launches, do not modify it
|
/**
|
||||||
unless it is explicitly mentioned in the issue you're fixing */
|
* Restores the tabs based on the provided webViewHistoryItemList.
|
||||||
|
*
|
||||||
|
* This method performs the following actions:
|
||||||
|
* - Resets the current web view index to zero.
|
||||||
|
* - Removes the first tab from the webViewList and updates the tabs adapter.
|
||||||
|
* - Iterates over the provided webViewHistoryItemList, creating new tabs and restoring
|
||||||
|
* their states based on the historical data.
|
||||||
|
* - Selects the specified tab to make it the currently active one.
|
||||||
|
* - Invokes the onComplete callback once the restoration is finished.
|
||||||
|
*
|
||||||
|
* If any error occurs during the restoration process, it logs a warning and displays
|
||||||
|
* a toast message to inform the user that the tabs could not be restored.
|
||||||
|
*
|
||||||
|
* @param webViewHistoryItemList List of WebViewHistoryItem representing the historical data for restoring tabs.
|
||||||
|
* @param currentTab Index of the tab to be set as the currently active tab after restoration.
|
||||||
|
* @param onComplete Callback to be invoked upon successful restoration of the tabs.
|
||||||
|
*
|
||||||
|
* @Warning: This method restores tabs state in new launches, do not modify it
|
||||||
|
* unless it is explicitly mentioned in the issue you're fixing.
|
||||||
|
*/
|
||||||
protected fun restoreTabs(
|
protected fun restoreTabs(
|
||||||
webViewHistoryItemList: List<WebViewHistoryItem>,
|
webViewHistoryItemList: List<WebViewHistoryItem>,
|
||||||
currentTab: Int
|
currentTab: Int,
|
||||||
|
onComplete: () -> Unit
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
currentWebViewIndex = 0
|
currentWebViewIndex = 0
|
||||||
@ -2643,8 +2775,9 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectTab(currentTab)
|
selectTab(currentTab)
|
||||||
} catch (e: JSONException) {
|
onComplete.invoke()
|
||||||
Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", e)
|
} catch (ignore: Exception) {
|
||||||
|
Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", ignore)
|
||||||
activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG)
|
activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
// After restoring the tabs, observe any search actions that the user might have triggered.
|
// After restoring the tabs, observe any search actions that the user might have triggered.
|
||||||
@ -2671,6 +2804,18 @@ abstract class CoreReaderFragment :
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores the state of a given KiwixWebView based on the provided WebViewHistoryItem.
|
||||||
|
*
|
||||||
|
* This method retrieves the back-forward list from the WebViewHistoryItem and
|
||||||
|
* uses it to restore the web view's state. It also sets the vertical scroll position
|
||||||
|
* of the web view to the position stored in the WebViewHistoryItem.
|
||||||
|
*
|
||||||
|
* If the provided WebViewHistoryItem is null, the method does nothing.
|
||||||
|
*
|
||||||
|
* @param webView The KiwixWebView instance whose state is to be restored.
|
||||||
|
* @param webViewHistoryItem The WebViewHistoryItem containing the saved state and scroll position.
|
||||||
|
*/
|
||||||
private fun restoreTabState(webView: KiwixWebView, webViewHistoryItem: WebViewHistoryItem?) {
|
private fun restoreTabState(webView: KiwixWebView, webViewHistoryItem: WebViewHistoryItem?) {
|
||||||
webViewHistoryItem?.webViewBackForwardListBundle?.let { bundle ->
|
webViewHistoryItem?.webViewBackForwardListBundle?.let { bundle ->
|
||||||
webView.restoreState(bundle)
|
webView.restoreState(bundle)
|
||||||
@ -2744,28 +2889,29 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the view state after successfully reading valid JSON from shared preferences.
|
* Restores the view state after successfully reading valid webViewHistory from room database.
|
||||||
* Developers modifying this method in subclasses, such as CustomReaderFragment and
|
* Developers modifying this method in subclasses, such as CustomReaderFragment and
|
||||||
* KiwixReaderFragment, should review and consider the implementations in those subclasses
|
* KiwixReaderFragment, should review and consider the implementations in those subclasses
|
||||||
* (e.g., CustomReaderFragment.restoreViewStateOnValidJSON,
|
* (e.g., CustomReaderFragment.restoreViewStateOnValidWebViewHistory,
|
||||||
* KiwixReaderFragment.restoreViewStateOnValidJSON) to ensure consistent behavior
|
* KiwixReaderFragment.restoreViewStateOnValidWebViewHistory) to ensure consistent behavior
|
||||||
* when handling valid JSON scenarios.
|
* when handling valid webViewHistory scenarios.
|
||||||
*/
|
*/
|
||||||
protected abstract fun restoreViewStateOnValidJSON(
|
protected abstract fun restoreViewStateOnValidWebViewHistory(
|
||||||
webViewHistoryItemList: List<WebViewHistoryItem>,
|
webViewHistoryItemList: List<WebViewHistoryItem>,
|
||||||
currentTab: Int,
|
currentTab: Int,
|
||||||
restoreOrigin: RestoreOrigin
|
restoreOrigin: RestoreOrigin,
|
||||||
|
onComplete: () -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the view state when the attempt to read JSON from shared preferences fails
|
* Restores the view state when the attempt to read webViewHistory from room database fails
|
||||||
* due to invalid or corrupted data. Developers modifying this method in subclasses, such as
|
* due to the absence of any history records. Developers modifying this method in subclasses, such as
|
||||||
* CustomReaderFragment and KiwixReaderFragment, should review and consider the implementations
|
* CustomReaderFragment and KiwixReaderFragment, should review and consider the implementations
|
||||||
* in those subclasses (e.g., CustomReaderFragment.restoreViewStateOnInvalidJSON,
|
* in those subclasses (e.g., CustomReaderFragment.restoreViewStateOnInvalidWebViewHistory,
|
||||||
* KiwixReaderFragment.restoreViewStateOnInvalidJSON) to ensure consistent behavior
|
* KiwixReaderFragment.restoreViewStateOnInvalidWebViewHistory) to ensure consistent behavior
|
||||||
* when handling invalid JSON scenarios.
|
* when handling invalid JSON scenarios.
|
||||||
*/
|
*/
|
||||||
abstract fun restoreViewStateOnInvalidJSON()
|
abstract fun restoreViewStateOnInvalidWebViewHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class RestoreOrigin {
|
enum class RestoreOrigin {
|
||||||
|
@ -61,6 +61,7 @@ class MainMenu(
|
|||||||
fun onRandomArticleMenuClicked()
|
fun onRandomArticleMenuClicked()
|
||||||
fun onReadAloudMenuClicked()
|
fun onReadAloudMenuClicked()
|
||||||
fun onFullscreenMenuClicked()
|
fun onFullscreenMenuClicked()
|
||||||
|
fun onSearchMenuClickedMenuClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -154,7 +155,7 @@ class MainMenu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateToSearch(): Boolean {
|
private fun navigateToSearch(): Boolean {
|
||||||
(activity as CoreMainActivity).openSearch(isOpenedFromTabView = isInTabSwitcher)
|
menuClickListener.onSearchMenuClickedMenuClicked()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,25 +150,26 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the view state when the attempt to read JSON from shared preferences fails
|
* Restores the view state when the attempt to read web view history from the room database fails
|
||||||
* due to invalid or corrupted data. In this case, it opens the homepage of the zim file,
|
* due to the absence of any history records. In this case, it navigates to the homepage of the
|
||||||
* as custom apps always have the zim file available.
|
* ZIM file, as custom apps are expected to have the ZIM file readily available.
|
||||||
*/
|
*/
|
||||||
override fun restoreViewStateOnInvalidJSON() {
|
override fun restoreViewStateOnInvalidWebViewHistory() {
|
||||||
openHomeScreen()
|
openHomeScreen()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores the view state when the JSON data is valid. This method restores the tabs
|
* Restores the view state when the webViewHistory data is valid.
|
||||||
* and loads the last opened article in the specified tab.
|
* This method restores the tabs with webView pages history.
|
||||||
*/
|
*/
|
||||||
override fun restoreViewStateOnValidJSON(
|
override fun restoreViewStateOnValidWebViewHistory(
|
||||||
webViewHistoryItemList: List<WebViewHistoryItem>,
|
webViewHistoryItemList: List<WebViewHistoryItem>,
|
||||||
currentTab: Int,
|
currentTab: Int,
|
||||||
// Unused in custom apps as there is only one ZIM file that is already set.
|
// Unused in custom apps as there is only one ZIM file that is already set.
|
||||||
restoreOrigin: RestoreOrigin
|
restoreOrigin: RestoreOrigin,
|
||||||
|
onComplete: () -> Unit
|
||||||
) {
|
) {
|
||||||
restoreTabs(webViewHistoryItemList, currentTab)
|
restoreTabs(webViewHistoryItemList, currentTab, onComplete)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -183,6 +184,27 @@ class CustomReaderFragment : CoreReaderFragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a ZIM file or an OBB file based on the validation of available files.
|
||||||
|
*
|
||||||
|
* This method uses the `customFileValidator` to check for the presence of required files.
|
||||||
|
* Depending on the validation results, it performs the following actions:
|
||||||
|
*
|
||||||
|
* - If a valid ZIM file is found:
|
||||||
|
* - It opens the ZIM file and creates a `ZimReaderSource` for it.
|
||||||
|
* - Saves the book information in the database to be displayed in the `ZimHostFragment`.
|
||||||
|
* - Manages the external launch and restores the view state if specified.
|
||||||
|
*
|
||||||
|
* - If both ZIM and OBB files are found:
|
||||||
|
* - The ZIM file is deleted, and the OBB file is opened instead.
|
||||||
|
* - Manages the external launch and restores the view state if specified.
|
||||||
|
*
|
||||||
|
* If no valid files are found and the app is not in test mode, the user is navigated to
|
||||||
|
* the `customDownloadFragment` to facilitate downloading the required files.
|
||||||
|
*
|
||||||
|
* @param shouldManageExternalLaunch Indicates whether to manage external launch and
|
||||||
|
* restore the view state after opening the file. Default is false.
|
||||||
|
*/
|
||||||
private fun openObbOrZim(shouldManageExternalLaunch: Boolean = false) {
|
private fun openObbOrZim(shouldManageExternalLaunch: Boolean = false) {
|
||||||
customFileValidator.validate(
|
customFileValidator.validate(
|
||||||
onFilesFound = {
|
onFilesFound = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user