mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-08 14:52:13 -04:00
Refactored the code to use coroutines instead of rxJava for saving/retrieving the bookmarks from libkiwix.
* Refactored the all unit and UI test cases according to it.
This commit is contained in:
parent
d6ef855795
commit
3e92cda80f
@ -28,6 +28,7 @@ import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import io.objectbox.Box
|
||||
import io.objectbox.BoxStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -130,7 +131,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
box = boxStore!!.boxFor(BookmarkEntity::class.java)
|
||||
|
||||
// clear the data before running the test case
|
||||
clearBookmarks()
|
||||
runBlocking { clearBookmarks() }
|
||||
|
||||
// add a file in fileSystem because we need to actual file path for making object of Archive.
|
||||
val loadFileStream =
|
||||
@ -162,7 +163,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
// check if data successfully migrated to room
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(1, actualDataAfterMigration.size)
|
||||
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), expectedZimFilePath)
|
||||
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
|
||||
@ -178,7 +179,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
// Migrate data from empty ObjectBox database
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertTrue(actualDataAfterMigration.isEmpty())
|
||||
// Clear the bookmarks list from device to not affect the other test cases.
|
||||
clearBookmarks()
|
||||
@ -212,7 +213,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
// Migrate data into Room database
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(2, actualDataAfterMigration.size)
|
||||
val existingItem =
|
||||
actualDataAfterMigration.find {
|
||||
@ -250,7 +251,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
// Check if data successfully migrated to Room
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(1000, actualDataAfterMigration.size)
|
||||
// Clear the bookmarks list from device to not affect the other test cases.
|
||||
clearBookmarks()
|
||||
@ -276,7 +277,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
// check if data successfully migrated to room
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(1, actualDataAfterMigration.size)
|
||||
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), null)
|
||||
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
|
||||
@ -307,7 +308,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
|
||||
// check if data successfully migrated to room
|
||||
val actualDataAfterMigration =
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(1, actualDataAfterMigration.size)
|
||||
assertEquals(actualDataAfterMigration[0].zimReaderSource?.toDatabase(), null)
|
||||
assertEquals(actualDataAfterMigration[0].zimId, expectedZimId)
|
||||
@ -317,11 +318,11 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
|
||||
clearBookmarks()
|
||||
}
|
||||
|
||||
private fun clearBookmarks() {
|
||||
private suspend fun clearBookmarks() {
|
||||
// delete bookmarks for testing other edge cases
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.deleteBookmarks(
|
||||
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks()
|
||||
.blockingFirst() as List<LibkiwixBookmarkItem>
|
||||
.first() as List<LibkiwixBookmarkItem>
|
||||
)
|
||||
box.removeAll()
|
||||
if (::zimFile.isInitialized) {
|
||||
|
@ -31,6 +31,7 @@ import com.google.android.apps.common.testing.accessibility.framework.Accessibil
|
||||
import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck
|
||||
import com.google.android.apps.common.testing.accessibility.framework.checks.TouchTargetSizeCheck
|
||||
import io.objectbox.BoxStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.hamcrest.Matchers.allOf
|
||||
import org.hamcrest.Matchers.anyOf
|
||||
@ -171,13 +172,13 @@ class ImportBookmarkTest : BaseActivityTest() {
|
||||
// test with empty data file
|
||||
var tempBookmarkFile = getTemporaryBookmarkFile(true)
|
||||
importBookmarks(tempBookmarkFile)
|
||||
var actualDataAfterImporting = libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
var actualDataAfterImporting = libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(0, actualDataAfterImporting.size)
|
||||
|
||||
// import the bookmark
|
||||
tempBookmarkFile = getTemporaryBookmarkFile()
|
||||
importBookmarks(tempBookmarkFile)
|
||||
actualDataAfterImporting = libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
actualDataAfterImporting = libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(3, actualDataAfterImporting.size)
|
||||
assertEquals(actualDataAfterImporting[0].title, "Main Page")
|
||||
assertEquals(actualDataAfterImporting[0].url, "https://kiwix.app/A/Main_Page")
|
||||
@ -185,7 +186,7 @@ class ImportBookmarkTest : BaseActivityTest() {
|
||||
|
||||
// import duplicate bookmarks
|
||||
importBookmarks(tempBookmarkFile)
|
||||
actualDataAfterImporting = libkiwixBookmarks.bookmarks().blockingFirst()
|
||||
actualDataAfterImporting = libkiwixBookmarks.bookmarks().first()
|
||||
assertEquals(3, actualDataAfterImporting.size)
|
||||
|
||||
// delete the temp file
|
||||
@ -200,11 +201,11 @@ class ImportBookmarkTest : BaseActivityTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearBookmarks() {
|
||||
private suspend fun clearBookmarks() {
|
||||
// delete bookmarks for testing other edge cases
|
||||
libkiwixBookmarks.deleteBookmarks(
|
||||
libkiwixBookmarks.bookmarks()
|
||||
.blockingFirst() as List<LibkiwixBookmarkItem>
|
||||
.first() as List<LibkiwixBookmarkItem>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -21,17 +21,18 @@ package org.kiwix.kiwixmobile.core.dao
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.util.Base64
|
||||
import io.reactivex.BackpressureStrategy
|
||||
import io.reactivex.BackpressureStrategy.LATEST
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.reactive.asPublisher
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.rx3.rxSingle
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kiwix.kiwixmobile.core.CoreApp
|
||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
@ -71,15 +72,19 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
private var bookmarkList: List<LibkiwixBookmarkItem> = arrayListOf()
|
||||
private var libraryBooksList: List<String> = arrayListOf()
|
||||
|
||||
@Suppress("CheckResult", "IgnoredReturnValue")
|
||||
private val bookmarkListBehaviour: BehaviorSubject<List<LibkiwixBookmarkItem>>? by lazy {
|
||||
BehaviorSubject.create<List<LibkiwixBookmarkItem>>().also { subject ->
|
||||
rxSingle { getBookmarksList() }
|
||||
.subscribeOn(io.reactivex.rxjava3.schedulers.Schedulers.io())
|
||||
.subscribe(subject::onNext, subject::onError)
|
||||
@Suppress("InjectDispatcher", "TooGenericExceptionCaught")
|
||||
private val bookmarkListFlow: MutableStateFlow<List<LibkiwixBookmarkItem>> by lazy {
|
||||
MutableStateFlow<List<LibkiwixBookmarkItem>>(emptyList()).also { flow ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val bookmarks = getBookmarksList()
|
||||
flow.emit(bookmarks)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val bookmarksFolderPath: String by lazy {
|
||||
if (Build.DEVICE.contains("generic")) {
|
||||
// Workaround for emulators: Emulators have limited memory and
|
||||
@ -112,30 +117,35 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
manager.readBookmarkFile(bookmarkFile.canonicalPath)
|
||||
}
|
||||
|
||||
fun bookmarks(): Flowable<List<Page>> =
|
||||
flowableBookmarkList()
|
||||
fun bookmarks(): Flow<List<Page>> =
|
||||
bookmarkListFlow
|
||||
.map { it }
|
||||
|
||||
override fun pages(): Flowable<List<Page>> = bookmarks()
|
||||
// Currently kept in RxJava Flowable because `PageViewModel` still expects RxJava streams.
|
||||
// This can be refactored to use Kotlin Flow once `PageViewModel` is migrated to coroutines.
|
||||
override fun pages(): Flowable<List<Page>> =
|
||||
Flowable.fromPublisher(bookmarks().asPublisher())
|
||||
|
||||
override fun deletePages(pagesToDelete: List<Page>) =
|
||||
deleteBookmarks(pagesToDelete as List<LibkiwixBookmarkItem>)
|
||||
|
||||
suspend fun getCurrentZimBookmarksUrl(zimFileReader: ZimFileReader?): List<String> {
|
||||
return zimFileReader?.let { reader ->
|
||||
getBookmarksList()
|
||||
.filter { it.zimId == reader.id }
|
||||
.map(LibkiwixBookmarkItem::bookmarkUrl)
|
||||
}.orEmpty()
|
||||
}
|
||||
@Suppress("InjectDispatcher")
|
||||
suspend fun getCurrentZimBookmarksUrl(zimFileReader: ZimFileReader?): List<String> =
|
||||
withContext(Dispatchers.IO) {
|
||||
return@withContext zimFileReader?.let { reader ->
|
||||
getBookmarksList()
|
||||
.filter { it.zimId == reader.id }
|
||||
.map(LibkiwixBookmarkItem::bookmarkUrl)
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
fun bookmarkUrlsForCurrentBook(zimId: String): Flowable<List<String>> =
|
||||
flowableBookmarkList()
|
||||
@Suppress("InjectDispatcher")
|
||||
fun bookmarkUrlsForCurrentBook(zimId: String): Flow<List<String>> =
|
||||
bookmarkListFlow
|
||||
.map { bookmarksList ->
|
||||
bookmarksList.filter { it.zimId == zimId }
|
||||
.map(LibkiwixBookmarkItem::bookmarkUrl)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
/**
|
||||
* Saves bookmarks in libkiwix. The use of `shouldWriteBookmarkToFile` is primarily
|
||||
@ -165,7 +175,7 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
library.addBookmark(bookmark).also {
|
||||
if (shouldWriteBookmarkToFile) {
|
||||
writeBookMarksAndSaveLibraryToFile()
|
||||
updateFlowableBookmarkList()
|
||||
updateFlowBookmarkList()
|
||||
}
|
||||
// dispose the bookmark
|
||||
bookmark.dispose()
|
||||
@ -185,7 +195,7 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
}
|
||||
}
|
||||
addBookToLibraryIfNotExist(book)
|
||||
updateFlowableBookmarkList()
|
||||
updateFlowBookmarkList()
|
||||
} catch (ignore: Exception) {
|
||||
Log.e(
|
||||
TAG,
|
||||
@ -228,7 +238,7 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
.also {
|
||||
CoroutineScope(dispatcher).launch {
|
||||
writeBookMarksAndSaveLibraryToFile()
|
||||
updateFlowableBookmarkList()
|
||||
updateFlowBookmarkList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -363,27 +373,8 @@ class LibkiwixBookmarks @Inject constructor(
|
||||
it.zimReaderSource == libkiwixBookmarkItem.zimReaderSource
|
||||
}
|
||||
|
||||
private fun flowableBookmarkList(
|
||||
backpressureStrategy: BackpressureStrategy = LATEST
|
||||
): Flowable<List<LibkiwixBookmarkItem>> {
|
||||
return Flowable.create({ emitter ->
|
||||
val disposable =
|
||||
bookmarkListBehaviour?.subscribe(
|
||||
{ list ->
|
||||
if (!emitter.isCancelled) {
|
||||
emitter.onNext(list.toList())
|
||||
}
|
||||
},
|
||||
emitter::onError,
|
||||
emitter::onComplete
|
||||
)
|
||||
|
||||
emitter.setDisposable(disposable)
|
||||
}, backpressureStrategy)
|
||||
}
|
||||
|
||||
private suspend fun updateFlowableBookmarkList() {
|
||||
bookmarkListBehaviour?.onNext(getBookmarksList())
|
||||
private suspend fun updateFlowBookmarkList() {
|
||||
bookmarkListFlow.emit(getBookmarksList())
|
||||
}
|
||||
|
||||
// Export the `bookmark.xml` file to the `Download/org.kiwix/` directory of internal storage.
|
||||
|
@ -41,11 +41,11 @@ interface DataSource {
|
||||
fun saveHistory(history: HistoryItem): Completable
|
||||
fun deleteHistory(historyList: List<HistoryListItem>): Completable
|
||||
fun clearHistory(): Completable
|
||||
fun getBookmarks(): Flowable<List<LibkiwixBookmarkItem>>
|
||||
fun getCurrentZimBookmarksUrl(): io.reactivex.rxjava3.core.Single<List<String>>
|
||||
fun saveBookmark(libkiwixBookmarkItem: LibkiwixBookmarkItem): io.reactivex.rxjava3.core.Completable
|
||||
fun deleteBookmarks(bookmarks: List<LibkiwixBookmarkItem>): Completable
|
||||
fun deleteBookmark(bookId: String, bookmarkUrl: String): Completable?
|
||||
fun getBookmarks(): Flow<List<LibkiwixBookmarkItem>>
|
||||
suspend fun getCurrentZimBookmarksUrl(): List<String>
|
||||
suspend fun saveBookmark(libkiwixBookmarkItem: LibkiwixBookmarkItem)
|
||||
suspend fun deleteBookmarks(bookmarks: List<LibkiwixBookmarkItem>)
|
||||
suspend fun deleteBookmark(bookId: String, bookmarkUrl: String)
|
||||
fun booksOnDiskAsListItems(): Flowable<List<BooksOnDiskListItem>>
|
||||
fun saveNote(noteListItem: NoteListItem): Completable
|
||||
fun deleteNote(noteTitle: String): Completable
|
||||
|
@ -21,9 +21,7 @@ package org.kiwix.kiwixmobile.core.data
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Scheduler
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.rx3.rxCompletable
|
||||
import kotlinx.coroutines.rx3.rxSingle
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
||||
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
||||
@ -122,24 +120,19 @@ class Repository @Inject internal constructor(
|
||||
}.subscribeOn(ioThread)
|
||||
|
||||
override fun getBookmarks() =
|
||||
libkiwixBookmarks.bookmarks() as Flowable<List<LibkiwixBookmarkItem>>
|
||||
libkiwixBookmarks.bookmarks() as Flow<List<LibkiwixBookmarkItem>>
|
||||
|
||||
override fun getCurrentZimBookmarksUrl() =
|
||||
rxSingle {
|
||||
libkiwixBookmarks.getCurrentZimBookmarksUrl(zimReaderContainer.zimFileReader)
|
||||
}.subscribeOn(io.reactivex.rxjava3.schedulers.Schedulers.io())
|
||||
override suspend fun getCurrentZimBookmarksUrl() =
|
||||
libkiwixBookmarks.getCurrentZimBookmarksUrl(zimReaderContainer.zimFileReader)
|
||||
|
||||
override fun saveBookmark(libkiwixBookmarkItem: LibkiwixBookmarkItem) =
|
||||
rxCompletable { libkiwixBookmarks.saveBookmark(libkiwixBookmarkItem) }
|
||||
.subscribeOn(io.reactivex.rxjava3.schedulers.Schedulers.io())
|
||||
override suspend fun saveBookmark(libkiwixBookmarkItem: LibkiwixBookmarkItem) =
|
||||
libkiwixBookmarks.saveBookmark(libkiwixBookmarkItem)
|
||||
|
||||
override fun deleteBookmarks(bookmarks: List<LibkiwixBookmarkItem>) =
|
||||
Completable.fromAction { libkiwixBookmarks.deleteBookmarks(bookmarks) }
|
||||
.subscribeOn(ioThread)
|
||||
override suspend fun deleteBookmarks(bookmarks: List<LibkiwixBookmarkItem>) =
|
||||
libkiwixBookmarks.deleteBookmarks(bookmarks)
|
||||
|
||||
override fun deleteBookmark(bookId: String, bookmarkUrl: String): Completable? =
|
||||
Completable.fromAction { libkiwixBookmarks.deleteBookmark(bookId, bookmarkUrl) }
|
||||
.subscribeOn(ioThread)
|
||||
override suspend fun deleteBookmark(bookId: String, bookmarkUrl: String) =
|
||||
libkiwixBookmarks.deleteBookmark(bookId, bookmarkUrl)
|
||||
|
||||
override fun saveNote(noteListItem: NoteListItem): Completable =
|
||||
Completable.fromAction { notesRoomDao.saveNote(noteListItem) }
|
||||
|
@ -94,15 +94,15 @@ import com.google.android.material.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.processors.BehaviorProcessor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
@ -202,7 +202,7 @@ abstract class CoreReaderFragment :
|
||||
NavigationHistoryClickListener,
|
||||
ShowDonationDialogCallback {
|
||||
protected val webViewList: MutableList<KiwixWebView> = ArrayList()
|
||||
private val webUrlsProcessor = BehaviorProcessor.create<String>()
|
||||
private val webUrlsFlow = MutableStateFlow("")
|
||||
private var fragmentReaderBinding: FragmentReaderBinding? = null
|
||||
|
||||
var toolbar: Toolbar? = null
|
||||
@ -333,7 +333,7 @@ abstract class CoreReaderFragment :
|
||||
private var tableDrawerRight: RecyclerView? = null
|
||||
private var tabCallback: ItemTouchHelper.Callback? = null
|
||||
private var donationLayout: FrameLayout? = null
|
||||
private var bookmarkingDisposable: Disposable? = null
|
||||
private var bookmarkingJob: Job? = null
|
||||
private var isBookmarked = false
|
||||
private lateinit var serviceConnection: ServiceConnection
|
||||
private var readAloudService: ReadAloudService? = null
|
||||
@ -1269,7 +1269,7 @@ abstract class CoreReaderFragment :
|
||||
(requireActivity() as? AppCompatActivity)?.setSupportActionBar(null)
|
||||
}
|
||||
repositoryActions?.dispose()
|
||||
safeDispose()
|
||||
safelyCancelBookmarkJob()
|
||||
unBindViewsAndBinding()
|
||||
tabCallback = null
|
||||
hideBackToTopTimer?.cancel()
|
||||
@ -1546,7 +1546,7 @@ abstract class CoreReaderFragment :
|
||||
tabsAdapter?.selected = currentWebViewIndex
|
||||
updateBottomToolbarVisibility()
|
||||
loadPrefs()
|
||||
updateUrlProcessor()
|
||||
updateUrlFlow()
|
||||
updateTableOfContents()
|
||||
updateTitle()
|
||||
}
|
||||
@ -1898,24 +1898,25 @@ abstract class CoreReaderFragment :
|
||||
}
|
||||
|
||||
protected fun setUpBookmarks(zimFileReader: ZimFileReader) {
|
||||
safeDispose()
|
||||
bookmarkingDisposable = Flowable.combineLatest(
|
||||
libkiwixBookmarks?.bookmarkUrlsForCurrentBook(zimFileReader.id),
|
||||
webUrlsProcessor,
|
||||
List<String?>::contains
|
||||
)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ isBookmarked: Boolean ->
|
||||
this.isBookmarked = isBookmarked
|
||||
safelyCancelBookmarkJob()
|
||||
bookmarkingJob = CoroutineScope(Dispatchers.Main).launch {
|
||||
combine(
|
||||
libkiwixBookmarks?.bookmarkUrlsForCurrentBook(zimFileReader.id) ?: emptyFlow(),
|
||||
webUrlsFlow,
|
||||
List<String?>::contains
|
||||
).collect { isBookmarked ->
|
||||
this@CoreReaderFragment.isBookmarked = isBookmarked
|
||||
bottomToolbarBookmark?.setImageResource(
|
||||
if (isBookmarked) R.drawable.ic_bookmark_24dp else R.drawable.ic_bookmark_border_24dp
|
||||
)
|
||||
}, Throwable::printStackTrace)
|
||||
updateUrlProcessor()
|
||||
}
|
||||
}
|
||||
updateUrlFlow()
|
||||
}
|
||||
|
||||
private fun safeDispose() {
|
||||
bookmarkingDisposable?.dispose()
|
||||
private fun safelyCancelBookmarkJob() {
|
||||
bookmarkingJob?.cancel()
|
||||
bookmarkingJob = null
|
||||
}
|
||||
|
||||
private fun isNotPreviouslyOpenZim(zimReaderSource: ZimReaderSource?): Boolean =
|
||||
@ -2464,8 +2465,8 @@ abstract class CoreReaderFragment :
|
||||
|
||||
protected fun urlIsValid(): Boolean = getCurrentWebView()?.url != null
|
||||
|
||||
private fun updateUrlProcessor() {
|
||||
getCurrentWebView()?.url?.let(webUrlsProcessor::offer)
|
||||
private fun updateUrlFlow() {
|
||||
getCurrentWebView()?.url?.let { webUrlsFlow.value = it }
|
||||
}
|
||||
|
||||
private fun updateNightMode() {
|
||||
@ -2673,7 +2674,7 @@ abstract class CoreReaderFragment :
|
||||
// If a URL fails to load, update the bookmark toggle.
|
||||
// This fixes the scenario where the previous page is bookmarked and the next
|
||||
// page fails to load, ensuring the bookmark toggle is unset correctly.
|
||||
updateUrlProcessor()
|
||||
updateUrlFlow()
|
||||
Log.d(TAG_KIWIX, String.format(getString(R.string.error_article_url_not_found), url))
|
||||
}
|
||||
}
|
||||
@ -2681,7 +2682,7 @@ abstract class CoreReaderFragment :
|
||||
@Suppress("MagicNumber")
|
||||
override fun webViewProgressChanged(progress: Int, webView: WebView) {
|
||||
if (isAdded) {
|
||||
updateUrlProcessor()
|
||||
updateUrlFlow()
|
||||
showProgressBarWithProgress(progress)
|
||||
if (progress == 100) {
|
||||
hideProgressBar()
|
||||
|
@ -19,6 +19,8 @@ package org.kiwix.kiwixmobile.core.main
|
||||
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
||||
import org.kiwix.kiwixmobile.core.data.DataSource
|
||||
import org.kiwix.kiwixmobile.core.di.ActivityScope
|
||||
@ -35,7 +37,6 @@ private const val TAG = "MainPresenter"
|
||||
@ActivityScope
|
||||
class MainRepositoryActions @Inject constructor(private val dataSource: DataSource) {
|
||||
private var saveHistoryDisposable: Disposable? = null
|
||||
private var saveBookmarkDisposable: io.reactivex.rxjava3.disposables.Disposable? = null
|
||||
private var saveNoteDisposable: Disposable? = null
|
||||
private var saveBookDisposable: Disposable? = null
|
||||
private var deleteNoteDisposable: Disposable? = null
|
||||
@ -48,16 +49,26 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour
|
||||
.subscribe({}, { e -> Log.e(TAG, "Unable to save history", e) })
|
||||
}
|
||||
|
||||
fun saveBookmark(bookmark: LibkiwixBookmarkItem) {
|
||||
saveBookmarkDisposable =
|
||||
dataSource.saveBookmark(bookmark)
|
||||
.subscribe({}, { e -> Log.e(TAG, "Unable to save bookmark", e) })
|
||||
@Suppress("InjectDispatcher", "TooGenericExceptionCaught")
|
||||
suspend fun saveBookmark(bookmark: LibkiwixBookmarkItem) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
dataSource.saveBookmark(bookmark)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to save bookmark", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteBookmark(bookId: String, bookmarkUrl: String) {
|
||||
dataSource.deleteBookmark(bookId, bookmarkUrl)
|
||||
?.subscribe({}, { e -> Log.e(TAG, "Unable to delete bookmark", e) })
|
||||
?: Log.e(TAG, "Unable to delete bookmark")
|
||||
@Suppress("InjectDispatcher", "TooGenericExceptionCaught")
|
||||
suspend fun deleteBookmark(bookId: String, bookmarkUrl: String) {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
dataSource.deleteBookmark(bookId, bookmarkUrl)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Unable to delete bookmark", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveNote(note: NoteListItem) {
|
||||
@ -93,7 +104,6 @@ class MainRepositoryActions @Inject constructor(private val dataSource: DataSour
|
||||
|
||||
fun dispose() {
|
||||
saveHistoryDisposable?.dispose()
|
||||
saveBookmarkDisposable?.dispose()
|
||||
saveNoteDisposable?.dispose()
|
||||
deleteNoteDisposable?.dispose()
|
||||
saveBookDisposable?.dispose()
|
||||
|
@ -21,11 +21,11 @@ package org.kiwix.kiwixmobile.core.page.bookmark.viewmodel
|
||||
import io.mockk.clearAllMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.reactivex.plugins.RxJavaPlugins
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.Flowable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.reactive.asPublisher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
@ -45,7 +45,6 @@ import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import org.kiwix.kiwixmobile.core.utils.dialog.AlertDialogShower
|
||||
import org.kiwix.sharedFunctions.InstantExecutorExtension
|
||||
import org.kiwix.sharedFunctions.setScheduler
|
||||
import java.util.UUID
|
||||
|
||||
@ExtendWith(InstantExecutorExtension::class)
|
||||
@ -58,13 +57,8 @@ internal class BookmarkViewModelTest {
|
||||
|
||||
private lateinit var viewModel: BookmarkViewModel
|
||||
|
||||
private val itemsFromDb: PublishProcessor<List<Page>> =
|
||||
PublishProcessor.create()
|
||||
|
||||
init {
|
||||
setScheduler(Schedulers.trampoline())
|
||||
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
|
||||
}
|
||||
private val itemsFromDb: MutableStateFlow<List<Page>> =
|
||||
MutableStateFlow(emptyList())
|
||||
|
||||
@BeforeEach
|
||||
fun init() {
|
||||
@ -72,8 +66,10 @@ internal class BookmarkViewModelTest {
|
||||
every { zimReaderContainer.id } returns "id"
|
||||
every { zimReaderContainer.name } returns "zimName"
|
||||
every { sharedPreferenceUtil.showBookmarksAllBooks } returns true
|
||||
every { libkiwixBookMarks.bookmarks() } returns itemsFromDb.distinctUntilChanged()
|
||||
every { libkiwixBookMarks.pages() } returns libkiwixBookMarks.bookmarks()
|
||||
every { libkiwixBookMarks.bookmarks() } returns itemsFromDb
|
||||
every { libkiwixBookMarks.pages() } returns Flowable.fromPublisher(
|
||||
libkiwixBookMarks.bookmarks().asPublisher()
|
||||
)
|
||||
viewModel =
|
||||
BookmarkViewModel(libkiwixBookMarks, zimReaderContainer, sharedPreferenceUtil).apply {
|
||||
alertDialogShower = dialogShower
|
||||
|
Loading…
x
Reference in New Issue
Block a user