Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving and Restoring the Web View Navigation History Across Sessions #3996

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d5848bc
Saved webbackforwardlist to room
MohitMaliDeveloper Dec 6, 2024
c3d110f
Retrieving page history from room
MohitMaliDeveloper Oct 22, 2024
a55033a
Restoring the internal webbackforwardlist
Saifuddin53 Sep 19, 2024
3672494
Fixed the detekt issue
MohitMaliDeveloper Sep 19, 2024
5be5186
Naming convention improved
MohitMaliDeveloper Oct 22, 2024
8295642
Code factor improvements
Saifuddin53 Sep 19, 2024
55e6798
Automated changes reverted
Saifuddin53 Sep 20, 2024
d7e4627
Automated changes reverted
Saifuddin53 Sep 20, 2024
c64052d
Updated room schema
Saifuddin53 Oct 11, 2024
07208c7
Naming conventions improved and some reviewed changes
Saifuddin53 Oct 18, 2024
8002e60
Fixed detekt issue.
MohitMaliDeveloper Oct 22, 2024
5df09c6
Implemented new approach to save and retrieve the webView history.
MohitMaliDeveloper Dec 6, 2024
d7f0ecc
Fixed: Restore web view history in Kiwix app.
MohitMaliDeveloper Oct 25, 2024
3a7181d
Fixed: Searched item was not opening in custom apps.
MohitMaliDeveloper Oct 25, 2024
af146ae
Fixed: FindInPage functionality not working in Kiwix and custom apps.
MohitMaliDeveloper Oct 25, 2024
0141329
Improved the saving of tabs.
MohitMaliDeveloper Dec 6, 2024
2240912
Fixed: Reader screen was showing twice when pressing the back button …
MohitMaliDeveloper Oct 29, 2024
b76ccc6
Fix: Main page of ZIM file not loading when opening a note in the not…
MohitMaliDeveloper Oct 29, 2024
0f32c43
Removed unnecessary data saving when opening note dialog in note screen.
MohitMaliDeveloper Dec 6, 2024
6cbd075
Fixed: SearchFragmentTest for custom apps was failing.
MohitMaliDeveloper Dec 6, 2024
feda7b4
Fixed: Application crashes at first launch.
MohitMaliDeveloper Dec 6, 2024
ee90904
Added debug logs which will help us in debugging if any error happens.
MohitMaliDeveloper Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import org.kiwix.kiwixmobile.core.main.RestoreOrigin
import org.kiwix.kiwixmobile.core.main.RestoreOrigin.FromExternalLaunch
import org.kiwix.kiwixmobile.core.main.RestoreOrigin.FromSearchScreen
import org.kiwix.kiwixmobile.core.main.ToolbarScrollingKiwixWebView
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource.Companion.fromDatabaseValue
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
Expand Down Expand Up @@ -229,48 +230,48 @@ class KiwixReaderFragment : CoreReaderFragment() {
}
}

