From d5848bca7706273001af809b3225f7d9c4649773 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 11:41:33 +0530 Subject: [PATCH 01/22] Saved webbackforwardlist to room --- .../kiwixmobile/core/dao/HistoryRoomDao.kt | 2 +- .../core/dao/PageHistoryRoomDao.kt | 45 ++++++++++++++++ .../dao/entities/PageHistoryRoomEntity.kt | 42 +++++++++++++++ .../kiwix/kiwixmobile/core/data/DataSource.kt | 5 ++ .../core/data/KiwixRoomDatabase.kt | 34 ++++++++++-- .../kiwix/kiwixmobile/core/data/Repository.kt | 19 +++++++ .../core/di/components/CoreComponent.kt | 2 + .../core/di/modules/DatabaseModule.kt | 4 ++ .../core/main/CoreReaderFragment.kt | 45 ++++++++++++++++ .../core/main/MainRepositoryActions.kt | 15 ++++++ .../page/history/adapter/PageHistoryItem.kt | 54 +++++++++++++++++++ .../res/values-b+be+tarask+old/strings.xml | 33 +++++++++--- 12 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt create mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt create mode 100644 core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/HistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/HistoryRoomDao.kt index 79ab8bebbd..1c6aa3a474 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/HistoryRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/HistoryRoomDao.kt @@ -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 diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt new file mode 100644 index 0000000000..93e8deaa35 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt @@ -0,0 +1,45 @@ +/* + * Kiwix Android + * Copyright (c) 2024 Kiwix + * 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 . + * + */ + +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.PageHistoryRoomEntity + +@Dao +abstract class PageHistoryRoomDao { + @Insert + abstract fun insertPageHistoryItem(pageHistoryRoomEntity: PageHistoryRoomEntity) + + @Query("SELECT * FROM PageHistoryRoomEntity") + abstract fun getAllPageHistory(): Flowable> + + @Query("Delete from PageHistoryRoomEntity") + abstract fun clearPageHistory() + + fun clearPageHistoryWithPrimaryKey() { + clearPageHistory() + resetPrimaryKey() + } + + @Query("DELETE FROM sqlite_sequence WHERE name='PageHistoryRoomEntity'") + abstract fun resetPrimaryKey() +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt new file mode 100644 index 0000000000..9acf14a571 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt @@ -0,0 +1,42 @@ +/* + * Kiwix Android + * Copyright (c) 2024 Kiwix + * 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 . + * + */ + +package org.kiwix.kiwixmobile.core.dao.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey +import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem + +@Entity +data class PageHistoryRoomEntity( + @PrimaryKey(autoGenerate = true) var id: Long = 0L, + val zimId: String, + val title: String, + val pageUrl: String, + val isForward: Boolean = false, + val timeStamp: Long +) { + constructor(pageHistoryItem: PageHistoryItem) : this( + pageHistoryItem.databaseId, + pageHistoryItem.zimId, + pageHistoryItem.title, + pageHistoryItem.pageUrl, + pageHistoryItem.isForward, + pageHistoryItem.timeStamp + ) +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt index 0b897b0393..3a2d4d20a3 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt @@ -23,6 +23,7 @@ import io.reactivex.Single 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 +import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.zim_manager.Language import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem @@ -53,4 +54,8 @@ interface DataSource { fun saveNote(noteListItem: NoteListItem): Completable fun deleteNote(noteTitle: String): Completable fun deleteNotes(noteList: List): Completable + + fun insertPageHistoryItem(pageHistory: PageHistoryItem): Completable + fun getAllPageHistory(): Flowable> + fun clearPageHistory(): Completable } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt index 58a89a6c70..443b74756b 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt @@ -29,10 +29,12 @@ import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao 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.PageHistoryRoomDao import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao 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.PageHistoryRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter @@ -42,9 +44,10 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter RecentSearchRoomEntity::class, HistoryRoomEntity::class, NotesRoomEntity::class, - DownloadRoomEntity::class + DownloadRoomEntity::class, + PageHistoryRoomEntity::class ], - version = 5, + version = 6, exportSchema = false ) @TypeConverters(HistoryRoomDaoCoverts::class, ZimSourceRoomConverter::class) @@ -53,6 +56,7 @@ abstract class KiwixRoomDatabase : RoomDatabase() { abstract fun historyRoomDao(): HistoryRoomDao abstract fun notesRoomDao(): NotesRoomDao abstract fun downloadRoomDao(): DownloadRoomDao + abstract fun pageHistoryRoomDao(): PageHistoryRoomDao companion object { private var db: KiwixRoomDatabase? = null @@ -62,7 +66,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 } } } @@ -202,6 +212,24 @@ 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 `PageHistoryRoomEntity` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `zimId` TEXT NOT NULL, + `title` TEXT NOT NULL, + `pageUrl` TEXT NOT NULL, + `isForward` INTEGER NOT NULL DEFAULT 0 + `timeStamp` INTEGER NOT NULL + ) + """ + ) + } + } + fun destroyInstance() { db = null } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt index de4c7884d4..90aeb258fd 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt @@ -28,13 +28,16 @@ import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks 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.PageHistoryRoomDao import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao +import org.kiwix.kiwixmobile.core.dao.entities.PageHistoryRoomEntity import org.kiwix.kiwixmobile.core.di.qualifiers.IO import org.kiwix.kiwixmobile.core.di.qualifiers.MainThread import org.kiwix.kiwixmobile.core.extensions.HeaderizableList 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 +import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.zim_manager.Language @@ -55,6 +58,7 @@ class Repository @Inject internal constructor( private val bookDao: NewBookDao, private val libkiwixBookmarks: LibkiwixBookmarks, private val historyRoomDao: HistoryRoomDao, + private val pageHistoryRoomDao: PageHistoryRoomDao, private val notesRoomDao: NotesRoomDao, private val languageDao: NewLanguagesDao, private val recentSearchRoomDao: RecentSearchRoomDao, @@ -144,6 +148,21 @@ class Repository @Inject internal constructor( Completable.fromAction { notesRoomDao.deleteNotes(noteList) } .subscribeOn(ioThread) + override fun insertPageHistoryItem(pageHistory: PageHistoryItem): Completable = + Completable.fromAction { + pageHistoryRoomDao.insertPageHistoryItem( + PageHistoryRoomEntity(pageHistory) + ) + } + .subscribeOn(io) + + override fun getAllPageHistory() = + pageHistoryRoomDao.getAllPageHistory() as Flowable> + + override fun clearPageHistory(): Completable = + Completable.fromAction(pageHistoryRoomDao::clearPageHistoryWithPrimaryKey) + .subscribeOn(io) + override fun deleteNote(noteTitle: String): Completable = Completable.fromAction { notesRoomDao.deleteNote(noteTitle) } .subscribeOn(ioThread) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt index d8aefd9d4a..56f4ff9948 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt @@ -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.PageHistoryRoomDao import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao import org.kiwix.kiwixmobile.core.data.DataModule import org.kiwix.kiwixmobile.core.data.DataSource @@ -106,6 +107,7 @@ interface CoreComponent { fun libkiwixBookmarks(): LibkiwixBookmarks fun recentSearchRoomDao(): RecentSearchRoomDao fun historyRoomDao(): HistoryRoomDao + fun pageHistoryRoomDao(): PageHistoryRoomDao fun noteRoomDao(): NotesRoomDao fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator fun context(): Context diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt index c7b374e5aa..667807cafc 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt @@ -86,6 +86,10 @@ open class DatabaseModule { @Singleton fun provideHistoryDao(db: KiwixRoomDatabase) = db.historyRoomDao() + @Provides + @Singleton + fun providePageHistoryRoomDao(db: KiwixRoomDatabase) = db.pageHistoryRoomDao() + @Singleton @Provides fun provideNoteRoomDao(db: KiwixRoomDatabase) = db.notesRoomDao() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index f71f909bb6..3be6fd19dd 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -134,6 +134,7 @@ import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryClickListener import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryDialog import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem +import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudCallbacks import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudService import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudService.Companion.ACTION_PAUSE_OR_RESUME_TTS @@ -325,6 +326,7 @@ abstract class CoreReaderFragment : private lateinit var serviceConnection: ServiceConnection private var readAloudService: ReadAloudService? = null private var navigationHistoryList: MutableList = ArrayList() + private var pageTimeStamp: MutableList = ArrayList() private var isReadSelection = false private var isReadAloudServiceRunning = false private var readerLifeCycleScope: CoroutineScope? = null @@ -2297,9 +2299,51 @@ abstract class CoreReaderFragment : editor.apply() } + private fun saveWebBackForwardListToRoom() { + val webBackForwardList = getCurrentWebView()?.copyBackForwardList() + val currentIndex = webBackForwardList?.currentIndex + if (currentIndex != null) { + repositoryActions?.clearPageHistory() + // Save BackStack + webBackForwardList.let { historyList -> + (0 until historyList.currentIndex) + .asSequence() + .forEach { + val historyItem = webBackForwardList.getItemAtIndex(it) + val pageHistory = PageHistoryItem( + zimId = zimReaderContainer?.zimFileReader?.id ?: "", + title = historyItem.title, + pageUrl = historyItem.url, + isForward = false, + timeStamp = 0 + ) + repositoryActions?.savePageHistory(pageHistory) + } + } + + // Save ForwardStack + webBackForwardList.let { historyList -> + (historyList.currentIndex + 1 until webBackForwardList.size) + .asSequence() + .forEach { + val historyItem = webBackForwardList.getItemAtIndex(it) + val pageHistory = PageHistoryItem( + zimId = zimReaderContainer?.zimFileReader?.id ?: "", + title = historyItem.title, + pageUrl = historyItem.url, + isForward = true, + timeStamp = 0 + ) + repositoryActions?.savePageHistory(pageHistory) + } + } + } + } + override fun onPause() { super.onPause() saveTabStates() + saveWebBackForwardListToRoom() Log.d( TAG_KIWIX, "onPause Save current zim file to preferences: " + @@ -2349,6 +2393,7 @@ abstract class CoreReaderFragment : val zimFileReader = zimReaderContainer?.zimFileReader if (hasValidFileAndUrl(getCurrentWebView()?.url, zimFileReader)) { val timeStamp = System.currentTimeMillis() + pageTimeStamp.add(timeStamp) val sdf = SimpleDateFormat( "d MMM yyyy", getCurrentLocale( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt index 5557c2b23c..a98eb705be 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt @@ -22,6 +22,7 @@ import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.di.ActivityScope import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.utils.files.Log import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk @@ -36,6 +37,8 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour private var saveNoteDisposable: Disposable? = null private var saveBookDisposable: Disposable? = null private var deleteNoteDisposable: Disposable? = null + private var savePageHistoryDisposable: Disposable? = null + private var clearPageHistoryDisposable: Disposable? = null fun saveHistory(history: HistoryItem) { saveHistoryDisposable = dataSource.saveHistory(history) @@ -68,11 +71,23 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour .subscribe({}, { e -> Log.e(TAG, "Unable to save book", e) }) } + fun savePageHistory(pageHistory: PageHistoryItem) { + savePageHistoryDisposable = dataSource.insertPageHistoryItem(pageHistory) + .subscribe({}, { e -> Log.e(TAG, "Unable to save page history", e) }) + } + + fun clearPageHistory() { + clearPageHistoryDisposable = dataSource.clearPageHistory() + .subscribe({}, { e -> Log.e(TAG, "Unable to clear page history", e) }) + } + fun dispose() { saveHistoryDisposable?.dispose() saveBookmarkDisposable?.dispose() saveNoteDisposable?.dispose() deleteNoteDisposable?.dispose() saveBookDisposable?.dispose() + savePageHistoryDisposable?.dispose() + clearPageHistoryDisposable?.dispose() } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt new file mode 100644 index 0000000000..436ec1da71 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt @@ -0,0 +1,54 @@ +/* + * Kiwix Android + * Copyright (c) 2024 Kiwix + * 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 . + * + */ + +package org.kiwix.kiwixmobile.core.page.history.adapter + +import org.kiwix.kiwixmobile.core.dao.entities.PageHistoryRoomEntity + +data class PageHistoryItem( + val databaseId: Long = 0L, + val zimId: String, + val title: String, + val pageUrl: String, + val isForward: Boolean, + val timeStamp: Long +) { + constructor( + zimId: String, + title: String, + pageUrl: String, + isForward: Boolean, + timeStamp: Long + ) : this( + 0L, + zimId, + title, + pageUrl, + isForward, + timeStamp + ) + + constructor(pageHistoryRoomEntity: PageHistoryRoomEntity) : this( + pageHistoryRoomEntity.id, + pageHistoryRoomEntity.zimId, + pageHistoryRoomEntity.title, + pageHistoryRoomEntity.pageUrl, + pageHistoryRoomEntity.isForward, + pageHistoryRoomEntity.timeStamp + ) +} diff --git a/core/src/main/res/values-b+be+tarask+old/strings.xml b/core/src/main/res/values-b+be+tarask+old/strings.xml index f7b21eb9f4..e692b350e5 100644 --- a/core/src/main/res/values-b+be+tarask+old/strings.xml +++ b/core/src/main/res/values-b+be+tarask+old/strings.xml @@ -1,8 +1,4 @@ - Дапамога Галоўная @@ -15,28 +11,36 @@ Чытаць уголас Спыніць чытаньне ўголас Падтрымаць Kiwix + Падтрымка %s + Пра праграму %s Пункт доступу WiFi Захаваць мэдыя Узьнікла памылка пры захаваньні мэдыяфайлу! Мэдыя-файл захаваны як %s у Downloads/org.kiwix…/ + Пошук + Пошукавы сьпіс Абярыце файл зьместу (*.zim) Адкрыць спасылку ў новай укладцы? + Сэрвісны канал пункту досягу Падобна, што ваш пункт доступу ўжо ўключаны. Каб працягнуць, адключыце пункт доступу вай-фай. Перайсьці да наладаў вай-фаю Немагчыма запусьціць сэрвэр. Калі ласка, уключыце ваш пункт доступу Немагчыма запусьціць сэрвэр. + Дэталі вашага лякальнага пункту досягу. \nSSID: %1$s \nСпокліч: %2$s Памылка: абраны ZIM-файл ня знойдзены. Памылка: абраны файл не зьяўляецца слушным ZIM-файлам. Памылка: загрузка артыкула (Url: %1$s) не атрымалася. Інфармацыя Вэрсія - Начны рэжым - Паказваць артыкулы ў інвэртаваных колерах + Цёмны рэжым + Паказваць артыкулы ў інвэртаваных колерах Вярнуцца ўгару Паказваць кнопку ў канцы старонкі для пракручваньня ўверх Мова Абярыце мову - Мова гэтай старонкі не падтрымліваецца або адпаведныя зьвесткі мовы не былі ўсталяваныя. Артыкул можа быць няправільна прачытаны. + Удзельнікі й ліцэнзіі + Стваральнікі + Мова гэтай старонкі не падтрымліваецца. Артыкул можа быць няправільна прачытаны. Ня знойдзеныя ўсталяваныя праграмы для гэтага тыпу файлу Ня знойдзеныя загалоўкі зьместу Каб атрымаць доступ да зьместу оф-лайн, нам трэба мець доступ да вашага сховішча @@ -44,10 +48,16 @@ Выдаліць гэты элемэнт? Уся гісторыя ачышчаная Ачысьціць усю гісторыю? + Падзяліцца файламі ZIM з: Выдаліць + Скасаваць Нядаўні пошук выдалены + Каб убачыць зьмест артыкулу, можаце прагарнуць улева Зразумела Ці ведалі вы? + Скасаваць + Закладка закрытая + Закладкі закрытыя Закладка дададзеная Калі ласка, ацаніце нас Ацаніць! @@ -57,12 +67,21 @@ Адкрыць новую ўкладку на фоне Пры адкрыцьці новай укладкі, яна будзе адкрытая на заднім пляне Дадаткова + Пошук у Kiwix Прылада + Анляйн + Бібліятэка Што робіць Kiwix? + Хоць Kiwix першапачаткова быў распрацаваны для афляйнавай падтрымкі Вікіпэдыі, але можа чытаць іншыя віды зьместу. Дзе зьмест? Выбачайце, мы не змаглі выдаліць некаторыя файлы. Паспрабуйце скарыстацца файлавым кіраўніком. Спыніць загрузку? Вы ўпэўненыя, што хочаце спыніць гэтую загрузку? + Няўдалая спроба ініцыялізацыі Тэксту-ў-Размову. Калі ласка, паспрабуйце яшчэ раз + засталося + Сёньня + Учора + Папярэджваць падчас уводу вонкавых спасылак Вы ўводзіце вонкавую спасылку. Гэта можа прывесьці да зьняцьця грошай мабільным апэратарам ці проста не спрацаваць, калі вы знаходзіцеся ў офлайне. Хочаце працягнуць? Болей не пытаць Выбраныя мовы: From c3d110f6a67c97ffc343bd74a7f6f51fafc34c4d Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 22 Oct 2024 14:20:00 +0530 Subject: [PATCH 02/22] Retrieving page history from room --- .../core/dao/PageHistoryRoomDao.kt | 3 +- .../kiwix/kiwixmobile/core/data/DataSource.kt | 3 +- .../kiwix/kiwixmobile/core/data/Repository.kt | 9 ++- .../core/main/CoreReaderFragment.kt | 55 ++++++++++++++++--- .../core/main/MainRepositoryActions.kt | 11 ++++ .../page/history/adapter/PageHistoryItem.kt | 5 ++ 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt index 93e8deaa35..afe290bfa6 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt @@ -29,7 +29,7 @@ abstract class PageHistoryRoomDao { @Insert abstract fun insertPageHistoryItem(pageHistoryRoomEntity: PageHistoryRoomEntity) - @Query("SELECT * FROM PageHistoryRoomEntity") + @Query("SELECT * FROM PageHistoryRoomEntity ORDER BY isForward ASC,timestamp DESC") abstract fun getAllPageHistory(): Flowable> @Query("Delete from PageHistoryRoomEntity") @@ -37,7 +37,6 @@ abstract class PageHistoryRoomDao { fun clearPageHistoryWithPrimaryKey() { clearPageHistory() - resetPrimaryKey() } @Query("DELETE FROM sqlite_sequence WHERE name='PageHistoryRoomEntity'") diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt index 3a2d4d20a3..7c1cd599b7 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt @@ -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.PageHistoryRoomEntity 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 @@ -56,6 +57,6 @@ interface DataSource { fun deleteNotes(noteList: List): Completable fun insertPageHistoryItem(pageHistory: PageHistoryItem): Completable - fun getAllPageHistory(): Flowable> + fun getAllPageHistory(): Single> fun clearPageHistory(): Completable } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt index 90aeb258fd..c7f2dc9af3 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt @@ -154,14 +154,17 @@ class Repository @Inject internal constructor( PageHistoryRoomEntity(pageHistory) ) } - .subscribeOn(io) + .subscribeOn(ioThread) override fun getAllPageHistory() = - pageHistoryRoomDao.getAllPageHistory() as Flowable> + pageHistoryRoomDao.getAllPageHistory() + .first(emptyList()) + .subscribeOn(ioThread) + .observeOn(mainThread) override fun clearPageHistory(): Completable = Completable.fromAction(pageHistoryRoomDao::clearPageHistoryWithPrimaryKey) - .subscribeOn(io) + .subscribeOn(ioThread) override fun deleteNote(noteTitle: String): Completable = Completable.fromAction { notesRoomDao.deleteNote(noteTitle) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 3be6fd19dd..7381ea0673 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -132,6 +132,7 @@ import org.kiwix.kiwixmobile.core.navigateToAppSettings import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryClickListener import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryDialog +import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem @@ -192,7 +193,8 @@ abstract class CoreReaderFragment : WebViewProvider, ReadAloudCallbacks, NavigationHistoryClickListener, - ShowDonationDialogCallback { + ShowDonationDialogCallback, + DataCallback { protected val webViewList: MutableList = ArrayList() private val webUrlsProcessor = BehaviorProcessor.create() private var fragmentReaderBinding: FragmentReaderBinding? = null @@ -326,7 +328,6 @@ abstract class CoreReaderFragment : private lateinit var serviceConnection: ServiceConnection private var readAloudService: ReadAloudService? = null private var navigationHistoryList: MutableList = ArrayList() - private var pageTimeStamp: MutableList = ArrayList() private var isReadSelection = false private var isReadAloudServiceRunning = false private var readerLifeCycleScope: CoroutineScope? = null @@ -993,6 +994,7 @@ abstract class CoreReaderFragment : override fun clearHistory() { getCurrentWebView()?.clearHistory() + repositoryActions?.clearPageHistory() updateBottomToolbarArrowsAlpha() toast(R.string.navigation_history_cleared) } @@ -1931,10 +1933,44 @@ abstract class CoreReaderFragment : } } + private fun loadWebViewHistory(pageHistory: List) { + val backStack = pageHistory.filter { !it.isForward } + val forwardStack = pageHistory.filter(PageHistoryItem::isForward) + activity.toast("${pageHistory.size} ${backStack.size}", Toast.LENGTH_LONG) + val currentPage = getCurrentWebView()?.copyBackForwardList()?.currentItem?.url + + // Now, restore the back and forward history manually + // First restore back history + backStack.indices.reversed() + .asSequence() + .map { backStack[it] } + .forEach { url -> loadUrlWithCurrentWebview(url.pageUrl) } + + loadUrlWithCurrentWebview(currentPage) + + forwardStack.indices.reversed() + .asSequence() + .map { forwardStack[it] } + .forEach { url -> loadUrlWithCurrentWebview(url.pageUrl) } + + repeat( + forwardStack.indices.count() + ) { getCurrentWebView()?.goBack() } + } + + override fun onDataFetched(pageHistory: List) { + loadWebViewHistory(pageHistory) + } + + override fun onError(error: Throwable) { + activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG) + } + override fun onResume() { super.onResume() updateBottomToolbarVisibility() updateNightMode() + repositoryActions?.loadPageHistory(this) if (tts == null) { setUpTTS() } @@ -2302,8 +2338,9 @@ abstract class CoreReaderFragment : private fun saveWebBackForwardListToRoom() { val webBackForwardList = getCurrentWebView()?.copyBackForwardList() val currentIndex = webBackForwardList?.currentIndex + val zimId = zimReaderContainer?.zimFileReader?.id ?: "" + if (currentIndex != null) { - repositoryActions?.clearPageHistory() // Save BackStack webBackForwardList.let { historyList -> (0 until historyList.currentIndex) @@ -2311,11 +2348,11 @@ abstract class CoreReaderFragment : .forEach { val historyItem = webBackForwardList.getItemAtIndex(it) val pageHistory = PageHistoryItem( - zimId = zimReaderContainer?.zimFileReader?.id ?: "", + zimId = zimId, title = historyItem.title, pageUrl = historyItem.url, isForward = false, - timeStamp = 0 + timeStamp = it.toLong() ) repositoryActions?.savePageHistory(pageHistory) } @@ -2328,11 +2365,11 @@ abstract class CoreReaderFragment : .forEach { val historyItem = webBackForwardList.getItemAtIndex(it) val pageHistory = PageHistoryItem( - zimId = zimReaderContainer?.zimFileReader?.id ?: "", + zimId = zimId, title = historyItem.title, pageUrl = historyItem.url, isForward = true, - timeStamp = 0 + timeStamp = it.toLong() ) repositoryActions?.savePageHistory(pageHistory) } @@ -2342,8 +2379,9 @@ abstract class CoreReaderFragment : override fun onPause() { super.onPause() - saveTabStates() + repositoryActions?.clearPageHistory() saveWebBackForwardListToRoom() + saveTabStates() Log.d( TAG_KIWIX, "onPause Save current zim file to preferences: " + @@ -2393,7 +2431,6 @@ abstract class CoreReaderFragment : val zimFileReader = zimReaderContainer?.zimFileReader if (hasValidFileAndUrl(getCurrentWebView()?.url, zimFileReader)) { val timeStamp = System.currentTimeMillis() - pageTimeStamp.add(timeStamp) val sdf = SimpleDateFormat( "d MMM yyyy", getCurrentLocale( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt index a98eb705be..6c621aec23 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt @@ -21,6 +21,7 @@ import io.reactivex.disposables.Disposable import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.di.ActivityScope import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem +import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem @@ -39,6 +40,7 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour private var deleteNoteDisposable: Disposable? = null private var savePageHistoryDisposable: Disposable? = null private var clearPageHistoryDisposable: Disposable? = null + private var getPageHistoryDisposable: Disposable? = null fun saveHistory(history: HistoryItem) { saveHistoryDisposable = dataSource.saveHistory(history) @@ -81,6 +83,14 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour .subscribe({}, { e -> Log.e(TAG, "Unable to clear page history", e) }) } + fun loadPageHistory(callBack: DataCallback) { + getPageHistoryDisposable = dataSource.getAllPageHistory() + .map { roomEntities -> + roomEntities.map(::PageHistoryItem) + } + .subscribe(callBack::onDataFetched) { e -> Log.e(TAG, "Unable to load page history", e) } + } + fun dispose() { saveHistoryDisposable?.dispose() saveBookmarkDisposable?.dispose() @@ -89,5 +99,6 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour saveBookDisposable?.dispose() savePageHistoryDisposable?.dispose() clearPageHistoryDisposable?.dispose() + getPageHistoryDisposable?.dispose() } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt index 436ec1da71..65c572e699 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt @@ -52,3 +52,8 @@ data class PageHistoryItem( pageHistoryRoomEntity.timeStamp ) } + +interface DataCallback { + fun onDataFetched(pageHistory: List) + fun onError(error: Throwable) +} From a55033a8b1220546682219ef4004c87b067e79c6 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Thu, 19 Sep 2024 10:48:47 +0530 Subject: [PATCH 03/22] Restoring the internal webbackforwardlist --- .idea/codeStyles/Project.xml | 21 +----- .../core/dao/PageHistoryRoomDao.kt | 2 +- .../core/main/CoreReaderFragment.kt | 65 ++++++++++++++----- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index ec9393b3a7..1e51fb58b9 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,7 +1,5 @@ - - + \ No newline at end of file diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt index afe290bfa6..d5d3b93a93 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt @@ -29,7 +29,7 @@ abstract class PageHistoryRoomDao { @Insert abstract fun insertPageHistoryItem(pageHistoryRoomEntity: PageHistoryRoomEntity) - @Query("SELECT * FROM PageHistoryRoomEntity ORDER BY isForward ASC,timestamp DESC") + @Query("SELECT * FROM PageHistoryRoomEntity ORDER BY isForward ASC,timestamp ASC") abstract fun getAllPageHistory(): Flowable> @Query("Delete from PageHistoryRoomEntity") diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 7381ea0673..61f3b59bc1 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -1936,26 +1936,57 @@ abstract class CoreReaderFragment : private fun loadWebViewHistory(pageHistory: List) { val backStack = pageHistory.filter { !it.isForward } val forwardStack = pageHistory.filter(PageHistoryItem::isForward) - activity.toast("${pageHistory.size} ${backStack.size}", Toast.LENGTH_LONG) - val currentPage = getCurrentWebView()?.copyBackForwardList()?.currentItem?.url + val currentWebView = getCurrentWebView() ?: return + val currentPageUrl = currentWebView.copyBackForwardList().currentItem?.url - // Now, restore the back and forward history manually - // First restore back history - backStack.indices.reversed() - .asSequence() - .map { backStack[it] } - .forEach { url -> loadUrlWithCurrentWebview(url.pageUrl) } + // If backStack and forwardStack are empty, return + if (backStack.isEmpty() && forwardStack.isEmpty()) { + return + } - loadUrlWithCurrentWebview(currentPage) + // Debug info: Toast to check the size of back and forward stack + activity.toast( + "${pageHistory.size} items loaded. Back stack size: ${backStack.size}", + Toast.LENGTH_LONG + ) - forwardStack.indices.reversed() - .asSequence() - .map { forwardStack[it] } - .forEach { url -> loadUrlWithCurrentWebview(url.pageUrl) } + if (backStack.isNotEmpty()) { + // Step 1: Load the first item immediately (0th index) + currentWebView.loadUrl(backStack[0].pageUrl) + } + + currentWebView.postDelayed({ + // Step 2: Clear WebView history after loading the first page + currentWebView.clearHistory() + + // Step 3: Load the remaining items from the backStack (starting from index 1) + backStack.drop(1).forEachIndexed { index, page -> + currentWebView.postDelayed({ + currentWebView.loadUrl(page.pageUrl) + }, index * 500L) // Delay to load each page sequentially + } - repeat( - forwardStack.indices.count() - ) { getCurrentWebView()?.goBack() } + // Step 4: After loading the back stack, load the current page + currentWebView.postDelayed({ + currentPageUrl?.let(::loadUrlWithCurrentWebview) + }, backStack.size * 500L) + + // Step 5: Load forward stack URLs sequentially + currentWebView.postDelayed({ + forwardStack.forEachIndexed { index, page -> + currentWebView.postDelayed({ + currentWebView.loadUrl(page.pageUrl) + }, index * 500L) // Delay for loading forward stack + } + + // Step 6: After loading forward stack, go back to the current page + currentWebView.postDelayed({ + repeat(forwardStack.size) { + currentWebView.goBack() + } + }, forwardStack.size * 500L) // Delay based on forward stack size + }, (backStack.size + 1) * 500L) // Delay based on the back stack size + }, 500L) // Initial delay to allow the first page to load } override fun onDataFetched(pageHistory: List) { @@ -1968,9 +1999,9 @@ abstract class CoreReaderFragment : override fun onResume() { super.onResume() + repositoryActions?.loadPageHistory(this) updateBottomToolbarVisibility() updateNightMode() - repositoryActions?.loadPageHistory(this) if (tts == null) { setUpTTS() } From 3672494d7c802cd1c5d912c7c350e62f7aba71d3 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Thu, 19 Sep 2024 12:51:43 +0530 Subject: [PATCH 04/22] Fixed the detekt issue --- .../core/main/CoreReaderFragment.kt | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 61f3b59bc1..4b7315be5c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -1933,6 +1933,7 @@ abstract class CoreReaderFragment : } } + @Suppress("MagicNumber") private fun loadWebViewHistory(pageHistory: List) { val backStack = pageHistory.filter { !it.isForward } val forwardStack = pageHistory.filter(PageHistoryItem::isForward) @@ -1955,38 +1956,44 @@ abstract class CoreReaderFragment : currentWebView.loadUrl(backStack[0].pageUrl) } - currentWebView.postDelayed({ - // Step 2: Clear WebView history after loading the first page - currentWebView.clearHistory() - - // Step 3: Load the remaining items from the backStack (starting from index 1) - backStack.drop(1).forEachIndexed { index, page -> - currentWebView.postDelayed({ - currentWebView.loadUrl(page.pageUrl) - }, index * 500L) // Delay to load each page sequentially - } - - // Step 4: After loading the back stack, load the current page - currentWebView.postDelayed({ - currentPageUrl?.let(::loadUrlWithCurrentWebview) - }, backStack.size * 500L) + currentWebView.postDelayed( + { + // Step 2: Clear WebView history after loading the first page + currentWebView.clearHistory() - // Step 5: Load forward stack URLs sequentially - currentWebView.postDelayed({ - forwardStack.forEachIndexed { index, page -> + // Step 3: Load the remaining items from the backStack (starting from index 1) + backStack.drop(1).forEachIndexed { index, page -> currentWebView.postDelayed({ currentWebView.loadUrl(page.pageUrl) - }, index * 500L) // Delay for loading forward stack + }, index * 500L) // Delay to load each page sequentially } - // Step 6: After loading forward stack, go back to the current page + // Step 4: After loading the back stack, load the current page currentWebView.postDelayed({ - repeat(forwardStack.size) { - currentWebView.goBack() - } - }, forwardStack.size * 500L) // Delay based on forward stack size - }, (backStack.size + 1) * 500L) // Delay based on the back stack size - }, 500L) // Initial delay to allow the first page to load + currentPageUrl?.let(::loadUrlWithCurrentWebview) + }, backStack.size * 500L) + + // Step 5: Load forward stack URLs sequentially + currentWebView.postDelayed( + { + forwardStack.forEachIndexed { index, page -> + currentWebView.postDelayed({ + currentWebView.loadUrl(page.pageUrl) + }, index * 500L) // Delay for loading forward stack + } + + // Step 6: After loading forward stack, go back to the current page + currentWebView.postDelayed({ + repeat(forwardStack.size) { + currentWebView.goBack() + } + }, forwardStack.size * 500L) // Delay based on forward stack size + }, + (backStack.size + 1) * 500L + ) // Delay based on the back stack size + }, + 500L + ) // Initial delay to allow the first page to load } override fun onDataFetched(pageHistory: List) { From 5be51866b537248888dd0c34f6771cd50aff2a9d Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 22 Oct 2024 14:22:05 +0530 Subject: [PATCH 05/22] Naming convention improved --- ...oryRoomDao.kt => WebViewHistoryRoomDao.kt} | 16 ++--- ...yRoomEntity.kt => WebViewHistoryEntity.kt} | 18 ++--- .../kiwix/kiwixmobile/core/data/DataSource.kt | 10 +-- .../core/data/KiwixRoomDatabase.kt | 32 +++++++-- .../kiwix/kiwixmobile/core/data/Repository.kt | 22 +++--- .../core/di/components/CoreComponent.kt | 4 +- .../core/main/CoreReaderFragment.kt | 72 +++++++++---------- .../core/main/MainRepositoryActions.kt | 16 ++--- ...geHistoryItem.kt => WebViewHistoryItem.kt} | 20 +++--- 9 files changed, 111 insertions(+), 99 deletions(-) rename core/src/main/java/org/kiwix/kiwixmobile/core/dao/{PageHistoryRoomDao.kt => WebViewHistoryRoomDao.kt} (68%) rename core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/{PageHistoryRoomEntity.kt => WebViewHistoryEntity.kt} (73%) rename core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/{PageHistoryItem.kt => WebViewHistoryItem.kt} (73%) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt similarity index 68% rename from core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt rename to core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt index d5d3b93a93..fe10889fd0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/PageHistoryRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt @@ -22,21 +22,21 @@ import androidx.room.Dao import androidx.room.Insert import androidx.room.Query import io.reactivex.Flowable -import org.kiwix.kiwixmobile.core.dao.entities.PageHistoryRoomEntity +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity @Dao -abstract class PageHistoryRoomDao { +abstract class WebViewHistoryRoomDao { @Insert - abstract fun insertPageHistoryItem(pageHistoryRoomEntity: PageHistoryRoomEntity) + abstract fun insertWebViewPageHistoryItem(webViewHistoryEntity: WebViewHistoryEntity) - @Query("SELECT * FROM PageHistoryRoomEntity ORDER BY isForward ASC,timestamp ASC") - abstract fun getAllPageHistory(): Flowable> + @Query("SELECT * FROM WebViewHistoryEntity ORDER BY isForward ASC,timestamp ASC") + abstract fun getAllWebViewPagesHistory(): Flowable> - @Query("Delete from PageHistoryRoomEntity") - abstract fun clearPageHistory() + @Query("Delete from WebViewHistoryEntity") + abstract fun clearWebViewPagesHistory() fun clearPageHistoryWithPrimaryKey() { - clearPageHistory() + clearWebViewPagesHistory() } @Query("DELETE FROM sqlite_sequence WHERE name='PageHistoryRoomEntity'") diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt similarity index 73% rename from core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt rename to core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt index 9acf14a571..5ae7494bdd 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/PageHistoryRoomEntity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt @@ -20,10 +20,10 @@ package org.kiwix.kiwixmobile.core.dao.entities import androidx.room.Entity import androidx.room.PrimaryKey -import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem @Entity -data class PageHistoryRoomEntity( +data class WebViewHistoryEntity( @PrimaryKey(autoGenerate = true) var id: Long = 0L, val zimId: String, val title: String, @@ -31,12 +31,12 @@ data class PageHistoryRoomEntity( val isForward: Boolean = false, val timeStamp: Long ) { - constructor(pageHistoryItem: PageHistoryItem) : this( - pageHistoryItem.databaseId, - pageHistoryItem.zimId, - pageHistoryItem.title, - pageHistoryItem.pageUrl, - pageHistoryItem.isForward, - pageHistoryItem.timeStamp + constructor(webViewHistoryItem: WebViewHistoryItem) : this( + webViewHistoryItem.databaseId, + webViewHistoryItem.zimId, + webViewHistoryItem.title, + webViewHistoryItem.pageUrl, + webViewHistoryItem.isForward, + webViewHistoryItem.timeStamp ) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt index 7c1cd599b7..db32ca28c4 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt @@ -20,11 +20,11 @@ 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.PageHistoryRoomEntity +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 -import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.zim_manager.Language import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem @@ -56,7 +56,7 @@ interface DataSource { fun deleteNote(noteTitle: String): Completable fun deleteNotes(noteList: List): Completable - fun insertPageHistoryItem(pageHistory: PageHistoryItem): Completable - fun getAllPageHistory(): Single> - fun clearPageHistory(): Completable + fun insertWebViewHistoryItem(pageHistory: WebViewHistoryItem): Completable + fun getAllWebViewPagesHistory(): Single> + fun clearWebViewPagesHistory(): Completable } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt index 443b74756b..73ed77a2d0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt @@ -29,12 +29,12 @@ import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao 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.PageHistoryRoomDao +import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao 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.PageHistoryRoomEntity +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter @@ -45,9 +45,9 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter HistoryRoomEntity::class, NotesRoomEntity::class, DownloadRoomEntity::class, - PageHistoryRoomEntity::class + WebViewHistoryEntity::class ], - version = 6, + version = 7, exportSchema = false ) @TypeConverters(HistoryRoomDaoCoverts::class, ZimSourceRoomConverter::class) @@ -56,7 +56,7 @@ abstract class KiwixRoomDatabase : RoomDatabase() { abstract fun historyRoomDao(): HistoryRoomDao abstract fun notesRoomDao(): NotesRoomDao abstract fun downloadRoomDao(): DownloadRoomDao - abstract fun pageHistoryRoomDao(): PageHistoryRoomDao + abstract fun pageHistoryRoomDao(): WebViewHistoryRoomDao companion object { private var db: KiwixRoomDatabase? = null @@ -71,7 +71,8 @@ abstract class KiwixRoomDatabase : RoomDatabase() { MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, - MIGRATION_5_6 + MIGRATION_5_6, + MIGRATION_6_7 ) .build().also { db = it } } @@ -230,6 +231,25 @@ abstract class KiwixRoomDatabase : RoomDatabase() { } } + @Suppress("MagicNumber") + private val MIGRATION_6_7 = object : Migration(6, 7) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("DROP TABLE PageHistoryRoomEntity") + database.execSQL( + """ + CREATE TABLE IF NOT EXISTS `WebViewHistoryEntity` ( + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `zimId` TEXT NOT NULL, + `title` TEXT NOT NULL, + `pageUrl` TEXT NOT NULL, + `isForward` INTEGER NOT NULL DEFAULT 0, + `timeStamp` INTEGER NOT NULL + ) + """ + ) + } + } + fun destroyInstance() { db = null } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt index c7f2dc9af3..56e0a10e88 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt @@ -28,16 +28,16 @@ import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks 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.PageHistoryRoomDao +import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao -import org.kiwix.kiwixmobile.core.dao.entities.PageHistoryRoomEntity +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 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 -import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.zim_manager.Language @@ -58,7 +58,7 @@ class Repository @Inject internal constructor( private val bookDao: NewBookDao, private val libkiwixBookmarks: LibkiwixBookmarks, private val historyRoomDao: HistoryRoomDao, - private val pageHistoryRoomDao: PageHistoryRoomDao, + private val webViewHistoryRoomDao: WebViewHistoryRoomDao, private val notesRoomDao: NotesRoomDao, private val languageDao: NewLanguagesDao, private val recentSearchRoomDao: RecentSearchRoomDao, @@ -148,22 +148,22 @@ class Repository @Inject internal constructor( Completable.fromAction { notesRoomDao.deleteNotes(noteList) } .subscribeOn(ioThread) - override fun insertPageHistoryItem(pageHistory: PageHistoryItem): Completable = + override fun insertWebViewHistoryItem(pageHistory: WebViewHistoryItem): Completable = Completable.fromAction { - pageHistoryRoomDao.insertPageHistoryItem( - PageHistoryRoomEntity(pageHistory) + webViewHistoryRoomDao.insertWebViewPageHistoryItem( + WebViewHistoryEntity(pageHistory) ) } .subscribeOn(ioThread) - override fun getAllPageHistory() = - pageHistoryRoomDao.getAllPageHistory() + override fun getAllWebViewPagesHistory() = + webViewHistoryRoomDao.getAllWebViewPagesHistory() .first(emptyList()) .subscribeOn(ioThread) .observeOn(mainThread) - override fun clearPageHistory(): Completable = - Completable.fromAction(pageHistoryRoomDao::clearPageHistoryWithPrimaryKey) + override fun clearWebViewPagesHistory(): Completable = + Completable.fromAction(webViewHistoryRoomDao::clearPageHistoryWithPrimaryKey) .subscribeOn(ioThread) override fun deleteNote(noteTitle: String): Completable = diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt index 56f4ff9948..adc4f97dff 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt @@ -38,7 +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.PageHistoryRoomDao +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 @@ -107,7 +107,7 @@ interface CoreComponent { fun libkiwixBookmarks(): LibkiwixBookmarks fun recentSearchRoomDao(): RecentSearchRoomDao fun historyRoomDao(): HistoryRoomDao - fun pageHistoryRoomDao(): PageHistoryRoomDao + fun pageHistoryRoomDao(): WebViewHistoryRoomDao fun noteRoomDao(): NotesRoomDao fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator fun context(): Context diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 4b7315be5c..61879a58b1 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -135,7 +135,7 @@ import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryDialog import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem -import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudCallbacks import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudService import org.kiwix.kiwixmobile.core.read_aloud.ReadAloudService.Companion.ACTION_PAUSE_OR_RESUME_TTS @@ -994,7 +994,7 @@ abstract class CoreReaderFragment : override fun clearHistory() { getCurrentWebView()?.clearHistory() - repositoryActions?.clearPageHistory() + repositoryActions?.clearWebViewPagesHistory() updateBottomToolbarArrowsAlpha() toast(R.string.navigation_history_cleared) } @@ -1934,23 +1934,19 @@ abstract class CoreReaderFragment : } @Suppress("MagicNumber") - private fun loadWebViewHistory(pageHistory: List) { + private fun loadWebViewHistory(pageHistory: List) { val backStack = pageHistory.filter { !it.isForward } - val forwardStack = pageHistory.filter(PageHistoryItem::isForward) + val forwardStack = pageHistory.filter(WebViewHistoryItem::isForward) val currentWebView = getCurrentWebView() ?: return val currentPageUrl = currentWebView.copyBackForwardList().currentItem?.url + val currentZimId = zimReaderContainer?.zimFileReader?.id // If backStack and forwardStack are empty, return - if (backStack.isEmpty() && forwardStack.isEmpty()) { + if (backStack.isEmpty() && forwardStack.isEmpty() || currentZimId != pageHistory[0].zimId) { + repositoryActions?.clearWebViewPagesHistory() return } - // Debug info: Toast to check the size of back and forward stack - activity.toast( - "${pageHistory.size} items loaded. Back stack size: ${backStack.size}", - Toast.LENGTH_LONG - ) - if (backStack.isNotEmpty()) { // Step 1: Load the first item immediately (0th index) currentWebView.loadUrl(backStack[0].pageUrl) @@ -1996,7 +1992,7 @@ abstract class CoreReaderFragment : ) // Initial delay to allow the first page to load } - override fun onDataFetched(pageHistory: List) { + override fun onDataFetched(pageHistory: List) { loadWebViewHistory(pageHistory) } @@ -2006,7 +2002,7 @@ abstract class CoreReaderFragment : override fun onResume() { super.onResume() - repositoryActions?.loadPageHistory(this) + repositoryActions?.loadWebViewPagesHistory(this) updateBottomToolbarVisibility() updateNightMode() if (tts == null) { @@ -2381,43 +2377,39 @@ abstract class CoreReaderFragment : if (currentIndex != null) { // Save BackStack webBackForwardList.let { historyList -> - (0 until historyList.currentIndex) - .asSequence() - .forEach { - val historyItem = webBackForwardList.getItemAtIndex(it) - val pageHistory = PageHistoryItem( - zimId = zimId, - title = historyItem.title, - pageUrl = historyItem.url, - isForward = false, - timeStamp = it.toLong() - ) - repositoryActions?.savePageHistory(pageHistory) - } + for (index in 0 until historyList.currentIndex) { + val historyItem = historyList.getItemAtIndex(index) + val pageHistory = WebViewHistoryItem( + zimId = zimId, + title = historyItem.title, + pageUrl = historyItem.url, + isForward = false, + timeStamp = index.toLong() + ) + repositoryActions?.saveWebViewPageHistory(pageHistory) + } } // Save ForwardStack webBackForwardList.let { historyList -> - (historyList.currentIndex + 1 until webBackForwardList.size) - .asSequence() - .forEach { - val historyItem = webBackForwardList.getItemAtIndex(it) - val pageHistory = PageHistoryItem( - zimId = zimId, - title = historyItem.title, - pageUrl = historyItem.url, - isForward = true, - timeStamp = it.toLong() - ) - repositoryActions?.savePageHistory(pageHistory) - } + for (index in (historyList.currentIndex + 1) until historyList.size) { + val historyItem = historyList.getItemAtIndex(index) + val pageHistory = WebViewHistoryItem( + zimId = zimId, + title = historyItem.title, + pageUrl = historyItem.url, + isForward = true, + timeStamp = index.toLong() + ) + repositoryActions?.saveWebViewPageHistory(pageHistory) + } } } } override fun onPause() { super.onPause() - repositoryActions?.clearPageHistory() + repositoryActions?.clearWebViewPagesHistory() saveWebBackForwardListToRoom() saveTabStates() Log.d( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt index 6c621aec23..8872398d30 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt @@ -23,7 +23,7 @@ import org.kiwix.kiwixmobile.core.di.ActivityScope import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem -import org.kiwix.kiwixmobile.core.page.history.adapter.PageHistoryItem +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.utils.files.Log import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk @@ -73,20 +73,20 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour .subscribe({}, { e -> Log.e(TAG, "Unable to save book", e) }) } - fun savePageHistory(pageHistory: PageHistoryItem) { - savePageHistoryDisposable = dataSource.insertPageHistoryItem(pageHistory) + fun saveWebViewPageHistory(pageHistory: WebViewHistoryItem) { + savePageHistoryDisposable = dataSource.insertWebViewHistoryItem(pageHistory) .subscribe({}, { e -> Log.e(TAG, "Unable to save page history", e) }) } - fun clearPageHistory() { - clearPageHistoryDisposable = dataSource.clearPageHistory() + fun clearWebViewPagesHistory() { + clearPageHistoryDisposable = dataSource.clearWebViewPagesHistory() .subscribe({}, { e -> Log.e(TAG, "Unable to clear page history", e) }) } - fun loadPageHistory(callBack: DataCallback) { - getPageHistoryDisposable = dataSource.getAllPageHistory() + fun loadWebViewPagesHistory(callBack: DataCallback) { + getPageHistoryDisposable = dataSource.getAllWebViewPagesHistory() .map { roomEntities -> - roomEntities.map(::PageHistoryItem) + roomEntities.map(::WebViewHistoryItem) } .subscribe(callBack::onDataFetched) { e -> Log.e(TAG, "Unable to load page history", e) } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt similarity index 73% rename from core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt rename to core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt index 65c572e699..aa4e912861 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/PageHistoryItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt @@ -18,9 +18,9 @@ package org.kiwix.kiwixmobile.core.page.history.adapter -import org.kiwix.kiwixmobile.core.dao.entities.PageHistoryRoomEntity +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity -data class PageHistoryItem( +data class WebViewHistoryItem( val databaseId: Long = 0L, val zimId: String, val title: String, @@ -43,17 +43,17 @@ data class PageHistoryItem( timeStamp ) - constructor(pageHistoryRoomEntity: PageHistoryRoomEntity) : this( - pageHistoryRoomEntity.id, - pageHistoryRoomEntity.zimId, - pageHistoryRoomEntity.title, - pageHistoryRoomEntity.pageUrl, - pageHistoryRoomEntity.isForward, - pageHistoryRoomEntity.timeStamp + constructor(webViewHistoryEntity: WebViewHistoryEntity) : this( + webViewHistoryEntity.id, + webViewHistoryEntity.zimId, + webViewHistoryEntity.title, + webViewHistoryEntity.pageUrl, + webViewHistoryEntity.isForward, + webViewHistoryEntity.timeStamp ) } interface DataCallback { - fun onDataFetched(pageHistory: List) + fun onDataFetched(pageHistory: List) fun onError(error: Throwable) } From 82956423752c499e2e123b851848a5ec5a39af86 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Thu, 19 Sep 2024 23:05:32 +0530 Subject: [PATCH 06/22] Code factor improvements --- .../java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 61879a58b1..8f327cce22 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -2392,7 +2392,7 @@ abstract class CoreReaderFragment : // Save ForwardStack webBackForwardList.let { historyList -> - for (index in (historyList.currentIndex + 1) until historyList.size) { + for (index in historyList.currentIndex + 1 until historyList.size) { val historyItem = historyList.getItemAtIndex(index) val pageHistory = WebViewHistoryItem( zimId = zimId, From 55e679857074a449a3874086e70d9115d73999d3 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 20 Sep 2024 18:37:39 +0530 Subject: [PATCH 07/22] Automated changes reverted --- .idea/codeStyles/Project.xml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 1e51fb58b9..ec9393b3a7 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,5 +1,7 @@ + - \ No newline at end of file + From d7e4627b610cb38ae5b676efaed54f68729b389a Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 20 Sep 2024 18:54:09 +0530 Subject: [PATCH 08/22] Automated changes reverted --- .../res/values-b+be+tarask+old/strings.xml | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/core/src/main/res/values-b+be+tarask+old/strings.xml b/core/src/main/res/values-b+be+tarask+old/strings.xml index e692b350e5..f7b21eb9f4 100644 --- a/core/src/main/res/values-b+be+tarask+old/strings.xml +++ b/core/src/main/res/values-b+be+tarask+old/strings.xml @@ -1,4 +1,8 @@ + Дапамога Галоўная @@ -11,36 +15,28 @@ Чытаць уголас Спыніць чытаньне ўголас Падтрымаць Kiwix - Падтрымка %s - Пра праграму %s Пункт доступу WiFi Захаваць мэдыя Узьнікла памылка пры захаваньні мэдыяфайлу! Мэдыя-файл захаваны як %s у Downloads/org.kiwix…/ - Пошук - Пошукавы сьпіс Абярыце файл зьместу (*.zim) Адкрыць спасылку ў новай укладцы? - Сэрвісны канал пункту досягу Падобна, што ваш пункт доступу ўжо ўключаны. Каб працягнуць, адключыце пункт доступу вай-фай. Перайсьці да наладаў вай-фаю Немагчыма запусьціць сэрвэр. Калі ласка, уключыце ваш пункт доступу Немагчыма запусьціць сэрвэр. - Дэталі вашага лякальнага пункту досягу. \nSSID: %1$s \nСпокліч: %2$s Памылка: абраны ZIM-файл ня знойдзены. Памылка: абраны файл не зьяўляецца слушным ZIM-файлам. Памылка: загрузка артыкула (Url: %1$s) не атрымалася. Інфармацыя Вэрсія - Цёмны рэжым - Паказваць артыкулы ў інвэртаваных колерах + Начны рэжым + Паказваць артыкулы ў інвэртаваных колерах Вярнуцца ўгару Паказваць кнопку ў канцы старонкі для пракручваньня ўверх Мова Абярыце мову - Удзельнікі й ліцэнзіі - Стваральнікі - Мова гэтай старонкі не падтрымліваецца. Артыкул можа быць няправільна прачытаны. + Мова гэтай старонкі не падтрымліваецца або адпаведныя зьвесткі мовы не былі ўсталяваныя. Артыкул можа быць няправільна прачытаны. Ня знойдзеныя ўсталяваныя праграмы для гэтага тыпу файлу Ня знойдзеныя загалоўкі зьместу Каб атрымаць доступ да зьместу оф-лайн, нам трэба мець доступ да вашага сховішча @@ -48,16 +44,10 @@ Выдаліць гэты элемэнт? Уся гісторыя ачышчаная Ачысьціць усю гісторыю? - Падзяліцца файламі ZIM з: Выдаліць - Скасаваць Нядаўні пошук выдалены - Каб убачыць зьмест артыкулу, можаце прагарнуць улева Зразумела Ці ведалі вы? - Скасаваць - Закладка закрытая - Закладкі закрытыя Закладка дададзеная Калі ласка, ацаніце нас Ацаніць! @@ -67,21 +57,12 @@ Адкрыць новую ўкладку на фоне Пры адкрыцьці новай укладкі, яна будзе адкрытая на заднім пляне Дадаткова - Пошук у Kiwix Прылада - Анляйн - Бібліятэка Што робіць Kiwix? - Хоць Kiwix першапачаткова быў распрацаваны для афляйнавай падтрымкі Вікіпэдыі, але можа чытаць іншыя віды зьместу. Дзе зьмест? Выбачайце, мы не змаглі выдаліць некаторыя файлы. Паспрабуйце скарыстацца файлавым кіраўніком. Спыніць загрузку? Вы ўпэўненыя, што хочаце спыніць гэтую загрузку? - Няўдалая спроба ініцыялізацыі Тэксту-ў-Размову. Калі ласка, паспрабуйце яшчэ раз - засталося - Сёньня - Учора - Папярэджваць падчас уводу вонкавых спасылак Вы ўводзіце вонкавую спасылку. Гэта можа прывесьці да зьняцьця грошай мабільным апэратарам ці проста не спрацаваць, калі вы знаходзіцеся ў офлайне. Хочаце працягнуць? Болей не пытаць Выбраныя мовы: From c64052d591367154065b76840e080d55bf96112c Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 11 Oct 2024 11:39:38 +0530 Subject: [PATCH 09/22] Updated room schema --- .../core/data/KiwixRoomDatabase.kt | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt index 73ed77a2d0..667ffc309c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt @@ -47,7 +47,7 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter DownloadRoomEntity::class, WebViewHistoryEntity::class ], - version = 7, + version = 6, exportSchema = false ) @TypeConverters(HistoryRoomDaoCoverts::class, ZimSourceRoomConverter::class) @@ -71,8 +71,7 @@ abstract class KiwixRoomDatabase : RoomDatabase() { MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, - MIGRATION_5_6, - MIGRATION_6_7 + MIGRATION_5_6 ) .build().also { db = it } } @@ -216,25 +215,6 @@ 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 `PageHistoryRoomEntity` ( - `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - `zimId` TEXT NOT NULL, - `title` TEXT NOT NULL, - `pageUrl` TEXT NOT NULL, - `isForward` INTEGER NOT NULL DEFAULT 0 - `timeStamp` INTEGER NOT NULL - ) - """ - ) - } - } - - @Suppress("MagicNumber") - private val MIGRATION_6_7 = object : Migration(6, 7) { - override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("DROP TABLE PageHistoryRoomEntity") database.execSQL( """ CREATE TABLE IF NOT EXISTS `WebViewHistoryEntity` ( From 07208c768acb98dfde7961c57846316a9aa7b760 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 18 Oct 2024 11:02:41 +0530 Subject: [PATCH 10/22] Naming conventions improved and some reviewed changes --- .../core/data/KiwixRoomDatabase.kt | 2 +- .../core/di/components/CoreComponent.kt | 2 +- .../core/di/modules/DatabaseModule.kt | 2 +- .../core/main/CoreReaderFragment.kt | 72 ++++++++++--------- .../core/main/MainRepositoryActions.kt | 24 +++---- .../history/adapter/WebViewHistoryItem.kt | 2 +- core/src/main/res/values/strings.xml | 1 + 7 files changed, 57 insertions(+), 48 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt index 667ffc309c..16a3998779 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt @@ -56,7 +56,7 @@ abstract class KiwixRoomDatabase : RoomDatabase() { abstract fun historyRoomDao(): HistoryRoomDao abstract fun notesRoomDao(): NotesRoomDao abstract fun downloadRoomDao(): DownloadRoomDao - abstract fun pageHistoryRoomDao(): WebViewHistoryRoomDao + abstract fun webViewHistoryRoomDao(): WebViewHistoryRoomDao companion object { private var db: KiwixRoomDatabase? = null diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt index adc4f97dff..00628c480d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/components/CoreComponent.kt @@ -107,7 +107,7 @@ interface CoreComponent { fun libkiwixBookmarks(): LibkiwixBookmarks fun recentSearchRoomDao(): RecentSearchRoomDao fun historyRoomDao(): HistoryRoomDao - fun pageHistoryRoomDao(): WebViewHistoryRoomDao + fun webViewHistoryRoomDao(): WebViewHistoryRoomDao fun noteRoomDao(): NotesRoomDao fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator fun context(): Context diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt index 667807cafc..31eb596cb7 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/DatabaseModule.kt @@ -88,7 +88,7 @@ open class DatabaseModule { @Provides @Singleton - fun providePageHistoryRoomDao(db: KiwixRoomDatabase) = db.pageHistoryRoomDao() + fun provideWebViewHistoryRoomDao(db: KiwixRoomDatabase) = db.webViewHistoryRoomDao() @Singleton @Provides diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 8f327cce22..647cfeffe0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -132,7 +132,7 @@ import org.kiwix.kiwixmobile.core.navigateToAppSettings import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryClickListener import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryDialog -import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem @@ -194,7 +194,7 @@ abstract class CoreReaderFragment : ReadAloudCallbacks, NavigationHistoryClickListener, ShowDonationDialogCallback, - DataCallback { + WebViewHistoryCallback { protected val webViewList: MutableList = ArrayList() private val webUrlsProcessor = BehaviorProcessor.create() private var fragmentReaderBinding: FragmentReaderBinding? = null @@ -994,7 +994,7 @@ abstract class CoreReaderFragment : override fun clearHistory() { getCurrentWebView()?.clearHistory() - repositoryActions?.clearWebViewPagesHistory() + repositoryActions?.clearWebViewPageHistory() updateBottomToolbarArrowsAlpha() toast(R.string.navigation_history_cleared) } @@ -1943,7 +1943,7 @@ abstract class CoreReaderFragment : // If backStack and forwardStack are empty, return if (backStack.isEmpty() && forwardStack.isEmpty() || currentZimId != pageHistory[0].zimId) { - repositoryActions?.clearWebViewPagesHistory() + repositoryActions?.clearWebViewPageHistory() return } @@ -1997,7 +1997,7 @@ abstract class CoreReaderFragment : } override fun onError(error: Throwable) { - activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG) + activity.toast(R.string.could_not_restore_web_view_history, Toast.LENGTH_LONG) } override fun onResume() { @@ -2369,6 +2369,26 @@ abstract class CoreReaderFragment : editor.apply() } + private fun saveWebViewHistoryItems( + startIndex: Int, + endIndex: Int, + zimId: String, + isForward: Boolean, + historyList: WebBackForwardList + ) { + for (index in startIndex until endIndex) { + val historyItem = historyList.getItemAtIndex(index) + val pageHistory = WebViewHistoryItem( + zimId = zimId, + title = historyItem.title, + pageUrl = historyItem.url, + isForward = isForward, + timeStamp = index.toLong() + ) + repositoryActions?.saveWebViewPageHistory(pageHistory) + } + } + private fun saveWebBackForwardListToRoom() { val webBackForwardList = getCurrentWebView()?.copyBackForwardList() val currentIndex = webBackForwardList?.currentIndex @@ -2376,40 +2396,28 @@ abstract class CoreReaderFragment : if (currentIndex != null) { // Save BackStack - webBackForwardList.let { historyList -> - for (index in 0 until historyList.currentIndex) { - val historyItem = historyList.getItemAtIndex(index) - val pageHistory = WebViewHistoryItem( - zimId = zimId, - title = historyItem.title, - pageUrl = historyItem.url, - isForward = false, - timeStamp = index.toLong() - ) - repositoryActions?.saveWebViewPageHistory(pageHistory) - } - } + saveWebViewHistoryItems( + 0, + webBackForwardList.currentIndex, + zimId, + false, + webBackForwardList + ) // Save ForwardStack - webBackForwardList.let { historyList -> - for (index in historyList.currentIndex + 1 until historyList.size) { - val historyItem = historyList.getItemAtIndex(index) - val pageHistory = WebViewHistoryItem( - zimId = zimId, - title = historyItem.title, - pageUrl = historyItem.url, - isForward = true, - timeStamp = index.toLong() - ) - repositoryActions?.saveWebViewPageHistory(pageHistory) - } - } + saveWebViewHistoryItems( + currentIndex + 1, + webBackForwardList.size, + zimId, + true, + webBackForwardList + ) } } override fun onPause() { super.onPause() - repositoryActions?.clearWebViewPagesHistory() + repositoryActions?.clearWebViewPageHistory() saveWebBackForwardListToRoom() saveTabStates() Log.d( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt index 8872398d30..3fb5d5abf0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt @@ -21,7 +21,7 @@ import io.reactivex.disposables.Disposable import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.di.ActivityScope import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem -import org.kiwix.kiwixmobile.core.page.history.adapter.DataCallback +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryCallback 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 @@ -38,9 +38,9 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour private var saveNoteDisposable: Disposable? = null private var saveBookDisposable: Disposable? = null private var deleteNoteDisposable: Disposable? = null - private var savePageHistoryDisposable: Disposable? = null - private var clearPageHistoryDisposable: Disposable? = null - private var getPageHistoryDisposable: Disposable? = null + private var saveWebViewHistoryDisposable: Disposable? = null + private var clearWebViewHistoryDisposable: Disposable? = null + private var getWebViewHistoryDisposable: Disposable? = null fun saveHistory(history: HistoryItem) { saveHistoryDisposable = dataSource.saveHistory(history) @@ -74,17 +74,17 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour } fun saveWebViewPageHistory(pageHistory: WebViewHistoryItem) { - savePageHistoryDisposable = dataSource.insertWebViewHistoryItem(pageHistory) + saveWebViewHistoryDisposable = dataSource.insertWebViewHistoryItem(pageHistory) .subscribe({}, { e -> Log.e(TAG, "Unable to save page history", e) }) } - fun clearWebViewPagesHistory() { - clearPageHistoryDisposable = dataSource.clearWebViewPagesHistory() + fun clearWebViewPageHistory() { + clearWebViewHistoryDisposable = dataSource.clearWebViewPagesHistory() .subscribe({}, { e -> Log.e(TAG, "Unable to clear page history", e) }) } - fun loadWebViewPagesHistory(callBack: DataCallback) { - getPageHistoryDisposable = dataSource.getAllWebViewPagesHistory() + fun loadWebViewPagesHistory(callBack: WebViewHistoryCallback) { + getWebViewHistoryDisposable = dataSource.getAllWebViewPagesHistory() .map { roomEntities -> roomEntities.map(::WebViewHistoryItem) } @@ -97,8 +97,8 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour saveNoteDisposable?.dispose() deleteNoteDisposable?.dispose() saveBookDisposable?.dispose() - savePageHistoryDisposable?.dispose() - clearPageHistoryDisposable?.dispose() - getPageHistoryDisposable?.dispose() + saveWebViewHistoryDisposable?.dispose() + clearWebViewHistoryDisposable?.dispose() + getWebViewHistoryDisposable?.dispose() } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt index aa4e912861..fdcf7c8e4c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt @@ -53,7 +53,7 @@ data class WebViewHistoryItem( ) } -interface DataCallback { +interface WebViewHistoryCallback { fun onDataFetched(pageHistory: List) fun onError(error: Throwable) } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index bc9dd344b8..faae6049f5 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -225,6 +225,7 @@ Close all tabs Close tab Could not restore tabs. + Could not restore web view history Pending In Progress Complete From 8002e609c26a8b0256ea128bbc58911980e9839f Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 22 Oct 2024 14:39:34 +0530 Subject: [PATCH 11/22] Fixed detekt issue. --- core/detekt_baseline.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/detekt_baseline.xml b/core/detekt_baseline.xml index a8770c6630..79441f26c6 100644 --- a/core/detekt_baseline.xml +++ b/core/detekt_baseline.xml @@ -12,7 +12,7 @@ LongParameterList:MainMenu.kt$MainMenu$( private val activity: Activity, zimFileReader: ZimFileReader?, menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, disableReadAloud: Boolean = false, disableTabs: Boolean = false, private val menuClickListener: MenuClickListener ) LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList<KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean ) 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" ) - 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 ) + 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 ) 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 ) MagicNumber:ArticleCount.kt$ArticleCount$3 MagicNumber:CompatFindActionModeCallback.kt$CompatFindActionModeCallback$100 From 5df09c672db4e406230c33f5eafe9601c8104e2f Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 11:44:02 +0530 Subject: [PATCH 12/22] Implemented new approach to save and retrieve the webView history. --- .../destination/reader/KiwixReaderFragment.kt | 13 +- .../core/dao/WebViewHistoryRoomDao.kt | 9 +- .../core/dao/entities/WebViewHistoryEntity.kt | 42 ++- .../kiwix/kiwixmobile/core/data/DataSource.kt | 4 +- .../core/data/KiwixRoomDatabase.kt | 18 +- .../kiwix/kiwixmobile/core/data/Repository.kt | 16 +- .../core/main/CoreReaderFragment.kt | 272 +++++++----------- .../core/main/MainRepositoryActions.kt | 23 +- .../history/adapter/WebViewHistoryItem.kt | 34 +-- core/src/main/res/values/strings.xml | 1 - .../custom/main/CustomReaderFragment.kt | 22 +- 11 files changed, 204 insertions(+), 250 deletions(-) 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 2dcb640bda..35f3729136 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 @@ -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 @@ -235,22 +236,20 @@ class KiwixReaderFragment : CoreReaderFragment() { } /** - * 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 webViewHistoryItemList JSON string 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. */ override fun restoreViewStateOnValidJSON( - zimArticles: String?, - zimPositions: String?, + webViewHistoryItemList: List, currentTab: Int, restoreOrigin: RestoreOrigin ) { @@ -270,7 +269,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } else { zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } - restoreTabs(zimArticles, zimPositions, currentTab) + restoreTabs(webViewHistoryItemList, currentTab) } else { getCurrentWebView()?.snack(string.zim_not_opened) exitBook() // hide the options for zim file to avoid unexpected UI behavior @@ -279,7 +278,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } FromSearchScreen -> { - restoreTabs(zimArticles, zimPositions, currentTab) + restoreTabs(webViewHistoryItemList, currentTab) } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt index fe10889fd0..19431f9687 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/WebViewHistoryRoomDao.kt @@ -26,10 +26,15 @@ import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity @Dao abstract class WebViewHistoryRoomDao { + + fun insertWebViewPageHistoryItem(webViewHistoryEntity: WebViewHistoryEntity) { + insertWebViewPageHistoryItems(listOf(webViewHistoryEntity)) + } + @Insert - abstract fun insertWebViewPageHistoryItem(webViewHistoryEntity: WebViewHistoryEntity) + abstract fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List) - @Query("SELECT * FROM WebViewHistoryEntity ORDER BY isForward ASC,timestamp ASC") + @Query("SELECT * FROM WebViewHistoryEntity ORDER BY webViewIndex ASC") abstract fun getAllWebViewPagesHistory(): Flowable> @Query("Delete from WebViewHistoryEntity") diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt index 5ae7494bdd..1e868b133b 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/WebViewHistoryEntity.kt @@ -18,25 +18,51 @@ 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 title: String, - val pageUrl: String, - val isForward: Boolean = false, - val timeStamp: Long + val webViewIndex: Int, + val webViewCurrentPosition: Int, + @TypeConverters(BundleRoomConverter::class) + val webViewBackForwardListBundle: Bundle? ) { constructor(webViewHistoryItem: WebViewHistoryItem) : this( webViewHistoryItem.databaseId, webViewHistoryItem.zimId, - webViewHistoryItem.title, - webViewHistoryItem.pageUrl, - webViewHistoryItem.isForward, - webViewHistoryItem.timeStamp + 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 + } +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt index db32ca28c4..149258556c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt @@ -56,7 +56,7 @@ interface DataSource { fun deleteNote(noteTitle: String): Completable fun deleteNotes(noteList: List): Completable - fun insertWebViewHistoryItem(pageHistory: WebViewHistoryItem): Completable + suspend fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List) fun getAllWebViewPagesHistory(): Single> - fun clearWebViewPagesHistory(): Completable + suspend fun clearWebViewPagesHistory() } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt index 16a3998779..8c0de8564d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/KiwixRoomDatabase.kt @@ -29,13 +29,14 @@ import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao 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.WebViewHistoryRoomDao 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.WebViewHistoryEntity 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") @@ -50,7 +51,11 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter 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 @@ -220,10 +225,9 @@ abstract class KiwixRoomDatabase : RoomDatabase() { CREATE TABLE IF NOT EXISTS `WebViewHistoryEntity` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `zimId` TEXT NOT NULL, - `title` TEXT NOT NULL, - `pageUrl` TEXT NOT NULL, - `isForward` INTEGER NOT NULL DEFAULT 0, - `timeStamp` INTEGER NOT NULL + `webViewIndex` INTEGER NOT NULL, + `webViewCurrentPosition` INTEGER NOT NULL, + `webViewBackForwardListBundle` BLOB NULL ) """ ) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt index 56e0a10e88..3a06d4f781 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt @@ -148,13 +148,9 @@ class Repository @Inject internal constructor( Completable.fromAction { notesRoomDao.deleteNotes(noteList) } .subscribeOn(ioThread) - override fun insertWebViewHistoryItem(pageHistory: WebViewHistoryItem): Completable = - Completable.fromAction { - webViewHistoryRoomDao.insertWebViewPageHistoryItem( - WebViewHistoryEntity(pageHistory) - ) - } - .subscribeOn(ioThread) + override suspend fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List) { + webViewHistoryRoomDao.insertWebViewPageHistoryItems(webViewHistoryEntityList) + } override fun getAllWebViewPagesHistory() = webViewHistoryRoomDao.getAllWebViewPagesHistory() @@ -162,9 +158,9 @@ class Repository @Inject internal constructor( .subscribeOn(ioThread) .observeOn(mainThread) - override fun clearWebViewPagesHistory(): Completable = - Completable.fromAction(webViewHistoryRoomDao::clearPageHistoryWithPrimaryKey) - .subscribeOn(ioThread) + override suspend fun clearWebViewPagesHistory() { + webViewHistoryRoomDao.clearPageHistoryWithPrimaryKey() + } override fun deleteNote(noteTitle: String): Completable = Completable.fromAction { notesRoomDao.deleteNote(noteTitle) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 647cfeffe0..d8ff4fb8a8 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -99,7 +99,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch -import org.json.JSONArray +import kotlinx.coroutines.withContext import org.json.JSONException import org.kiwix.kiwixmobile.core.BuildConfig import org.kiwix.kiwixmobile.core.DarkModeConfig @@ -108,6 +108,7 @@ import org.kiwix.kiwixmobile.core.StorageObserver import org.kiwix.kiwixmobile.core.base.BaseFragment import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity import org.kiwix.kiwixmobile.core.databinding.FragmentReaderBinding import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.consumeObservable import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.hasNotificationPermission @@ -132,7 +133,6 @@ import org.kiwix.kiwixmobile.core.navigateToAppSettings import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryClickListener import org.kiwix.kiwixmobile.core.page.history.NavigationHistoryDialog -import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryCallback import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem import org.kiwix.kiwixmobile.core.page.history.adapter.NavigationHistoryListItem import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem @@ -158,14 +158,11 @@ import org.kiwix.kiwixmobile.core.utils.REQUEST_POST_NOTIFICATION_PERMISSION import org.kiwix.kiwixmobile.core.utils.REQUEST_STORAGE_PERMISSION import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.StyleUtils.getAttributes -import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_ARTICLES import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE -import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_POSITIONS import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_TAB import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED import org.kiwix.kiwixmobile.core.utils.TAG_FILE_SEARCHED_NEW_TAB import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX -import org.kiwix.kiwixmobile.core.utils.UpdateUtils.reformatProviderUrl import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog import org.kiwix.kiwixmobile.core.utils.dialog.UnsupportedMimeTypeHandler @@ -193,8 +190,7 @@ abstract class CoreReaderFragment : WebViewProvider, ReadAloudCallbacks, NavigationHistoryClickListener, - ShowDonationDialogCallback, - WebViewHistoryCallback { + ShowDonationDialogCallback { protected val webViewList: MutableList = ArrayList() private val webUrlsProcessor = BehaviorProcessor.create() private var fragmentReaderBinding: FragmentReaderBinding? = null @@ -288,6 +284,7 @@ abstract class CoreReaderFragment : private var bottomToolbarToc: ImageView? = null private var isFirstTimeMainPageLoaded = true + private var isFromManageExternalLaunch = false @JvmField @Inject @@ -994,7 +991,9 @@ abstract class CoreReaderFragment : override fun clearHistory() { getCurrentWebView()?.clearHistory() - repositoryActions?.clearWebViewPageHistory() + CoroutineScope(Dispatchers.IO).launch { + repositoryActions?.clearWebViewPageHistory() + } updateBottomToolbarArrowsAlpha() toast(R.string.navigation_history_cleared) } @@ -1308,7 +1307,7 @@ abstract class CoreReaderFragment : } } - private fun initalizeWebView(url: String): KiwixWebView? { + private fun initalizeWebView(url: String, shouldLoadUrl: Boolean = true): KiwixWebView? { if (isAdded) { val attrs = requireActivity().getAttributes(R.xml.webview) val webView: KiwixWebView? = try { @@ -1321,7 +1320,9 @@ abstract class CoreReaderFragment : null } webView?.let { - loadUrl(url, it) + if (shouldLoadUrl) { + loadUrl(url, it) + } setUpWithTextToSpeech(it) documentParser?.initInterface(it) ServiceWorkerUninitialiser(::openMainPage).initInterface(it) @@ -1354,8 +1355,12 @@ abstract class CoreReaderFragment : newTab(url, false) } - private fun newTab(url: String, selectTab: Boolean = true): KiwixWebView? { - val webView = initalizeWebView(url) + private fun newTab( + url: String, + selectTab: Boolean = true, + shouldLoadUrl: Boolean = true + ): KiwixWebView? { + val webView = initalizeWebView(url, shouldLoadUrl) webView?.let { webViewList.add(it) if (selectTab) { @@ -1684,7 +1689,12 @@ abstract class CoreReaderFragment : unsupportedMimeTypeHandler?.showSaveOrOpenUnsupportedFilesDialog(url, documentType) } - suspend fun openZimFile(zimReaderSource: ZimReaderSource, isCustomApp: Boolean = false) { + suspend fun openZimFile( + zimReaderSource: ZimReaderSource, + isCustomApp: Boolean = false, + isFromManageExternalLaunch: Boolean = false + ) { + this.isFromManageExternalLaunch = isFromManageExternalLaunch if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || isCustomApp) { if (zimReaderSource.canOpenInLibkiwix()) { // Show content if there is `Open Library` button showing @@ -1729,7 +1739,9 @@ abstract class CoreReaderFragment : val zimFileReader = zimReaderContainer.zimFileReader zimFileReader?.let { zimFileReader -> // uninitialized the service worker to fix https://github.com/kiwix/kiwix-android/issues/2561 - openArticle(UNINITIALISER_ADDRESS) + if (!isFromManageExternalLaunch) { + openArticle(UNINITIALISER_ADDRESS) + } mainMenu?.onFileOpened(urlIsValid()) setUpBookmarks(zimFileReader) } ?: kotlin.run { @@ -1933,76 +1945,8 @@ abstract class CoreReaderFragment : } } - @Suppress("MagicNumber") - private fun loadWebViewHistory(pageHistory: List) { - val backStack = pageHistory.filter { !it.isForward } - val forwardStack = pageHistory.filter(WebViewHistoryItem::isForward) - val currentWebView = getCurrentWebView() ?: return - val currentPageUrl = currentWebView.copyBackForwardList().currentItem?.url - val currentZimId = zimReaderContainer?.zimFileReader?.id - - // If backStack and forwardStack are empty, return - if (backStack.isEmpty() && forwardStack.isEmpty() || currentZimId != pageHistory[0].zimId) { - repositoryActions?.clearWebViewPageHistory() - return - } - - if (backStack.isNotEmpty()) { - // Step 1: Load the first item immediately (0th index) - currentWebView.loadUrl(backStack[0].pageUrl) - } - - currentWebView.postDelayed( - { - // Step 2: Clear WebView history after loading the first page - currentWebView.clearHistory() - - // Step 3: Load the remaining items from the backStack (starting from index 1) - backStack.drop(1).forEachIndexed { index, page -> - currentWebView.postDelayed({ - currentWebView.loadUrl(page.pageUrl) - }, index * 500L) // Delay to load each page sequentially - } - - // Step 4: After loading the back stack, load the current page - currentWebView.postDelayed({ - currentPageUrl?.let(::loadUrlWithCurrentWebview) - }, backStack.size * 500L) - - // Step 5: Load forward stack URLs sequentially - currentWebView.postDelayed( - { - forwardStack.forEachIndexed { index, page -> - currentWebView.postDelayed({ - currentWebView.loadUrl(page.pageUrl) - }, index * 500L) // Delay for loading forward stack - } - - // Step 6: After loading forward stack, go back to the current page - currentWebView.postDelayed({ - repeat(forwardStack.size) { - currentWebView.goBack() - } - }, forwardStack.size * 500L) // Delay based on forward stack size - }, - (backStack.size + 1) * 500L - ) // Delay based on the back stack size - }, - 500L - ) // Initial delay to allow the first page to load - } - - override fun onDataFetched(pageHistory: List) { - loadWebViewHistory(pageHistory) - } - - override fun onError(error: Throwable) { - activity.toast(R.string.could_not_restore_web_view_history, Toast.LENGTH_LONG) - } - override fun onResume() { super.onResume() - repositoryActions?.loadWebViewPagesHistory(this) updateBottomToolbarVisibility() updateNightMode() if (tts == null) { @@ -2350,75 +2294,53 @@ abstract class CoreReaderFragment : } private fun saveTabStates() { - val settings = requireActivity().getSharedPreferences( - SharedPreferenceUtil.PREF_KIWIX_MOBILE, - 0 - ) - val editor = settings.edit() - val urls = JSONArray() - val positions = JSONArray() - for (view in webViewList) { - if (view.url == null) continue - urls.put(view.url) - positions.put(view.scrollY) - } - editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase()) - editor.putString(TAG_CURRENT_ARTICLES, "$urls") - editor.putString(TAG_CURRENT_POSITIONS, "$positions") - editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex) - editor.apply() - } - - private fun saveWebViewHistoryItems( - startIndex: Int, - endIndex: Int, - zimId: String, - isForward: Boolean, - historyList: WebBackForwardList - ) { - for (index in startIndex until endIndex) { - val historyItem = historyList.getItemAtIndex(index) - val pageHistory = WebViewHistoryItem( - zimId = zimId, - title = historyItem.title, - pageUrl = historyItem.url, - isForward = isForward, - timeStamp = index.toLong() - ) - repositoryActions?.saveWebViewPageHistory(pageHistory) - } - } - - private fun saveWebBackForwardListToRoom() { - val webBackForwardList = getCurrentWebView()?.copyBackForwardList() - val currentIndex = webBackForwardList?.currentIndex - val zimId = zimReaderContainer?.zimFileReader?.id ?: "" - - if (currentIndex != null) { - // Save BackStack - saveWebViewHistoryItems( - 0, - webBackForwardList.currentIndex, - zimId, - false, - webBackForwardList + CoroutineScope(Dispatchers.Main).launch { + // clear the previous history saved in database + withContext(Dispatchers.IO) { + repositoryActions?.clearWebViewPageHistory() + } + val settings = requireActivity().getSharedPreferences( + SharedPreferenceUtil.PREF_KIWIX_MOBILE, + 0 ) - - // Save ForwardStack - saveWebViewHistoryItems( - currentIndex + 1, - webBackForwardList.size, - zimId, - true, - webBackForwardList + val editor = settings.edit() + val webViewHistoryEntityList = arrayListOf() + webViewList.forEachIndexed { index, view -> + if (view.url == null) return@forEachIndexed + getWebViewHistoryEntity(view, index)?.let(webViewHistoryEntityList::add) + } + withContext(Dispatchers.IO) { + repositoryActions?.saveWebViewPageHistory(webViewHistoryEntityList) + } + editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase()) + editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex) + editor.apply() + } + } + + private fun getWebViewHistoryEntity( + webView: KiwixWebView, + webViewIndex: Int + ): WebViewHistoryEntity? { + val bundle = Bundle() + val webBackForwardList = webView.saveState(bundle) + val zimId = zimReaderContainer?.zimFileReader?.id + + if (zimId != null && webBackForwardList != null && webBackForwardList.size > 0) { + return WebViewHistoryEntity( + WebViewHistoryItem( + zimId = zimId, + webViewIndex = webViewIndex, + webViewPosition = webView.scrollY, + webViewBackForwardList = bundle + ) ) } + return null } override fun onPause() { super.onPause() - repositoryActions?.clearWebViewPageHistory() - saveWebBackForwardListToRoom() saveTabStates() Log.d( TAG_KIWIX, @@ -2445,9 +2367,9 @@ abstract class CoreReaderFragment : // it will not remove the service worker from the history, so it will remain in the history. // To clear this, we are clearing the history when the main page is loaded for the first time. val mainPageUrl = zimReaderContainer?.mainPage - if (mainPageUrl != null && - isFirstTimeMainPageLoaded && - getCurrentWebView()?.url?.endsWith(mainPageUrl) == true + if (isFirstTimeMainPageLoaded && + !isFromManageExternalLaunch && + mainPageUrl?.let { getCurrentWebView()?.url?.endsWith(it) } == true ) { // Set isFirstTimeMainPageLoaded to false. This ensures that if the user clicks // on the home menu after visiting multiple pages, the history will not be erased. @@ -2606,9 +2528,7 @@ abstract class CoreReaderFragment : ) } - private fun isInvalidJson(jsonString: String?): Boolean = - jsonString == null || jsonString == "[]" - + @SuppressLint("CheckResult") protected fun manageExternalLaunchAndRestoringViewState( restoreOrigin: RestoreOrigin = FromExternalLaunch ) { @@ -2616,14 +2536,22 @@ abstract class CoreReaderFragment : SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0 ) - val zimArticles = settings.getString(TAG_CURRENT_ARTICLES, null) - val zimPositions = settings.getString(TAG_CURRENT_POSITIONS, null) val currentTab = safelyGetCurrentTab(settings) - if (isInvalidJson(zimArticles) || isInvalidJson(zimPositions)) { - restoreViewStateOnInvalidJSON() - } else { - restoreViewStateOnValidJSON(zimArticles, zimPositions, currentTab, restoreOrigin) - } + repositoryActions?.loadWebViewPagesHistory() + ?.subscribe({ webViewHistoryItemList -> + Log.e( + "VALID_DATA", + "manageExternalLaunchAndRestoringViewState: ${webViewHistoryItemList.size}" + ) + if (webViewHistoryItemList.isEmpty()) { + restoreViewStateOnInvalidJSON() + return@subscribe + } + restoreViewStateOnValidJSON(webViewHistoryItemList, currentTab, restoreOrigin) + }, { + Log.e("INVALID_DATA", "manageExternalLaunchAndRestoringViewState: $it") + restoreViewStateOnInvalidJSON() + }) } private fun safelyGetCurrentTab(settings: SharedPreferences): Int = @@ -2632,36 +2560,35 @@ abstract class CoreReaderFragment : /* 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( - zimArticles: String?, - zimPositions: String?, + webViewHistoryItemList: List, currentTab: Int ) { try { - val urls = JSONArray(zimArticles) - val positions = JSONArray(zimPositions) currentWebViewIndex = 0 tabsAdapter?.apply { + webViewList.removeAt(0) notifyItemRemoved(0) notifyDataSetChanged() } - var cursor = 0 - getCurrentWebView()?.let { kiwixWebView -> - kiwixWebView.loadUrl(reformatProviderUrl(urls.getString(cursor))) - kiwixWebView.scrollY = positions.getInt(cursor) - cursor++ - while (cursor < urls.length()) { - newTab(reformatProviderUrl(urls.getString(cursor))) - kiwixWebView.scrollY = positions.getInt(cursor) - cursor++ + webViewHistoryItemList.forEach { webViewHistoryItem -> + newTab("", shouldLoadUrl = false)?.let { + restoreTabState(it, webViewHistoryItem) } - selectTab(currentTab) } + selectTab(currentTab) } catch (e: JSONException) { Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", e) activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG) } } + private fun restoreTabState(webView: KiwixWebView, webViewHistoryItem: WebViewHistoryItem?) { + webViewHistoryItem?.webViewBackForwardListBundle?.let { bundle -> + webView.restoreState(bundle) + webView.scrollY = webViewHistoryItem.webViewCurrentPosition + } + } + override fun onReadAloudPauseOrResume(isPauseTTS: Boolean) { tts?.currentTTSTask?.let { if (it.paused != isPauseTTS) { @@ -2736,8 +2663,7 @@ abstract class CoreReaderFragment : * when handling valid JSON scenarios. */ protected abstract fun restoreViewStateOnValidJSON( - zimArticles: String?, - zimPositions: String?, + webViewHistoryItemList: List, currentTab: Int, restoreOrigin: RestoreOrigin ) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt index 3fb5d5abf0..1b9b60cd71 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainRepositoryActions.kt @@ -17,11 +17,12 @@ */ package org.kiwix.kiwixmobile.core.main +import io.reactivex.Single import io.reactivex.disposables.Disposable +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.di.ActivityScope import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem -import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryCallback 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 @@ -73,23 +74,23 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour .subscribe({}, { e -> Log.e(TAG, "Unable to save book", e) }) } - fun saveWebViewPageHistory(pageHistory: WebViewHistoryItem) { - saveWebViewHistoryDisposable = dataSource.insertWebViewHistoryItem(pageHistory) - .subscribe({}, { e -> Log.e(TAG, "Unable to save page history", e) }) + suspend fun saveWebViewPageHistory(webViewHistoryEntityList: List) { + dataSource.insertWebViewPageHistoryItems(webViewHistoryEntityList) } - fun clearWebViewPageHistory() { - clearWebViewHistoryDisposable = dataSource.clearWebViewPagesHistory() - .subscribe({}, { e -> Log.e(TAG, "Unable to clear page history", e) }) + suspend fun clearWebViewPageHistory() { + dataSource.clearWebViewPagesHistory() } - fun loadWebViewPagesHistory(callBack: WebViewHistoryCallback) { - getWebViewHistoryDisposable = dataSource.getAllWebViewPagesHistory() + fun loadWebViewPagesHistory(): Single> = + dataSource.getAllWebViewPagesHistory() .map { roomEntities -> roomEntities.map(::WebViewHistoryItem) } - .subscribe(callBack::onDataFetched) { e -> Log.e(TAG, "Unable to load page history", e) } - } + .onErrorReturn { + Log.e(TAG, "Unable to load page history", it) + emptyList() + } fun dispose() { saveHistoryDisposable?.dispose() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt index fdcf7c8e4c..1e19d5340c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt @@ -18,42 +18,34 @@ package org.kiwix.kiwixmobile.core.page.history.adapter +import android.os.Bundle import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity data class WebViewHistoryItem( val databaseId: Long = 0L, val zimId: String, - val title: String, - val pageUrl: String, - val isForward: Boolean, - val timeStamp: Long + val webViewIndex: Int, + val webViewCurrentPosition: Int, + val webViewBackForwardListBundle: Bundle? ) { constructor( zimId: String, - title: String, - pageUrl: String, - isForward: Boolean, - timeStamp: Long + webViewIndex: Int, + webViewPosition: Int, + webViewBackForwardList: Bundle ) : this( 0L, zimId, - title, - pageUrl, - isForward, - timeStamp + webViewIndex, + webViewPosition, + webViewBackForwardList ) constructor(webViewHistoryEntity: WebViewHistoryEntity) : this( webViewHistoryEntity.id, webViewHistoryEntity.zimId, - webViewHistoryEntity.title, - webViewHistoryEntity.pageUrl, - webViewHistoryEntity.isForward, - webViewHistoryEntity.timeStamp + webViewHistoryEntity.webViewIndex, + webViewHistoryEntity.webViewCurrentPosition, + webViewHistoryEntity.webViewBackForwardListBundle ) } - -interface WebViewHistoryCallback { - fun onDataFetched(pageHistory: List) - fun onError(error: Throwable) -} diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index faae6049f5..bc9dd344b8 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -225,7 +225,6 @@ Close all tabs Close tab Could not restore tabs. - Could not restore web view history Pending In Progress Complete 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 690cd65791..55e24a16a9 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 @@ -40,6 +40,7 @@ import org.kiwix.kiwixmobile.core.extensions.isFileExist import org.kiwix.kiwixmobile.core.main.CoreReaderFragment import org.kiwix.kiwixmobile.core.main.MainMenu import org.kiwix.kiwixmobile.core.main.RestoreOrigin +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.reader.ZimReaderSource import org.kiwix.kiwixmobile.core.utils.LanguageUtils import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower @@ -143,8 +144,7 @@ class CustomReaderFragment : CoreReaderFragment() { // See https://github.com/kiwix/kiwix-android/issues/3541 zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } else { - openObbOrZim() - manageExternalLaunchAndRestoringViewState() + openObbOrZim(true) } requireArguments().clear() } @@ -163,13 +163,12 @@ class CustomReaderFragment : CoreReaderFragment() { * and loads the last opened article in the specified tab. */ override fun restoreViewStateOnValidJSON( - zimArticles: String?, - zimPositions: String?, + webViewHistoryItemList: List, currentTab: Int, // Unused in custom apps as there is only one ZIM file that is already set. restoreOrigin: RestoreOrigin ) { - restoreTabs(zimArticles, zimPositions, currentTab) + restoreTabs(webViewHistoryItemList, currentTab) } /** @@ -184,7 +183,7 @@ class CustomReaderFragment : CoreReaderFragment() { ) } - private fun openObbOrZim() { + private fun openObbOrZim(shouldManageExternalLaunch: Boolean = false) { customFileValidator.validate( onFilesFound = { coreReaderLifeCycleScope?.launch { @@ -196,7 +195,8 @@ class CustomReaderFragment : CoreReaderFragment() { null, it.assetFileDescriptorList ), - true + true, + shouldManageExternalLaunch ) // Save book in the database to display it in `ZimHostFragment`. zimReaderContainer?.zimFileReader?.let { zimFileReader -> @@ -207,11 +207,17 @@ class CustomReaderFragment : CoreReaderFragment() { val bookOnDisk = BookOnDisk(zimFileReader) repositoryActions?.saveBook(bookOnDisk) } + if (shouldManageExternalLaunch) { + manageExternalLaunchAndRestoringViewState() + } } is ValidationState.HasBothFiles -> { it.zimFile.delete() - openZimFile(ZimReaderSource(it.obbFile), true) + openZimFile(ZimReaderSource(it.obbFile), true, shouldManageExternalLaunch) + if (shouldManageExternalLaunch) { + manageExternalLaunchAndRestoringViewState() + } } else -> {} From d7f0ecc16b8adf14d8fb34aafe70993786b69090 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 25 Oct 2024 16:23:23 +0530 Subject: [PATCH 13/22] 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. --- .../destination/reader/KiwixReaderFragment.kt | 44 +++- .../kiwix/kiwixmobile/core/data/DataSource.kt | 1 - .../kiwix/kiwixmobile/core/data/Repository.kt | 9 +- .../core/main/CoreReaderFragment.kt | 218 +++++++++++++++--- .../kiwix/kiwixmobile/core/main/MainMenu.kt | 3 +- .../custom/main/CustomReaderFragment.kt | 40 +++- 6 files changed, 254 insertions(+), 61 deletions(-) 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 35f3729136..69ad126b0b 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 @@ -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.reader.ZimReaderSource 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.TAG_CURRENT_FILE import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX @@ -69,6 +70,7 @@ private const val HIDE_TAB_SWITCHER_DELAY: Long = 300 class KiwixReaderFragment : CoreReaderFragment() { private var isFullScreenVideo: Boolean = false + private var searchItemToOpen: SearchItemToOpen? = null override fun inject(baseActivity: BaseActivity) { baseActivity.cachedComponent.inject(this) @@ -112,7 +114,16 @@ class KiwixReaderFragment : CoreReaderFragment() { } else { val restoreOrigin = 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() @@ -152,6 +163,18 @@ class KiwixReaderFragment : CoreReaderFragment() { 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() { drawerLayout = requireActivity().findViewById(R.id.navigation_container) tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view) @@ -230,7 +253,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") exitBook() } @@ -243,15 +266,16 @@ class KiwixReaderFragment : CoreReaderFragment() { * 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 webViewHistoryItemList JSON string representing the list of articles to be restored. - * @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( + override fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, - restoreOrigin: RestoreOrigin + restoreOrigin: RestoreOrigin, + onComplete: () -> Unit ) { when (restoreOrigin) { FromExternalLaunch -> { @@ -261,7 +285,7 @@ class KiwixReaderFragment : CoreReaderFragment() { 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()}" @@ -269,7 +293,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } else { zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } - restoreTabs(webViewHistoryItemList, currentTab) + restoreTabs(webViewHistoryItemList, currentTab, onComplete) } else { getCurrentWebView()?.snack(string.zim_not_opened) exitBook() // hide the options for zim file to avoid unexpected UI behavior @@ -278,7 +302,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } FromSearchScreen -> { - restoreTabs(webViewHistoryItemList, currentTab) + restoreTabs(webViewHistoryItemList, currentTab, onComplete) } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt index 149258556c..45713cb45a 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/DataSource.kt @@ -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.history.adapter.HistoryListItem 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.zim_manager.Language import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt index 3a06d4f781..8938cf27bd 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/Repository.kt @@ -28,8 +28,8 @@ import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks 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.WebViewHistoryRoomDao 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 @@ -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.history.adapter.HistoryListItem 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.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.zim_manager.Language @@ -148,7 +147,9 @@ class Repository @Inject internal constructor( Completable.fromAction { notesRoomDao.deleteNotes(noteList) } .subscribeOn(ioThread) - override suspend fun insertWebViewPageHistoryItems(webViewHistoryEntityList: List) { + override suspend fun insertWebViewPageHistoryItems( + webViewHistoryEntityList: List + ) { webViewHistoryRoomDao.insertWebViewPageHistoryItems(webViewHistoryEntityList) } @@ -159,7 +160,7 @@ class Repository @Inject internal constructor( .observeOn(mainThread) override suspend fun clearWebViewPagesHistory() { - webViewHistoryRoomDao.clearPageHistoryWithPrimaryKey() + webViewHistoryRoomDao.clearWebViewPagesHistory() } override fun deleteNote(noteTitle: String): Completable = diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index d8ff4fb8a8..2bd05781c8 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -100,8 +100,8 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.json.JSONException import org.kiwix.kiwixmobile.core.BuildConfig +import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.DarkModeConfig import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.StorageObserver @@ -285,6 +285,7 @@ abstract class CoreReaderFragment : private var isFirstTimeMainPageLoaded = true private var isFromManageExternalLaunch = false + private var shouldSaveTabsOnPause = true @JvmField @Inject @@ -420,6 +421,9 @@ abstract class CoreReaderFragment : savedInstanceState: Bundle? ) { 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() donationDialogHandler?.setDonationDialogCallBack(this) val activity = requireActivity() as AppCompatActivity? @@ -1307,6 +1311,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? { if (isAdded) { val attrs = requireActivity().getAttributes(R.xml.webview) @@ -1355,6 +1368,17 @@ abstract class CoreReaderFragment : 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( url: String, selectTab: Boolean = true, @@ -1527,6 +1551,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") override fun onReadAloudMenuClicked() { if (requireActivity().hasNotificationPermission(sharedPreferenceUtil)) { @@ -2062,7 +2097,21 @@ abstract class CoreReaderFragment : 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) { createNewTab() } @@ -2293,13 +2342,42 @@ abstract class CoreReaderFragment : 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 { // clear the previous history saved in database withContext(Dispatchers.IO) { repositoryActions?.clearWebViewPageHistory() } - val settings = requireActivity().getSharedPreferences( + val coreApp = sharedPreferenceUtil?.context as CoreApp + val settings = coreApp.getMainActivity().getSharedPreferences( SharedPreferenceUtil.PREF_KIWIX_MOBILE, 0 ) @@ -2315,10 +2393,43 @@ abstract class CoreReaderFragment : editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase()) editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex) 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, webViewIndex: Int ): WebViewHistoryEntity? { @@ -2339,14 +2450,14 @@ abstract class CoreReaderFragment : return null } + /** + * @see shouldSaveTabsOnPause + */ override fun onPause() { super.onPause() - saveTabStates() - Log.d( - TAG_KIWIX, - "onPause Save current zim file to preferences: " + - "${zimReaderContainer?.zimReaderSource?.toDatabase()}" - ) + if (shouldSaveTabsOnPause) { + saveTabStates() + } } override fun webViewUrlLoading() { @@ -2530,7 +2641,8 @@ abstract class CoreReaderFragment : @SuppressLint("CheckResult") protected fun manageExternalLaunchAndRestoringViewState( - restoreOrigin: RestoreOrigin = FromExternalLaunch + restoreOrigin: RestoreOrigin = FromExternalLaunch, + onComplete: () -> Unit = {} ) { val settings = requireActivity().getSharedPreferences( SharedPreferenceUtil.PREF_KIWIX_MOBILE, @@ -2539,29 +2651,49 @@ abstract class CoreReaderFragment : val currentTab = safelyGetCurrentTab(settings) repositoryActions?.loadWebViewPagesHistory() ?.subscribe({ webViewHistoryItemList -> - Log.e( - "VALID_DATA", - "manageExternalLaunchAndRestoringViewState: ${webViewHistoryItemList.size}" - ) if (webViewHistoryItemList.isEmpty()) { - restoreViewStateOnInvalidJSON() + restoreViewStateOnInvalidWebViewHistory() return@subscribe } - restoreViewStateOnValidJSON(webViewHistoryItemList, currentTab, restoreOrigin) + restoreViewStateOnValidWebViewHistory( + webViewHistoryItemList, + currentTab, + restoreOrigin, + onComplete + ) }, { - Log.e("INVALID_DATA", "manageExternalLaunchAndRestoringViewState: $it") - restoreViewStateOnInvalidJSON() + restoreViewStateOnInvalidWebViewHistory() }) } private fun safelyGetCurrentTab(settings: SharedPreferences): Int = 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( webViewHistoryItemList: List, - currentTab: Int + currentTab: Int, + onComplete: () -> Unit ) { try { currentWebViewIndex = 0 @@ -2576,12 +2708,25 @@ abstract class CoreReaderFragment : } } selectTab(currentTab) - } catch (e: JSONException) { - Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", e) + onComplete.invoke() + } catch (ignore: Exception) { + Log.w(TAG_KIWIX, "Kiwix shared preferences corrupted", ignore) activity.toast(R.string.could_not_restore_tabs, Toast.LENGTH_LONG) } } + /** + * 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?) { webViewHistoryItem?.webViewBackForwardListBundle?.let { bundle -> webView.restoreState(bundle) @@ -2655,28 +2800,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 * KiwixReaderFragment, should review and consider the implementations in those subclasses - * (e.g., CustomReaderFragment.restoreViewStateOnValidJSON, - * KiwixReaderFragment.restoreViewStateOnValidJSON) to ensure consistent behavior - * when handling valid JSON scenarios. + * (e.g., CustomReaderFragment.restoreViewStateOnValidWebViewHistory, + * KiwixReaderFragment.restoreViewStateOnValidWebViewHistory) to ensure consistent behavior + * when handling valid webViewHistory scenarios. */ - protected abstract fun restoreViewStateOnValidJSON( + protected abstract fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, - restoreOrigin: RestoreOrigin + restoreOrigin: RestoreOrigin, + onComplete: () -> Unit ) /** - * Restores the view state when the attempt to read JSON from shared preferences fails - * due to invalid or corrupted data. Developers modifying this method in subclasses, such as + * Restores the view state when the attempt to read webViewHistory from room database fails + * 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 - * in those subclasses (e.g., CustomReaderFragment.restoreViewStateOnInvalidJSON, - * KiwixReaderFragment.restoreViewStateOnInvalidJSON) to ensure consistent behavior + * in those subclasses (e.g., CustomReaderFragment.restoreViewStateOnInvalidWebViewHistory, + * KiwixReaderFragment.restoreViewStateOnInvalidWebViewHistory) to ensure consistent behavior * when handling invalid JSON scenarios. */ - abstract fun restoreViewStateOnInvalidJSON() + abstract fun restoreViewStateOnInvalidWebViewHistory() } enum class RestoreOrigin { diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainMenu.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainMenu.kt index 6123f1cfb8..277b8a2fef 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainMenu.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/MainMenu.kt @@ -61,6 +61,7 @@ class MainMenu( fun onRandomArticleMenuClicked() fun onReadAloudMenuClicked() fun onFullscreenMenuClicked() + fun onSearchMenuClickedMenuClicked() } init { @@ -154,7 +155,7 @@ class MainMenu( } private fun navigateToSearch(): Boolean { - (activity as CoreMainActivity).openSearch(isOpenedFromTabView = isInTabSwitcher) + menuClickListener.onSearchMenuClickedMenuClicked() return true } 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 55e24a16a9..b2c87e7144 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 @@ -150,25 +150,26 @@ class CustomReaderFragment : CoreReaderFragment() { } /** - * Restores the view state when the attempt to read JSON from shared preferences fails - * due to invalid or corrupted data. In this case, it opens the homepage of the zim file, - * as custom apps always have the zim file available. + * Restores the view state when the attempt to read web view history from the room database fails + * 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 restoreViewStateOnInvalidJSON() { + override fun restoreViewStateOnInvalidWebViewHistory() { openHomeScreen() } /** - * Restores the view state when the JSON data is valid. This method restores the tabs - * and loads the last opened article in the specified tab. + * Restores the view state when the webViewHistory data is valid. + * This method restores the tabs with webView pages history. */ - override fun restoreViewStateOnValidJSON( + override fun restoreViewStateOnValidWebViewHistory( webViewHistoryItemList: List, currentTab: Int, // 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) { customFileValidator.validate( onFilesFound = { From 3a7181d837ffd5bbbe62163e980469961b34010e Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 25 Oct 2024 17:17:21 +0530 Subject: [PATCH 14/22] Fixed: Searched item was not opening in custom apps. * Created a common approach for both Kiwix and custom apps to open the searched item after restoring the tabs, ensuring smooth functionality in both applications and reducing the likelihood of future errors. --- .../destination/reader/KiwixReaderFragment.kt | 25 +------------ .../core/main/CoreReaderFragment.kt | 37 +++++++++++++------ .../custom/main/CustomReaderFragment.kt | 3 ++ 3 files changed, 29 insertions(+), 36 deletions(-) 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 69ad126b0b..7a858fc090 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 @@ -58,7 +58,6 @@ 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.search.viewmodel.effects.SearchItemToOpen import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX @@ -70,7 +69,6 @@ private const val HIDE_TAB_SWITCHER_DELAY: Long = 300 class KiwixReaderFragment : CoreReaderFragment() { private var isFullScreenVideo: Boolean = false - private var searchItemToOpen: SearchItemToOpen? = null override fun inject(baseActivity: BaseActivity) { baseActivity.cachedComponent.inject(this) @@ -114,16 +112,7 @@ class KiwixReaderFragment : CoreReaderFragment() { } else { val restoreOrigin = if (args.searchItemTitle.isNotEmpty()) FromSearchScreen else FromExternalLaunch - 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 - } + manageExternalLaunchAndRestoringViewState(restoreOrigin) } } requireArguments().clear() @@ -163,18 +152,6 @@ class KiwixReaderFragment : CoreReaderFragment() { 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() { drawerLayout = requireActivity().findViewById(R.id.navigation_container) tableDrawerRightContainer = requireActivity().findViewById(R.id.reader_drawer_nav_view) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 2bd05781c8..9f4341f6d0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -286,6 +286,7 @@ abstract class CoreReaderFragment : private var isFirstTimeMainPageLoaded = true private var isFromManageExternalLaunch = false private var shouldSaveTabsOnPause = true + private var searchItemToOpen: SearchItemToOpen? = null @JvmField @Inject @@ -516,7 +517,7 @@ abstract class CoreReaderFragment : requireActivity().observeNavigationResult( TAG_FILE_SEARCHED, viewLifecycleOwner, - Observer(::openSearchItem) + Observer(::storeSearchItem) ) handleClicks() } @@ -2097,6 +2098,18 @@ abstract class CoreReaderFragment : openSearch("", isOpenedFromTabView = false, isVoice) } + /** + * 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. + */ + private fun storeSearchItem(item: SearchItemToOpen) { + searchItemToOpen = item + } + /** * Opens a search item based on its properties. * @@ -2105,13 +2118,8 @@ abstract class CoreReaderFragment : * 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) { + private fun openSearchItem(item: SearchItemToOpen) { if (item.shouldOpenInNewTab) { createNewTab() } @@ -2641,8 +2649,7 @@ abstract class CoreReaderFragment : @SuppressLint("CheckResult") protected fun manageExternalLaunchAndRestoringViewState( - restoreOrigin: RestoreOrigin = FromExternalLaunch, - onComplete: () -> Unit = {} + restoreOrigin: RestoreOrigin = FromExternalLaunch ) { val settings = requireActivity().getSharedPreferences( SharedPreferenceUtil.PREF_KIWIX_MOBILE, @@ -2658,9 +2665,15 @@ abstract class CoreReaderFragment : restoreViewStateOnValidWebViewHistory( webViewHistoryItemList, currentTab, - restoreOrigin, - onComplete - ) + 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 openSearchItem + // method to open the specified search item. After opening, it sets `searchItemToOpen` + // to null to prevent any unexpected behavior on subsequent calls. + searchItemToOpen?.let(::openSearchItem) + searchItemToOpen = null + } }, { restoreViewStateOnInvalidWebViewHistory() }) 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 b2c87e7144..dc56ff7f04 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 @@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.custom.main import android.app.Dialog import android.os.Bundle +import android.util.Log import android.view.Menu import android.view.MenuInflater import android.view.View @@ -139,11 +140,13 @@ class CustomReaderFragment : CoreReaderFragment() { private fun loadPageFromNavigationArguments() { val args = CustomReaderFragmentArgs.fromBundle(requireArguments()) if (args.pageUrl.isNotEmpty()) { + Log.e("OPEN_PAGE", "loadPageFromNavigationArguments: ${args.pageUrl}") loadUrlWithCurrentWebview(args.pageUrl) // Setup bookmark for current book // See https://github.com/kiwix/kiwix-android/issues/3541 zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } else { + Log.e("OPEN_PAGE", "loadPageFromNavigationArguments: else part") openObbOrZim(true) } requireArguments().clear() From af146ae507a4b83ab71e054f3070e21569f406fa Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 25 Oct 2024 17:32:08 +0530 Subject: [PATCH 15/22] Fixed: FindInPage functionality not working in Kiwix and custom apps. * Established a unified approach for both Kiwix and custom apps to trigger findInPage after restoring tabs, ensuring consistent functionality across both applications and minimizing potential future errors. --- .../core/main/CoreReaderFragment.kt | 31 ++++++++++++++++--- .../custom/main/CustomReaderFragment.kt | 3 -- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 9f4341f6d0..60900fb28f 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -287,6 +287,7 @@ abstract class CoreReaderFragment : private var isFromManageExternalLaunch = false private var shouldSaveTabsOnPause = true private var searchItemToOpen: SearchItemToOpen? = null + private var findInPageTitle: String? = null @JvmField @Inject @@ -512,7 +513,7 @@ abstract class CoreReaderFragment : requireActivity().observeNavigationResult( FIND_IN_PAGE_SEARCH_STRING, viewLifecycleOwner, - Observer(::findInPage) + Observer(::storeFindInPageTitle) ) requireActivity().observeNavigationResult( TAG_FILE_SEARCHED, @@ -2291,6 +2292,23 @@ abstract class CoreReaderFragment : } } + /** + * Stores the given title for a "find in page" search operation. + * This title is used later when triggering the "find in page" functionality. + * + * @param title The title or keyword to search for within the current WebView content. + */ + private fun storeFindInPageTitle(title: String) { + findInPageTitle = title + } + + /** + * Initiates the "find in page" UI for searching within the current WebView content. + * If the `compatCallback` is active, it sets up the WebView to search for the + * specified title and displays the search input UI. + * + * @param title The search term or keyword to locate within the page. If null, no action is taken. + */ private fun findInPage(title: String?) { // if the search is localized trigger find in page UI. compatCallback?.apply { @@ -2667,12 +2685,15 @@ abstract class CoreReaderFragment : currentTab, 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 openSearchItem - // method to open the specified search item. After opening, it sets `searchItemToOpen` - // to null to prevent any unexpected behavior on subsequent calls. + // This lambda is executed after the tabs have been restored. It checks if there is a + // search item to open. If `searchItemToOpen` is not null, it calls `openSearchItem` + // 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. searchItemToOpen?.let(::openSearchItem) searchItemToOpen = null + findInPageTitle?.let(::findInPage) + findInPageTitle = null } }, { restoreViewStateOnInvalidWebViewHistory() 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 dc56ff7f04..b2c87e7144 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 @@ -20,7 +20,6 @@ package org.kiwix.kiwixmobile.custom.main import android.app.Dialog import android.os.Bundle -import android.util.Log import android.view.Menu import android.view.MenuInflater import android.view.View @@ -140,13 +139,11 @@ class CustomReaderFragment : CoreReaderFragment() { private fun loadPageFromNavigationArguments() { val args = CustomReaderFragmentArgs.fromBundle(requireArguments()) if (args.pageUrl.isNotEmpty()) { - Log.e("OPEN_PAGE", "loadPageFromNavigationArguments: ${args.pageUrl}") loadUrlWithCurrentWebview(args.pageUrl) // Setup bookmark for current book // See https://github.com/kiwix/kiwix-android/issues/3541 zimReaderContainer?.zimFileReader?.let(::setUpBookmarks) } else { - Log.e("OPEN_PAGE", "loadPageFromNavigationArguments: else part") openObbOrZim(true) } requireArguments().clear() From 0141329c60284862100ac13ef7162e153fda7221 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 11:46:31 +0530 Subject: [PATCH 16/22] Improved the saving of tabs. --- .../core/main/CoreReaderFragment.kt | 77 ++++++++----------- 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 60900fb28f..1ab98dbacd 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -99,6 +99,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import org.kiwix.kiwixmobile.core.BuildConfig import org.kiwix.kiwixmobile.core.CoreApp @@ -285,7 +287,7 @@ abstract class CoreReaderFragment : private var isFirstTimeMainPageLoaded = true private var isFromManageExternalLaunch = false - private var shouldSaveTabsOnPause = true + private val savingTabsMutex = Mutex() private var searchItemToOpen: SearchItemToOpen? = null private var findInPageTitle: String? = null @@ -423,9 +425,6 @@ abstract class CoreReaderFragment : savedInstanceState: Bundle? ) { 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() donationDialogHandler?.setDonationDialogCallBack(this) val activity = requireActivity() as AppCompatActivity? @@ -1554,9 +1553,6 @@ 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. @@ -2398,33 +2394,35 @@ abstract class CoreReaderFragment : */ private fun saveTabStates(onComplete: () -> Unit = {}) { CoroutineScope(Dispatchers.Main).launch { - // clear the previous history saved in database - withContext(Dispatchers.IO) { - repositoryActions?.clearWebViewPageHistory() - } - val coreApp = sharedPreferenceUtil?.context as CoreApp - val settings = coreApp.getMainActivity().getSharedPreferences( - SharedPreferenceUtil.PREF_KIWIX_MOBILE, - 0 - ) - val editor = settings.edit() - val webViewHistoryEntityList = arrayListOf() - webViewList.forEachIndexed { index, view -> - if (view.url == null) return@forEachIndexed - getWebViewHistoryEntity(view, index)?.let(webViewHistoryEntityList::add) - } - withContext(Dispatchers.IO) { - repositoryActions?.saveWebViewPageHistory(webViewHistoryEntityList) - } - editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase()) - editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex) - editor.apply() - Log.d( - TAG_KIWIX, - "Save current zim file to preferences: " + - "${zimReaderContainer?.zimReaderSource?.toDatabase()}" - ) - onComplete.invoke() + savingTabsMutex.withLock { + // clear the previous history saved in database + withContext(Dispatchers.IO) { + repositoryActions?.clearWebViewPageHistory() + } + val coreApp = sharedPreferenceUtil?.context as CoreApp + val settings = coreApp.getMainActivity().getSharedPreferences( + SharedPreferenceUtil.PREF_KIWIX_MOBILE, + 0 + ) + val editor = settings.edit() + val webViewHistoryEntityList = arrayListOf() + webViewList.forEachIndexed { index, view -> + if (view.url == null) return@forEachIndexed + getWebViewHistoryEntity(view, index)?.let(webViewHistoryEntityList::add) + } + withContext(Dispatchers.IO) { + repositoryActions?.saveWebViewPageHistory(webViewHistoryEntityList) + } + editor.putString(TAG_CURRENT_FILE, zimReaderContainer?.zimReaderSource?.toDatabase()) + editor.putInt(TAG_CURRENT_TAB, currentWebViewIndex) + editor.apply() + Log.d( + TAG_KIWIX, + "Save current zim file to preferences: " + + "${zimReaderContainer?.zimReaderSource?.toDatabase()}" + ) + onComplete.invoke() + } } } @@ -2476,16 +2474,6 @@ abstract class CoreReaderFragment : return null } - /** - * @see shouldSaveTabsOnPause - */ - override fun onPause() { - super.onPause() - if (shouldSaveTabsOnPause) { - saveTabStates() - } - } - override fun webViewUrlLoading() { if (isFirstRun && !BuildConfig.DEBUG) { contentsDrawerHint() @@ -2572,6 +2560,7 @@ abstract class CoreReaderFragment : showProgressBarWithProgress(progress) if (progress == 100) { hideProgressBar() + saveTabStates() Log.d(TAG_KIWIX, "Loaded URL: " + getCurrentWebView()?.url) } (webView.context as AppCompatActivity).invalidateOptionsMenu() From 2240912e6a3d074354d54bf981829c755fc6ed7a Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 29 Oct 2024 15:16:33 +0530 Subject: [PATCH 17/22] Fixed: Reader screen was showing twice when pressing the back button after opening a page from the history, bookmarks, or notes screens in custom apps. --- .../kiwix/kiwixmobile/core/main/CoreMainActivity.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt index ed4affa788..ad43ea14ab 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt @@ -39,6 +39,7 @@ import androidx.fragment.app.FragmentContainerView import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.NavDirections +import androidx.navigation.NavOptions import com.google.android.material.navigation.NavigationView import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -349,6 +350,10 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { navController.navigate(fragmentId, bundle) } + fun navigate(fragmentId: Int, bundle: Bundle, navOptions: NavOptions) { + navController.navigate(fragmentId, bundle, navOptions) + } + private fun openSettings() { handleDrawerOnNavigation() navigate(settingsFragmentResId) @@ -391,13 +396,18 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { if (zimReaderSource != null) { zimFileUri = zimReaderSource.toDatabase() } + val navOptions = NavOptions.Builder() + .setLaunchSingleTop(true) + .setPopUpTo(readerFragmentResId, inclusive = true) + .build() navigate( readerFragmentResId, bundleOf( PAGE_URL_KEY to pageUrl, ZIM_FILE_URI_KEY to zimFileUri, SHOULD_OPEN_IN_NEW_TAB to shouldOpenInNewTab - ) + ), + navOptions ) } From b76ccc675da8cccef010bce2ee158bbfc68ace5c Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Tue, 29 Oct 2024 17:50:27 +0530 Subject: [PATCH 18/22] Fix: Main page of ZIM file not loading when opening a note in the notes screen * Resolved the issue where the main page of the ZIM file was not loading when a note was opened from the notes screen, when a different ZIM file was set in the reader. Now, when opening notes, the application correctly sets the corresponding ZIM file in the reader, ensuring the main page is displayed as expected. --- .../core/main/CoreReaderFragment.kt | 14 +++- .../history/adapter/WebViewHistoryItem.kt | 2 +- .../viewmodel/effects/ShowOpenNoteDialog.kt | 71 ++++++++++++------- .../kiwix/kiwixmobile/core/utils/Constants.kt | 2 - 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 1ab98dbacd..1db3afd3ed 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -2739,21 +2739,29 @@ abstract class CoreReaderFragment : } /** - * Restores the state of a given KiwixWebView based on the provided WebViewHistoryItem. + * Restores the state of the specified 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. + * If the provided WebViewHistoryItem is null, the method instead loads the main page + * of the currently opened ZIM file. This fallback behavior is triggered, for example, + * when opening a note in the notes screen, where the webViewHistoryList is intentionally + * set to null to indicate that the main page of the newly opened ZIM file should be loaded. * * @param webView The KiwixWebView instance whose state is to be restored. - * @param webViewHistoryItem The WebViewHistoryItem containing the saved state and scroll position. + * @param webViewHistoryItem The WebViewHistoryItem containing the saved state and scroll position, + * or null if the main page should be loaded. */ private fun restoreTabState(webView: KiwixWebView, webViewHistoryItem: WebViewHistoryItem?) { webViewHistoryItem?.webViewBackForwardListBundle?.let { bundle -> webView.restoreState(bundle) webView.scrollY = webViewHistoryItem.webViewCurrentPosition + } ?: kotlin.run { + zimReaderContainer?.zimFileReader?.let { + webView.loadUrl(redirectOrOriginal(contentUrl("${it.mainPage}"))) + } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt index 1e19d5340c..6d711e7a51 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/history/adapter/WebViewHistoryItem.kt @@ -32,7 +32,7 @@ data class WebViewHistoryItem( zimId: String, webViewIndex: Int, webViewPosition: Int, - webViewBackForwardList: Bundle + webViewBackForwardList: Bundle? ) : this( 0L, zimId, diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt index cb8990da66..48ad4966b9 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt @@ -19,21 +19,27 @@ package org.kiwix.kiwixmobile.core.page.notes.viewmodel.effects import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope import io.reactivex.processors.PublishProcessor +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.json.JSONArray import org.kiwix.kiwixmobile.core.base.SideEffect +import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity +import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.cachedComponent import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.isCustomApp +import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.page.adapter.Page +import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenNote import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenPage import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil -import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_ARTICLES import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE -import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_POSITIONS import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_TAB import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.ShowNoteDialog @@ -45,6 +51,7 @@ data class ShowOpenNoteDialog( private val zimReaderContainer: ZimReaderContainer ) : SideEffect { @Inject lateinit var dialogShower: DialogShower + @Inject lateinit var dataSource: DataSource override fun invokeWith(activity: AppCompatActivity) { activity.cachedComponent.inject(this) dialogShower.show( @@ -56,31 +63,45 @@ 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.zimReaderSource?.toDatabase().let { - val currentZimReaderSource = zimReaderContainer.zimReaderSource - if (!activity.isCustomApp()) { - zimReaderContainer.setZimReaderSource(item.zimReaderSource) - } - if (zimReaderContainer.zimReaderSource != currentZimReaderSource) { - // if current zim file is not the same set the main page of that zim file - // so that when we go back it properly loads the article, and do nothing if the - // zim file is same because there might be multiple tabs opened. - val settings = activity.getSharedPreferences( - SharedPreferenceUtil.PREF_KIWIX_MOBILE, - 0 - ) - val editor = settings.edit() - val urls = JSONArray() - val positions = JSONArray() - urls.put(CONTENT_PREFIX + zimReaderContainer.mainPage) - positions.put(0) - editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimReaderSource?.toDatabase()) - editor.putString(TAG_CURRENT_ARTICLES, "$urls") - editor.putString(TAG_CURRENT_POSITIONS, "$positions") - editor.putInt(TAG_CURRENT_TAB, 0) - editor.apply() + (activity as CoreMainActivity).lifecycleScope.launch { + val currentZimReaderSource = zimReaderContainer.zimReaderSource + if (!activity.isCustomApp()) { + zimReaderContainer.setZimReaderSource(item.zimReaderSource) + } + if (zimReaderContainer.zimReaderSource != currentZimReaderSource) { + // if current zim file is not the same set the main page of that zim file + // so that when we go back it properly loads the article, and do nothing if the + // zim file is same because there might be multiple tabs opened. + val settings = activity.getSharedPreferences( + SharedPreferenceUtil.PREF_KIWIX_MOBILE, + 0 + ) + val zimId = zimReaderContainer.zimFileReader?.id ?: "" + withContext(Dispatchers.IO) { + dataSource.clearWebViewPagesHistory() + dataSource.insertWebViewPageHistoryItems( + listOf( + WebViewHistoryEntity( + WebViewHistoryItem( + zimId = zimId, + webViewIndex = 0, + webViewPosition = 0, + webViewBackForwardList = null + ) + ) + ) + ) + } + val editor = settings.edit() + val urls = JSONArray() + urls.put(CONTENT_PREFIX + zimReaderContainer.mainPage) + editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimReaderSource?.toDatabase()) + editor.putInt(TAG_CURRENT_TAB, 0) + editor.apply() + } } + effects.offer(OpenNote(item.noteFilePath, item.zimUrl, item.title)) } - effects.offer(OpenNote(item.noteFilePath, item.zimUrl, item.title)) } ) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/Constants.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/Constants.kt index e2732e7d8d..348d459591 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/utils/Constants.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/utils/Constants.kt @@ -29,8 +29,6 @@ const val REQUEST_POST_NOTIFICATION_PERMISSION = 4 const val TAG_FILE_SEARCHED = "searchedarticle" const val TAG_FILE_SEARCHED_NEW_TAB = "searchedarticlenewtab" const val TAG_CURRENT_FILE = "currentzimfile" -const val TAG_CURRENT_ARTICLES = "currentarticles" -const val TAG_CURRENT_POSITIONS = "currentpositions" const val TAG_CURRENT_TAB = "currenttab" const val TAG_FROM_TAB_SWITCHER = "fromtabswitcher" From 0f32c43502eb264c1f8d1a8e477eb24115604401 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 14:26:12 +0530 Subject: [PATCH 19/22] Removed unnecessary data saving when opening note dialog in note screen. --- .../core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt index 48ad4966b9..fdac2e6f19 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/page/notes/viewmodel/effects/ShowOpenNoteDialog.kt @@ -24,7 +24,6 @@ import io.reactivex.processors.PublishProcessor import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.json.JSONArray import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity import org.kiwix.kiwixmobile.core.data.DataSource @@ -36,7 +35,6 @@ import org.kiwix.kiwixmobile.core.page.history.adapter.WebViewHistoryItem import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenNote import org.kiwix.kiwixmobile.core.page.viewmodel.effects.OpenPage -import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.TAG_CURRENT_FILE @@ -93,8 +91,6 @@ data class ShowOpenNoteDialog( ) } val editor = settings.edit() - val urls = JSONArray() - urls.put(CONTENT_PREFIX + zimReaderContainer.mainPage) editor.putString(TAG_CURRENT_FILE, zimReaderContainer.zimReaderSource?.toDatabase()) editor.putInt(TAG_CURRENT_TAB, 0) editor.apply() From 6cbd075f97b2a7a2ac85f8e10534e90195622624 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 17:41:56 +0530 Subject: [PATCH 20/22] Fixed: SearchFragmentTest for custom apps was failing. --- .../search/SearchFragmentTestForCustomApp.kt | 37 +++---------------- .../kiwixmobile/custom/search/SearchRobot.kt | 2 +- 2 files changed, 7 insertions(+), 32 deletions(-) diff --git a/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchFragmentTestForCustomApp.kt b/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchFragmentTestForCustomApp.kt index 0dcc83daf0..e88672bed4 100644 --- a/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchFragmentTestForCustomApp.kt +++ b/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchFragmentTestForCustomApp.kt @@ -20,8 +20,7 @@ package org.kiwix.kiwixmobile.custom.search import android.Manifest import android.content.Context -import android.content.res.AssetFileDescriptor -import android.os.ParcelFileDescriptor +import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.NavHostFragment @@ -61,7 +60,6 @@ import org.kiwix.kiwixmobile.custom.testutils.TestUtils.closeSystemDialogs import org.kiwix.kiwixmobile.custom.testutils.TestUtils.isSystemUINotRespondingDialogVisible import java.io.File import java.io.FileOutputStream -import java.io.IOException import java.net.URI import java.util.concurrent.TimeUnit import javax.inject.Singleton @@ -145,7 +143,7 @@ class SearchFragmentTestForCustomApp { UiThreadStatement.runOnUiThread { customMainActivity.navigate(customMainActivity.readerFragmentResId) } - openZimFileInReaderWithAssetFileDescriptor(downloadingZimFile) + openZimFileInReader(downloadingZimFile) openSearchWithQuery() val searchTerm = "gard" val searchedItem = "Gardanta Spirito" @@ -223,7 +221,7 @@ class SearchFragmentTestForCustomApp { UiThreadStatement.runOnUiThread { customMainActivity.navigate(customMainActivity.readerFragmentResId) } - openZimFileInReaderWithAssetFileDescriptor(downloadingZimFile) + openZimFileInReader(downloadingZimFile) openSearchWithQuery(searchTerms[0]) // wait for searchFragment become visible on screen. delay(2000) @@ -264,13 +262,7 @@ class SearchFragmentTestForCustomApp { } } - private fun openZimFileInReaderWithAssetFileDescriptor(downloadingZimFile: File) { - getAssetFileDescriptorFromFile(downloadingZimFile)?.let(::openZimFileInReader) ?: run { - throw RuntimeException("Unable to get fileDescriptor from file. Original exception") - } - } - - private fun openZimFileInReader(assetFileDescriptor: AssetFileDescriptor) { + private fun openZimFileInReader(file: File) { UiThreadStatement.runOnUiThread { val navHostFragment: NavHostFragment = customMainActivity.supportFragmentManager @@ -281,30 +273,13 @@ class SearchFragmentTestForCustomApp { navHostFragment.childFragmentManager.fragments[0] as CustomReaderFragment runBlocking { customReaderFragment.openZimFile( - ZimReaderSource(null, null, listOf(assetFileDescriptor)), + ZimReaderSource(file, null, null), true ) } } } - private fun getAssetFileDescriptorFromFile(file: File): AssetFileDescriptor? { - val parcelFileDescriptor = getFileDescriptor(file) - if (parcelFileDescriptor != null) { - return AssetFileDescriptor(parcelFileDescriptor, 0, file.length()) - } - return null - } - - private fun getFileDescriptor(file: File?): ParcelFileDescriptor? { - try { - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY) - } catch (e: IOException) { - e.printStackTrace() - return null - } - } - private fun writeZimFileData(responseBody: ResponseBody, file: File) { FileOutputStream(file).use { outputStream -> responseBody.byteStream().use { inputStream -> @@ -324,7 +299,7 @@ class SearchFragmentTestForCustomApp { .build() private fun getDownloadingZimFile(): File { - val zimFile = File(context.cacheDir, "ray_charles.zim") + val zimFile = File(ContextCompat.getExternalFilesDirs(context, null)[0], "ray_charles.zim") if (zimFile.exists()) zimFile.delete() zimFile.createNewFile() return zimFile diff --git a/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchRobot.kt b/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchRobot.kt index 3191c6a8e4..e0979a4513 100644 --- a/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchRobot.kt +++ b/custom/src/androidTest/java/org/kiwix/kiwixmobile/custom/search/SearchRobot.kt @@ -95,7 +95,7 @@ class SearchRobot { clickOnSearchItemInSearchList() } - fun clickOnSearchItemInSearchList() { + private fun clickOnSearchItemInSearchList() { testFlakyView({ BaristaSleepInteractions.sleep(TestUtils.TEST_PAUSE_MS_FOR_SEARCH_TEST.toLong()) Espresso.onView(ViewMatchers.withId(R.id.search_list)).perform( From feda7b4aff470ab74790eea594f9475f23bcf6a9 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Fri, 6 Dec 2024 18:13:18 +0530 Subject: [PATCH 21/22] Fixed: Application crashes at first launch. --- .../nav/destination/reader/KiwixReaderFragment.kt | 5 +++-- .../org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) 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 7a858fc090..5d85c134f2 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 @@ -257,9 +257,10 @@ class KiwixReaderFragment : CoreReaderFragment() { 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, isFromManageExternalLaunch = true) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 1db3afd3ed..5b00676817 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -1222,6 +1222,7 @@ abstract class CoreReaderFragment : override fun onDestroyView() { super.onDestroyView() try { + coreReaderLifeCycleScope?.cancel() readerLifeCycleScope?.cancel() readerLifeCycleScope = null } catch (ignore: Exception) { From ee90904b06b9baa058826eae71941940235e0e64 Mon Sep 17 00:00:00 2001 From: MohitMaliFtechiz Date: Mon, 9 Dec 2024 14:25:59 +0530 Subject: [PATCH 22/22] Added debug logs which will help us in debugging if any error happens. --- .../org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt index 5b00676817..8e335ec30c 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.kt @@ -2686,6 +2686,10 @@ abstract class CoreReaderFragment : findInPageTitle = null } }, { + Log.e( + TAG_KIWIX, + "Could not restore tabs. Original exception = ${it.printStackTrace()}" + ) restoreViewStateOnInvalidWebViewHistory() }) }