mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-09 07:16:04 -04:00
Refactored the LanguageViewModel to fetch the language list from an online source.
This commit is contained in:
parent
8b02f96c1c
commit
014ef2bcef
@ -29,6 +29,7 @@ import androidx.compose.foundation.lazy.LazyListState
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -37,6 +38,9 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.semantics.testTag
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.extensions.CollectSideEffectWithActivity
|
import org.kiwix.kiwixmobile.core.extensions.CollectSideEffectWithActivity
|
||||||
@ -45,11 +49,13 @@ import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
|||||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixSearchView
|
import org.kiwix.kiwixmobile.core.ui.components.KiwixSearchView
|
||||||
import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
|
import org.kiwix.kiwixmobile.core.ui.models.ActionMenuItem
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.ComposeDimens.FOUR_DP
|
||||||
import org.kiwix.kiwixmobile.language.composables.LanguageList
|
import org.kiwix.kiwixmobile.language.composables.LanguageList
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.Action
|
import org.kiwix.kiwixmobile.language.viewmodel.Action
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.LanguageViewModel
|
import org.kiwix.kiwixmobile.language.viewmodel.LanguageViewModel
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.State
|
import org.kiwix.kiwixmobile.language.viewmodel.State
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Content
|
import org.kiwix.kiwixmobile.language.viewmodel.State.Content
|
||||||
|
import org.kiwix.kiwixmobile.nav.destination.library.online.NO_CONTENT_VIEW_TEXT_TESTING_TAG
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@SuppressLint("ComposableLambdaParameterNaming")
|
@SuppressLint("ComposableLambdaParameterNaming")
|
||||||
@ -115,11 +121,29 @@ fun LanguageScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is State.Error -> ShowErrorMessage((state as State.Error).errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ShowErrorMessage(errorMessage: String) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = errorMessage,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = FOUR_DP)
|
||||||
|
.semantics { testTag = NO_CONTENT_VIEW_TEXT_TESTING_TAG }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LoadingScreen() {
|
fun LoadingScreen() {
|
||||||
Box(
|
Box(
|
||||||
|
@ -25,5 +25,6 @@ sealed class Action {
|
|||||||
data class UpdateLanguages(val languages: List<Language>) : Action()
|
data class UpdateLanguages(val languages: List<Language>) : Action()
|
||||||
data class Filter(val filter: String) : Action()
|
data class Filter(val filter: String) : Action()
|
||||||
data class Select(val language: LanguageItem) : Action()
|
data class Select(val language: LanguageItem) : Action()
|
||||||
|
data class Error(val errorMessage: String) : Action()
|
||||||
object SaveAll : Action()
|
object SaveAll : Action()
|
||||||
}
|
}
|
||||||
|
@ -18,19 +18,40 @@
|
|||||||
|
|
||||||
package org.kiwix.kiwixmobile.language.viewmodel
|
package org.kiwix.kiwixmobile.language.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
|
||||||
|
import org.kiwix.kiwixmobile.core.BuildConfig
|
||||||
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
|
import org.kiwix.kiwixmobile.core.data.remote.UserAgentInterceptor
|
||||||
|
import org.kiwix.kiwixmobile.core.di.modules.CALL_TIMEOUT
|
||||||
|
import org.kiwix.kiwixmobile.core.di.modules.CONNECTION_TIMEOUT
|
||||||
|
import org.kiwix.kiwixmobile.core.di.modules.KIWIX_LANGUAGE_URL
|
||||||
|
import org.kiwix.kiwixmobile.core.di.modules.READ_TIMEOUT
|
||||||
|
import org.kiwix.kiwixmobile.core.di.modules.USER_AGENT
|
||||||
|
import org.kiwix.kiwixmobile.core.extensions.registerReceiver
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.TAG_KIWIX
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.files.Log
|
||||||
|
import org.kiwix.kiwixmobile.core.zim_manager.ConnectivityBroadcastReceiver
|
||||||
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
|
import org.kiwix.kiwixmobile.core.zim_manager.NetworkState
|
||||||
import org.kiwix.kiwixmobile.language.composables.LanguageListItem.LanguageItem
|
import org.kiwix.kiwixmobile.language.composables.LanguageListItem.LanguageItem
|
||||||
|
import org.kiwix.kiwixmobile.language.viewmodel.Action.Error
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter
|
import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.Action.SaveAll
|
import org.kiwix.kiwixmobile.language.viewmodel.Action.SaveAll
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.Action.Select
|
import org.kiwix.kiwixmobile.language.viewmodel.Action.Select
|
||||||
@ -38,10 +59,14 @@ import org.kiwix.kiwixmobile.language.viewmodel.Action.UpdateLanguages
|
|||||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Content
|
import org.kiwix.kiwixmobile.language.viewmodel.State.Content
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Loading
|
import org.kiwix.kiwixmobile.language.viewmodel.State.Loading
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Saving
|
import org.kiwix.kiwixmobile.language.viewmodel.State.Saving
|
||||||
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class LanguageViewModel @Inject constructor(
|
class LanguageViewModel @Inject constructor(
|
||||||
private val languageRoomDao: LanguageRoomDao
|
private val context: Application,
|
||||||
|
private val sharedPreferenceUtil: SharedPreferenceUtil,
|
||||||
|
private var kiwixService: KiwixService,
|
||||||
|
private val connectivityBroadcastReceiver: ConnectivityBroadcastReceiver
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val state = MutableStateFlow<State>(Loading)
|
val state = MutableStateFlow<State>(Loading)
|
||||||
val actions = MutableSharedFlow<Action>(extraBufferCapacity = Int.MAX_VALUE)
|
val actions = MutableSharedFlow<Action>(extraBufferCapacity = Int.MAX_VALUE)
|
||||||
@ -49,6 +74,7 @@ class LanguageViewModel @Inject constructor(
|
|||||||
private val coroutineJobs = mutableListOf<Job>()
|
private val coroutineJobs = mutableListOf<Job>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
context.registerReceiver(connectivityBroadcastReceiver)
|
||||||
coroutineJobs.apply {
|
coroutineJobs.apply {
|
||||||
add(observeActions())
|
add(observeActions())
|
||||||
add(observeLanguages())
|
add(observeLanguages())
|
||||||
@ -62,17 +88,64 @@ class LanguageViewModel @Inject constructor(
|
|||||||
.onEach { newState -> state.value = newState }
|
.onEach { newState -> state.value = newState }
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
private fun observeLanguages() =
|
private suspend fun fetchLanguages(): List<Language>? =
|
||||||
languageRoomDao.languages()
|
runCatching {
|
||||||
.filter { it.isNotEmpty() }
|
kiwixService =
|
||||||
.onEach { languages -> actions.tryEmit(UpdateLanguages(languages)) }
|
KiwixService.ServiceCreator.newHackListService(getOkHttpClient(), KIWIX_LANGUAGE_URL)
|
||||||
.launchIn(viewModelScope)
|
val feed = kiwixService.getLanguages()
|
||||||
|
buildList {
|
||||||
|
// Add default item to show all language.
|
||||||
|
add(
|
||||||
|
Language(
|
||||||
|
languageCode = "",
|
||||||
|
active = sharedPreferenceUtil.selectedOnlineContentLanguage.isEmpty(),
|
||||||
|
occurrencesOfLanguage = 0,
|
||||||
|
id = 0L
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add the rest of the fetched languages
|
||||||
|
feed.entries.orEmpty().mapIndexedNotNull { index, languageEntry ->
|
||||||
|
runCatching {
|
||||||
|
Language(
|
||||||
|
languageCode = languageEntry.languageCode,
|
||||||
|
active = sharedPreferenceUtil.selectedOnlineContentLanguage == languageEntry.languageCode,
|
||||||
|
occurrencesOfLanguage = languageEntry.count,
|
||||||
|
id = (index + 1).toLong()
|
||||||
|
)
|
||||||
|
}.onFailure {
|
||||||
|
Log.w(TAG_KIWIX, "Unsupported locale code: ${languageEntry.languageCode}", it)
|
||||||
|
}.getOrNull()
|
||||||
|
}.forEach { add(it) }
|
||||||
|
}
|
||||||
|
}.onFailure { it.printStackTrace() }.getOrNull()
|
||||||
|
|
||||||
|
private fun observeLanguages() = viewModelScope.launch {
|
||||||
|
state.value = Loading
|
||||||
|
if (connectivityBroadcastReceiver.networkStates.value == NetworkState.NOT_CONNECTED) {
|
||||||
|
actions.emit(Error(context.getString(R.string.no_network_connection)))
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val languages = fetchLanguages()
|
||||||
|
if (languages?.isNotEmpty() == true) {
|
||||||
|
actions.emit(UpdateLanguages(languages))
|
||||||
|
} else {
|
||||||
|
Log.w("LanguageViewModel", "Fetched empty language list.")
|
||||||
|
actions.emit(Error(context.getString(R.string.no_language_available)))
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("LanguageViewModel", "Error fetching languages", e)
|
||||||
|
actions.emit(Error(context.getString(R.string.no_language_available)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
coroutineJobs.forEach {
|
coroutineJobs.forEach {
|
||||||
it.cancel()
|
it.cancel()
|
||||||
}
|
}
|
||||||
coroutineJobs.clear()
|
coroutineJobs.clear()
|
||||||
|
context.unregisterReceiver(connectivityBroadcastReceiver)
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +154,8 @@ class LanguageViewModel @Inject constructor(
|
|||||||
currentState: State
|
currentState: State
|
||||||
): State {
|
): State {
|
||||||
return when (action) {
|
return when (action) {
|
||||||
|
is Error -> State.Error(action.errorMessage)
|
||||||
|
|
||||||
is UpdateLanguages ->
|
is UpdateLanguages ->
|
||||||
when (currentState) {
|
when (currentState) {
|
||||||
Loading -> Content(action.languages)
|
Loading -> Content(action.languages)
|
||||||
@ -111,8 +186,8 @@ class LanguageViewModel @Inject constructor(
|
|||||||
private fun saveAll(currentState: Content): State {
|
private fun saveAll(currentState: Content): State {
|
||||||
effects.tryEmit(
|
effects.tryEmit(
|
||||||
SaveLanguagesAndFinish(
|
SaveLanguagesAndFinish(
|
||||||
currentState.items,
|
currentState.items.first(),
|
||||||
languageRoomDao,
|
sharedPreferenceUtil,
|
||||||
viewModelScope
|
viewModelScope
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -128,4 +203,18 @@ class LanguageViewModel @Inject constructor(
|
|||||||
filter: String,
|
filter: String,
|
||||||
currentState: Content
|
currentState: Content
|
||||||
) = currentState.updateFilter(filter)
|
) = currentState.updateFilter(filter)
|
||||||
|
|
||||||
|
private fun getOkHttpClient() = OkHttpClient().newBuilder()
|
||||||
|
.followRedirects(true)
|
||||||
|
.followSslRedirects(true)
|
||||||
|
.connectTimeout(CONNECTION_TIMEOUT, SECONDS)
|
||||||
|
.readTimeout(READ_TIMEOUT, SECONDS)
|
||||||
|
.callTimeout(CALL_TIMEOUT, SECONDS)
|
||||||
|
.addNetworkInterceptor(
|
||||||
|
HttpLoggingInterceptor().apply {
|
||||||
|
level = if (BuildConfig.DEBUG) BASIC else NONE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.addNetworkInterceptor(UserAgentInterceptor(USER_AGENT))
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -19,25 +19,21 @@ package org.kiwix.kiwixmobile.language.viewmodel
|
|||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
@Suppress("InjectDispatcher")
|
||||||
data class SaveLanguagesAndFinish(
|
data class SaveLanguagesAndFinish(
|
||||||
private val languages: List<Language>,
|
private val languages: Language,
|
||||||
private val languageRoomDao: LanguageRoomDao,
|
private val sharedPreferenceUtil: SharedPreferenceUtil,
|
||||||
private val lifecycleScope: CoroutineScope
|
private val lifecycleScope: CoroutineScope
|
||||||
) : SideEffect<Unit> {
|
) : SideEffect<Unit> {
|
||||||
override fun invokeWith(activity: AppCompatActivity) {
|
override fun invokeWith(activity: AppCompatActivity) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
withContext(Dispatchers.IO) {
|
sharedPreferenceUtil.selectedOnlineContentLanguage = languages.languageCode
|
||||||
languageRoomDao.insert(languages)
|
|
||||||
}
|
|
||||||
activity.onBackPressedDispatcher.onBackPressed()
|
activity.onBackPressedDispatcher.onBackPressed()
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
|
@ -24,6 +24,7 @@ import org.kiwix.kiwixmobile.language.composables.LanguageListItem.HeaderItem
|
|||||||
import org.kiwix.kiwixmobile.language.composables.LanguageListItem.LanguageItem
|
import org.kiwix.kiwixmobile.language.composables.LanguageListItem.LanguageItem
|
||||||
|
|
||||||
sealed class State {
|
sealed class State {
|
||||||
|
data class Error(val errorMessage: String) : State()
|
||||||
object Loading : State()
|
object Loading : State()
|
||||||
object Saving : State()
|
object Saving : State()
|
||||||
data class Content(
|
data class Content(
|
||||||
|
@ -68,7 +68,6 @@ import org.kiwix.kiwixmobile.core.base.SideEffect
|
|||||||
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.convertToLocal
|
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.convertToLocal
|
||||||
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isWifi
|
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.isWifi
|
||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.data.DataSource
|
import org.kiwix.kiwixmobile.core.data.DataSource
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
@ -139,7 +138,6 @@ const val FOUR = 4
|
|||||||
class ZimManageViewModel @Inject constructor(
|
class ZimManageViewModel @Inject constructor(
|
||||||
private val downloadDao: DownloadRoomDao,
|
private val downloadDao: DownloadRoomDao,
|
||||||
private val libkiwixBookOnDisk: LibkiwixBookOnDisk,
|
private val libkiwixBookOnDisk: LibkiwixBookOnDisk,
|
||||||
private val languageRoomDao: LanguageRoomDao,
|
|
||||||
private val storageObserver: StorageObserver,
|
private val storageObserver: StorageObserver,
|
||||||
private var kiwixService: KiwixService,
|
private var kiwixService: KiwixService,
|
||||||
val context: Application,
|
val context: Application,
|
||||||
@ -164,9 +162,9 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class OnlineLibraryRequest(
|
data class OnlineLibraryRequest(
|
||||||
val query: String?,
|
val query: String? = null,
|
||||||
val category: String?,
|
val category: String? = null,
|
||||||
val lang: String?,
|
val lang: String? = null,
|
||||||
val isLoadMoreItem: Boolean,
|
val isLoadMoreItem: Boolean,
|
||||||
val page: Int
|
val page: Int
|
||||||
)
|
)
|
||||||
@ -327,16 +325,17 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
private fun observeCoroutineFlows(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
|
private fun observeCoroutineFlows(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
|
||||||
val downloads = downloadDao.downloads()
|
val downloads = downloadDao.downloads()
|
||||||
val booksFromDao = books()
|
val booksFromDao = books()
|
||||||
val languages = languageRoomDao.languages()
|
val selectedLanguage = sharedPreferenceUtil.onlineContentLanguage
|
||||||
coroutineJobs.apply {
|
coroutineJobs.apply {
|
||||||
add(scanBooksFromStorage(dispatcher))
|
add(scanBooksFromStorage(dispatcher))
|
||||||
add(updateBookItems())
|
add(updateBookItems())
|
||||||
add(fileSelectActions())
|
add(fileSelectActions())
|
||||||
add(updateLibraryItems(booksFromDao, downloads, networkLibrary, languages))
|
add(updateLibraryItems(booksFromDao, downloads, networkLibrary, selectedLanguage))
|
||||||
add(updateLanguagesInDao(networkLibrary, languages))
|
// add(updateLanguagesInDao(networkLibrary, selectedLanguage))
|
||||||
add(updateNetworkStates())
|
add(updateNetworkStates())
|
||||||
add(requestsAndConnectivityChangesToLibraryRequests(networkLibrary))
|
add(requestsAndConnectivityChangesToLibraryRequests(networkLibrary))
|
||||||
add(onlineLibraryRequest())
|
add(onlineLibraryRequest())
|
||||||
|
add(observeLanguageChanges())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,6 +349,16 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
super.onCleared()
|
super.onCleared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeLanguageChanges(dispatcher: CoroutineDispatcher = Dispatchers.IO) =
|
||||||
|
sharedPreferenceUtil.onlineContentLanguage
|
||||||
|
.onEach {
|
||||||
|
updateOnlineLibraryFilters(
|
||||||
|
OnlineLibraryRequest(lang = it, page = ZERO, isLoadMoreItem = false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.flowOn(dispatcher)
|
||||||
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
fun updateOnlineLibraryFilters(newRequest: OnlineLibraryRequest) {
|
fun updateOnlineLibraryFilters(newRequest: OnlineLibraryRequest) {
|
||||||
onlineLibraryRequest.update { current ->
|
onlineLibraryRequest.update { current ->
|
||||||
current.copy(
|
current.copy(
|
||||||
@ -589,7 +598,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
localBooksFromLibkiwix: Flow<List<Book>>,
|
localBooksFromLibkiwix: Flow<List<Book>>,
|
||||||
downloads: Flow<List<DownloadModel>>,
|
downloads: Flow<List<DownloadModel>>,
|
||||||
library: MutableStateFlow<List<LibkiwixBook>>,
|
library: MutableStateFlow<List<LibkiwixBook>>,
|
||||||
languages: Flow<List<Language>>,
|
languages: StateFlow<String>,
|
||||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) = viewModelScope.launch(dispatcher) {
|
) = viewModelScope.launch(dispatcher) {
|
||||||
val requestFilteringFlow = merge(
|
val requestFilteringFlow = merge(
|
||||||
@ -632,23 +641,25 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
.collect { _libraryItems.emit(it) }
|
.collect { _libraryItems.emit(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLanguagesInDao(
|
// private fun updateLanguagesInDao(
|
||||||
library: MutableStateFlow<List<LibkiwixBook>>,
|
// library: MutableStateFlow<List<LibkiwixBook>>,
|
||||||
languages: Flow<List<Language>>,
|
// languages: StateFlow<String>,
|
||||||
dispatcher: CoroutineDispatcher = Dispatchers.IO
|
// dispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||||
) =
|
// ) =
|
||||||
combine(
|
// combine(
|
||||||
library,
|
// library,
|
||||||
languages
|
// languages
|
||||||
) { books, existingLanguages ->
|
// ) { books, existingLanguages ->
|
||||||
combineToLanguageList(books, existingLanguages)
|
// combineToLanguageList(books, existingLanguages)
|
||||||
}.map { it.sortedBy(Language::language) }
|
// }.map { it.sortedBy(Language::language) }
|
||||||
.filter { it.isNotEmpty() }
|
// .filter { it.isNotEmpty() }
|
||||||
.distinctUntilChanged()
|
// .distinctUntilChanged()
|
||||||
.catch { it.printStackTrace() }
|
// .catch { it.printStackTrace() }
|
||||||
.onEach { languageRoomDao.insert(it) }
|
// .onEach {
|
||||||
.flowOn(dispatcher)
|
// // languageRoomDao.insert(it)
|
||||||
.launchIn(viewModelScope)
|
// }
|
||||||
|
// .flowOn(dispatcher)
|
||||||
|
// .launchIn(viewModelScope)
|
||||||
|
|
||||||
private suspend fun combineToLanguageList(
|
private suspend fun combineToLanguageList(
|
||||||
booksFromNetwork: List<LibkiwixBook>,
|
booksFromNetwork: List<LibkiwixBook>,
|
||||||
|
@ -28,7 +28,6 @@ import org.assertj.core.api.Assertions.assertThat
|
|||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
import org.kiwix.kiwixmobile.language.composables.LanguageListItem
|
import org.kiwix.kiwixmobile.language.composables.LanguageListItem
|
||||||
import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter
|
import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter
|
||||||
|
@ -27,7 +27,6 @@ import io.mockk.verify
|
|||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||||
|
|
||||||
class SaveLanguagesAndFinishTest {
|
class SaveLanguagesAndFinishTest {
|
||||||
|
@ -54,7 +54,6 @@ import org.junit.jupiter.api.extension.ExtendWith
|
|||||||
import org.kiwix.kiwixmobile.core.R
|
import org.kiwix.kiwixmobile.core.R
|
||||||
import org.kiwix.kiwixmobile.core.StorageObserver
|
import org.kiwix.kiwixmobile.core.StorageObserver
|
||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.data.DataSource
|
import org.kiwix.kiwixmobile.core.data.DataSource
|
||||||
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
import org.kiwix.kiwixmobile.core.data.remote.KiwixService
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.dao
|
|
||||||
|
|
||||||
import androidx.room.Dao
|
|
||||||
import androidx.room.Insert
|
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
|
||||||
import androidx.room.Transaction
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.LanguageRoomEntity
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
abstract class LanguageRoomDao {
|
|
||||||
@Query("SELECT * FROM LanguageRoomEntity")
|
|
||||||
abstract fun languageAsEntity(): Flow<List<LanguageRoomEntity>>
|
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
||||||
abstract fun saveLanguages(languageRoomEntityList: List<LanguageRoomEntity>)
|
|
||||||
|
|
||||||
@Query("DELETE FROM LanguageRoomEntity")
|
|
||||||
abstract fun deleteAllLanguages()
|
|
||||||
|
|
||||||
fun languages(): Flow<List<Language>> =
|
|
||||||
languageAsEntity().map { it.map(LanguageRoomEntity::toLanguageModel) }
|
|
||||||
|
|
||||||
@Transaction
|
|
||||||
open fun insert(languages: List<Language>) {
|
|
||||||
deleteAllLanguages()
|
|
||||||
saveLanguages(languages.map(::LanguageRoomEntity))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.dao.entities
|
|
||||||
|
|
||||||
import androidx.room.Entity
|
|
||||||
import androidx.room.PrimaryKey
|
|
||||||
import androidx.room.TypeConverter
|
|
||||||
import androidx.room.TypeConverters
|
|
||||||
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.convertToLocal
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
data class LanguageRoomEntity(
|
|
||||||
@PrimaryKey(autoGenerate = true) var id: Long = 0,
|
|
||||||
@TypeConverters(StringToLocalRoomConverter::class)
|
|
||||||
var locale: Locale = Locale.ENGLISH,
|
|
||||||
var active: Boolean = false,
|
|
||||||
var occurencesOfLanguage: Int = 0
|
|
||||||
) {
|
|
||||||
constructor(language: Language) : this(
|
|
||||||
0,
|
|
||||||
language.languageCode.convertToLocal(),
|
|
||||||
language.active,
|
|
||||||
language.occurencesOfLanguage
|
|
||||||
)
|
|
||||||
|
|
||||||
fun toLanguageModel() =
|
|
||||||
Language(locale, active, occurencesOfLanguage, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
class StringToLocalRoomConverter {
|
|
||||||
@TypeConverter
|
|
||||||
fun convertToDatabaseValue(entityProperty: Locale?): String =
|
|
||||||
entityProperty?.isO3Language ?: Locale.ENGLISH.isO3Language
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
fun convertToEntityProperty(databaseValue: String?): Locale =
|
|
||||||
databaseValue?.convertToLocal() ?: Locale.ENGLISH
|
|
||||||
}
|
|
@ -23,7 +23,6 @@ import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
|
|||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
||||||
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
||||||
import org.kiwix.libkiwix.Book
|
import org.kiwix.libkiwix.Book
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ interface DataSource {
|
|||||||
fun getLanguageCategorizedBooks(): Flow<List<BooksOnDiskListItem>>
|
fun getLanguageCategorizedBooks(): Flow<List<BooksOnDiskListItem>>
|
||||||
suspend fun saveBook(book: Book)
|
suspend fun saveBook(book: Book)
|
||||||
suspend fun saveBooks(book: List<Book>)
|
suspend fun saveBooks(book: List<Book>)
|
||||||
suspend fun saveLanguages(languages: List<Language>)
|
|
||||||
suspend fun saveHistory(history: HistoryItem)
|
suspend fun saveHistory(history: HistoryItem)
|
||||||
suspend fun deleteHistory(historyList: List<HistoryListItem>)
|
suspend fun deleteHistory(historyList: List<HistoryListItem>)
|
||||||
suspend fun clearHistory()
|
suspend fun clearHistory()
|
||||||
|
@ -28,17 +28,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
|
|||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDaoCoverts
|
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDaoCoverts
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao
|
import org.kiwix.kiwixmobile.core.dao.WebViewHistoryRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.BundleRoomConverter
|
import org.kiwix.kiwixmobile.core.dao.entities.BundleRoomConverter
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.DownloadRoomEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.HistoryRoomEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.HistoryRoomEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.LanguageRoomEntity
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.StringToLocalRoomConverter
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.WebViewHistoryEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter
|
import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter
|
||||||
|
|
||||||
@ -49,17 +46,15 @@ import org.kiwix.kiwixmobile.core.dao.entities.ZimSourceRoomConverter
|
|||||||
HistoryRoomEntity::class,
|
HistoryRoomEntity::class,
|
||||||
NotesRoomEntity::class,
|
NotesRoomEntity::class,
|
||||||
DownloadRoomEntity::class,
|
DownloadRoomEntity::class,
|
||||||
WebViewHistoryEntity::class,
|
WebViewHistoryEntity::class
|
||||||
LanguageRoomEntity::class
|
|
||||||
],
|
],
|
||||||
version = 9,
|
version = 8,
|
||||||
exportSchema = false
|
exportSchema = false
|
||||||
)
|
)
|
||||||
@TypeConverters(
|
@TypeConverters(
|
||||||
HistoryRoomDaoCoverts::class,
|
HistoryRoomDaoCoverts::class,
|
||||||
ZimSourceRoomConverter::class,
|
ZimSourceRoomConverter::class,
|
||||||
BundleRoomConverter::class,
|
BundleRoomConverter::class
|
||||||
StringToLocalRoomConverter::class
|
|
||||||
)
|
)
|
||||||
abstract class KiwixRoomDatabase : RoomDatabase() {
|
abstract class KiwixRoomDatabase : RoomDatabase() {
|
||||||
abstract fun recentSearchRoomDao(): RecentSearchRoomDao
|
abstract fun recentSearchRoomDao(): RecentSearchRoomDao
|
||||||
@ -67,7 +62,6 @@ abstract class KiwixRoomDatabase : RoomDatabase() {
|
|||||||
abstract fun notesRoomDao(): NotesRoomDao
|
abstract fun notesRoomDao(): NotesRoomDao
|
||||||
abstract fun downloadRoomDao(): DownloadRoomDao
|
abstract fun downloadRoomDao(): DownloadRoomDao
|
||||||
abstract fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
|
abstract fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
|
||||||
abstract fun languageRoomDao(): LanguageRoomDao
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var db: KiwixRoomDatabase? = null
|
private var db: KiwixRoomDatabase? = null
|
||||||
@ -84,8 +78,7 @@ abstract class KiwixRoomDatabase : RoomDatabase() {
|
|||||||
MIGRATION_4_5,
|
MIGRATION_4_5,
|
||||||
MIGRATION_5_6,
|
MIGRATION_5_6,
|
||||||
MIGRATION_6_7,
|
MIGRATION_6_7,
|
||||||
MIGRATION_7_8,
|
MIGRATION_7_8
|
||||||
MIGRATION_8_9
|
|
||||||
)
|
)
|
||||||
.build().also { db = it }
|
.build().also { db = it }
|
||||||
}
|
}
|
||||||
@ -312,23 +305,6 @@ abstract class KiwixRoomDatabase : RoomDatabase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
|
||||||
private val MIGRATION_8_9 =
|
|
||||||
object : Migration(8, 9) {
|
|
||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
|
||||||
database.execSQL(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS `LanguageRoomEntity` (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
||||||
`locale` TEXT NOT NULL DEFAULT 'eng',
|
|
||||||
`active` INTEGER NOT NULL DEFAULT 0,
|
|
||||||
`occurencesOfLanguage` INTEGER NOT NULL DEFAULT 0
|
|
||||||
)
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun destroyInstance() {
|
fun destroyInstance() {
|
||||||
db = null
|
db = null
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import kotlinx.coroutines.flow.flowOn
|
|||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
||||||
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
|
||||||
@ -37,7 +36,6 @@ import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
|
|||||||
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem
|
||||||
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
|
||||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.LanguageItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.LanguageItem
|
||||||
@ -56,7 +54,6 @@ class Repository @Inject internal constructor(
|
|||||||
private val historyRoomDao: HistoryRoomDao,
|
private val historyRoomDao: HistoryRoomDao,
|
||||||
private val webViewHistoryRoomDao: WebViewHistoryRoomDao,
|
private val webViewHistoryRoomDao: WebViewHistoryRoomDao,
|
||||||
private val notesRoomDao: NotesRoomDao,
|
private val notesRoomDao: NotesRoomDao,
|
||||||
private val languageRoomDao: LanguageRoomDao,
|
|
||||||
private val recentSearchRoomDao: RecentSearchRoomDao,
|
private val recentSearchRoomDao: RecentSearchRoomDao,
|
||||||
private val zimReaderContainer: ZimReaderContainer
|
private val zimReaderContainer: ZimReaderContainer
|
||||||
) : DataSource {
|
) : DataSource {
|
||||||
@ -99,12 +96,6 @@ class Repository @Inject internal constructor(
|
|||||||
libkiwixBookOnDisk.insert(listOf(book))
|
libkiwixBookOnDisk.insert(listOf(book))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
override suspend fun saveLanguages(languages: List<Language>) =
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
languageRoomDao.insert(languages)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
@Suppress("InjectDispatcher")
|
||||||
override suspend fun saveHistory(history: HistoryItem) = withContext(Dispatchers.IO) {
|
override suspend fun saveHistory(history: HistoryItem) = withContext(Dispatchers.IO) {
|
||||||
historyRoomDao.saveHistory(history)
|
historyRoomDao.saveHistory(history)
|
||||||
|
@ -39,6 +39,9 @@ interface KiwixService {
|
|||||||
@Url url: String
|
@Url url: String
|
||||||
): MetaLinkNetworkEntity?
|
): MetaLinkNetworkEntity?
|
||||||
|
|
||||||
|
@GET("catalog/v2/languages")
|
||||||
|
suspend fun getLanguages(): LanguageFeed
|
||||||
|
|
||||||
/******** Helper class that sets up new services */
|
/******** Helper class that sets up new services */
|
||||||
object ServiceCreator {
|
object ServiceCreator {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Kiwix Android
|
||||||
|
* Copyright (c) 2025 Kiwix <android.kiwix.org>
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.kiwix.kiwixmobile.core.data.remote
|
||||||
|
|
||||||
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||||
|
import org.simpleframework.xml.Element
|
||||||
|
import org.simpleframework.xml.ElementList
|
||||||
|
import org.simpleframework.xml.Namespace
|
||||||
|
import org.simpleframework.xml.Root
|
||||||
|
|
||||||
|
@Root(name = "feed", strict = false)
|
||||||
|
@Namespace(reference = "http://www.w3.org/2005/Atom")
|
||||||
|
class LanguageFeed {
|
||||||
|
@field:ElementList(name = "entry", inline = true, required = false)
|
||||||
|
var entries: List<LanguageEntry>? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Root(name = "entry", strict = false)
|
||||||
|
@Namespace(reference = "http://www.w3.org/2005/Atom")
|
||||||
|
class LanguageEntry {
|
||||||
|
@field:Element(name = "title", required = false)
|
||||||
|
var title: String = ""
|
||||||
|
|
||||||
|
@field:Element(name = "language", required = false)
|
||||||
|
@Namespace(prefix = "dc", reference = "http://purl.org/dc/terms/")
|
||||||
|
var languageCode: String = ""
|
||||||
|
|
||||||
|
@field:Element(name = "count", required = false)
|
||||||
|
@Namespace(prefix = "thr", reference = "http://purl.org/syndication/thread/1.0")
|
||||||
|
var count: Int = ZERO
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,6 @@ import io.objectbox.BoxStore
|
|||||||
import io.objectbox.kotlin.boxFor
|
import io.objectbox.kotlin.boxFor
|
||||||
import org.kiwix.kiwixmobile.core.CoreApp
|
import org.kiwix.kiwixmobile.core.CoreApp
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.HistoryEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.HistoryEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.LanguageEntity
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.NotesEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.NotesEntity
|
||||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
|
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
|
||||||
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
|
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
|
||||||
@ -50,9 +49,6 @@ class ObjectBoxToRoomMigrator {
|
|||||||
if (!sharedPreferenceUtil.prefIsNotesMigrated) {
|
if (!sharedPreferenceUtil.prefIsNotesMigrated) {
|
||||||
migrateNotes(boxStore.boxFor())
|
migrateNotes(boxStore.boxFor())
|
||||||
}
|
}
|
||||||
if (!sharedPreferenceUtil.prefLanguageListMigrated) {
|
|
||||||
migrateLanguages(boxStore.boxFor())
|
|
||||||
}
|
|
||||||
// TODO we will migrate here for other entities
|
// TODO we will migrate here for other entities
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +87,4 @@ class ObjectBoxToRoomMigrator {
|
|||||||
}
|
}
|
||||||
sharedPreferenceUtil.putPrefNotesMigrated(true)
|
sharedPreferenceUtil.putPrefNotesMigrated(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun migrateLanguages(box: Box<LanguageEntity>) {
|
|
||||||
kiwixRoomDatabase.languageRoomDao()
|
|
||||||
.insert(
|
|
||||||
box.all.map { it.toLanguageModel() }
|
|
||||||
)
|
|
||||||
sharedPreferenceUtil.putPrefLanguageListMigrated(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import org.kiwix.kiwixmobile.core.StorageObserver
|
|||||||
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.HistoryDao
|
import org.kiwix.kiwixmobile.core.dao.HistoryDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
|
||||||
import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao
|
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
|
||||||
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
|
||||||
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
||||||
@ -108,7 +107,6 @@ interface CoreComponent {
|
|||||||
fun historyRoomDao(): HistoryRoomDao
|
fun historyRoomDao(): HistoryRoomDao
|
||||||
fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
|
fun webViewHistoryRoomDao(): WebViewHistoryRoomDao
|
||||||
fun noteRoomDao(): NotesRoomDao
|
fun noteRoomDao(): NotesRoomDao
|
||||||
fun languageRoomDao(): LanguageRoomDao
|
|
||||||
fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator
|
fun objectBoxToRoomMigrator(): ObjectBoxToRoomMigrator
|
||||||
fun context(): Context
|
fun context(): Context
|
||||||
fun downloader(): Downloader
|
fun downloader(): Downloader
|
||||||
|
@ -100,8 +100,4 @@ open class DatabaseModule {
|
|||||||
db.downloadRoomDao().also {
|
db.downloadRoomDao().also {
|
||||||
it.libkiwixBookOnDisk = libkiwixBookOnDisk
|
it.libkiwixBookOnDisk = libkiwixBookOnDisk
|
||||||
}
|
}
|
||||||
|
|
||||||
@Singleton
|
|
||||||
@Provides
|
|
||||||
fun provideLanguageRoomDao(db: KiwixRoomDatabase) = db.languageRoomDao()
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ const val READ_TIMEOUT = 300L
|
|||||||
const val CALL_TIMEOUT = 300L
|
const val CALL_TIMEOUT = 300L
|
||||||
const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}"
|
const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}"
|
||||||
const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/"
|
const val KIWIX_OPDS_LIBRARY_URL = "https://opds.library.kiwix.org/"
|
||||||
|
const val KIWIX_LANGUAGE_URL = "https://library.kiwix.org/"
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class NetworkModule {
|
class NetworkModule {
|
||||||
|
@ -60,6 +60,9 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
|
|||||||
val prefWifiOnly: Boolean
|
val prefWifiOnly: Boolean
|
||||||
get() = sharedPreferences.getBoolean(PREF_WIFI_ONLY, true)
|
get() = sharedPreferences.getBoolean(PREF_WIFI_ONLY, true)
|
||||||
|
|
||||||
|
private val _onlineContentLanguage = MutableStateFlow("")
|
||||||
|
val onlineContentLanguage = _onlineContentLanguage.asStateFlow()
|
||||||
|
|
||||||
val prefIsFirstRun: Boolean
|
val prefIsFirstRun: Boolean
|
||||||
get() = sharedPreferences.getBoolean(PREF_IS_FIRST_RUN, true)
|
get() = sharedPreferences.getBoolean(PREF_IS_FIRST_RUN, true)
|
||||||
|
|
||||||
@ -117,9 +120,6 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
|
|||||||
val prefIsBookOnDiskMigrated: Boolean
|
val prefIsBookOnDiskMigrated: Boolean
|
||||||
get() = sharedPreferences.getBoolean(PREF_BOOK_ON_DISK_MIGRATED, false)
|
get() = sharedPreferences.getBoolean(PREF_BOOK_ON_DISK_MIGRATED, false)
|
||||||
|
|
||||||
val prefLanguageListMigrated: Boolean
|
|
||||||
get() = sharedPreferences.getBoolean(PREF_LANGUAGE_LIST_MIGRATED, false)
|
|
||||||
|
|
||||||
val prefStorage: String
|
val prefStorage: String
|
||||||
get() {
|
get() {
|
||||||
val storage = sharedPreferences.getString(PREF_STORAGE, null)
|
val storage = sharedPreferences.getString(PREF_STORAGE, null)
|
||||||
@ -172,9 +172,6 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
|
|||||||
fun putPrefBookOnDiskMigrated(isMigrated: Boolean) =
|
fun putPrefBookOnDiskMigrated(isMigrated: Boolean) =
|
||||||
sharedPreferences.edit { putBoolean(PREF_BOOK_ON_DISK_MIGRATED, isMigrated) }
|
sharedPreferences.edit { putBoolean(PREF_BOOK_ON_DISK_MIGRATED, isMigrated) }
|
||||||
|
|
||||||
fun putPrefLanguageListMigrated(isMigrated: Boolean) =
|
|
||||||
sharedPreferences.edit { putBoolean(PREF_LANGUAGE_LIST_MIGRATED, isMigrated) }
|
|
||||||
|
|
||||||
fun putPrefLanguage(language: String) =
|
fun putPrefLanguage(language: String) =
|
||||||
sharedPreferences.edit { putString(PREF_LANG, language) }
|
sharedPreferences.edit { putString(PREF_LANG, language) }
|
||||||
|
|
||||||
@ -308,6 +305,18 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var selectedOnlineContentLanguage: String
|
||||||
|
get() = sharedPreferences.getString(SELECTED_ONLINE_CONTENT_LANGUAGE, "").orEmpty()
|
||||||
|
set(selectedOnlineContentLanguage) {
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putString(
|
||||||
|
SELECTED_ONLINE_CONTENT_LANGUAGE,
|
||||||
|
selectedOnlineContentLanguage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_onlineContentLanguage.tryEmit(selectedOnlineContentLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
fun getPublicDirectoryPath(path: String): String =
|
fun getPublicDirectoryPath(path: String): String =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
path
|
path
|
||||||
@ -358,10 +367,10 @@ class SharedPreferenceUtil @Inject constructor(val context: Context) {
|
|||||||
const val PREF_NOTES_MIGRATED = "pref_notes_migrated"
|
const val PREF_NOTES_MIGRATED = "pref_notes_migrated"
|
||||||
const val PREF_APP_DIRECTORY_TO_PUBLIC_MIGRATED = "pref_app_directory_to_public_migrated"
|
const val PREF_APP_DIRECTORY_TO_PUBLIC_MIGRATED = "pref_app_directory_to_public_migrated"
|
||||||
const val PREF_BOOK_ON_DISK_MIGRATED = "pref_book_on_disk_migrated"
|
const val PREF_BOOK_ON_DISK_MIGRATED = "pref_book_on_disk_migrated"
|
||||||
const val PREF_LANGUAGE_LIST_MIGRATED = "pref_language_list_migrated"
|
|
||||||
const val PREF_SHOW_COPY_MOVE_STORAGE_SELECTION_DIALOG = "pref_show_copy_move_storage_dialog"
|
const val PREF_SHOW_COPY_MOVE_STORAGE_SELECTION_DIALOG = "pref_show_copy_move_storage_dialog"
|
||||||
private const val PREF_LATER_CLICKED_MILLIS = "pref_later_clicked_millis"
|
private const val PREF_LATER_CLICKED_MILLIS = "pref_later_clicked_millis"
|
||||||
const val PREF_LAST_DONATION_POPUP_SHOWN_IN_MILLISECONDS =
|
const val PREF_LAST_DONATION_POPUP_SHOWN_IN_MILLISECONDS =
|
||||||
"pref_last_donation_shown_in_milliseconds"
|
"pref_last_donation_shown_in_milliseconds"
|
||||||
|
private const val SELECTED_ONLINE_CONTENT_LANGUAGE = "selectedOnlineContentLanguage"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,9 @@ data class Language constructor(
|
|||||||
constructor(
|
constructor(
|
||||||
languageCode: String,
|
languageCode: String,
|
||||||
active: Boolean,
|
active: Boolean,
|
||||||
occurrencesOfLanguage: Int
|
occurrencesOfLanguage: Int,
|
||||||
) : this(languageCode.convertToLocal(), active, occurrencesOfLanguage)
|
id: Long = 0
|
||||||
|
) : this(languageCode.convertToLocal(), active, occurrencesOfLanguage, id)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean =
|
override fun equals(other: Any?): Boolean =
|
||||||
(other as Language).language == language && other.active == active
|
(other as Language).language == language && other.active == active
|
||||||
|
@ -210,6 +210,7 @@
|
|||||||
<string name="table_of_contents">Table of contents</string>
|
<string name="table_of_contents">Table of contents</string>
|
||||||
<string name="select_languages" tools:keep="@string/select_languages">Select languages</string>
|
<string name="select_languages" tools:keep="@string/select_languages">Select languages</string>
|
||||||
<string name="save_languages" tools:keep="@string/save_languages">Save languages</string>
|
<string name="save_languages" tools:keep="@string/save_languages">Save languages</string>
|
||||||
|
<string name="no_language_available" tools:keep="@string/no_language_available">No languages available</string>
|
||||||
<string name="expand">Expand</string>
|
<string name="expand">Expand</string>
|
||||||
<string name="history">History</string>
|
<string name="history">History</string>
|
||||||
<string name="history_from_current_book">View History From All Books</string>
|
<string name="history_from_current_book">View History From All Books</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user