Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Data Contract-Based Noun Suggestion with Plural and Gender Handling #300

2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ plugins {
id("de.mannodermaus.android-junit5") version "1.11.2.0"
id("org.jetbrains.kotlin.plugin.compose") version "2.0.0"
id("jacoco")
kotlin("plugin.serialization") version "1.9.0"
}

jacoco {
Expand Down Expand Up @@ -247,6 +248,7 @@ dependencies {
api("com.google.code.gson:gson:2.10.1")
api("com.github.bumptech.glide:glide:4.14.2")
ksp("com.github.bumptech.glide:ksp:4.14.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}

tasks.register<Copy>("moveFromi18n") {
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/assets/data-contracts/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@
},
"3": {
"title": "Perfekt",
"1": { "ich": "" },
"2": { "du": "" },
"3": { "er/sie/es": "" },
"4": { "wir": "" },
"5": { "ihr": "" },
"6": { "sie/Sie": "" }
"1": { "ich": "[auxiliaryVerb] pastParticiple" },
"2": { "du": "[auxiliaryVerb] pastParticiple" },
"3": { "er/sie/es": "[auxiliaryVerb] pastParticiple" },
"4": { "wir": "[auxiliaryVerb] pastParticiple" },
"5": { "ihr": "[auxiliaryVerb] pastParticiple" },
"6": { "sie/Sie": "[auxiliaryVerb] pastParticiple" }
}
}
}
53 changes: 40 additions & 13 deletions app/src/main/assets/data-contracts/en.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
{
"numbers": { "singular": "plural" },
"genders": {
"canonical": [],
"feminines": [],
"masculines": [],
"commons": [],
"neuters": []
"genders": {
"canonical": ["NOT_INCLUDED"],
"feminines": ["NOT_INCLUDED"],
"masculines": ["NOT_INCLUDED"],
"commons": ["NOT_INCLUDED"],
"neuters": ["NOT_INCLUDED"]
},
"conjugations": {
"1": {
"title": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"6": ""
"title": "Present",
"1": { "I": "simplePresent" },
"2": { "you": "simplePresent" },
"3": { "he/she/it": "simplePresentThirdPersonSingular" },
"4": { "we": "simplePresent" },
"5": { "you all": "simplePresent" },
"6": { "they": "simplePresent" }
},
"2": {
"title": "Past",
"1": { "I": "simplePast" },
"2": { "you": "simplePast" },
"3": { "he/she/it": "simplePast" },
"4": { "we": "simplePast" },
"5": { "you all": "simplePast" },
"6": { "they": "simplePast" }
},
"3": {
"title": "Perfect",
"1": { "I": "presentParticiple simplePast" },
"2": { "you": "presentParticiple simplePast" },
"3": { "he/she/it": "presentParticiple simplePast" },
"4": { "we": "presentParticiple simplePast" },
"5": { "you all": "presentParticiple simplePast" },
"6": { "they": "presentParticiple simplePast" }
},
"4": {
"title": "Past Perfect",
"1": { "I": "pastParticiple simplePast" },
"2": { "you": "pastParticiple simplePast" },
"3": { "he/she/it": "pastParticiple simplePast" },
"4": { "we": "pastParticiple simplePast" },
"5": { "you all": "pastParticiple simplePast" },
"6": { "they": "pastParticiple simplePast" }
}
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/be/scri/helpers/DatabaseFileManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package be.scri.helpers

import android.content.Context
import android.util.Log
import java.io.FileOutputStream

class DatabaseFileManager(
private val context: Context,
) {
fun loadDatabaseFile(language: String) {
val databaseName = "${language}LanguageData.sqlite"
val dbFile = context.getDatabasePath(databaseName)
Log.i("ALPHA", "Loaded Database")

if (!dbFile.exists()) {
context.assets.open("data/$databaseName").use { inputStream ->
FileOutputStream(dbFile).use { outputStream ->
inputStream.copyTo(outputStream)
outputStream.flush()
}
}
}
}
}
97 changes: 31 additions & 66 deletions app/src/main/java/be/scri/helpers/DatabaseHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@
package be.scri.helpers

import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream

class DatabaseHelper(
private val context: Context,
) : SQLiteOpenHelper(context, null, null, DATABASE_VERSION) {
context: Context,
) : SQLiteOpenHelper(
context,
null,
null,
DATABASE_VERSION,
) {
private val dbManagers = DatabaseManagers(context)

companion object {
private const val DATABASE_VERSION = 1
}
Expand All @@ -34,66 +37,28 @@ class DatabaseHelper(
}

fun loadDatabase(language: String) {
val databaseName = "${language}LanguageData.sqlite"
val dbFile = context.getDatabasePath(databaseName)
if (!dbFile.exists()) {
val inputStream: InputStream = context.assets.open("data/$databaseName")
val outputStream: OutputStream = FileOutputStream(dbFile)

inputStream.copyTo(outputStream)

outputStream.flush()
outputStream.close()
inputStream.close()
}
}

fun getEmojiKeywords(language: String): HashMap<String, MutableList<String>> {
val hashMap = HashMap<String, MutableList<String>>()
val dbFile = context.getDatabasePath("${language}LanguageData.sqlite")
val db = SQLiteDatabase.openDatabase(dbFile.path, null, SQLiteDatabase.OPEN_READONLY)
val cursor = db.rawQuery("SELECT * FROM emoji_keywords", null)

cursor.use {
if (cursor.moveToFirst()) {
do {
val key = cursor.getString(0)
hashMap[key] = getEmojiKeyMaps(cursor)
} while (cursor.moveToNext())
}
}
return hashMap
dbManagers.fileManager.loadDatabaseFile(language)
}

fun getEmojiKeyMaps(cursor: Cursor): MutableList<String> {
val values = mutableListOf<String>()

for (i in 1 until cursor.columnCount) {
values.add(cursor.getString(i))
}
return values
}

fun getNounKeywords(language: String): HashMap<String, MutableList<String>> {
val hashMap = HashMap<String, MutableList<String>>()
val dbFile = context.getDatabasePath("${language}LanguageData.sqlite")
val db = SQLiteDatabase.openDatabase(dbFile.path, null, SQLiteDatabase.OPEN_READONLY)
val cursor = db.rawQuery("SELECT * FROM nouns", null)

cursor.use {
if (cursor.moveToFirst()) {
do {
val key = cursor.getString(0).lowercase()
hashMap[key] = getNounKeyMaps(cursor)
} while (cursor.moveToNext())
}
}
return hashMap
}

fun getNounKeyMaps(cursor: Cursor): MutableList<String> {
val values = mutableListOf<String>()
values.add(cursor.getString(2))
return values
}
fun getRequiredData(language: String): DataContract? =
dbManagers.contractLoader.loadContract(
language,
)

fun getEmojiKeywords(language: String): HashMap<String, MutableList<String>> =
dbManagers.emojiManager.getEmojiKeywords(
language,
)

fun findGenderOfWord(language: String): HashMap<String, List<String>> =
dbManagers.genderManager.findGenderOfWord(
language,
getRequiredData(language),
)

fun checkIfWordIsPlural(language: String): List<String>? =
dbManagers.pluralManager.checkIfWordIsPlural(
language,
getRequiredData(language),
)
}
17 changes: 17 additions & 0 deletions app/src/main/java/be/scri/helpers/DatabaseManagers.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package be.scri.helpers

import ContractDataLoader
import EmojiDataManager
import GenderDataManager
import PluralFormsManager
import android.content.Context

class DatabaseManagers(
context: Context,
) {
val fileManager = DatabaseFileManager(context)
val contractLoader = ContractDataLoader(context)
val emojiManager = EmojiDataManager(context)
val genderManager = GenderDataManager(context)
val pluralManager = PluralFormsManager(context)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

import android.content.Context
import android.util.Log
import kotlinx.serialization.json.Json
import java.io.IOException

class ContractDataLoader(
private val context: Context,
) {
fun loadContract(language: String): DataContract? {
val contractName = "${language.lowercase()}.json"
Log.i("ALPHA", "This is the $language")

return try {
val json = Json { ignoreUnknownKeys = true }
context.assets.open("data-contracts/$contractName").use { contractFile ->
val content = contractFile.bufferedReader().readText()
Log.i("ALPHA", content)
json.decodeFromString<DataContract>(content).also {
Log.i("MY-TAG", it.toString())
}
}
} catch (e: IOException) {
Log.e("MY-TAG", "Error loading contract: $contractName", e)
null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@


import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase

class EmojiDataManager(
private val context: Context,
) {
fun getEmojiKeywords(language: String): HashMap<String, MutableList<String>> {
val dbFile = context.getDatabasePath("${language}LanguageData.sqlite")
return processEmojiKeywords(dbFile.path)
}

private fun processEmojiKeywords(dbPath: String): HashMap<String, MutableList<String>> {
val hashMap = HashMap<String, MutableList<String>>()
val db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READONLY)

db.use { database ->
database.rawQuery("SELECT * FROM emoji_keywords", null).use { cursor ->
processEmojiCursor(cursor, hashMap)
}
}
return hashMap
}

private fun processEmojiCursor(
cursor: Cursor,
hashMap: HashMap<String, MutableList<String>>,
) {
if (!cursor.moveToFirst()) return

do {
val key = cursor.getString(0)
hashMap[key] = getEmojiKeyMaps(cursor)
} while (cursor.moveToNext())
}

private fun getEmojiKeyMaps(cursor: Cursor): MutableList<String> =
MutableList(cursor.columnCount - 1) { index ->
cursor.getString(index + 1)
}
}
Loading
Loading