diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/data/local/dao/LanguageRoomDaoTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/data/local/dao/LanguageRoomDaoTest.kt new file mode 100644 index 000000000..949edf3ca --- /dev/null +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/data/local/dao/LanguageRoomDaoTest.kt @@ -0,0 +1,97 @@ +/* + * Kiwix Android + * Copyright (c) 2023 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.data.local.dao + +import android.content.Context +import androidx.room.Room +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.runner.RunWith +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao +import org.kiwix.kiwixmobile.core.dao.entities.LanguageRoomEntity +import org.kiwix.kiwixmobile.core.data.local.KiwixRoomDatabase +import org.kiwix.kiwixmobile.core.zim_manager.Language +import java.io.IOException + +@RunWith(AndroidJUnit4::class) +class LanguageRoomDaoTest { + + private lateinit var languageRoomDao: LanguageRoomDao + private lateinit var db: KiwixRoomDatabase + + @Test + @Throws(IOException::class) + fun test_inserting_a_language() = runBlocking { + val context = ApplicationProvider.getApplicationContext() + db = Room.inMemoryDatabaseBuilder( + context, KiwixRoomDatabase::class.java + ).build() + languageRoomDao = db.languageRoomDao() + val language: Language = mockk() + languageRoomDao.insert(LanguageRoomEntity(language)) + Assertions.assertEquals(1, languageRoomDao.languages().count()) + } + + @Test + @Throws(IOException::class) + fun test_inserting_multiple_language() = runBlocking { + val context = ApplicationProvider.getApplicationContext() + db = Room.inMemoryDatabaseBuilder( + context, KiwixRoomDatabase::class.java + ).build() + languageRoomDao = db.languageRoomDao() + val language: Language = mockk() + val language2: Language = mockk() + val language3: Language = mockk() + val language4: Language = mockk() + val language5: Language = mockk() + + val languageLists = listOf( + language, language2, language3, language4, language5 + ) + languageRoomDao.insert(languageLists) + Assertions.assertEquals(5, languageRoomDao.languages().count()) + } + + @Test + @Throws(IOException::class) + fun test_deleting_multiple_language() = runBlocking { + val context = ApplicationProvider.getApplicationContext() + db = Room.inMemoryDatabaseBuilder( + context, KiwixRoomDatabase::class.java + ).build() + languageRoomDao = db.languageRoomDao() + val language: Language = mockk() + val language2: Language = mockk() + val language3: Language = mockk() + val language4: Language = mockk() + val language5: Language = mockk() + + val languageLists = listOf( + language, language2, language3, language4, language5 + ) + languageRoomDao.insert(languageLists) + languageRoomDao.deleteLanguages() + Assertions.assertEquals(0, languageRoomDao.languages().count()) + } +} diff --git a/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/LanguageViewModel.kt b/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/LanguageViewModel.kt index 40cc8fd96..6b37817e7 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/LanguageViewModel.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/LanguageViewModel.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.ViewModel import io.reactivex.disposables.CompositeDisposable import io.reactivex.processors.PublishProcessor import org.kiwix.kiwixmobile.core.base.SideEffect -import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.language.adapter.LanguageListItem.LanguageItem import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter import org.kiwix.kiwixmobile.language.viewmodel.Action.SaveAll @@ -35,7 +35,7 @@ import org.kiwix.kiwixmobile.language.viewmodel.State.Saving import javax.inject.Inject class LanguageViewModel @Inject constructor( - private val languageDao: NewLanguagesDao + private val languageRoomDao: LanguageRoomDao ) : ViewModel() { val state = MutableLiveData().apply { value = Loading } @@ -49,7 +49,7 @@ class LanguageViewModel @Inject constructor( actions.map { reduce(it, state.value!!) } .distinctUntilChanged() .subscribe(state::postValue, Throwable::printStackTrace), - languageDao.languages().filter { it.isNotEmpty() } + languageRoomDao.languages().filter { it.isNotEmpty() } .subscribe( { actions.offer(UpdateLanguages(it)) }, Throwable::printStackTrace @@ -93,7 +93,7 @@ class LanguageViewModel @Inject constructor( private fun saveAll(currentState: Content): State { effects.offer( SaveLanguagesAndFinish( - currentState.items, languageDao + currentState.items, languageRoomDao ) ) return Saving diff --git a/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/SaveLanguagesAndFinish.kt b/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/SaveLanguagesAndFinish.kt index 33a731d55..233f2334a 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/SaveLanguagesAndFinish.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/language/viewmodel/SaveLanguagesAndFinish.kt @@ -21,16 +21,16 @@ import androidx.appcompat.app.AppCompatActivity import io.reactivex.Flowable import io.reactivex.schedulers.Schedulers import org.kiwix.kiwixmobile.core.base.SideEffect -import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.core.zim_manager.Language data class SaveLanguagesAndFinish( val languages: List, - val languageDao: NewLanguagesDao + val languageRoomDao: LanguageRoomDao ) : SideEffect { override fun invokeWith(activity: AppCompatActivity) { - Flowable.fromCallable { languageDao.insert(languages) } + Flowable.fromCallable { languageRoomDao.insert(languages) } .subscribeOn(Schedulers.io()) .subscribe({ activity.onBackPressed() diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt index a614c6c1c..95892d7ed 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt @@ -35,8 +35,8 @@ import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.StorageObserver import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.core.dao.NewBookDao -import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.data.remote.KiwixService import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel @@ -77,10 +77,11 @@ import java.util.Locale import java.util.concurrent.TimeUnit.MILLISECONDS import javax.inject.Inject +@Suppress("LongParameterList") class ZimManageViewModel @Inject constructor( private val downloadDao: FetchDownloadDao, private val bookDao: NewBookDao, - private val languageDao: NewLanguagesDao, + private val languageRoomDao: LanguageRoomDao, private val storageObserver: StorageObserver, private val kiwixService: KiwixService, private val context: Application, @@ -143,7 +144,7 @@ class ZimManageViewModel @Inject constructor( val downloads = downloadDao.downloads() val booksFromDao = books() val networkLibrary = PublishProcessor.create() - val languages = languageDao.languages() + val languages = languageRoomDao.languages() return arrayOf( updateBookItems(), checkFileSystemForBooksOnRequest(booksFromDao), @@ -301,7 +302,7 @@ class ZimManageViewModel @Inject constructor( .map { it.sortedBy(Language::language) } .filter(List::isNotEmpty) .subscribe( - languageDao::insert, + languageRoomDao::insert, Throwable::printStackTrace ) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LanguageRoomDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LanguageRoomDao.kt new file mode 100644 index 000000000..e285069f3 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/LanguageRoomDao.kt @@ -0,0 +1,63 @@ +/* + * Kiwix Android + * Copyright (c) 2023 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 androidx.room.Transaction +import androidx.room.TypeConverter +import io.reactivex.Flowable +import org.kiwix.kiwixmobile.core.dao.entities.LanguageRoomEntity +import org.kiwix.kiwixmobile.core.zim_manager.Language +import java.util.Locale + +@Dao +abstract class LanguageRoomDao { + @Query("SELECT * FROM LanguageRoomEntity") + abstract fun languageEntityList(): Flowable> + + fun languages(): Flowable> = languageEntityList().map { + it.map(LanguageRoomEntity::toLanguageModel) + } + + @Query("DELETE FROM LanguageRoomEntity") + abstract fun deleteLanguages() + + @Insert + abstract fun insert(languageRoomEntity: LanguageRoomEntity) + + @Transaction + open fun insert(languages: List) { + deleteLanguages() + languages.map { + insert(LanguageRoomEntity(it)) + } + } +} + +class StringToLocalConverterDao { + @TypeConverter + fun convertToDatabaseValue(entityProperty: Locale?): String = + entityProperty?.isO3Language ?: Locale.ENGLISH.isO3Language + + @TypeConverter + fun convertToEntityProperty(databaseValue: String?): Locale = + databaseValue?.let(::Locale) ?: Locale.ENGLISH +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/NewLanguagesDao.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/NewLanguagesDao.kt index 0ea78ceec..928a128db 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/NewLanguagesDao.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/NewLanguagesDao.kt @@ -28,6 +28,7 @@ import org.kiwix.kiwixmobile.core.zim_manager.Language import javax.inject.Inject import javax.inject.Singleton +@Deprecated("Replaced with the Room") @Singleton class NewLanguagesDao @Inject constructor(private val box: Box) { fun languages() = box.asFlowable() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageEntity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageEntity.kt index c1c146f3f..baa709fa2 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageEntity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageEntity.kt @@ -25,6 +25,7 @@ import io.objectbox.converter.PropertyConverter import org.kiwix.kiwixmobile.core.zim_manager.Language import java.util.Locale +@Deprecated("Replaced with the Room") @Entity data class LanguageEntity( @Id var id: Long = 0, diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageRoomEntity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageRoomEntity.kt new file mode 100644 index 000000000..fc1923dd3 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/dao/entities/LanguageRoomEntity.kt @@ -0,0 +1,44 @@ +/* + * Kiwix Android + * Copyright (c) 2023 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.zim_manager.Language +import java.util.Locale + +@Entity +data class LanguageRoomEntity( + @PrimaryKey(autoGenerate = true) + var id: Long = 0, + val locale: Locale = Locale.ENGLISH, + val active: Boolean = false, + val occurencesOfLanguage: Int = 0 +) { + + constructor(language: Language) : this( + 0, + Locale(language.languageCode), + language.active, + language.occurencesOfLanguage + ) + + fun toLanguageModel() = + Language(locale, active, occurencesOfLanguage, id) +} 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 c6e7e5bd9..9c5d498e6 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 @@ -23,9 +23,9 @@ import io.reactivex.Flowable import io.reactivex.Scheduler import io.reactivex.Single import org.kiwix.kiwixmobile.core.dao.HistoryDao +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.core.dao.NewBookDao import org.kiwix.kiwixmobile.core.dao.NewBookmarksDao -import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao import org.kiwix.kiwixmobile.core.dao.NewRecentSearchRoomDao import org.kiwix.kiwixmobile.core.dao.NotesRoomDao import org.kiwix.kiwixmobile.core.di.qualifiers.IO @@ -56,7 +56,7 @@ class Repository @Inject internal constructor( private val bookmarksDao: NewBookmarksDao, private val historyDao: HistoryDao, private val notesRoomDao: NotesRoomDao, - private val languageDao: NewLanguagesDao, + private val languageRoomDao: LanguageRoomDao, private val recentSearchDao: NewRecentSearchRoomDao, private val zimReaderContainer: ZimReaderContainer ) : DataSource { @@ -86,7 +86,7 @@ class Repository @Inject internal constructor( .subscribeOn(io) override fun saveLanguages(languages: List) = - Completable.fromAction { languageDao.insert(languages) } + Completable.fromAction { languageRoomDao.insert(languages) } .subscribeOn(io) override fun saveHistory(history: HistoryItem) = diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/local/KiwixRoomDatabase.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/local/KiwixRoomDatabase.kt index dca9ce5d0..bebf471e6 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/local/KiwixRoomDatabase.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/local/KiwixRoomDatabase.kt @@ -22,18 +22,27 @@ import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase +import androidx.room.TypeConverters import io.objectbox.BoxStore import io.objectbox.kotlin.boxFor +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.core.dao.NewRecentSearchRoomDao import org.kiwix.kiwixmobile.core.dao.NotesRoomDao +import org.kiwix.kiwixmobile.core.dao.StringToLocalConverterDao +import org.kiwix.kiwixmobile.core.dao.entities.LanguageRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.NotesRoomEntity import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity @Suppress("UnnecessaryAbstractClass") -@Database(entities = [RecentSearchRoomEntity::class, NotesRoomEntity::class], version = 2) +@Database( + entities = [RecentSearchRoomEntity::class, NotesRoomEntity::class, LanguageRoomEntity::class], + version = 3 +) +@TypeConverters(StringToLocalConverterDao::class) abstract class KiwixRoomDatabase : RoomDatabase() { abstract fun newRecentSearchRoomDao(): NewRecentSearchRoomDao abstract fun noteRoomDao(): NotesRoomDao + abstract fun languageRoomDao(): LanguageRoomDao 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 50214f00c..9962cf659 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 @@ -28,6 +28,7 @@ import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.StorageObserver import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao import org.kiwix.kiwixmobile.core.dao.HistoryDao +import org.kiwix.kiwixmobile.core.dao.LanguageRoomDao import org.kiwix.kiwixmobile.core.dao.NewBookDao import org.kiwix.kiwixmobile.core.dao.NewBookmarksDao import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao @@ -93,6 +94,7 @@ interface CoreComponent { fun noteDao(): NewNoteDao fun newLanguagesDao(): NewLanguagesDao fun recentSearchDao(): NewRecentSearchDao + fun languageRoomDao(): LanguageRoomDao fun recentSearchRoomDao(): NewRecentSearchRoomDao fun noteRoomDao(): NotesRoomDao fun newBookmarksDao(): NewBookmarksDao 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 c63f245db..a5563251f 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 @@ -92,4 +92,8 @@ open class DatabaseModule { @Singleton @Provides fun provideNoteRoomDao(db: KiwixRoomDatabase) = db.noteRoomDao() + + @Singleton + @Provides + fun provideLanguageRoomDao(db: KiwixRoomDatabase) = db.languageRoomDao() }