override fun restoreViewStateOnInvalidJSON() {
override fun restoreViewStateOnInvalidWebViewHistory() {
Log.d(TAG_KIWIX, "Kiwix normal start, no zimFile loaded last time -> display home page")
exitBook()
}

/**
* Restores the view state based on the provided JSON data and restore origin.
* Restores the view state based on the provided webViewHistoryItemList data and restore origin.
*
* Depending on the `restoreOrigin`, this method either restores the last opened ZIM file
* (if the launch is external) or skips re-opening the ZIM file when coming from the search screen,
* 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.
*
* @param zimArticles JSON string representing the list of articles to be restored.
* @param zimPositions JSON string representing the positions of the restored articles.
* @param currentTab Index of the tab to be restored as the currently active one.
* @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 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 restoreViewStateOnValidJSON(
zimArticles: String?,
zimPositions: String?,
override fun restoreViewStateOnValidWebViewHistory(
webViewHistoryItemList: List<WebViewHistoryItem>,
currentTab: Int,
restoreOrigin: RestoreOrigin
restoreOrigin: RestoreOrigin,
onComplete: () -> Unit
) {
when (restoreOrigin) {
FromExternalLaunch -> {
coreReaderLifeCycleScope?.launch {
if (!isAdded) return@launch
val settings =
requireActivity().getSharedPreferences(SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0)
val zimReaderSource = fromDatabaseValue(settings.getString(TAG_CURRENT_FILE, null))
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)
openZimFile(zimReaderSource, isFromManageExternalLaunch = true)
Log.d(
TAG_KIWIX,
"Kiwix normal start, Opened last used zimFile: -> ${zimReaderSource.toDatabase()}"
)
} else {
zimReaderContainer?.zimFileReader?.let(::setUpBookmarks)
}
restoreTabs(zimArticles, zimPositions, currentTab)
restoreTabs(webViewHistoryItemList, currentTab, onComplete)
} else {
getCurrentWebView()?.snack(string.zim_not_opened)
exitBook() // hide the options for zim file to avoid unexpected UI behavior
Expand All @@ -279,7 +280,7 @@ class KiwixReaderFragment : CoreReaderFragment() {
}

FromSearchScreen -> {
restoreTabs(zimArticles, zimPositions, currentTab)
restoreTabs(webViewHistoryItemList, currentTab, onComplete)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/detekt_baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<ID>LongParameterList:MainMenu.kt$MainMenu$( private val activity: Activity, zimFileReader: ZimFileReader?, menu: Menu, webViews: MutableList&lt;KiwixWebView>, urlIsValid: Boolean, disableReadAloud: Boolean = false, disableTabs: Boolean = false, private val menuClickListener: MenuClickListener )</ID>
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList&lt;KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
<ID>LongParameterList:PageTestHelpers.kt$( bookmarkTitle: String = "bookmarkTitle", isSelected: Boolean = false, id: Long = 2, zimId: String = "zimId", zimName: String = "zimName", zimFilePath: String = "zimFilePath", bookmarkUrl: String = "bookmarkUrl", favicon: String = "favicon" )</ID>
<ID>LongParameterList:Repository.kt$Repository$( @param:IO private val ioThread: Scheduler, @param:MainThread private val mainThread: Scheduler, private val bookDao: NewBookDao, private val libkiwixBookmarks: LibkiwixBookmarks, private val historyRoomDao: HistoryRoomDao, private val notesRoomDao: NotesRoomDao, private val languageDao: NewLanguagesDao, private val recentSearchRoomDao: RecentSearchRoomDao, private val zimReaderContainer: ZimReaderContainer )</ID>
<ID>LongParameterList:Repository.kt$Repository$( @param:IO private val ioThread: Scheduler, @param:MainThread private val mainThread: Scheduler, private val bookDao: NewBookDao, private val libkiwixBookmarks: LibkiwixBookmarks, private val historyRoomDao: HistoryRoomDao, private val webViewHistoryRoomDao: WebViewHistoryRoomDao, private val notesRoomDao: NotesRoomDao, private val languageDao: NewLanguagesDao, private val recentSearchRoomDao: RecentSearchRoomDao, private val zimReaderContainer: ZimReaderContainer )</ID>
<ID>LongParameterList:ToolbarScrollingKiwixWebView.kt$ToolbarScrollingKiwixWebView$( context: Context, callback: WebViewCallback, attrs: AttributeSet, nonVideoView: ViewGroup, videoView: ViewGroup, webViewClient: CoreWebViewClient, private val toolbarView: View, private val bottomBarView: View, sharedPreferenceUtil: SharedPreferenceUtil, private val parentNavigationBar: View? = null )</ID>
<ID>MagicNumber:ArticleCount.kt$ArticleCount$3</ID>
<ID>MagicNumber:CompatFindActionModeCallback.kt$CompatFindActionModeCallback$100</ID>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ abstract class HistoryRoomDao : PageDao {
historyItem.dateString
)?.let {
it.apply {
// update the exiting entity
// update the existing entity
historyUrl = historyItem.historyUrl
historyTitle = historyItem.title
timeStamp = historyItem.timeStamp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Kiwix Android
* Copyright (c) 2024 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package org.kiwix.kiwixmobile.core.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import io.reactivex.Flowable
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity

@Dao
abstract class WebViewHistoryRoomDao {

fun insertWebViewPageHistoryItem(webViewHistoryEntity: WebViewHistoryEntity) {
insertWebViewPageHistoryItems(listOf(webViewHistoryEntity))
}

@Insert
abstract fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List<WebViewHistoryEntity>)

@Query("SELECT * FROM WebViewHistoryEntity ORDER BY webViewIndex ASC")
abstract fun getAllWebViewPagesHistory(): Flowable<List<WebViewHistoryEntity>>

@Query("Delete from WebViewHistoryEntity")
abstract fun clearWebViewPagesHistory()

fun clearPageHistoryWithPrimaryKey() {
clearWebViewPagesHistory()
}

@Query("DELETE FROM sqlite_sequence WHERE name='PageHistoryRoomEntity'")
abstract fun resetPrimaryKey()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Kiwix Android
* Copyright (c) 2024 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package org.kiwix.kiwixmobile.core.dao.entities

import android.os.Bundle
import android.os.Parcel
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem

@Entity
data class WebViewHistoryEntity(
@PrimaryKey(autoGenerate = true) var id: Long = 0L,
val zimId: String,
val webViewIndex: Int,
val webViewCurrentPosition: Int,
@TypeConverters(BundleRoomConverter::class)
val webViewBackForwardListBundle: Bundle?
) {
constructor(webViewHistoryItem: WebViewHistoryItem) : this(
webViewHistoryItem.databaseId,
webViewHistoryItem.zimId,
webViewHistoryItem.webViewIndex,
webViewHistoryItem.webViewCurrentPosition,
webViewHistoryItem.webViewBackForwardListBundle,
)
}

class BundleRoomConverter {
@TypeConverter
fun convertToDatabaseValue(bundle: Bundle?): ByteArray? {
if (bundle == null) return null
val parcel = Parcel.obtain()
parcel.writeBundle(bundle)
val bytes = parcel.marshall()
parcel.recycle()
return bytes
}

@TypeConverter
fun convertToEntityProperty(byteArray: ByteArray?): Bundle? {
if (byteArray == null) return null
val parcel = Parcel.obtain()
parcel.unmarshall(byteArray, 0, byteArray.size)
parcel.setDataPosition(0)
val bundle = parcel.readBundle(Bundle::class.java.classLoader)
parcel.recycle()
return bundle
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.core.data
import io.reactivex.Completable
import io.reactivex.Flowable
import io.reactivex.Single
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
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.HistoryItem
Expand Down Expand Up @@ -53,4 +54,8 @@ interface DataSource {
fun saveNote(noteListItem: NoteListItem): Completable
fun deleteNote(noteTitle: String): Completable
fun deleteNotes(noteList: List<NoteListItem>): Completable

suspend fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List<WebViewHistoryEntity>)
fun getAllWebViewPagesHistory(): Single<List<WebViewHistoryEntity>>
suspend fun clearWebViewPagesHistory()
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDaoCoverts
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao
import org.kiwix.kiwixmobile.core.dao.entities.BundleRoomConverter
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
import org.kiwix.kiwixmobile.core.dao.entities.HistoryRoomEntity
import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter

@Suppress("UnnecessaryAbstractClass")
Expand All @@ -42,17 +45,23 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter
RecentSearchRoomEntity::class,
HistoryRoomEntity::class,
NotesRoomEntity::class,
DownloadRoomEntity::class
DownloadRoomEntity::class,
WebViewHistoryEntity::class
],
version = 5,
version = 6,
exportSchema = false
)
@TypeConverters(HistoryRoomDaoCoverts::class, ZimSourceRoomConverter::class)
@TypeConverters(
HistoryRoomDaoCoverts::class,
ZimSourceRoomConverter::class,
BundleRoomConverter::class
)
abstract class KiwixRoomDatabase : RoomDatabase() {
abstract fun recentSearchRoomDao(): RecentSearchRoomDao
abstract fun historyRoomDao(): HistoryRoomDao
abstract fun notesRoomDao(): NotesRoomDao
abstract fun downloadRoomDao(): DownloadRoomDao
abstract fun webViewHistoryRoomDao(): WebViewHistoryRoomDao

companion object {
private var db: KiwixRoomDatabase? = null
Expand All @@ -62,7 +71,13 @@ abstract class KiwixRoomDatabase : RoomDatabase() {
?: Room.databaseBuilder(context, KiwixRoomDatabase::class.java, "KiwixRoom.db")
// We have already database name called kiwix.db in order to avoid complexity we named
// as kiwixRoom.db
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5)
.addMigrations(
MIGRATION_1_2,
MIGRATION_2_3,
MIGRATION_3_4,
MIGRATION_4_5,
MIGRATION_5_6
)
.build().also { db = it }
}
}
Expand Down Expand Up @@ -202,6 +217,23 @@ abstract class KiwixRoomDatabase : RoomDatabase() {
}
}

@Suppress("MagicNumber")
private val MIGRATION_5_6 = object : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `WebViewHistoryEntity` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`zimId` TEXT NOT NULL,
`webViewIndex` INTEGER NOT NULL,
`webViewCurrentPosition` INTEGER NOT NULL,
`webViewBackForwardListBundle` BLOB NULL
)
"""
)
}
}

fun destroyInstance() {
db = null
}
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
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.di.qualifiers.IO
import org.kiwix.kiwixmobile.core.di.qualifiers.MainThread
import org.kiwix.kiwixmobile.core.extensions.HeaderizableList
Expand All @@ -55,6 +57,7 @@ class Repository @Inject internal constructor(
private val bookDao: NewBookDao,
private val libkiwixBookmarks: LibkiwixBookmarks,
private val historyRoomDao: HistoryRoomDao,
private val webViewHistoryRoomDao: WebViewHistoryRoomDao,
private val notesRoomDao: NotesRoomDao,
private val languageDao: NewLanguagesDao,
private val recentSearchRoomDao: RecentSearchRoomDao,
Expand Down Expand Up @@ -144,6 +147,22 @@ class Repository @Inject internal constructor(
Completable.fromAction { notesRoomDao.deleteNotes(noteList) }
.subscribeOn(ioThread)

override suspend fun insertWebViewPageHistoryItems(
webViewHistoryEntityList: List<WebViewHistoryEntity>
) {
webViewHistoryRoomDao.insertWebViewPageHistoryItems(webViewHistoryEntityList)
}

override fun getAllWebViewPagesHistory() =
webViewHistoryRoomDao.getAllWebViewPagesHistory()
.first(emptyList())
.subscribeOn(ioThread)
.observeOn(mainThread)

override suspend fun clearWebViewPagesHistory() {
webViewHistoryRoomDao.clearWebViewPagesHistory()
}

override fun deleteNote(noteTitle: String): Completable =
Completable.fromAction { notesRoomDao.deleteNote(noteTitle) }
.subscribeOn(ioThread)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
import org.kiwix.kiwixmobile.core.dao.NewNoteDao
import org.kiwix.kiwixmobile.core.dao.NewRecentSearchDao
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.data.DataModule
import org.kiwix.kiwixmobile.core.data.DataSource
Expand Down Expand Up @@ -106,6 +107,7 @@ interface CoreComponent {
fun libkiwixBookmarks(): LibkiwixBookmarks
fun recentSearchRoomDao(): RecentSearchRoomDao
fun historyRoomDao(): HistoryRoomDao
fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
fun noteRoomDao(): NotesRoomDao
fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator
fun context(): Context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ open class DatabaseModule {
@Singleton
fun provideHistoryDao(db: KiwixRoomDatabase) = db.historyRoomDao()

@Provides
@Singleton
fun provideWebViewHistoryRoomDao(db: KiwixRoomDatabase) = db.webViewHistoryRoomDao()

@Singleton
@Provides
fun provideNoteRoomDao(db: KiwixRoomDatabase) = db.notesRoomDao()
Expand Down
Loading