diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt index ffb90cf4e..56f397916 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/reader/KiwixReaderFragment.kt @@ -110,6 +110,7 @@ class KiwixReaderFragment : CoreReaderFragment() { if (zimFileUri.isNotEmpty()) { tryOpeningZimFile(zimFileUri) } else { + isWebViewHistoryRestoring = true val restoreOrigin = if (searchItemTitle.isNotEmpty()) FromSearchScreen else FromExternalLaunch manageExternalLaunchAndRestoringViewState(restoreOrigin) @@ -224,7 +225,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } } - override fun restoreViewStateOnInvalidWebViewHistory() { + override suspend fun restoreViewStateOnInvalidWebViewHistory() { Log.d(TAG_KIWIX, "Kiwix normal start, no zimFile loaded last time -> display home page") exitBook() } @@ -242,7 +243,7 @@ class KiwixReaderFragment : CoreReaderFragment() { * @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 suspend fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, restoreOrigin: RestoreOrigin, @@ -250,29 +251,27 @@ class KiwixReaderFragment : CoreReaderFragment() { ) { when (restoreOrigin) { FromExternalLaunch -> { - coreReaderLifeCycleScope?.launch { - if (!isAdded) return@launch - val settings = - activity?.getSharedPreferences(SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0) - val zimReaderSource = fromDatabaseValue(settings?.getString(TAG_CURRENT_FILE, null)) - if (zimReaderSource?.canOpenInLibkiwix() == true) { - if (zimReaderContainer?.zimReaderSource == null) { - openZimFile(zimReaderSource, isFromManageExternalLaunch = true) - Log.d( - TAG_KIWIX, - "Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}" - ) - } else { - zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) - } - restoreTabs(webViewHistoryItemList, currentTab, onComplete) - } else { - readerScreenState.value.snackBarHostState.snack( - requireActivity().getString(string.zim_not_opened), - lifecycleScope = lifecycleScope + if (!isAdded) return + val settings = + activity?.getSharedPreferences(SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0) + val zimReaderSource = fromDatabaseValue(settings?.getString(TAG_CURRENT_FILE, null)) + if (zimReaderSource?.canOpenInLibkiwix() == true) { + if (zimReaderContainer?.zimReaderSource == null) { + openZimFile(zimReaderSource, isFromManageExternalLaunch = true) + Log.d( + TAG_KIWIX, + "Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}" ) - exitBook() // hide the options for zim file to avoid unexpected UI behavior + } else { + zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } + restoreTabs(webViewHistoryItemList, currentTab, onComplete) + } else { + readerScreenState.value.snackBarHostState.snack( + requireActivity().getString(string.zim_not_opened), + lifecycleScope = lifecycleScope + ) + exitBook() // hide the options for zim file to avoid unexpected UI behavior } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt index 90fc8119b..b50c40469 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/reader/CoreReaderFragment.kt @@ -172,6 +172,7 @@ import java.io.IOException import java.text.SimpleDateFormat import java.util.Date import javax.inject.Inject +import kotlin.concurrent.Volatile import kotlin.math.max const val SEARCH_ITEM_TITLE_KEY = "searchItemTitle" @@ -224,6 +225,8 @@ abstract class CoreReaderFragment : protected var currentWebViewIndex by mutableStateOf(0) private var currentTtsWebViewIndex = 0 private var isFirstTimeMainPageLoaded = true + + @Volatile private var isFromManageExternalLaunch = false private val savingTabsMutex = Mutex() private var searchItemToOpen: SearchItemToOpen? = null @@ -340,6 +343,8 @@ abstract class CoreReaderFragment : */ private var pendingIntent: Intent? = null + @Volatile var isWebViewHistoryRestoring = false + private var storagePermissionForNotesLauncher: ActivityResultLauncher? = registerForActivityResult( ActivityResultContracts.RequestPermission() @@ -2333,7 +2338,9 @@ abstract class CoreReaderFragment : showProgressBarWithProgress(progress) if (progress == 100) { hideProgressBar() - saveTabStates() + if (!isWebViewHistoryRestoring) { + saveTabStates() + } Log.d(TAG_KIWIX, "Loaded URL: " + getCurrentWebView()?.url) } (webView.context as AppCompatActivity).invalidateOptionsMenu() @@ -2434,6 +2441,7 @@ abstract class CoreReaderFragment : restoreViewStateOnInvalidWebViewHistory() // handle the pending intent if any present. handlePendingIntent() + isWebViewHistoryRestoring = false return } restoreViewStateOnValidWebViewHistory( @@ -2446,11 +2454,14 @@ abstract class CoreReaderFragment : // to open the specified item, then sets `searchItemToOpen` to null to prevent // any unexpected behavior on future calls. Similarly, if `findInPageTitle` is set, // it invokes `findInPage` and resets `findInPageTitle` to null. + isWebViewHistoryRestoring = false searchItemToOpen?.let(::openSearchItem) searchItemToOpen = null findInPageTitle?.let(::findInPage) findInPageTitle = null handlePendingIntent() + // When the restoration completes than save the tabs history. + saveTabStates() } }.onFailure { Log.e( @@ -2460,6 +2471,7 @@ abstract class CoreReaderFragment : restoreViewStateOnInvalidWebViewHistory() // handle the pending intent if any present. handlePendingIntent() + isWebViewHistoryRestoring = false } } @@ -2487,7 +2499,7 @@ abstract class CoreReaderFragment : * @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 suspend fun restoreTabs( webViewHistoryItemList: List, currentTab: Int, onComplete: () -> Unit @@ -2612,7 +2624,7 @@ abstract class CoreReaderFragment : * KiwixReaderFragment.restoreViewStateOnValidWebViewHistory) to ensure consistent behavior * when handling valid webViewHistory scenarios. */ - protected abstract fun restoreViewStateOnValidWebViewHistory( + protected abstract suspend fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, restoreOrigin: RestoreOrigin, @@ -2627,7 +2639,7 @@ abstract class CoreReaderFragment : * KiwixReaderFragment.restoreViewStateOnInvalidWebViewHistory) to ensure consistent behavior * when handling invalid JSON scenarios. */ - abstract fun restoreViewStateOnInvalidWebViewHistory() + abstract suspend fun restoreViewStateOnInvalidWebViewHistory() } enum class RestoreOrigin { diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt index 87433e13f..f2c17f225 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomReaderFragment.kt @@ -185,6 +185,7 @@ class CustomReaderFragment : CoreReaderFragment() { // See https://github.com/kiwix/kiwix-android/issues/3541 zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } else { + isWebViewHistoryRestoring = true coreReaderLifeCycleScope?.launch { openObbOrZim(true) } @@ -197,7 +198,7 @@ class CustomReaderFragment : CoreReaderFragment() { * due to the absence of any history records. In this case, it navigates to the homepage of the * ZIM file, as custom apps are expected to have the ZIM file readily available. */ - override fun restoreViewStateOnInvalidWebViewHistory() { + override suspend fun restoreViewStateOnInvalidWebViewHistory() { openHomeScreen() } @@ -205,7 +206,7 @@ class CustomReaderFragment : CoreReaderFragment() { * Restores the view state when the webViewHistory data is valid. * This method restores the tabs with webView pages history. */ - override fun restoreViewStateOnValidWebViewHistory( + override suspend fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, // Unused in custom apps as there is only one ZIM file that is already set. @@ -430,6 +431,7 @@ class CustomReaderFragment : CoreReaderFragment() { super.onResume() if (appSettingsLaunched) { appSettingsLaunched = false + isWebViewHistoryRestoring = true coreReaderLifeCycleScope?.launch { openObbOrZim(true) }