Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8234092
feat: contract-driven dynamic database download from API
catreedle Feb 10, 2026
d49a99c
feat: persist download states across app relaunches
catreedle Feb 11, 2026
ed6e803
fix: fix installed keyboards not showing in Settings
catreedle Feb 11, 2026
5e2c593
feat: trigger download and "Downloading" state from Select Translatio…
catreedle Feb 11, 2026
88f8148
redirect to Download Screen on confirming translation source change
catreedle Feb 11, 2026
cf24823
feat: set Update state for download button using data version endpoint
catreedle Feb 12, 2026
d645f83
fix download Toast display message
catreedle Feb 13, 2026
14f2ebb
Add new YAML based contract files
andrewtavis Feb 15, 2026
f23e677
Finalize form of YAML contracts
andrewtavis Feb 15, 2026
3af7f7a
Fix included double quote in en.yaml
andrewtavis Feb 15, 2026
8dad758
Update version of data contracts with necessary fields
andrewtavis Feb 15, 2026
17626a2
Minor fix in comment in contracts
andrewtavis Feb 15, 2026
430c058
feat: change to using YAML for data contract
catreedle Feb 16, 2026
8d0d370
remove json contracts
catreedle Feb 16, 2026
19e6fc7
fix minor typo
catreedle Feb 16, 2026
f5b6ff0
feat: read from new db and check for table and column existence
catreedle Feb 17, 2026
1bef6c9
Merge branch 'main' into read-new-db
catreedle Mar 2, 2026
7944c77
fix minor import
catreedle Mar 2, 2026
cac5b54
fix build error from merge conflict
catreedle Mar 2, 2026
704507b
fix merge conflict duplicate functions
catreedle Mar 2, 2026
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
Binary file removed app/src/main/assets/data/DELanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/ENLanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/ESLanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/FRLanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/ITLanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/PTLanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/RULanguageData.sqlite
Binary file not shown.
Binary file removed app/src/main/assets/data/SVLanguageData.sqlite
Binary file not shown.
2 changes: 1 addition & 1 deletion app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import be.scri.data.model.DataResponse
class DynamicDbHelper(
context: Context,
language: String,
) : SQLiteOpenHelper(context, "$language.db", null, 1) {
) : SQLiteOpenHelper(context, "${language}LanguageData.sqlite", null, 1) {
override fun onCreate(db: SQLiteDatabase) {
// Tables are created dynamically via syncDatabase from API contract.
}
Expand Down
14 changes: 13 additions & 1 deletion app/src/main/java/be/scri/helpers/DatabaseFileManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,19 @@ class DatabaseFileManager(
*/
fun getLanguageDatabase(language: String): SQLiteDatabase? {
val dbName = "${language}LanguageData.sqlite"
return getDatabase(dbName, "data/$dbName")
val dbFile = context.getDatabasePath(dbName)

if (!dbFile.exists()) {
Log.w(TAG, "Database $dbName not found. User needs to download data first")
return null
}

return try {
SQLiteDatabase.openDatabase(dbFile.path, null, SQLiteDatabase.OPEN_READONLY)
} catch (e: SQLiteException) {
Log.e(TAG, "Failed to open database $dbName", e)
null
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AutoSuggestionDataManager(
val suggestionMap = HashMap<String, List<String>>()
val columnsToSelect = listOf("word", "autosuggestion_0", "autosuggestion_1", "autosuggestion_2")

if (!db.tableExists("autosuggestions")) return suggestionMap
db.rawQuery("SELECT * FROM autosuggestions LIMIT 1", null).use { tempCursor ->
for (column in columnsToSelect) {
if (tempCursor.getColumnIndex(column) == -1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ class AutocompletionDataManager(
* @param language The language code (e.g. "en", "id") for which to load words.
*/
fun loadWords(language: String) {
val db = fileManager.getLanguageDatabase(language)
db?.rawQuery("SELECT word FROM autocomplete_lexicon", null).use { cursor ->
val wordIndex = cursor!!.getColumnIndex("word")
while (cursor.moveToNext()) {
val word = cursor.getString(wordIndex)?.lowercase()?.trim()
if (!word.isNullOrEmpty()) {
trie.insert(word)
val db = fileManager.getLanguageDatabase(language) ?: return

db.use { database ->
if (!database.tableExists("autocomplete_lexicon")) return

database.rawQuery("SELECT word FROM autocomplete_lexicon", null).use { cursor ->
val wordIndex = cursor.getColumnIndex("word")
while (cursor.moveToNext()) {
val word = cursor.getString(wordIndex)?.lowercase()?.trim()
if (!word.isNullOrEmpty()) {
trie.insert(word)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ class ConjugateDataManager(
): String {
if (form.isNullOrEmpty()) return ""
return fileManager.getLanguageDatabase(language)?.use { db ->
if (!db.tableExists("verbs")) {
return ""
}

val columnName = if (language == "SV") "verb" else "infinitive"
if (!db.columnExists("verbs", columnName)) {
return ""
}

getVerbCursor(db, word, language)?.use { cursor ->
getConjugatedValueFromCursor(cursor, form, language)
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/be/scri/helpers/data/EmojiDataManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class EmojiDataManager(
val db = fileManager.getLanguageDatabase(language) ?: return emojiMap

db.use {
if (!it.tableExists("emoji_keywords")) return emojiMap

it.rawQuery("SELECT MAX(LENGTH(word)) FROM emoji_keywords", null).use { cursor ->
if (cursor.moveToFirst()) {
maxKeywordLength = cursor.getInt(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class PrepositionDataManager(
return hashMapOf()
}
return fileManager.getLanguageDatabase(language)?.use { db ->
if (!db.tableExists("prepositions")) return@use hashMapOf()
db.rawQuery("SELECT preposition, grammaticalCase FROM prepositions", null).use { cursor ->
processCursor(cursor)
} // handle case where cursor is null
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/be/scri/helpers/data/SQLiteExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package be.scri.helpers.data

import android.database.sqlite.SQLiteDatabase

fun SQLiteDatabase.tableExists(tableName: String): Boolean =
rawQuery(
"SELECT name FROM sqlite_master WHERE type='table' AND name='$tableName'",
null,
).use { it.moveToFirst() }

fun SQLiteDatabase.columnExists(
tableName: String,
columnName: String,
): Boolean =
rawQuery("PRAGMA table_info($tableName)", null).use { cursor ->
if (cursor.moveToFirst()) {
val nameIndex = cursor.getColumnIndex("name")
do {
if (cursor.getString(nameIndex) == columnName) {
return true
}
} while (cursor.moveToNext())
}
false
}
Loading