Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import be.scri.helpers.english.ENInterfaceVariables.ALREADY_PLURAL_MSG
import be.scri.helpers.getCategoryIconRes
import be.scri.helpers.getRecentEmojis
import be.scri.helpers.parseRawEmojiSpecsFile
import be.scri.models.ScribeLanguage
import be.scri.models.ScribeState
import be.scri.services.GeneralKeyboardIME
import be.scri.views.KeyboardView
Expand Down Expand Up @@ -418,11 +419,12 @@ class KeyboardUIManager(
languageOutput?.get(title)?.toList() ?: listOf("", "", "", "")
}

val scribeLanguage = ScribeLanguage.fromDisplayName(language)
val layoutResId =
when {
isSubSelection -> R.layout.conjugate_grid_2x1
language == "English" && forms.size <= 4 -> R.layout.conjugate_grid_2x2
language in listOf("Russian", "Swedish") && forms.size <= 4 -> R.layout.conjugate_grid_2x2
scribeLanguage == ScribeLanguage.ENGLISH && forms.size <= 4 -> R.layout.conjugate_grid_2x2
scribeLanguage in listOf(ScribeLanguage.RUSSIAN, ScribeLanguage.SWEDISH) && forms.size <= 4 -> R.layout.conjugate_grid_2x2
forms.size > 4 -> R.layout.conjugate_grid_3x2
else -> R.layout.conjugate_grid_2x2
}
Expand Down
14 changes: 8 additions & 6 deletions app/src/main/java/be/scri/ui/screens/ConjugateViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.lifecycle.viewModelScope
import be.scri.helpers.DatabaseFileManager
import be.scri.helpers.data.getInfinitiveColumnName
import be.scri.helpers.data.tableExists
import be.scri.models.ScribeLanguage
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand All @@ -35,6 +36,10 @@ data class ConjugateSearchResult(
class ConjugateViewModel(
application: Application,
) : AndroidViewModel(application) {
companion object {
private val SUPPORTED_ALIASES = ScribeLanguage.entries.map { it.isoCode }
}

private val prefs = application.getSharedPreferences("scribe_conjugate_search_prefs", Context.MODE_PRIVATE)

private val _searchQuery = MutableStateFlow("")
Expand Down Expand Up @@ -67,13 +72,11 @@ class ConjugateViewModel(
/**
* Returns a list of language aliases that have been downloaded (i.e. conjugate database exists).
*/
fun getDownloadedLanguages(): List<String> {
val aliases = listOf("EN", "FR", "DE", "IT", "PT", "RU", "ES", "SV")
return aliases.filter { alias ->
fun getDownloadedLanguages(): List<String> =
SUPPORTED_ALIASES.filter { alias ->
val dbName = "${alias}ConjugateData.sqlite"
getApplication<Application>().getDatabasePath(dbName).exists()
}
}

/**
* Formats the list of downloaded languages into a user-friendly display string.
Expand Down Expand Up @@ -115,9 +118,8 @@ class ConjugateViewModel(
viewModelScope.launch(Dispatchers.IO) {
val results = mutableListOf<ConjugateSearchResult>()
val fileManager = DatabaseFileManager(getApplication())
val aliases = listOf("EN", "FR", "DE", "IT", "PT", "RU", "ES", "SV")

for (alias in aliases) {
for (alias in SUPPORTED_ALIASES) {
val db = fileManager.getConjugateDatabase(alias) ?: continue

try {
Expand Down
134 changes: 134 additions & 0 deletions app/src/test/kotlin/be/scri/ui/screens/ConjugateViewModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.content.SharedPreferences
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import java.io.File
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -98,4 +99,137 @@ class ConjugateViewModelTest {
assertEquals(ConjugateSearchResult("essere", "IT"), list[0])
assertEquals(ConjugateSearchResult("parler", "FR"), list[1])
}

@Test
fun getDownloadedLanguages_AllDatabasesExist_ReturnsAllEightAliasesInExpectedOrder() {
// Arrange
val expectedAliases = listOf("EN", "FR", "DE", "IT", "PT", "RU", "ES", "SV")
every { application.getDatabasePath(any()) } answers {
val file = mockk<File>()
every { file.exists() } returns true
file
}
val viewModel = ConjugateViewModel(application)

// Act
val actualLanguages = viewModel.getDownloadedLanguages()

// Assert
assertEquals(expectedAliases, actualLanguages)
assertEquals(8, actualLanguages.size)
}

@Test
fun getDownloadedLanguages_PartialDatabasesExist_ReturnsMatchingAliases() {
// Arrange
every { application.getDatabasePath(any()) } answers {
val dbName = firstArg<String>()
val file = mockk<File>()
every { file.exists() } returns (dbName == "ENConjugateData.sqlite" || dbName == "ESConjugateData.sqlite")
file
}
val viewModel = ConjugateViewModel(application)

// Act
val actualLanguages = viewModel.getDownloadedLanguages()

// Assert
assertEquals(listOf("EN", "ES"), actualLanguages)
}

@Test
fun getDownloadedLanguages_NoDatabasesExist_ReturnsEmptyList() {
// Arrange
every { application.getDatabasePath(any()) } answers {
val file = mockk<File>()
every { file.exists() } returns false
file
}
val viewModel = ConjugateViewModel(application)

// Act
val actualLanguages = viewModel.getDownloadedLanguages()

// Assert
assertTrue(actualLanguages.isEmpty())
}

@Test
fun getDownloadedLanguages_UnrecognizedDatabasesPresent_OnlyReturnsSupportedAliases() {
// Arrange
every { application.getDatabasePath(any()) } answers {
val dbName = firstArg<String>()
val file = mockk<File>()
every { file.exists() } returns (
dbName == "ENConjugateData.sqlite" ||
dbName == "XYZConjugateData.sqlite" ||
dbName == "UNKNOWNConjugateData.sqlite"
)
file
}
val viewModel = ConjugateViewModel(application)

// Act
val actualLanguages = viewModel.getDownloadedLanguages()

// Assert
assertEquals(listOf("EN"), actualLanguages)
}

@Test
fun getDownloadedLanguagesFormatted_FormatsCorrectlyForVariousCounts() {
// Arrange
val viewModel = ConjugateViewModel(application)

// 0 languages
every { application.getDatabasePath(any()) } answers {
val file = mockk<File>()
every { file.exists() } returns false
file
}
assertEquals("", viewModel.getDownloadedLanguagesFormatted())

// 1 language
every { application.getDatabasePath(any()) } answers {
val dbName = firstArg<String>()
val file = mockk<File>()
every { file.exists() } returns (dbName == "ENConjugateData.sqlite")
file
}
assertEquals("English", viewModel.getDownloadedLanguagesFormatted())

// 2 languages
every { application.getDatabasePath(any()) } answers {
val dbName = firstArg<String>()
val file = mockk<File>()
every { file.exists() } returns (dbName == "ENConjugateData.sqlite" || dbName == "FRConjugateData.sqlite")
file
}
assertEquals("English and Français", viewModel.getDownloadedLanguagesFormatted())

// 3 languages
every { application.getDatabasePath(any()) } answers {
val dbName = firstArg<String>()
val file = mockk<File>()
every { file.exists() } returns (
dbName == "ENConjugateData.sqlite" ||
dbName == "FRConjugateData.sqlite" ||
dbName == "DEConjugateData.sqlite"
)
file
}
assertEquals("English, Français and Deutsch", viewModel.getDownloadedLanguagesFormatted())
}

@Test
fun testLoadRecentlyConjugatedWithUnrecognizedLanguageAlias() {
every { sharedPreferences.getString("recently_conjugated_list", null) } returns "parler,XYZ;mangiare,INVALID_ALIAS;speak,EN"

val testViewModel = ConjugateViewModel(application)
val list = testViewModel.recentlyConjugated.value
assertEquals(3, list.size)
assertEquals(ConjugateSearchResult("parler", "XYZ"), list[0])
assertEquals(ConjugateSearchResult("mangiare", "INVALID_ALIAS"), list[1])
assertEquals(ConjugateSearchResult("speak", "EN"), list[2])
}
}
Loading
Loading