From 823409207a5a27488cc7f227814c321d13abe145 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Tue, 10 Feb 2026 15:01:24 +0700 Subject: [PATCH 01/22] feat: contract-driven dynamic database download from API --- app/build.gradle.kts | 7 ++ app/src/main/AndroidManifest.xml | 2 + .../java/be/scri/data/model/DataResponse.kt | 31 ++++++ .../be/scri/data/model/DataVersionResponse.kt | 15 +++ .../java/be/scri/data/remote/ApiService.kt | 23 ++++ .../be/scri/data/remote/DynamicDbHelper.kt | 70 ++++++++++++ .../be/scri/data/remote/RetrofitClient.kt | 24 +++++ .../screens/download/DataDownloadViewModel.kt | 101 +++++++++++++++--- 8 files changed, 257 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/be/scri/data/model/DataResponse.kt create mode 100644 app/src/main/java/be/scri/data/model/DataVersionResponse.kt create mode 100644 app/src/main/java/be/scri/data/remote/ApiService.kt create mode 100644 app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt create mode 100644 app/src/main/java/be/scri/data/remote/RetrofitClient.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b3e548f4..badfeeca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -233,6 +233,13 @@ dependencies { // ========================== implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.21") + // ========================== + // API + // ========================== + implementation("com.squareup.retrofit2:retrofit:2.11.0") + implementation("com.squareup.retrofit2:converter-gson:2.11.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") + // ========================== // Layout and UI // ========================== diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b70ae9e9..da738c60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,8 @@ + + >>, +) + +/** + * Represents the contract details for the data response, + * including version, update timestamp, and field definitions. + */ +data class Contract( + @SerializedName("version") + val version: String, + @SerializedName("updated_at") + val updatedAt: String, + @SerializedName("fields") + val fields: Map>, +) diff --git a/app/src/main/java/be/scri/data/model/DataVersionResponse.kt b/app/src/main/java/be/scri/data/model/DataVersionResponse.kt new file mode 100644 index 00000000..d7b25243 --- /dev/null +++ b/app/src/main/java/be/scri/data/model/DataVersionResponse.kt @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.model + +import com.google.gson.annotations.SerializedName + +/** + * Represents the data version response for a specific language. + */ +data class DataVersionResponse( + @SerializedName("language") + val language: String, + @SerializedName("versions") + val versions: Map, +) diff --git a/app/src/main/java/be/scri/data/remote/ApiService.kt b/app/src/main/java/be/scri/data/remote/ApiService.kt new file mode 100644 index 00000000..698fc213 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/ApiService.kt @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import be.scri.data.model.DataResponse +import be.scri.data.model.DataVersionResponse +import retrofit2.http.GET +import retrofit2.http.Path + +/** + * Defines the API service for fetching data and data version information. + */ +interface ApiService { + @GET("data/{lang}") + suspend fun getData( + @Path("lang") language: String, + ): DataResponse + + @GET("data-version/{lang}") + suspend fun getDataVersion( + @Path("lang") language: String, + ): DataVersionResponse +} diff --git a/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt b/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt new file mode 100644 index 00000000..e382ef95 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import android.content.ContentValues +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteException +import android.database.sqlite.SQLiteOpenHelper +import android.util.Log +import be.scri.data.model.DataResponse + +/** + * Helper class for managing dynamic SQLite databases based on language. + * It creates tables and inserts data according to the provided DataResponse. + */ +class DynamicDbHelper( + context: Context, + language: String, +) : SQLiteOpenHelper(context, "$language.db", null, 1) { + override fun onCreate(db: SQLiteDatabase) { + // Tables are created dynamically via syncDatabase from API contract. + } + + override fun onUpgrade( + db: SQLiteDatabase, + old: Int, + new: Int, + ) { + // Dynamic schema updates are handled via syncDatabase. + } + + /** + * Synchronizes the database schema and data based on the provided DataResponse. + * @param response The data response containing the contract and data to be inserted. + */ + fun syncDatabase(response: DataResponse) { + val db = writableDatabase + + // Create Tables. + response.contract.fields.forEach { (tableName, columns) -> + val colDefinition = columns.keys.joinToString(", ") { "$it TEXT" } + db.execSQL("CREATE TABLE IF NOT EXISTS $tableName (id INTEGER PRIMARY KEY AUTOINCREMENT, $colDefinition)") + db.execSQL("DELETE FROM $tableName") // clear old data + } + + // Insert Data with Transaction. + db.beginTransaction() + try { + response.data.forEach { (tableName, rows) -> + + rows.forEach { row -> + val cv = ContentValues() + row.forEach { (key, value) -> + cv.put(key, value?.toString() ?: "") + } + val result = db.insert(tableName, null, cv) + if (result == -1L) { + Log.e("SCRIBE_DB", "Failed to insert row into $tableName") + } + } + } + db.setTransactionSuccessful() + } catch (e: SQLiteException) { + Log.e("SCRIBE_DB", "Error during insert: ${e.message}") + } finally { + db.endTransaction() + } + } +} diff --git a/app/src/main/java/be/scri/data/remote/RetrofitClient.kt b/app/src/main/java/be/scri/data/remote/RetrofitClient.kt new file mode 100644 index 00000000..9efcdad4 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/RetrofitClient.kt @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +/** + * Singleton object to provide Retrofit client instance for API calls. + */ +object RetrofitClient { + private const val BASE_URL = "https://scribe-server.toolforge.org/api/v1/" + + val apiService: ApiService by lazy { + val retrofit = + Retrofit + .Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + retrofit.create(ApiService::class.java) + } +} diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index e3230e5d..ad8ff578 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -2,19 +2,36 @@ package be.scri.ui.screens.download +import android.app.Application +import android.content.Context +import android.database.sqlite.SQLiteException +import android.widget.Toast import androidx.compose.runtime.mutableStateMapOf -import androidx.lifecycle.ViewModel +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import be.scri.data.remote.DynamicDbHelper +import be.scri.data.remote.RetrofitClient +import be.scri.helpers.LanguageMappingConstants +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import java.io.IOException import java.time.LocalDate -private const val PLACEBO_SERVER_UPDATED_AT = "2025-01-10" -private const val PLACEBO_LOCAL_UPDATED_AT = "2025-01-01" - /** ViewModel to manage data download states and actions. */ -class DataDownloadViewModel : ViewModel() { +class DataDownloadViewModel( + application: Application, +) : AndroidViewModel(application) { val downloadStates = mutableStateMapOf() + private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) /** - * @return true if server data is newer than local data. + * Checks if an update is available by comparing local and server update timestamps. + * + * @param localUpdatedAt The last update timestamp stored locally. + * @param serverUpdatedAt The last update timestamp from the server. + * @return True if an update is available, false otherwise. */ private fun isUpdateAvailable( localUpdatedAt: String, @@ -32,19 +49,71 @@ class DataDownloadViewModel : ViewModel() { * @param key The key identifying the download item. */ fun handleDownloadAction(key: String) { + // Prevent double clicks. val currentState = downloadStates[key] ?: DownloadState.Ready - downloadStates[key] = - when (currentState) { - DownloadState.Ready -> DownloadState.Downloading - DownloadState.Downloading -> DownloadState.Completed - DownloadState.Completed -> - if (isUpdateAvailable(PLACEBO_LOCAL_UPDATED_AT, PLACEBO_SERVER_UPDATED_AT)) { - DownloadState.Update - } else { - DownloadState.Completed + if (currentState == DownloadState.Downloading || currentState == DownloadState.Completed) { + // If already up to date, tell the user and stop. + if (currentState == DownloadState.Completed) { + Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + } + return + } + + // Set to downloading before hitting the network. + downloadStates[key] = DownloadState.Downloading + + val langCode = + LanguageMappingConstants + .getLanguageAlias( + key.replaceFirstChar { it.uppercase() }, + ).lowercase() + + val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" + + viewModelScope.launch(Dispatchers.IO) { + try { + // Fetch API. + val response = RetrofitClient.apiService.getData(langCode) + val serverLastUpdate = response.contract.updatedAt + + if (isUpdateAvailable(localLastUpdate, serverLastUpdate)) { + // Sync to SQLite. + val dbHelper = DynamicDbHelper(getApplication(), langCode) + dbHelper.syncDatabase(response) + + // Save timestamp. + prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() + + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() } - DownloadState.Update -> DownloadState.Downloading + } else { + // Already up to date: Skip the DB work. + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + } + } + } catch (e: IOException) { + updateErrorState(key, "Network Error: ${e.message}") + } catch (e: SQLiteException) { + updateErrorState(key, "Database Error: ${e.message}") + } catch (e: HttpException) { + updateErrorState(key, "Server Error: ${e.code()}") } + } + } + + private suspend fun updateErrorState( + key: String, + message: String, + ) { + withContext(Dispatchers.Main) { + // Reset status so user can retry. + downloadStates[key] = DownloadState.Ready + Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() + } } } From d49a99ccbe5033e8e97cac27e65ffc461a461834 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 09:11:12 +0700 Subject: [PATCH 02/22] feat: persist download states across app relaunches --- app/src/main/java/be/scri/App.kt | 2 ++ .../ui/screens/download/DataDownloadScreen.kt | 10 +++++++ .../screens/download/DataDownloadViewModel.kt | 26 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index ad2cda99..665362b2 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -81,6 +81,7 @@ fun ScribeApp( val navBackStackEntry by navController.currentBackStackEntryAsState() val downloadStates = downloadViewModel.downloadStates val onDownloadAction = downloadViewModel::handleDownloadAction + val inititalizeStates = downloadViewModel::initializeStates ScribeTheme( useDarkTheme = isDarkTheme, @@ -212,6 +213,7 @@ fun ScribeApp( }, downloadStates = downloadStates, onDownloadAction = onDownloadAction, + initializeStates = inititalizeStates, modifier = Modifier.padding(innerPadding), ) } diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index e3a21942..0bfb02ee 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -18,8 +18,11 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -52,7 +55,9 @@ fun DownloadDataScreen( modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), onDownloadAction: (String) -> Unit = {}, + initializeStates: (List) -> Unit = {}, ) { + val currentInitializeStates by rememberUpdatedState(initializeStates) val scrollState = rememberScrollState() val checkForNewData = remember { mutableStateOf(false) } val regularlyUpdateData = remember { mutableStateOf(true) } @@ -89,6 +94,11 @@ fun DownloadDataScreen( } } + LaunchedEffect(languages) { + val keys = languages.map { it.first } + currentInitializeStates(keys) + } + ScribeBaseScreen( pageTitle = stringResource(R.string.i18n_app__global_download_data), lastPage = stringResource(R.string.i18n_app_installation_title), diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index ad8ff578..6315dde7 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -26,6 +26,32 @@ class DataDownloadViewModel( val downloadStates = mutableStateMapOf() private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) + /** + * Initializes the download states for the provided languages. + * + * @param languages A list of language keys to initialize states for. + */ + fun initializeStates(languages: List) { + languages.forEach { key -> + if (key == "all") return@forEach + + val langCode = + LanguageMappingConstants + .getLanguageAlias( + key.replaceFirstChar { it.uppercase() }, + ).lowercase() + + // Check if a timestamp exists in SharedPreferences. + val savedTimestamp = prefs.getString("last_update_$langCode", null) + + if (savedTimestamp != null) { + downloadStates[key] = DownloadState.Completed + } else { + downloadStates[key] = DownloadState.Ready + } + } + } + /** * Checks if an update is available by comparing local and server update timestamps. * From ed6e803b28234b14564b6d36929433537b9d1bac Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 12:03:08 +0700 Subject: [PATCH 03/22] fix: fix installed keyboards not showing in Settings --- app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt b/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt index 16258974..b47eae15 100644 --- a/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt +++ b/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt @@ -26,7 +26,7 @@ object SettingsUtil { fun checkKeyboardInstallation(context: Context): Boolean { val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - return imm.enabledInputMethodList.any { it.packageName == "be.scri.debug" } + return imm.enabledInputMethodList.any { it.packageName == context.packageName } } /** From 5e2c593027cfb408ba18f02d7928c69e877a776f Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 16:20:43 +0700 Subject: [PATCH 04/22] feat: trigger download and "Downloading" state from Select Translation Source Language Screen --- .../scri/ui/screens/SelectLanguageScreen.kt | 4 +- .../ui/screens/download/DataDownloadScreen.kt | 6 +- .../screens/download/DataDownloadViewModel.kt | 95 ++++++++++++------- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt index 7446a804..fad200aa 100644 --- a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt @@ -46,7 +46,7 @@ fun SelectTranslationSourceLanguageScreen( onBackNavigation: () -> Unit, onNavigateToDownloadData: () -> Unit, modifier: Modifier = Modifier, - onDownloadAction: (String) -> Unit = {}, + onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, ) { val context = LocalContext.current val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) @@ -143,7 +143,7 @@ fun SelectTranslationSourceLanguageScreen( val downloadKey = currentLanguage.lowercase() // trigger the download action in the ViewModel. - onDownloadAction(downloadKey) + onDownloadAction(downloadKey, true) showDialog.value = false // Navigate to the download data screen. onNavigateToDownloadData() diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index 0bfb02ee..50e985e6 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -54,7 +54,7 @@ fun DownloadDataScreen( onNavigateToTranslation: (String) -> Unit, modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), - onDownloadAction: (String) -> Unit = {}, + onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, initializeStates: (List) -> Unit = {}, ) { val currentInitializeStates by rememberUpdatedState(initializeStates) @@ -178,7 +178,7 @@ fun DownloadDataScreen( if (currentStatus == DownloadState.Ready) { selectedLanguage.value = lang } else { - onDownloadAction(key) + onDownloadAction(key, false) } }, isDarkTheme = isDark, @@ -216,7 +216,7 @@ fun DownloadDataScreen( ), textChange = stringResource(R.string.i18n_app_download_menu_ui_translation_source_tooltip_change_language), onConfirm = { - onDownloadAction(key) + onDownloadAction(key, false) selectedLanguage.value = null }, onChange = { onNavigateToTranslation(languageId) }, diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index 6315dde7..fe24df32 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -13,6 +13,7 @@ import be.scri.data.remote.DynamicDbHelper import be.scri.data.remote.RetrofitClient import be.scri.helpers.LanguageMappingConstants import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import retrofit2.HttpException @@ -24,6 +25,7 @@ class DataDownloadViewModel( application: Application, ) : AndroidViewModel(application) { val downloadStates = mutableStateMapOf() + private val downloadJobs = mutableMapOf() private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) /** @@ -34,6 +36,7 @@ class DataDownloadViewModel( fun initializeStates(languages: List) { languages.forEach { key -> if (key == "all") return@forEach + if (downloadStates.containsKey(key)) return@forEach val langCode = LanguageMappingConstants @@ -73,16 +76,24 @@ class DataDownloadViewModel( * Handles the download action based on the current state. * * @param key The key identifying the download item. + * @param forceDownload If true, cancels any existing download and forces a new one. */ - fun handleDownloadAction(key: String) { - // Prevent double clicks. + fun handleDownloadAction( + key: String, + forceDownload: Boolean = false, + ) { val currentState = downloadStates[key] ?: DownloadState.Ready - if (currentState == DownloadState.Downloading || currentState == DownloadState.Completed) { - // If already up to date, tell the user and stop. + if (forceDownload) { + downloadJobs[key]?.cancel() + } else { + if (currentState == DownloadState.Downloading) { + return + } + if (currentState == DownloadState.Completed) { Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + return } - return } // Set to downloading before hitting the network. @@ -96,39 +107,44 @@ class DataDownloadViewModel( val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" - viewModelScope.launch(Dispatchers.IO) { - try { - // Fetch API. - val response = RetrofitClient.apiService.getData(langCode) - val serverLastUpdate = response.contract.updatedAt - - if (isUpdateAvailable(localLastUpdate, serverLastUpdate)) { - // Sync to SQLite. - val dbHelper = DynamicDbHelper(getApplication(), langCode) - dbHelper.syncDatabase(response) - - // Save timestamp. - prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() - - withContext(Dispatchers.Main) { - downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() - } - } else { - // Already up to date: Skip the DB work. - withContext(Dispatchers.Main) { - downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + // Store the job so we can cancel it later if needed. + downloadJobs[key] = + viewModelScope.launch(Dispatchers.IO) { + try { + // Fetch API. + val response = RetrofitClient.apiService.getData(langCode) + val serverLastUpdate = response.contract.updatedAt + + // Always download when forcing, or when update is available. + if (forceDownload || isUpdateAvailable(localLastUpdate, serverLastUpdate)) { + val dbHelper = DynamicDbHelper(getApplication(), langCode) + dbHelper.syncDatabase(response) + + // Save timestamp. + prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() + + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() + } + } else { + // Already up to date: Skip the DB work. + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + } } + } catch (e: IOException) { + updateErrorState(key, "Network Error: ${e.message}") + } catch (e: SQLiteException) { + updateErrorState(key, "Database Error: ${e.message}") + } catch (e: HttpException) { + updateErrorState(key, "Server Error: ${e.code()}") + } finally { + // Clean up the job reference when done. + downloadJobs.remove(key) } - } catch (e: IOException) { - updateErrorState(key, "Network Error: ${e.message}") - } catch (e: SQLiteException) { - updateErrorState(key, "Database Error: ${e.message}") - } catch (e: HttpException) { - updateErrorState(key, "Server Error: ${e.code()}") } - } } private suspend fun updateErrorState( @@ -141,6 +157,15 @@ class DataDownloadViewModel( Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() } } + + /** + * Cancels all ongoing downloads. Useful for cleanup. + */ + override fun onCleared() { + super.onCleared() + downloadJobs.values.forEach { it.cancel() } + downloadJobs.clear() + } } /** From 88f81484faa99839ff1ae49bf54f7d91aaed69cc Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 17:48:06 +0700 Subject: [PATCH 05/22] redirect to Download Screen on confirming translation source change --- app/src/main/java/be/scri/App.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index 665362b2..538021d9 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -245,7 +245,7 @@ fun ScribeApp( navController.popBackStack() }, onNavigateToDownloadData = { - navController.popBackStack() + navController.navigate("download_data") }, onDownloadAction = onDownloadAction, modifier = Modifier.padding(innerPadding), From cf24823686ace8d1ce3ce2da0cc6683bbf0a1f16 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Thu, 12 Feb 2026 15:37:34 +0700 Subject: [PATCH 06/22] feat: set Update state for download button using data version endpoint --- app/src/main/java/be/scri/App.kt | 2 + .../ui/screens/download/DataDownloadScreen.kt | 10 ++- .../screens/download/DataDownloadViewModel.kt | 67 ++++++++++++++++++- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index 538021d9..632f0c43 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -82,6 +82,7 @@ fun ScribeApp( val downloadStates = downloadViewModel.downloadStates val onDownloadAction = downloadViewModel::handleDownloadAction val inititalizeStates = downloadViewModel::initializeStates + val checkAllForUpdates = downloadViewModel::checkAllForUpdates ScribeTheme( useDarkTheme = isDarkTheme, @@ -214,6 +215,7 @@ fun ScribeApp( downloadStates = downloadStates, onDownloadAction = onDownloadAction, initializeStates = inititalizeStates, + checkAllForUpdates = checkAllForUpdates, modifier = Modifier.padding(innerPadding), ) } diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index 50e985e6..0ca440bc 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -47,6 +47,8 @@ import be.scri.ui.screens.settings.SettingsUtil * @param modifier Modifier for layout and styling. * @param downloadStates Map of language keys to their download states. * @param onDownloadAction Callback for download action when a language is selected and confirmed. + * @param initializeStates Callback to initialize download states for given languages. + * @param checkAllForUpdates Callback to check all languages for available updates. */ @Composable fun DownloadDataScreen( @@ -56,6 +58,7 @@ fun DownloadDataScreen( downloadStates: Map = emptyMap(), onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, initializeStates: (List) -> Unit = {}, + checkAllForUpdates: () -> Unit, ) { val currentInitializeStates by rememberUpdatedState(initializeStates) val scrollState = rememberScrollState() @@ -131,7 +134,12 @@ fun DownloadDataScreen( Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { CircleClickableItemComp( title = stringResource(R.string.i18n_app_download_menu_ui_update_data_check_new), - onClick = { checkForNewData.value = !checkForNewData.value }, + onClick = { + checkForNewData.value = !checkForNewData.value + if (checkForNewData.value) { + checkAllForUpdates() + } + }, isSelected = checkForNewData.value, ) diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index fe24df32..80b5a7c8 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -5,6 +5,7 @@ package be.scri.ui.screens.download import android.app.Application import android.content.Context import android.database.sqlite.SQLiteException +import android.util.Log import android.widget.Toast import androidx.compose.runtime.mutableStateMapOf import androidx.lifecycle.AndroidViewModel @@ -53,6 +54,9 @@ class DataDownloadViewModel( downloadStates[key] = DownloadState.Ready } } + + // After initializing, check for updates on all Completed languages. + checkAllForUpdates() } /** @@ -66,8 +70,8 @@ class DataDownloadViewModel( localUpdatedAt: String, serverUpdatedAt: String, ): Boolean { - val localDate = LocalDate.parse(localUpdatedAt) - val serverDate = LocalDate.parse(serverUpdatedAt) + val localDate = LocalDate.parse(localUpdatedAt.take(10)) + val serverDate = LocalDate.parse(serverUpdatedAt.take(10)) return serverDate.isAfter(localDate) } @@ -147,6 +151,63 @@ class DataDownloadViewModel( } } + /** + * Checks for available updates using the data version API. + * Sets state to Update if server has newer data. + * + * @param key The key identifying the download item. + */ + fun checkForUpdates(key: String) { + val currentState = downloadStates[key] ?: DownloadState.Ready + if (currentState == DownloadState.Downloading) return + + val langCode = + LanguageMappingConstants + .getLanguageAlias(key.replaceFirstChar { it.uppercase() }) + .lowercase() + + val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" + + viewModelScope.launch(Dispatchers.IO) { + try { + val response = RetrofitClient.apiService.getDataVersion(langCode) + + val hasUpdate = + response.versions.values.any { serverDate -> + isUpdateAvailable(localLastUpdate, serverDate) + } + + withContext(Dispatchers.Main) { + downloadStates[key] = + if (hasUpdate) { + DownloadState.Update + } else { + DownloadState.Completed + } + } + } catch (e: IOException) { + Log.w("DownloadVM", "Network error while checking updates for $key: ${e.message}") + } catch (e: HttpException) { + Log.w("DownloadVM", "Server error while checking updates for $key: ${e.code()}") + } catch (e: SQLiteException) { + Log.w("DownloadVM", "Database error while checking updates for $key: ${e.message}") + } + } + } + + /** + * Checks all languages for updates. + */ + fun checkAllForUpdates() { + downloadStates.keys.forEach { key -> + if (key == "all") return@forEach + // Only check languages that have been downloaded before. + if (downloadStates[key] == DownloadState.Completed) { + checkForUpdates(key) + } + } + } + private suspend fun updateErrorState( key: String, message: String, @@ -159,7 +220,7 @@ class DataDownloadViewModel( } /** - * Cancels all ongoing downloads. Useful for cleanup. + * Cancels all ongoing downloads. */ override fun onCleared() { super.onCleared() From d645f8376a83b7e5d6c08720a369bfef43f4b589 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Fri, 13 Feb 2026 13:50:00 +0700 Subject: [PATCH 07/22] fix download Toast display message --- .../be/scri/ui/screens/download/DataDownloadViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index 80b5a7c8..38e09082 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -87,6 +87,7 @@ class DataDownloadViewModel( forceDownload: Boolean = false, ) { val currentState = downloadStates[key] ?: DownloadState.Ready + val displayLang = key.replaceFirstChar { it.uppercase() } if (forceDownload) { downloadJobs[key]?.cancel() } else { @@ -95,7 +96,7 @@ class DataDownloadViewModel( } if (currentState == DownloadState.Completed) { - Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + Toast.makeText(getApplication(), "$displayLang data is already up to date", Toast.LENGTH_SHORT).show() return } } @@ -129,7 +130,7 @@ class DataDownloadViewModel( withContext(Dispatchers.Main) { downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() + Toast.makeText(getApplication(), "Download $displayLang data finished!", Toast.LENGTH_SHORT).show() } } else { // Already up to date: Skip the DB work. From 14f2ebb462038445d05f8a60e615b02317ccbf2c Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 13:24:16 +0100 Subject: [PATCH 08/22] Add new YAML based contract files --- app/src/main/assets/data-contracts/de.yaml | 46 +++++++ app/src/main/assets/data-contracts/en.yaml | 136 +++++++++++++++++++++ app/src/main/assets/data-contracts/es.yaml | 66 ++++++++++ app/src/main/assets/data-contracts/fr.yaml | 78 ++++++++++++ app/src/main/assets/data-contracts/it.yaml | 64 ++++++++++ app/src/main/assets/data-contracts/pt.yaml | 80 ++++++++++++ app/src/main/assets/data-contracts/ru.yaml | 44 +++++++ app/src/main/assets/data-contracts/sv.yaml | 43 +++++++ 8 files changed, 557 insertions(+) create mode 100644 app/src/main/assets/data-contracts/de.yaml create mode 100644 app/src/main/assets/data-contracts/en.yaml create mode 100644 app/src/main/assets/data-contracts/es.yaml create mode 100644 app/src/main/assets/data-contracts/fr.yaml create mode 100644 app/src/main/assets/data-contracts/it.yaml create mode 100644 app/src/main/assets/data-contracts/pt.yaml create mode 100644 app/src/main/assets/data-contracts/ru.yaml create mode 100644 app/src/main/assets/data-contracts/sv.yaml diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml new file mode 100644 index 00000000..980cc075 --- /dev/null +++ b/app/src/main/assets/data-contracts/de.yaml @@ -0,0 +1,46 @@ + +numbers: + nominativeSingular: nominativePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + "1": + title: Präsens + conjugationTypes: + "1": + title: Präsens + conjugationForms: + ich: indicativePresentFirstPersonSingular + du: indicativePresentSecondPersonSingular + er/sie/es: indicativePresentThirdPersonSingular + wir: indicativePresentFirstPersonPlural + ihr: indicativePresentSecondPersonPlural + sie/Sie: indicativePresentThirdPersonPlural + "2": + title: Preterite + conjugationTypes: + "1": + title: Preterite + conjugationForms: + ich: indicativePreteriteFirstPersonSingular + du: indicativePreteriteFirstPersonPlural + er/sie/es: indicativePreteriteSecondPersonSingular + wir: indicativePreteriteSecondPersonPlural + ihr: indicativePreteriteThirdPersonSingular + sie/Sie: indicativePreteriteThirdPersonPlural + "3": + title: Perfekt + conjugationTypes: + "1": + title: Perfekt + conjugationForms: + ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" + du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" + er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" + wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" + ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" + sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml new file mode 100644 index 00000000..2eaa5946 --- /dev/null +++ b/app/src/main/assets/data-contracts/en.yaml @@ -0,0 +1,136 @@ +{ + "numbers": { + "singular": "plural" + }, + "genders": { + "canonical": [], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Present", + "conjugationTypes": { + "1": { + "title": "Pr. Simple", + "conjugationForms": { + "I/you/plural": "simplePresent", + "he/she/it": "simplePresentThirdPersonSingular" + } + }, + "2": { + "title": "Pr. Perfect", + "conjugationForms": { + "I/you/plural": "[have] pastParticiple", + "he/she/it": "[has] pastParticiple" + } + }, + "3": { + "title": "Pr. Continuous", + "conjugationForms": { + "I": "[am] presentParticiple", + "you/plural": "[are] presentParticiple", + "he/she/it": "[is] presentParticiple" + } + }, + "4": { + "title": "Pr. Perf. Continuous", + "conjugationForms": { + "I/you/plural": "[have been] presentParticiple", + "he/she/it": "[has been] presentParticiple" + } + } + } + }, + "2": { + "title": "Past", + "conjugationTypes": { + "1": { + "title": "Past Simple", + "conjugationForms": { + "all": "simplePast" + } + }, + "2": { + "title": "Past Perfect", + "conjugationForms": { + "all": "[had] pastParticiple" + } + }, + "3": { + "title": "Past Continuous", + "conjugationForms": { + "I/he/she/it": "[was] presentParticiple", + "you/plural": "[were] presentParticiple" + } + }, + "4": { + "title": "Past Perf. Continuous", + "conjugationForms": { + "all": "[had been] presentParticiple" + } + } + } + }, + "3": { + "title": "Future", + "conjugationTypes": { + "1": { + "title": "Fut. Simple", + "conjugationForms": { + "all": "[will] infinitive" + } + }, + "2": { + "title": "Fut. Perfect", + "conjugationForms": { + "all": "[will have] pastParticiple" + } + }, + "3": { + "title": "Fut. Continuous", + "conjugationForms": { + "all": "[will be] presentParticiple" + } + }, + "4": { + "title": "Fut. Perf. Continuous", + "conjugationForms": { + "all": "[will have been] presentParticiple" + } + } + } + }, + "4": { + "title": "Conditional", + "conjugationTypes": { + "1": { + "title": "Cond. Simple", + "conjugationForms": { + "all": "[would] infinitive" + } + }, + "2": { + "title": "Cond. Perfect", + "conjugationForms": { + "all": "[would have] pastParticiple" + } + }, + "3": { + "title": "Cond. Continuous", + "conjugationForms": { + "all": "[would be] presentParticiple" + } + }, + "4": { + "title": "Cond. Perf. Continuous", + "conjugationForms": { + "all": "[would have been] presentParticiple" + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml new file mode 100644 index 00000000..63ec1131 --- /dev/null +++ b/app/src/main/assets/data-contracts/es.yaml @@ -0,0 +1,66 @@ +{ + "numbers": { + "feminineSingular": "femininePlural", + "masculineSingular": "masculinePlural" + }, + "genders": { + "canonical": [], + "feminines": ["feminineSingular"], + "masculines": ["masculineSingular"], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "yo": "indicativePresentFirstPersonSingular", + "tú": "indicativePresentFirstPersonPlural", + "él/ella/Ud.": "indicativePresentSecondPersonSingular", + "nosotros": "indicativePresentSecondPersonPlural", + "vosotros": "indicativePresentThirdPersonSingular", + "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Pretérito", + "conjugationTypes": { + "1": { + "title": "Pretérito", + "conjugationForms": { + "yo": "preteriteFirstPersonSingular", + "tú": "preteriteFirstPersonPlural", + "él/ella/Ud.": "preteriteSecondPersonSingular", + "nosotros": "preteriteSecondPersonPlural", + "vosotros": "preteriteThirdPersonSingular", + "ellos/ellas/Uds.": "preteriteThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Imperfecto", + "conjugationTypes" : { + "1": { + "title": "Imperfecto", + "conjugationForms": { + "yo": "pastImperfectFirstPersonSingular", + "tú": "pastImperfectFirstPersonPlural", + "él/ella/Ud.": "pastImperfectSecondPersonSingular", + "nosotros": "pastImperfectSecondPersonPlural", + "vosotros": "pastImperfectThirdPersonSingular", + "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml new file mode 100644 index 00000000..44833124 --- /dev/null +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -0,0 +1,78 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Présent", + "conjugationTypes": { + "1": { + "title": "Présent", + "conjugationForms": { + "je": "indicativePresentFirstPersonSingular", + "tu": "indicativePresentFirstPersonPlural", + "il/elle": "indicativePresentSecondPersonSingular", + "nous": "indicativePresentSecondPersonPlural", + "vous": "indicativePresentThirdPersonSingular", + "ils/elles": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Passé simple", + "conjugationTypes": { + "1": { + "title": "Passé simple", + "conjugationForms": { + "je": "indicativePreteriteFirstPersonSingular", + "tu": "indicativePreteriteFirstPersonPlural", + "il/elle": "indicativePreteriteSecondPersonSingular", + "nous": "indicativePreteriteSecondPersonPlural", + "vous": "indicativePreteriteThirdPersonSingular", + "ils/elles": "indicativePreteriteThirdPersonPlural" + } + } + } + }, + "3": { + "title": "Imparfait", + "conjugationTypes": { + "1": { + "title": "Imparfait", + "conjugationForms": { + "je": "indicativeImperfectFirstPersonSingular", + "tu": "indicativeImperfectFirstPersonPlural", + "il/elle": "indicativeImperfectSecondPersonSingular", + "nous": "indicativeImperfectSecondPersonPlural", + "vous": "indicativeImperfectThirdPersonSingular", + "ils/elles": "indicativeImperfectThirdPersonPlural" + } + } + } + + }, + "4": { + "title": "Futur", + "conjugationTypes":{ + "1": { + "title": "Futur", + "conjugationForms": { + "je": "indicativeSimpleFutureFirstPersonSingular", + "tu": "indicativeSimpleFutureFirstPersonPlural", + "il/elle": "indicativeSimpleFutureSecondPersonSingular", + "nous": "indicativeSimpleFutureSecondPersonPlural", + "vous": "indicativeSimpleFutureThirdPersonSingular", + "ils/elles": "indicativeSimpleFutureThirdPersonPlural" + } + } + } + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml new file mode 100644 index 00000000..f30709b0 --- /dev/null +++ b/app/src/main/assets/data-contracts/it.yaml @@ -0,0 +1,64 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "io": "presentIndicativeFirstPersonSingular", + "tu": "presentIndicativeFirstPersonPlural", + "lei/lui": "presentIndicativeSecondPersonSingular", + "noi": "presentIndicativeSecondPersonPlural", + "voi": "presentIndicativeThirdPersonSingular", + "loro": "presentIndicativeThirdPersonPlural" + } + } + } + + }, + "2": { + "title": "Preterito", + "conjugationTypes": { + "1": { + "title": "Preterito", + "conjugationForms": { + "io": "preteriteFirstPersonSingular", + "tu": "preteriteFirstPersonPlural", + "lei/lui": "preteriteSecondPersonSingular", + "noi": "preteriteSecondPersonPlural", + "voi": "preteriteThirdPersonSingular", + "loro": "preteriteThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Imperfetto", + "conjugationTypes": { + "1": { + "title": "Imperfetto", + "conjugationForms": { + "io": "pastImperfectFirstPersonSingular", + "tu": "pastImperfectFirstPersonPlural", + "lei/lui": "pastImperfectSecondPersonSingular", + "noi": "pastImperfectSecondPersonPlural", + "voi": "pastImperfectThirdPersonSingular", + "loro": "pastImperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml new file mode 100644 index 00000000..7a3b55f3 --- /dev/null +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -0,0 +1,80 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "eu": "indicativePresentFirstPersonSingular", + "tu": "indicativePresentFirstPersonPlural", + "ele/ela/você": "indicativePresentSecondPersonSingular", + "nós": "indicativePresentSecondPersonPlural", + "vós": "indicativePresentThirdPersonSingular", + "eles/elas/vocês": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Pretérito Perfeito", + "conjugationTypes": { +"1": { + "title": "Pretérito Perfeito", + "conjugationForms": { + "eu": "indicativePastPerfectFirstPersonSingular", + "tu": "indicativePastPerfectFirstPersonPlural", + "ele/ela/você": "indicativePastPerfectSecondPersonSingular", + "nós": "indicativePastPerfectSecondPersonPlural", + "vós": "indicativePastPerfectThirdPersonSingular", + "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Pretérito Imperfeito", + "conjugationTypes": { +"1": { + "title": "Pretérito Imperfeito", + "conjugationForms": { + "eu": "indicativePastImperfectFirstPersonSingular", + "tu": "indicativePastImperfectFirstPersonPlural", + "ele/ela/você": "indicativePastImperfectSecondPersonSingular", + "nós": "indicativePastImperfectSecondPersonPlural", + "vós": "indicativePastImperfectThirdPersonSingular", + "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" + } + } + } + + }, + "4": { + "title": "Futuro Simples", + "conjugationTypes": { +"1": { + "title": "Futuro Simples", + "conjugationForms": { + "eu": "indicativePluperfectFirstPersonSingular", + "tu": "indicativePluperfectFirstPersonPlural", + "ele/ela/você": "indicativePluperfectSecondPersonSingular", + "nós": "indicativePluperfectSecondPersonPlural", + "vós": "indicativePluperfectThirdPersonSingular", + "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml new file mode 100644 index 00000000..1742fb91 --- /dev/null +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -0,0 +1,44 @@ +{ + "numbers": { + "nominativeSingular": "nominativePlural" + }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Настоящее (Present)", + "conjugationTypes": { + "1": { + "title": "Indicative Present", + "conjugationForms": { + "я (I)": "indicativePresentFirstPersonSingular", + "ты (you, sing.)": "indicativePresentSecondPersonSingular", + "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", + "мы (we)": "indicativePresentFirstPersonPlural", + "вы (you, pl.)": "indicativePresentSecondPersonPlural", + "они (they)": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Прошедшее (Past)", + "conjugationTypes": { + "1": { + "title": "Indicative Past", + "conjugationForms": { + "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", + "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", + "оно (it, neut.)": "neuterIndicativePast", + "мы/вы/они (we/you/they)": "indicativePastPlural" + } + } + } + } + } +} diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml new file mode 100644 index 00000000..6bdb2e62 --- /dev/null +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -0,0 +1,43 @@ +{ + "numbers": { + "nominativeIndefiniteSingular": "nominativeIndefinitePlural", + "nominativeDefiniteSingular": "nominativeDefinitePlural" + }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Aktiv", + "conjugationTypes": { + "1": { + "title": "Aktiv", + "conjugationForms": { + "infinitiv": "activeInfinitive", + "presens": "activePresent", + "preteritum": "activePreterite", + "supinum": "activeSupine" + } + } + } + }, + "2": { + "title": "Passiv", + "conjugationTypes": { + "1": { + "title": "Passiv", + "conjugationForms": { + "infinitiv": "passiveInfinitive", + "presens": "passivePresent", + "preteritum": "passivePreterite", + "supinum": "passiveSupine" + } + } + } + } + } +} From f23e677b3a133be9eebbead142465e17f381992c Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 14:28:33 +0100 Subject: [PATCH 09/22] Finalize form of YAML contracts --- app/src/main/assets/data-contracts/de.yaml | 85 ++++---- app/src/main/assets/data-contracts/en.yaml | 227 +++++++++------------ app/src/main/assets/data-contracts/es.yaml | 112 +++++----- app/src/main/assets/data-contracts/fr.yaml | 135 ++++++------ app/src/main/assets/data-contracts/it.yaml | 109 ++++------ app/src/main/assets/data-contracts/pt.yaml | 138 ++++++------- app/src/main/assets/data-contracts/ru.yaml | 75 +++---- app/src/main/assets/data-contracts/sv.yaml | 73 +++---- 8 files changed, 400 insertions(+), 554 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index 980cc075..b4aac3a6 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -1,46 +1,45 @@ - numbers: - nominativeSingular: nominativePlural + nominativeSingular: nominativePlural genders: - canonical: [gender] - feminines: [] - masculines: [] - commons: [] - neuters: [] + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] conjugations: - "1": - title: Präsens - conjugationTypes: - "1": - title: Präsens - conjugationForms: - ich: indicativePresentFirstPersonSingular - du: indicativePresentSecondPersonSingular - er/sie/es: indicativePresentThirdPersonSingular - wir: indicativePresentFirstPersonPlural - ihr: indicativePresentSecondPersonPlural - sie/Sie: indicativePresentThirdPersonPlural - "2": - title: Preterite - conjugationTypes: - "1": - title: Preterite - conjugationForms: - ich: indicativePreteriteFirstPersonSingular - du: indicativePreteriteFirstPersonPlural - er/sie/es: indicativePreteriteSecondPersonSingular - wir: indicativePreteriteSecondPersonPlural - ihr: indicativePreteriteThirdPersonSingular - sie/Sie: indicativePreteriteThirdPersonPlural - "3": - title: Perfekt - conjugationTypes: - "1": - title: Perfekt - conjugationForms: - ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" - du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" - er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" - wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" - ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" - sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" + 1: + sectionTitle: Präsens + tenses: + 1: + tenseTitle: Präsens + tenseForms: + ich: indicativePresentFirstPersonSingular + du: indicativePresentSecondPersonSingular + er/sie/es: indicativePresentThirdPersonSingular + wir: indicativePresentFirstPersonPlural + ihr: indicativePresentSecondPersonPlural + sie/Sie: indicativePresentThirdPersonPlural + 2: + sectionTitle: Preterite + tenses: + 1: + tenseTitle: Preterite + tenseForms: + ich: indicativePreteriteFirstPersonSingular + du: indicativePreteriteFirstPersonPlural + er/sie/es: indicativePreteriteSecondPersonSingular + wir: indicativePreteriteSecondPersonPlural + ihr: indicativePreteriteThirdPersonSingular + sie/Sie: indicativePreteriteThirdPersonPlural + 3: + sectionTitle: Perfekt + tenses: + 1: + tenseTitle: Perfekt + tenseForms: + ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" + du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" + er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" + wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" + ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" + sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 2eaa5946..2b10f075 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -1,136 +1,91 @@ -{ - "numbers": { - "singular": "plural" - }, - "genders": { - "canonical": [], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Present", - "conjugationTypes": { - "1": { - "title": "Pr. Simple", - "conjugationForms": { - "I/you/plural": "simplePresent", - "he/she/it": "simplePresentThirdPersonSingular" - } - }, - "2": { - "title": "Pr. Perfect", - "conjugationForms": { - "I/you/plural": "[have] pastParticiple", - "he/she/it": "[has] pastParticiple" - } - }, - "3": { - "title": "Pr. Continuous", - "conjugationForms": { - "I": "[am] presentParticiple", - "you/plural": "[are] presentParticiple", - "he/she/it": "[is] presentParticiple" - } - }, - "4": { - "title": "Pr. Perf. Continuous", - "conjugationForms": { - "I/you/plural": "[have been] presentParticiple", - "he/she/it": "[has been] presentParticiple" - } - } - } - }, - "2": { - "title": "Past", - "conjugationTypes": { - "1": { - "title": "Past Simple", - "conjugationForms": { - "all": "simplePast" - } - }, - "2": { - "title": "Past Perfect", - "conjugationForms": { - "all": "[had] pastParticiple" - } - }, - "3": { - "title": "Past Continuous", - "conjugationForms": { - "I/he/she/it": "[was] presentParticiple", - "you/plural": "[were] presentParticiple" - } - }, - "4": { - "title": "Past Perf. Continuous", - "conjugationForms": { - "all": "[had been] presentParticiple" - } - } - } - }, - "3": { - "title": "Future", - "conjugationTypes": { - "1": { - "title": "Fut. Simple", - "conjugationForms": { - "all": "[will] infinitive" - } - }, - "2": { - "title": "Fut. Perfect", - "conjugationForms": { - "all": "[will have] pastParticiple" - } - }, - "3": { - "title": "Fut. Continuous", - "conjugationForms": { - "all": "[will be] presentParticiple" - } - }, - "4": { - "title": "Fut. Perf. Continuous", - "conjugationForms": { - "all": "[will have been] presentParticiple" - } - } - } - }, - "4": { - "title": "Conditional", - "conjugationTypes": { - "1": { - "title": "Cond. Simple", - "conjugationForms": { - "all": "[would] infinitive" - } - }, - "2": { - "title": "Cond. Perfect", - "conjugationForms": { - "all": "[would have] pastParticiple" - } - }, - "3": { - "title": "Cond. Continuous", - "conjugationForms": { - "all": "[would be] presentParticiple" - } - }, - "4": { - "title": "Cond. Perf. Continuous", - "conjugationForms": { - "all": "[would have been] presentParticiple" - } - } - } - } - } -} \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Present + tenses: + 1: + tenseTitle: Pr. Simple + tenseForms: + I/you/plural: simplePresent + he/she/it: simplePresentThirdPersonSingular + 2: + tenseTitle: Pr. Perfect + tenseForms: + I/you/plural: "[have] pastParticiple" + he/she/it: "[has] pastParticiple" + 3: + tenseTitle: Pr. Continuous + tenseForms: + I: "[am] presentParticiple" + you/plural: "[are] presentParticiple" + he/she/it: "[is] presentParticiple" + 4: + tenseTitle: Pr. Perf. Continuous + tenseForms: + I/you/plural: "[have been] presentParticiple" + he/she/it: "[has been] presentParticiple" + 2: + sectionTitle: Past + tenses: + 1: + tenseTitle: Past Simple + tenseForms: + all: simplePast + 2: + tenseTitle: Past Perfect + tenseForms: + all: "[had] pastParticiple" + 3: + tenseTitle: Past Continuous + tenseForms: + I/he/she/it: "[was] presentParticiple" + you/plural: "[were] presentParticiple" + 4: + tenseTitle: Past Perf. Continuous + tenseForms: + all: "[had been] presentParticiple" + 3: + sectionTitle: Future + tenses: + 1: + tenseTitle": Fut. Simple + tenseForms: + all: "[will] infinitive" + 2: + tenseTitle: Fut. Perfect + tenseForms: + all: "[will have] pastParticiple" + 3: + tenseTitle: Fut. Continuous + tenseForms: + all: "[will be] presentParticiple" + 4: + tenseTitle: Fut. Perf. Continuous + tenseForms: + all: "[will have been] presentParticiple" + 4: + sectionTitle: Conditional + tenses: + 1: + tenseTitle: Cond. Simple + tenseForms: + all: "[would] infinitive" + 2: + tenseTitle: Cond. Perfect + tenseForms: + all: "[would have] pastParticiple" + 3: + tenseTitle: Cond. Continuous + tenseForms: + all: "[would be] presentParticiple" + 4: + tenseTitle: Cond. Perf. Continuous + tenseForms: + all: "[would have been] presentParticiple" diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 63ec1131..40de86ec 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -1,66 +1,46 @@ -{ - "numbers": { - "feminineSingular": "femininePlural", - "masculineSingular": "masculinePlural" - }, - "genders": { - "canonical": [], - "feminines": ["feminineSingular"], - "masculines": ["masculineSingular"], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "yo": "indicativePresentFirstPersonSingular", - "tú": "indicativePresentFirstPersonPlural", - "él/ella/Ud.": "indicativePresentSecondPersonSingular", - "nosotros": "indicativePresentSecondPersonPlural", - "vosotros": "indicativePresentThirdPersonSingular", - "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito", - "conjugationTypes": { - "1": { - "title": "Pretérito", - "conjugationForms": { - "yo": "preteriteFirstPersonSingular", - "tú": "preteriteFirstPersonPlural", - "él/ella/Ud.": "preteriteSecondPersonSingular", - "nosotros": "preteriteSecondPersonPlural", - "vosotros": "preteriteThirdPersonSingular", - "ellos/ellas/Uds.": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfecto", - "conjugationTypes" : { - "1": { - "title": "Imperfecto", - "conjugationForms": { - "yo": "pastImperfectFirstPersonSingular", - "tú": "pastImperfectFirstPersonPlural", - "él/ella/Ud.": "pastImperfectSecondPersonSingular", - "nosotros": "pastImperfectSecondPersonPlural", - "vosotros": "pastImperfectThirdPersonSingular", - "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file +numbers: + feminineSingular: femininePlural + masculineSingular: masculinePlural +genders: + canonical: [] + feminines: [feminineSingular] + masculines: [masculineSingular] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + yo: indicativePresentFirstPersonSingular + tú: indicativePresentFirstPersonPlural + él/ella/Ud.: indicativePresentSecondPersonSingular + nosotros: indicativePresentSecondPersonPlural + vosotros: indicativePresentThirdPersonSingular + ellos/ellas/Uds.: indicativePresentThirdPersonPlural + 2: + sectionTitle: Pretérito + tenses: + 1: + tenseTitle: Pretérito + tenseForms: + yo: preteriteFirstPersonSingular + tú: preteriteFirstPersonPlural + él/ella/Ud.: preteriteSecondPersonSingular + nosotros: preteriteSecondPersonPlural + vosotros: preteriteThirdPersonSingular + ellos/ellas/Uds.: preteriteThirdPersonPlural + 3: + sectionTitle: Imperfecto + tenses: + 1: + tenseTitle: Imperfecto + tenseForms: + yo: pastImperfectFirstPersonSingular + tú: pastImperfectFirstPersonPlural + él/ella/Ud.: pastImperfectSecondPersonSingular + nosotros: pastImperfectSecondPersonPlural + vosotros: pastImperfectThirdPersonSingular + ellos/ellas/Uds.: pastImperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index 44833124..704148f5 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -1,78 +1,57 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Présent", - "conjugationTypes": { - "1": { - "title": "Présent", - "conjugationForms": { - "je": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "il/elle": "indicativePresentSecondPersonSingular", - "nous": "indicativePresentSecondPersonPlural", - "vous": "indicativePresentThirdPersonSingular", - "ils/elles": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Passé simple", - "conjugationTypes": { - "1": { - "title": "Passé simple", - "conjugationForms": { - "je": "indicativePreteriteFirstPersonSingular", - "tu": "indicativePreteriteFirstPersonPlural", - "il/elle": "indicativePreteriteSecondPersonSingular", - "nous": "indicativePreteriteSecondPersonPlural", - "vous": "indicativePreteriteThirdPersonSingular", - "ils/elles": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Imparfait", - "conjugationTypes": { - "1": { - "title": "Imparfait", - "conjugationForms": { - "je": "indicativeImperfectFirstPersonSingular", - "tu": "indicativeImperfectFirstPersonPlural", - "il/elle": "indicativeImperfectSecondPersonSingular", - "nous": "indicativeImperfectSecondPersonPlural", - "vous": "indicativeImperfectThirdPersonSingular", - "ils/elles": "indicativeImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futur", - "conjugationTypes":{ - "1": { - "title": "Futur", - "conjugationForms": { - "je": "indicativeSimpleFutureFirstPersonSingular", - "tu": "indicativeSimpleFutureFirstPersonPlural", - "il/elle": "indicativeSimpleFutureSecondPersonSingular", - "nous": "indicativeSimpleFutureSecondPersonPlural", - "vous": "indicativeSimpleFutureThirdPersonSingular", - "ils/elles": "indicativeSimpleFutureThirdPersonPlural" - } - } - } - } - } - } - \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Présent + tenses: + 1: + tenseTitle: Présent + tenseForms: + je: indicativePresentFirstPersonSingular + tu: indicativePresentFirstPersonPlural + il/elle: indicativePresentSecondPersonSingular + nous: indicativePresentSecondPersonPlural + vous: indicativePresentThirdPersonSingular + ils/elles: indicativePresentThirdPersonPlural + 2: + sectionTitle: Passé simple + tenses: + 1: + tenseTitle: Passé simple + tenseForms: + je: indicativePreteriteFirstPersonSingular + tu: indicativePreteriteFirstPersonPlural + il/elle: indicativePreteriteSecondPersonSingular + nous: indicativePreteriteSecondPersonPlural + vous: indicativePreteriteThirdPersonSingular + ils/elles: indicativePreteriteThirdPersonPlural + 3: + sectionTitle: Imparfait + tenses: + 1: + tenseTitle: Imparfait + tenseForms: + je: indicativeImperfectFirstPersonSingular + tu: indicativeImperfectFirstPersonPlural + il/elle: indicativeImperfectSecondPersonSingular + nous: indicativeImperfectSecondPersonPlural + vous: indicativeImperfectThirdPersonSingular + ils/elles: indicativeImperfectThirdPersonPlural + 4: + sectionTitle: Futur + tenses: + 1: + tenseTitle: Futur + tenseForms: + je: indicativeSimpleFutureFirstPersonSingular + tu: indicativeSimpleFutureFirstPersonPlural + il/elle: indicativeSimpleFutureSecondPersonSingular + nous: indicativeSimpleFutureSecondPersonPlural + vous: indicativeSimpleFutureThirdPersonSingular + ils/elles: indicativeSimpleFutureThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index f30709b0..3a002283 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -1,64 +1,45 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "io": "presentIndicativeFirstPersonSingular", - "tu": "presentIndicativeFirstPersonPlural", - "lei/lui": "presentIndicativeSecondPersonSingular", - "noi": "presentIndicativeSecondPersonPlural", - "voi": "presentIndicativeThirdPersonSingular", - "loro": "presentIndicativeThirdPersonPlural" - } - } - } - - }, - "2": { - "title": "Preterito", - "conjugationTypes": { - "1": { - "title": "Preterito", - "conjugationForms": { - "io": "preteriteFirstPersonSingular", - "tu": "preteriteFirstPersonPlural", - "lei/lui": "preteriteSecondPersonSingular", - "noi": "preteriteSecondPersonPlural", - "voi": "preteriteThirdPersonSingular", - "loro": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfetto", - "conjugationTypes": { - "1": { - "title": "Imperfetto", - "conjugationForms": { - "io": "pastImperfectFirstPersonSingular", - "tu": "pastImperfectFirstPersonPlural", - "lei/lui": "pastImperfectSecondPersonSingular", - "noi": "pastImperfectSecondPersonPlural", - "voi": "pastImperfectThirdPersonSingular", - "loro": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + io: presentIndicativeFirstPersonSingular + tu: presentIndicativeFirstPersonPlural + lei/lui: presentIndicativeSecondPersonSingular + noi: presentIndicativeSecondPersonPlural + voi: presentIndicativeThirdPersonSingular + loro: presentIndicativeThirdPersonPlural + 2: + sectionTitle: Preterito + tenses: + 1: + tenseTitle: Preterito + tenseForms: + io: preteriteFirstPersonSingular + tu: preteriteFirstPersonPlural + lei/lui: preteriteSecondPersonSingular + noi: preteriteSecondPersonPlural + voi: preteriteThirdPersonSingular + loro: preteriteThirdPersonPlural + 3: + sectionTitle: Imperfetto + tenses: + 1: + tenseTitle: Imperfetto + tenseForms: + io: pastImperfectFirstPersonSingular + tu: pastImperfectFirstPersonPlural + lei/lui: pastImperfectSecondPersonSingular + noi: pastImperfectSecondPersonPlural + voi: pastImperfectThirdPersonSingular + loro: pastImperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index 7a3b55f3..71be56f7 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -1,80 +1,58 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "eu": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "ele/ela/você": "indicativePresentSecondPersonSingular", - "nós": "indicativePresentSecondPersonPlural", - "vós": "indicativePresentThirdPersonSingular", - "eles/elas/vocês": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito Perfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Perfeito", - "conjugationForms": { - "eu": "indicativePastPerfectFirstPersonSingular", - "tu": "indicativePastPerfectFirstPersonPlural", - "ele/ela/você": "indicativePastPerfectSecondPersonSingular", - "nós": "indicativePastPerfectSecondPersonPlural", - "vós": "indicativePastPerfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Pretérito Imperfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Imperfeito", - "conjugationForms": { - "eu": "indicativePastImperfectFirstPersonSingular", - "tu": "indicativePastImperfectFirstPersonPlural", - "ele/ela/você": "indicativePastImperfectSecondPersonSingular", - "nós": "indicativePastImperfectSecondPersonPlural", - "vós": "indicativePastImperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futuro Simples", - "conjugationTypes": { -"1": { - "title": "Futuro Simples", - "conjugationForms": { - "eu": "indicativePluperfectFirstPersonSingular", - "tu": "indicativePluperfectFirstPersonPlural", - "ele/ela/você": "indicativePluperfectSecondPersonSingular", - "nós": "indicativePluperfectSecondPersonPlural", - "vós": "indicativePluperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file + +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + eu: indicativePresentFirstPersonSingular + tu: indicativePresentFirstPersonPlural + ele/ela/você: indicativePresentSecondPersonSingular + nós: indicativePresentSecondPersonPlural + vós: indicativePresentThirdPersonSingular + eles/elas/vocês: indicativePresentThirdPersonPlural + 2: + sectionTitle: Pretérito Perfeito + tenses: + 1: + tenseTitle: Pretérito Perfeito + tenseForms: + eu: indicativePastPerfectFirstPersonSingular + tu: indicativePastPerfectFirstPersonPlural + ele/ela/você: indicativePastPerfectSecondPersonSingular + nós: indicativePastPerfectSecondPersonPlural + vós: indicativePastPerfectThirdPersonSingular + eles/elas/vocês: indicativePastPerfectThirdPersonPlural + 3: + sectionTitle: Pretérito Imperfeito + tenses: + 1: + tenseTitle: Pretérito Imperfeito + tenseForms: + eu: indicativePastImperfectFirstPersonSingular + tu: indicativePastImperfectFirstPersonPlural + ele/ela/você: indicativePastImperfectSecondPersonSingular + nós: indicativePastImperfectSecondPersonPlural + vós: indicativePastImperfectThirdPersonSingular + eles/elas/vocês: indicativePastImperfectThirdPersonPlural + 4: + sectionTitle: Futuro Simples + tenses: + 1: + tenseTitle: Futuro Simples + tenseForms: + eu: indicativePluperfectFirstPersonSingular + tu: indicativePluperfectFirstPersonPlural + ele/ela/você: indicativePluperfectSecondPersonSingular + nós: indicativePluperfectSecondPersonPlural + vós: indicativePluperfectThirdPersonSingular + eles/elas/vocês: indicativePluperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 1742fb91..065dcffc 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -1,44 +1,31 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Настоящее (Present)", - "conjugationTypes": { - "1": { - "title": "Indicative Present", - "conjugationForms": { - "я (I)": "indicativePresentFirstPersonSingular", - "ты (you, sing.)": "indicativePresentSecondPersonSingular", - "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", - "мы (we)": "indicativePresentFirstPersonPlural", - "вы (you, pl.)": "indicativePresentSecondPersonPlural", - "они (they)": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Прошедшее (Past)", - "conjugationTypes": { - "1": { - "title": "Indicative Past", - "conjugationForms": { - "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", - "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", - "оно (it, neut.)": "neuterIndicativePast", - "мы/вы/они (we/you/they)": "indicativePastPlural" - } - } - } - } - } -} +numbers: + nominativeSingular: nominativePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Настоящее + tenses: + 1: + tenseTitle: Indicative Present + tenseForms: + я: indicativePresentFirstPersonSingular + ты: indicativePresentSecondPersonSingular + он/она/оно: indicativePresentThirdPersonSingular + мы: indicativePresentFirstPersonPlural + вы: indicativePresentSecondPersonPlural + они: indicativePresentThirdPersonPlural + 2: + sectionTitle: Прошедшее + tenses: + 1: + tenseTitle: Indicative Past + tenseForms: + я/ты/она: feminineIndicativePast + я/ты/он: masculineIndicativePast + оно: neuterIndicativePast + мы/вы/они: indicativePastPlural diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 6bdb2e62..44075b1e 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -1,43 +1,30 @@ -{ - "numbers": { - "nominativeIndefiniteSingular": "nominativeIndefinitePlural", - "nominativeDefiniteSingular": "nominativeDefinitePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Aktiv", - "conjugationTypes": { - "1": { - "title": "Aktiv", - "conjugationForms": { - "infinitiv": "activeInfinitive", - "presens": "activePresent", - "preteritum": "activePreterite", - "supinum": "activeSupine" - } - } - } - }, - "2": { - "title": "Passiv", - "conjugationTypes": { - "1": { - "title": "Passiv", - "conjugationForms": { - "infinitiv": "passiveInfinitive", - "presens": "passivePresent", - "preteritum": "passivePreterite", - "supinum": "passiveSupine" - } - } - } - } - } -} +numbers: + nominativeIndefiniteSingular: nominativeIndefinitePlural + nominativeDefiniteSingular: nominativeDefinitePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Aktiv + tenses: + 1: + tenseTitle: Aktiv + tenseForms: + infinitiv: activeInfinitive + presens: activePresent + preteritum: activePreterite + supinum: activeSupine + 2: + sectionTitle: Passiv + tenses: + 1: + tenseTitle: Passiv + tenseForms: + infinitiv: passiveInfinitive + presens: passivePresent + preteritum: passivePreterite + supinum: passiveSupine From 3af7f7a5ed2e8535e98ff5421b6735f1749943d3 Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 15:34:01 +0100 Subject: [PATCH 10/22] Fix included double quote in en.yaml --- app/src/main/assets/data-contracts/en.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 2b10f075..5c886bbe 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -55,7 +55,7 @@ conjugations: sectionTitle: Future tenses: 1: - tenseTitle": Fut. Simple + tenseTitle: Fut. Simple tenseForms: all: "[will] infinitive" 2: From 8dad75876ac76e94184da9bc6226fa136999a01e Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 23:11:50 +0100 Subject: [PATCH 11/22] Update version of data contracts with necessary fields --- app/src/main/assets/data-contracts/de.yaml | 494 ++++++++++++++++++++- app/src/main/assets/data-contracts/en.yaml | 83 +++- app/src/main/assets/data-contracts/es.yaml | 72 ++- app/src/main/assets/data-contracts/fr.yaml | 71 ++- app/src/main/assets/data-contracts/it.yaml | 70 ++- app/src/main/assets/data-contracts/pt.yaml | 70 ++- app/src/main/assets/data-contracts/ru.yaml | 153 ++++++- app/src/main/assets/data-contracts/sv.yaml | 71 ++- 8 files changed, 1066 insertions(+), 18 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index b4aac3a6..b47ffbe3 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -1,11 +1,26 @@ -numbers: - nominativeSingular: nominativePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeSingular: nominativePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Präsens @@ -19,6 +34,7 @@ conjugations: wir: indicativePresentFirstPersonPlural ihr: indicativePresentSecondPersonPlural sie/Sie: indicativePresentThirdPersonPlural + 2: sectionTitle: Preterite tenses: @@ -31,6 +47,7 @@ conjugations: wir: indicativePreteriteSecondPersonPlural ihr: indicativePreteriteThirdPersonSingular sie/Sie: indicativePreteriteThirdPersonPlural + 3: sectionTitle: Perfekt tenses: @@ -43,3 +60,476 @@ conjugations: wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Übersetzungsworttyp auswählen + + adjective: + displayValue: Adjektiv + sectionTitle: Adjektiv Übersetzung auswählen + + adverb: + displayValue: Adverb + sectionTitle: Adjektiv Übersetzung auswählen + + article: + displayValue: Artikel + sectionTitle: Artikel Übersetzung auswählen + + conjunction: + displayValue: Konjunktion + sectionTitle: Konjunktion Übersetzung auswählen + + noun: + displayValue: Nomen + sectionTitle: Nomen Übersetzung auswählen + + postposition: + displayValue: Postposition + sectionTitle: Postposition Übersetzung auswählen + + preposition: + displayValue: Preposition + sectionTitle: Preposition Übersetzung auswählen + + proper_noun: + displayValue: Eigenname + sectionTitle: Eigenname Übersetzung auswählen + + pronoun: + displayValue: Pronomen + sectionTitle: Pronomen Übersetzung auswählen + + verb: + displayValue: Verb + sectionTitle: Verb Übersetzung auswählen + +# MARK: Decline + +# Map of pronoun declensions given cases. +declensions: + 1: + sectionTitle: Akkusativ Definitpronomen + declensionForms: + M: den + F: die + N: das + PL: die + + 2: + sectionTitle: Akkusativ Indefinitpronomen + declensionForms: + M: einen + F: eine + N: ein + PL: welche + + 3: + sectionTitle: Akkusativ Personalpronomen + declensionForms: + ich: mich + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: dich + formell: Sie + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: ihn + sie: sie + es: es + + wir: uns + + ihr: euch + + sie: sie + + 4: + sectionTitle: Akkusativ Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meinen + F: meine + N: mein + PL: meine + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deinen + F: deine + N: dein + PL: deine + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihren + F: Ihre + N: Ihr + PL: Ihre + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinen + F: seine + N: sein + PL: seine + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihren + F: ihre + N: ihr + PL: ihre + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinen + F: seine + N: sein + PL: seine + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsren + F: unsre + N: unser + PL: unsre + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: euren + F: eure + N: euer + PL: eure + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihren + F: ihre + N: ihr + PL: ihre + + 5: + sectionTitle: Akkusativ Demonstrativpronomen + declensionForms: + M: diesen + F: diese + N: dieses + PL: diese + + 6: + sectionTitle: Dativ Definitpronomen + declensionForms: + M: dem + F: der + N: dem + PL: den + + 7: + sectionTitle: Dativ Indefinitpronomen + declensionForms: + M: einem + F: einer + N: einem + PL: welchen + + 8: + sectionTitle: Dativ Personalpronomen + declensionForms: + ich: mir + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: dir + formell: Ihnen + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: ihm + sie: ihr + es: ihm + + wir: uns + + ihr: euch + + sie: ihnen + + 9: + sectionTitle: Dativ Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meinem + F: meiner + N: meinem + PL: meinen + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deinem + F: deiner + N: deinem + PL: deinen + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihrem + F: Ihrer + N: Ihrem + PL: Ihren + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinem + F: seiner + N: seinem + PL: seinen + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihrem + F: ihrer + N: ihrem + PL: ihren + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinem + F: seiner + N: seinem + PL: seinen + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsrem + F: unsrer + N: unsrem + PL: unsren + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: eurem + F: eurer + N: eurem + PL: euren + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihrem + F: ihrer + N: ihrem + PL: ihren + + 10: + sectionTitle: Dativ Demonstrativpronomen + declensionForms: + M: diesem + F: dieser + N: diesem + PL: diesen + + 11: + sectionTitle: Genitiv Definitpronomen + declensionForms: + M: des + F: der + N: des + PL: der + + 12: + sectionTitle: Genitiv Indefinitpronomen + declensionForms: + M: eines + F: einer + N: eines + PL: welcher + + 13: + sectionTitle: Genitiv Personalpronomen + declensionForms: + ich: meiner + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: deiner + formell: Ihrer + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: seiner + sie: ihrer + es: seiner + + wir: unser + + ihr: euer + + sie: ihrer + + 14: + sectionTitle: Genitiv Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meines + F: meiner + N: meines + PL: meiner + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deines + F: deiner + N: deines + PL: deiner + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihres + F: Ihrer + N: Ihres + PL: Ihrer + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seines + F: seiner + N: seines + PL: seiner + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihres + F: ihr + N: ihres + PL: ihr + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seines + F: seiner + N: seines + PL: seiner + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsres + F: unsrer + N: unsres + PL: unsrer + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: eures + F: eurer + N: eures + PL: eurer + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihres + F: ihrer + N: ihres + PL: ihrer + + 15: + sectionTitle: Genitiv Demonstrativpronomen + declensionForms: + M: dieses + F: dieser + N: dieses + PL: dieser diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 5c886bbe..9e281174 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Present @@ -15,22 +30,26 @@ conjugations: tenseForms: I/you/plural: simplePresent he/she/it: simplePresentThirdPersonSingular + 2: tenseTitle: Pr. Perfect tenseForms: I/you/plural: "[have] pastParticiple" he/she/it: "[has] pastParticiple" + 3: tenseTitle: Pr. Continuous tenseForms: I: "[am] presentParticiple" you/plural: "[are] presentParticiple" he/she/it: "[is] presentParticiple" + 4: tenseTitle: Pr. Perf. Continuous tenseForms: I/you/plural: "[have been] presentParticiple" he/she/it: "[has been] presentParticiple" + 2: sectionTitle: Past tenses: @@ -38,19 +57,23 @@ conjugations: tenseTitle: Past Simple tenseForms: all: simplePast + 2: tenseTitle: Past Perfect tenseForms: all: "[had] pastParticiple" + 3: tenseTitle: Past Continuous tenseForms: I/he/she/it: "[was] presentParticiple" you/plural: "[were] presentParticiple" + 4: tenseTitle: Past Perf. Continuous tenseForms: all: "[had been] presentParticiple" + 3: sectionTitle: Future tenses: @@ -58,18 +81,22 @@ conjugations: tenseTitle: Fut. Simple tenseForms: all: "[will] infinitive" + 2: tenseTitle: Fut. Perfect tenseForms: all: "[will have] pastParticiple" + 3: tenseTitle: Fut. Continuous tenseForms: all: "[will be] presentParticiple" + 4: tenseTitle: Fut. Perf. Continuous tenseForms: all: "[will have been] presentParticiple" + 4: sectionTitle: Conditional tenses: @@ -77,15 +104,67 @@ conjugations: tenseTitle: Cond. Simple tenseForms: all: "[would] infinitive" + 2: tenseTitle: Cond. Perfect tenseForms: all: "[would have] pastParticiple" + 3: tenseTitle: Cond. Continuous tenseForms: all: "[would be] presentParticiple" + 4: tenseTitle: Cond. Perf. Continuous tenseForms: all: "[would have been] presentParticiple" + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Select translation word type + + adjective: + displayValue: adjective + sectionTitle: Select adjective translation + + adverb: + displayValue: adverb + sectionTitle: Select adverb translation + + article: + displayValue: article + sectionTitle: Select article translation + + conjunction: + displayValue: conjunction + sectionTitle: Select conjunction translation + + noun: + displayValue: noun + sectionTitle: Select noun translation + + postposition: + displayValue: postposition + sectionTitle: Select postposition translation + + preposition: + displayValue: preposition + sectionTitle: Select preposition translation + + proper_noun: + displayValue: proper noun + sectionTitle: Select proper noun translation + + pronoun: + displayValue: pronoun + sectionTitle: Select pronoun translation + + verb: + displayValue: verb + sectionTitle: Select verb infinitive diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 40de86ec..8634c04c 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -1,12 +1,27 @@ -numbers: - feminineSingular: femininePlural - masculineSingular: masculinePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [] feminines: [feminineSingular] masculines: [masculineSingular] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + feminineSingular: femininePlural + masculineSingular: masculinePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -20,6 +35,7 @@ conjugations: nosotros: indicativePresentSecondPersonPlural vosotros: indicativePresentThirdPersonSingular ellos/ellas/Uds.: indicativePresentThirdPersonPlural + 2: sectionTitle: Pretérito tenses: @@ -32,6 +48,7 @@ conjugations: nosotros: preteriteSecondPersonPlural vosotros: preteriteThirdPersonSingular ellos/ellas/Uds.: preteriteThirdPersonPlural + 3: sectionTitle: Imperfecto tenses: @@ -44,3 +61,52 @@ conjugations: nosotros: pastImperfectSecondPersonPlural vosotros: pastImperfectThirdPersonSingular ellos/ellas/Uds.: pastImperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Seleccione el tipo de traducción + + adjective: + displayValue: adjetivo + sectionTitle: Seleccione traducción de adjetivo + + adverb: + displayValue: adverbio + sectionTitle: Seleccione traducción de adverbio + + article: + displayValue: artículo + sectionTitle: Seleccione traducción de artículo + + conjunction: + displayValue: conjunción + sectionTitle: Seleccione traducción de conjunción + + noun: + displayValue: sustantivo + sectionTitle: Seleccione traducción de sustantivo + + postposition: + displayValue: posposición + sectionTitle: Seleccione traducción de posposición + + preposition: + displayValue: preposición + sectionTitle: Seleccione traducción de preposición + + proper_noun: + displayValue: nombre propio + sectionTitle: Seleccione traducción de nombre propio + + pronoun: + displayValue: pronombre + sectionTitle: Seleccione traducción de pronombre + + verb: + displayValue: verbo + sectionTitle: Seleccionar verbo infinitivo diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index 704148f5..d03529ad 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Présent @@ -19,6 +34,7 @@ conjugations: nous: indicativePresentSecondPersonPlural vous: indicativePresentThirdPersonSingular ils/elles: indicativePresentThirdPersonPlural + 2: sectionTitle: Passé simple tenses: @@ -31,6 +47,7 @@ conjugations: nous: indicativePreteriteSecondPersonPlural vous: indicativePreteriteThirdPersonSingular ils/elles: indicativePreteriteThirdPersonPlural + 3: sectionTitle: Imparfait tenses: @@ -43,6 +60,7 @@ conjugations: nous: indicativeImperfectSecondPersonPlural vous: indicativeImperfectThirdPersonSingular ils/elles: indicativeImperfectThirdPersonPlural + 4: sectionTitle: Futur tenses: @@ -55,3 +73,52 @@ conjugations: nous: indicativeSimpleFutureSecondPersonPlural vous: indicativeSimpleFutureThirdPersonSingular ils/elles: indicativeSimpleFutureThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Sélectionnez le type à traduire + + adjective: + displayValue: adjectif + sectionTitle: Sélectionner la traduction de l'adjectif + + adverb: + displayValue: adverbe + sectionTitle: Sélectionner la traduction de l'adverbe + + article: + displayValue: article + sectionTitle: Sélectionner la traduction de l'article + + conjunction: + displayValue: conjonction + sectionTitle: Sélectionner la traduction de conjonction + + noun: + displayValue: nom + sectionTitle: Sélectionner la traduction du nom + + postposition: + displayValue: postposition + sectionTitle: Sélectionnez la traduction de la postposition + + preposition: + displayValue: préposition + sectionTitle: Sélectionnez la traduction de la préposition + + proper_noun: + displayValue: nom propre + sectionTitle: Sélectionnez la traduction du nom propre + + pronoun: + displayValue: pronom + sectionTitle: Sélectionner la traduction des pronoms + + verb: + displayValue: verbe + sectionTitle: Sélectionnez l'infinitif du verbe diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index 3a002283..cabe3463 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -19,6 +34,7 @@ conjugations: noi: presentIndicativeSecondPersonPlural voi: presentIndicativeThirdPersonSingular loro: presentIndicativeThirdPersonPlural + 2: sectionTitle: Preterito tenses: @@ -31,6 +47,7 @@ conjugations: noi: preteriteSecondPersonPlural voi: preteriteThirdPersonSingular loro: preteriteThirdPersonPlural + 3: sectionTitle: Imperfetto tenses: @@ -43,3 +60,52 @@ conjugations: noi: pastImperfectSecondPersonPlural voi: pastImperfectThirdPersonSingular loro: pastImperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Seleziona il tipo da tradurre + + adjective: + displayValue: aggettivo + sectionTitle: Seleziona la traduzione dell'aggettivo + + adverb: + displayValue: avverbio + sectionTitle: Seleziona la traduzione dell'avverbio + + article: + displayValue: articolo + sectionTitle: Seleziona la traduzione dell'articolo + + conjunction: + displayValue: congiunzione + sectionTitle: Seleziona la traduzione della congiunzione + + noun: + displayValue: nome + sectionTitle: Seleziona la traduzione del nome + + postposition: + displayValue: posposizione + sectionTitle: Seleziona la traduzione della posposizione + + preposition: + displayValue: preposizione + sectionTitle: Seleziona la traduzione della preposizione + + proper_noun: + displayValue: nome proprio + sectionTitle: Seleziona la traduzione del nome proprio + + pronoun: + displayValue: pronome + sectionTitle: Seleziona la traduzione del pronome + + verb: + displayValue: verbo + sectionTitle: Seleziona il verbo infinito diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index 71be56f7..cfedac96 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -1,12 +1,26 @@ +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). -numbers: - singular: plural +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -20,6 +34,7 @@ conjugations: nós: indicativePresentSecondPersonPlural vós: indicativePresentThirdPersonSingular eles/elas/vocês: indicativePresentThirdPersonPlural + 2: sectionTitle: Pretérito Perfeito tenses: @@ -32,6 +47,7 @@ conjugations: nós: indicativePastPerfectSecondPersonPlural vós: indicativePastPerfectThirdPersonSingular eles/elas/vocês: indicativePastPerfectThirdPersonPlural + 3: sectionTitle: Pretérito Imperfeito tenses: @@ -44,6 +60,7 @@ conjugations: nós: indicativePastImperfectSecondPersonPlural vós: indicativePastImperfectThirdPersonSingular eles/elas/vocês: indicativePastImperfectThirdPersonPlural + 4: sectionTitle: Futuro Simples tenses: @@ -56,3 +73,52 @@ conjugations: nós: indicativePluperfectSecondPersonPlural vós: indicativePluperfectThirdPersonSingular eles/elas/vocês: indicativePluperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Selecione o tipo a ser traduzida + + adjective: + displayValue: adjetivo + sectionTitle: Selecione a tradução do adjetivo + + adverb: + displayValue: advérbio + sectionTitle: Selecione a tradução do advérbio + + article: + displayValue: artigo + sectionTitle: Selecione a tradução do artigo + + conjunction: + displayValue: conjunção + sectionTitle: Selecione a tradução da conjunção + + noun: + displayValue: nome + sectionTitle: Selecione a tradução do substantivo + + postposition: + displayValue: posposição + sectionTitle: Selecione a tradução de posposição + + preposition: + displayValue: preposição + sectionTitle: Selecione a tradução da preposiçãon + + proper_noun: + displayValue: nome próprio + sectionTitle: Selecione a tradução do nome próprio + + pronoun: + displayValue: pronome + sectionTitle: Selecione a tradução do pronome + + verb: + displayValue: verbo + sectionTitle: Selecione o verbo no infinitivo diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 065dcffc..75f4c229 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -1,11 +1,26 @@ -numbers: - nominativeSingular: nominativePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeSingular: nominativePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Настоящее @@ -19,6 +34,7 @@ conjugations: мы: indicativePresentFirstPersonPlural вы: indicativePresentSecondPersonPlural они: indicativePresentThirdPersonPlural + 2: sectionTitle: Прошедшее tenses: @@ -29,3 +45,136 @@ conjugations: я/ты/он: masculineIndicativePast оно: neuterIndicativePast мы/вы/они: indicativePastPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Выберите тип переводимого слова + + adjective: + displayValue: прилагательное + sectionTitle: Выберите перевод прилагательного + + adverb: + displayValue: наречие + sectionTitle: Выберите перевод наречия + + article: + displayValue: статья + sectionTitle: Выберите перевод статьи + + conjunction: + displayValue: соединение + sectionTitle: Выберите перевод союза + + noun: + displayValue: существительное + sectionTitle: Выберите перевод существительного + + postposition: + displayValue: послелог + sectionTitle: Выберите перевод послелога + + preposition: + displayValue: предлог + sectionTitle: Выберите перевод предлога + + proper_noun: + displayValue: имя собственное + sectionTitle: Выберите перевод имени собственного. + + pronoun: + displayValue: местоимение + sectionTitle: Выберите перевод местоимения + + verb: + displayValue: глагол + sectionTitle: Выберите инфинитив глагола + +# MARK: Decline + +# Map of pronoun declensions given cases. +declensions: + 1: + title: Винительные местоимения + declensionForms: + я: меня + ты: тебя + он/она/оно: + displayValue: его/её/его + title: Пол объекта? + declensionForms: + он: его + она: её + оно: его + мы: нас + вы: вас + они: их + + 2: + title: Дательные местоимения + declensionForms: + я: мне + ты: тебе + он/она/оно: + displayValue: ему/ей/ему + title: Пол объекта? + declensionForms: + он: ему + она: ей + оно: ему + мы: нам + вы: вам + они: им + + 3: + title: Родительные местоимения + declensionForms: + я: меня + ты: тебя + он/она/оно: + displayValue: его/её/его + title: Пол объекта? + declensionForms: + он: его + она: её + оно: его + мы: нас + вы: вас + они: их + + 4: + title: Творительные местоимения + declensionForms": + я: мной + ты: тобой + он/она/оно: + displayValue: им/ей/им + title: Пол объекта? + declensionForms: + он: им + она: ей + оно: им + мы: нами + вы: вами + они: ими + + 5: + title: Предложные местоимения + declensionForms: + я: мне + ты": тебе + он/она/оно: + displayValue: нём/ней/нём + title: Пол объекта? + declensionForms: + он: нём + она: ней + оно: нём + мы: нас + вы: вас + они: них diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 44075b1e..179e62a3 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -1,12 +1,27 @@ -numbers: - nominativeIndefiniteSingular: nominativeIndefinitePlural - nominativeDefiniteSingular: nominativeDefinitePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeIndefiniteSingular: nominativeIndefinitePlural + nominativeDefiniteSingular: nominativeDefinitePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Aktiv @@ -18,6 +33,7 @@ conjugations: presens: activePresent preteritum: activePreterite supinum: activeSupine + 2: sectionTitle: Passiv tenses: @@ -28,3 +44,52 @@ conjugations: presens: passivePresent preteritum: passivePreterite supinum: passiveSupine + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Välj översättningsordtyp + + adjective: + displayValue: adjektiv + sectionTitle: Välj adjektivöversättning + + adverb: + displayValue: adverb + sectionTitle: Välj adverböversättning + + article: + displayValue: artikel + sectionTitle: Välj artikelöversättning + + conjunction: + displayValue: konjunktion + sectionTitle: Välj konjunktionsöversättning + + noun: + displayValue: substantiv + sectionTitle: Välj substantivöversättning + + postposition: + displayValue: postposition + sectionTitle: Välj postpositionsöversättning + + preposition: + displayValue: preposition + sectionTitle: Välj prepositionsöversättning + + proper_noun: + displayValue: egennamn + sectionTitle: Välj egennamnöversättning + + pronoun: + displayValue: pronomen + sectionTitle: Välj pronomenöversättning + + verb: + displayValue: verb + sectionTitle: Välj verbinfinitiv From 17626a2c3f5e0718c600dd30ab32d028615b9974 Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 23:40:47 +0100 Subject: [PATCH 12/22] Minor fix in comment in contracts --- app/src/main/assets/data-contracts/de.yaml | 2 +- app/src/main/assets/data-contracts/en.yaml | 2 +- app/src/main/assets/data-contracts/es.yaml | 2 +- app/src/main/assets/data-contracts/fr.yaml | 2 +- app/src/main/assets/data-contracts/it.yaml | 2 +- app/src/main/assets/data-contracts/pt.yaml | 2 +- app/src/main/assets/data-contracts/ru.yaml | 2 +- app/src/main/assets/data-contracts/sv.yaml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index b47ffbe3..efd00ac1 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 9e281174..ca4ce817 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [] feminines: [] diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 8634c04c..735a2bad 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [] feminines: [feminineSingular] diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index d03529ad..69efd0c2 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index cabe3463..42db0996 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index cfedac96..2f6db0ba 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 75f4c229..43694e7f 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 179e62a3..c37972ef 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] From 430c0583d93f33299efeb85cefb326cc5a011f63 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 14:57:19 +0700 Subject: [PATCH 13/22] feat: change to using YAML for data contract --- app/build.gradle.kts | 1 + .../scri/helpers/data/ConjugateDataManager.kt | 24 +++++----- .../scri/helpers/data/ContractDataLoader.kt | 24 ++++++---- .../scri/helpers/data/PluralFormsManager.kt | 12 ++--- .../main/java/be/scri/models/DataContract.kt | 47 +++++++++++++++++-- 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index badfeeca..40876295 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -325,6 +325,7 @@ dependencies { ksp("com.github.bumptech.glide:ksp:4.16.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") + implementation("com.charleskorn.kaml:kaml:0.57.0") } tasks.register("moveFromi18n") { diff --git a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt index d0678fba..159f344f 100644 --- a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt +++ b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt @@ -20,7 +20,7 @@ class ConjugateDataManager( * The returned map is structured by tense/mood, then by conjugation type (e.g., "Indicative Present"). * * @param language The language code (e.g., "EN", "SV") to determine the correct database. - * @param jsonData The data contract for the language, which defines the structure of conjugations. + * @param yamlData The data contract for the language, which defines the structure of conjugations. * @param word The specific verb to look up conjugations for. * * @return A nested map where the outer key is the tense group title @@ -29,20 +29,20 @@ class ConjugateDataManager( */ fun getTheConjugateLabels( language: String, - jsonData: DataContract?, + yamlData: DataContract?, word: String, ): MutableMap>>? { val finalOutput: MutableMap>> = mutableMapOf() - jsonData?.conjugations?.values?.forEach { tenseGroup -> + yamlData?.conjugations?.values?.forEach { tenseGroup -> val conjugateForms: MutableMap> = mutableMapOf() - tenseGroup.conjugationTypes.values.forEach { conjugationCategory -> + tenseGroup.tenses.values.forEach { conjugationCategory -> val forms = - conjugationCategory.conjugationForms.values.map { form -> + conjugationCategory.tenseForms.values.map { form -> getTheValueForTheConjugateWord(word.lowercase(), form, language) } - conjugateForms[conjugationCategory.title] = forms + conjugateForms[conjugationCategory.tenseTitle] = forms } - finalOutput[tenseGroup.title] = conjugateForms + finalOutput[tenseGroup.sectionTitle] = conjugateForms } return if (finalOutput.isEmpty() || finalOutput.values.all { it.isEmpty() || it.values.all { forms -> forms.all { it.isEmpty() } } }) { null @@ -55,19 +55,19 @@ class ConjugateDataManager( * Extracts a unique set of all conjugation form keys (e.g., "1ps", "2ps", "participle") * from the data contract. * - * @param jsonData The data contract containing the conjugation structure. + * @param yamlData The data contract containing the conjugation structure. * @param word The base word, which is also added to the set. * * @return A `Set` of unique strings representing all possible conjugation form identifiers. */ fun extractConjugateHeadings( - jsonData: DataContract?, + yamlData: DataContract?, word: String, ): Set { val allFormKeys = mutableSetOf() - jsonData?.conjugations?.values?.forEach { tenseGroup -> - tenseGroup.conjugationTypes.values.forEach { conjugationCategory -> - allFormKeys.addAll(conjugationCategory.conjugationForms.keys) + yamlData?.conjugations?.values?.forEach { tenseGroup -> + tenseGroup.tenses.values.forEach { conjugationCategory -> + allFormKeys.addAll(conjugationCategory.tenseForms.keys) } } allFormKeys.add(word) diff --git a/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt b/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt index 085abc8b..9f6e3886 100644 --- a/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt +++ b/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt @@ -4,8 +4,9 @@ package be.scri.helpers.data import DataContract import android.content.Context import android.util.Log -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.Json +import com.charleskorn.kaml.Yaml +import com.charleskorn.kaml.YamlConfiguration +import com.charleskorn.kaml.YamlException import java.io.IOException /** @@ -16,29 +17,32 @@ class ContractDataLoader( private val context: Context, ) { /** - * Loads and deserializes a data contract from a JSON file in the assets folder. - * It gracefully handles file-not-found and JSON parsing errors by returning null. + * Loads and deserializes a data contract from a YAML file in the assets folder. + * It gracefully handles file-not-found and YAML parsing errors by returning null. * - * @param language The language code (e.g., "DE", "EN") used to determine the filename (e.g., "de.json"). + * @param language The language code (e.g., "DE", "EN") used to determine the filename (e.g., "de.yaml"). * * @return The decoded [DataContract] object if successful, or `null` * if the file does not exist or cannot be parsed. */ fun loadContract(language: String): DataContract? { - val contractName = "${language.lowercase()}.json" + val contractName = "${language.lowercase()}.yaml" Log.i("ContractDataLoader", "Attempting to load contract: $contractName") return try { - val jsonParser = Json { ignoreUnknownKeys = true } context.assets.open("data-contracts/$contractName").use { contractFile -> val content = contractFile.bufferedReader().readText() - jsonParser.decodeFromString(content) + val yaml = + Yaml( + configuration = YamlConfiguration(strictMode = false), + ) + yaml.decodeFromString(DataContract.serializer(), content) } } catch (e: IOException) { Log.e("ContractDataLoader", "Error loading contract file: $contractName. It may not exist.", e) null - } catch (e: SerializationException) { - Log.e("ContractDataLoader", "Error parsing JSON for contract: $contractName", e) + } catch (e: YamlException) { + Log.e("ContractDataLoader", "Error parsing YAML for contract: $contractName", e) null } } diff --git a/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt b/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt index eb1c4d0a..0d4b84f2 100644 --- a/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt +++ b/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt @@ -17,16 +17,16 @@ class PluralFormsManager( * Retrieves a list of all known plural forms for a given language from the database. * * @param language The language code (e.g., "EN", "DE") to select the correct database. - * @param jsonData The data contract, which specifies the names of the columns containing plural forms. + * @param yamlData The data contract, which specifies the names of the columns containing plural forms. * * @return A [List] of all plural word forms, or `null` * if the operation fails or no plural columns are defined. */ fun getAllPluralForms( language: String, - jsonData: DataContract?, + yamlData: DataContract?, ): List? = - jsonData?.numbers?.values?.toList()?.takeIf { it.isNotEmpty() }?.let { pluralForms -> + yamlData?.numbers?.values?.toList()?.takeIf { it.isNotEmpty() }?.let { pluralForms -> fileManager.getLanguageDatabase(language)?.use { db -> queryAllPluralForms(db, pluralForms) } @@ -36,7 +36,7 @@ class PluralFormsManager( * Retrieves the specific plural representation for a single noun. * * @param language The language code to select the correct database. - * @param jsonData The data contract, which specifies the singular and plural column names. + * @param yamlData The data contract, which specifies the singular and plural column names. * @param noun The singular noun to find the plural for. * * @return A [Map] containing the singular noun as the key and @@ -44,10 +44,10 @@ class PluralFormsManager( */ fun getPluralRepresentation( language: String, - jsonData: DataContract?, + yamlData: DataContract?, noun: String, ): Map = - jsonData?.numbers?.let { numbers -> + yamlData?.numbers?.let { numbers -> val singularCol = numbers.keys.firstOrNull() val pluralCol = numbers.values.firstOrNull() diff --git a/app/src/main/java/be/scri/models/DataContract.kt b/app/src/main/java/be/scri/models/DataContract.kt index 6a4015d8..2241026f 100644 --- a/app/src/main/java/be/scri/models/DataContract.kt +++ b/app/src/main/java/be/scri/models/DataContract.kt @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later @file:Suppress("ktlint:standard:kdoc") +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable /** @@ -13,7 +14,8 @@ import kotlinx.serialization.Serializable data class DataContract( val numbers: Map, val genders: Genders, - val conjugations: Map, + val conjugations: Map, + val translations: Translations, ) /** @@ -33,8 +35,8 @@ data class Genders( */ @Serializable data class TenseGroup( - val title: String = "", - val conjugationTypes: Map, + val sectionTitle: String = "", + val tenses: Map, ) /** @@ -42,6 +44,41 @@ data class TenseGroup( */ @Serializable data class ConjugationCategory( - val title: String = "", - val conjugationForms: Map = emptyMap(), + val tenseTitle: String = "", + val tenseForms: Map = emptyMap(), +) + +/** + * Represents the structure of translations for different word types. + */ +@Serializable +data class Translations( + val wordType: WordType, +) + +/** + * Represents the various parts of speech and their associated display values and section titles. + */ +@Serializable +data class WordType( + val sectionTitle: String, + val adjective: WordTypeEntry, + val adverb: WordTypeEntry, + val article: WordTypeEntry, + val conjunction: WordTypeEntry, + val noun: WordTypeEntry, + val postposition: WordTypeEntry, + val preposition: WordTypeEntry, + @SerialName("proper_noun") val properNoun: WordTypeEntry, + val pronoun: WordTypeEntry, + val verb: WordTypeEntry, +) + +/** + * Represents the display value and section title for a specific part of speech. + */ +@Serializable +data class WordTypeEntry( + val displayValue: String, + val sectionTitle: String, ) From 8d0d37038c24b3ba226a27a0438a0caddf1ddca1 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 15:16:39 +0700 Subject: [PATCH 14/22] remove json contracts --- app/build.gradle.kts | 1 - app/src/main/assets/data-contracts/de.json | 64 ---------- app/src/main/assets/data-contracts/en.json | 136 --------------------- app/src/main/assets/data-contracts/es.json | 66 ---------- app/src/main/assets/data-contracts/fr.json | 78 ------------ app/src/main/assets/data-contracts/it.json | 64 ---------- app/src/main/assets/data-contracts/pt.json | 80 ------------ app/src/main/assets/data-contracts/ru.json | 44 ------- app/src/main/assets/data-contracts/sv.json | 43 ------- 9 files changed, 576 deletions(-) delete mode 100644 app/src/main/assets/data-contracts/de.json delete mode 100644 app/src/main/assets/data-contracts/en.json delete mode 100644 app/src/main/assets/data-contracts/es.json delete mode 100644 app/src/main/assets/data-contracts/fr.json delete mode 100644 app/src/main/assets/data-contracts/it.json delete mode 100644 app/src/main/assets/data-contracts/pt.json delete mode 100644 app/src/main/assets/data-contracts/ru.json delete mode 100644 app/src/main/assets/data-contracts/sv.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 40876295..ede0a79c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -323,7 +323,6 @@ dependencies { api("com.google.code.gson:gson:2.13.1") api("com.github.bumptech.glide:glide:4.16.0") ksp("com.github.bumptech.glide:ksp:4.16.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") implementation("com.charleskorn.kaml:kaml:0.57.0") } diff --git a/app/src/main/assets/data-contracts/de.json b/app/src/main/assets/data-contracts/de.json deleted file mode 100644 index 05180f58..00000000 --- a/app/src/main/assets/data-contracts/de.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": [ - "gender" - ], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Präsens", - "conjugationTypes": { - "1": { - "title": "Präsens", - "conjugationForms": { - "ich": "indicativePresentFirstPersonSingular", - "du": "indicativePresentSecondPersonSingular", - "er/sie/es": "indicativePresentThirdPersonSingular", - "wir": "indicativePresentFirstPersonPlural", - "ihr": "indicativePresentSecondPersonPlural", - "sie/Sie": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Preterite", - "conjugationTypes": { - "1": { - "title": "Preterite", - "conjugationForms": { - "ich": "indicativePreteriteFirstPersonSingular", - "du": "indicativePreteriteFirstPersonPlural", - "er/sie/es": "indicativePreteriteSecondPersonSingular", - "wir": "indicativePreteriteSecondPersonPlural", - "ihr": "indicativePreteriteThirdPersonSingular", - "sie/Sie": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Perfekt", - "conjugationTypes": { - "1": { - "title": "Perfekt", - "conjugationForms": { - "ich": "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple", - "du": "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple", - "er/sie/es": "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple", - "wir": "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple", - "ihr": "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple", - "sie/Sie": "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" - } - } - } - } - } -} diff --git a/app/src/main/assets/data-contracts/en.json b/app/src/main/assets/data-contracts/en.json deleted file mode 100644 index 2eaa5946..00000000 --- a/app/src/main/assets/data-contracts/en.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "numbers": { - "singular": "plural" - }, - "genders": { - "canonical": [], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Present", - "conjugationTypes": { - "1": { - "title": "Pr. Simple", - "conjugationForms": { - "I/you/plural": "simplePresent", - "he/she/it": "simplePresentThirdPersonSingular" - } - }, - "2": { - "title": "Pr. Perfect", - "conjugationForms": { - "I/you/plural": "[have] pastParticiple", - "he/she/it": "[has] pastParticiple" - } - }, - "3": { - "title": "Pr. Continuous", - "conjugationForms": { - "I": "[am] presentParticiple", - "you/plural": "[are] presentParticiple", - "he/she/it": "[is] presentParticiple" - } - }, - "4": { - "title": "Pr. Perf. Continuous", - "conjugationForms": { - "I/you/plural": "[have been] presentParticiple", - "he/she/it": "[has been] presentParticiple" - } - } - } - }, - "2": { - "title": "Past", - "conjugationTypes": { - "1": { - "title": "Past Simple", - "conjugationForms": { - "all": "simplePast" - } - }, - "2": { - "title": "Past Perfect", - "conjugationForms": { - "all": "[had] pastParticiple" - } - }, - "3": { - "title": "Past Continuous", - "conjugationForms": { - "I/he/she/it": "[was] presentParticiple", - "you/plural": "[were] presentParticiple" - } - }, - "4": { - "title": "Past Perf. Continuous", - "conjugationForms": { - "all": "[had been] presentParticiple" - } - } - } - }, - "3": { - "title": "Future", - "conjugationTypes": { - "1": { - "title": "Fut. Simple", - "conjugationForms": { - "all": "[will] infinitive" - } - }, - "2": { - "title": "Fut. Perfect", - "conjugationForms": { - "all": "[will have] pastParticiple" - } - }, - "3": { - "title": "Fut. Continuous", - "conjugationForms": { - "all": "[will be] presentParticiple" - } - }, - "4": { - "title": "Fut. Perf. Continuous", - "conjugationForms": { - "all": "[will have been] presentParticiple" - } - } - } - }, - "4": { - "title": "Conditional", - "conjugationTypes": { - "1": { - "title": "Cond. Simple", - "conjugationForms": { - "all": "[would] infinitive" - } - }, - "2": { - "title": "Cond. Perfect", - "conjugationForms": { - "all": "[would have] pastParticiple" - } - }, - "3": { - "title": "Cond. Continuous", - "conjugationForms": { - "all": "[would be] presentParticiple" - } - }, - "4": { - "title": "Cond. Perf. Continuous", - "conjugationForms": { - "all": "[would have been] presentParticiple" - } - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/es.json b/app/src/main/assets/data-contracts/es.json deleted file mode 100644 index 63ec1131..00000000 --- a/app/src/main/assets/data-contracts/es.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "numbers": { - "feminineSingular": "femininePlural", - "masculineSingular": "masculinePlural" - }, - "genders": { - "canonical": [], - "feminines": ["feminineSingular"], - "masculines": ["masculineSingular"], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "yo": "indicativePresentFirstPersonSingular", - "tú": "indicativePresentFirstPersonPlural", - "él/ella/Ud.": "indicativePresentSecondPersonSingular", - "nosotros": "indicativePresentSecondPersonPlural", - "vosotros": "indicativePresentThirdPersonSingular", - "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito", - "conjugationTypes": { - "1": { - "title": "Pretérito", - "conjugationForms": { - "yo": "preteriteFirstPersonSingular", - "tú": "preteriteFirstPersonPlural", - "él/ella/Ud.": "preteriteSecondPersonSingular", - "nosotros": "preteriteSecondPersonPlural", - "vosotros": "preteriteThirdPersonSingular", - "ellos/ellas/Uds.": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfecto", - "conjugationTypes" : { - "1": { - "title": "Imperfecto", - "conjugationForms": { - "yo": "pastImperfectFirstPersonSingular", - "tú": "pastImperfectFirstPersonPlural", - "él/ella/Ud.": "pastImperfectSecondPersonSingular", - "nosotros": "pastImperfectSecondPersonPlural", - "vosotros": "pastImperfectThirdPersonSingular", - "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/fr.json b/app/src/main/assets/data-contracts/fr.json deleted file mode 100644 index 44833124..00000000 --- a/app/src/main/assets/data-contracts/fr.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Présent", - "conjugationTypes": { - "1": { - "title": "Présent", - "conjugationForms": { - "je": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "il/elle": "indicativePresentSecondPersonSingular", - "nous": "indicativePresentSecondPersonPlural", - "vous": "indicativePresentThirdPersonSingular", - "ils/elles": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Passé simple", - "conjugationTypes": { - "1": { - "title": "Passé simple", - "conjugationForms": { - "je": "indicativePreteriteFirstPersonSingular", - "tu": "indicativePreteriteFirstPersonPlural", - "il/elle": "indicativePreteriteSecondPersonSingular", - "nous": "indicativePreteriteSecondPersonPlural", - "vous": "indicativePreteriteThirdPersonSingular", - "ils/elles": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Imparfait", - "conjugationTypes": { - "1": { - "title": "Imparfait", - "conjugationForms": { - "je": "indicativeImperfectFirstPersonSingular", - "tu": "indicativeImperfectFirstPersonPlural", - "il/elle": "indicativeImperfectSecondPersonSingular", - "nous": "indicativeImperfectSecondPersonPlural", - "vous": "indicativeImperfectThirdPersonSingular", - "ils/elles": "indicativeImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futur", - "conjugationTypes":{ - "1": { - "title": "Futur", - "conjugationForms": { - "je": "indicativeSimpleFutureFirstPersonSingular", - "tu": "indicativeSimpleFutureFirstPersonPlural", - "il/elle": "indicativeSimpleFutureSecondPersonSingular", - "nous": "indicativeSimpleFutureSecondPersonPlural", - "vous": "indicativeSimpleFutureThirdPersonSingular", - "ils/elles": "indicativeSimpleFutureThirdPersonPlural" - } - } - } - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/it.json b/app/src/main/assets/data-contracts/it.json deleted file mode 100644 index f30709b0..00000000 --- a/app/src/main/assets/data-contracts/it.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "io": "presentIndicativeFirstPersonSingular", - "tu": "presentIndicativeFirstPersonPlural", - "lei/lui": "presentIndicativeSecondPersonSingular", - "noi": "presentIndicativeSecondPersonPlural", - "voi": "presentIndicativeThirdPersonSingular", - "loro": "presentIndicativeThirdPersonPlural" - } - } - } - - }, - "2": { - "title": "Preterito", - "conjugationTypes": { - "1": { - "title": "Preterito", - "conjugationForms": { - "io": "preteriteFirstPersonSingular", - "tu": "preteriteFirstPersonPlural", - "lei/lui": "preteriteSecondPersonSingular", - "noi": "preteriteSecondPersonPlural", - "voi": "preteriteThirdPersonSingular", - "loro": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfetto", - "conjugationTypes": { - "1": { - "title": "Imperfetto", - "conjugationForms": { - "io": "pastImperfectFirstPersonSingular", - "tu": "pastImperfectFirstPersonPlural", - "lei/lui": "pastImperfectSecondPersonSingular", - "noi": "pastImperfectSecondPersonPlural", - "voi": "pastImperfectThirdPersonSingular", - "loro": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/pt.json b/app/src/main/assets/data-contracts/pt.json deleted file mode 100644 index 7a3b55f3..00000000 --- a/app/src/main/assets/data-contracts/pt.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "eu": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "ele/ela/você": "indicativePresentSecondPersonSingular", - "nós": "indicativePresentSecondPersonPlural", - "vós": "indicativePresentThirdPersonSingular", - "eles/elas/vocês": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito Perfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Perfeito", - "conjugationForms": { - "eu": "indicativePastPerfectFirstPersonSingular", - "tu": "indicativePastPerfectFirstPersonPlural", - "ele/ela/você": "indicativePastPerfectSecondPersonSingular", - "nós": "indicativePastPerfectSecondPersonPlural", - "vós": "indicativePastPerfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Pretérito Imperfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Imperfeito", - "conjugationForms": { - "eu": "indicativePastImperfectFirstPersonSingular", - "tu": "indicativePastImperfectFirstPersonPlural", - "ele/ela/você": "indicativePastImperfectSecondPersonSingular", - "nós": "indicativePastImperfectSecondPersonPlural", - "vós": "indicativePastImperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futuro Simples", - "conjugationTypes": { -"1": { - "title": "Futuro Simples", - "conjugationForms": { - "eu": "indicativePluperfectFirstPersonSingular", - "tu": "indicativePluperfectFirstPersonPlural", - "ele/ela/você": "indicativePluperfectSecondPersonSingular", - "nós": "indicativePluperfectSecondPersonPlural", - "vós": "indicativePluperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/ru.json b/app/src/main/assets/data-contracts/ru.json deleted file mode 100644 index 1742fb91..00000000 --- a/app/src/main/assets/data-contracts/ru.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Настоящее (Present)", - "conjugationTypes": { - "1": { - "title": "Indicative Present", - "conjugationForms": { - "я (I)": "indicativePresentFirstPersonSingular", - "ты (you, sing.)": "indicativePresentSecondPersonSingular", - "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", - "мы (we)": "indicativePresentFirstPersonPlural", - "вы (you, pl.)": "indicativePresentSecondPersonPlural", - "они (they)": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Прошедшее (Past)", - "conjugationTypes": { - "1": { - "title": "Indicative Past", - "conjugationForms": { - "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", - "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", - "оно (it, neut.)": "neuterIndicativePast", - "мы/вы/они (we/you/they)": "indicativePastPlural" - } - } - } - } - } -} diff --git a/app/src/main/assets/data-contracts/sv.json b/app/src/main/assets/data-contracts/sv.json deleted file mode 100644 index 6bdb2e62..00000000 --- a/app/src/main/assets/data-contracts/sv.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "numbers": { - "nominativeIndefiniteSingular": "nominativeIndefinitePlural", - "nominativeDefiniteSingular": "nominativeDefinitePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Aktiv", - "conjugationTypes": { - "1": { - "title": "Aktiv", - "conjugationForms": { - "infinitiv": "activeInfinitive", - "presens": "activePresent", - "preteritum": "activePreterite", - "supinum": "activeSupine" - } - } - } - }, - "2": { - "title": "Passiv", - "conjugationTypes": { - "1": { - "title": "Passiv", - "conjugationForms": { - "infinitiv": "passiveInfinitive", - "presens": "passivePresent", - "preteritum": "passivePreterite", - "supinum": "passiveSupine" - } - } - } - } - } -} From 19e6fc755b63f56e8e9c2d8869e601429a10a483 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 19:04:44 +0700 Subject: [PATCH 15/22] fix minor typo --- app/src/main/assets/data-contracts/ru.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 43694e7f..0677a4c4 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -149,7 +149,7 @@ declensions: 4: title: Творительные местоимения - declensionForms": + declensionForms: я: мной ты: тобой он/она/оно: @@ -167,7 +167,7 @@ declensions: title: Предложные местоимения declensionForms: я: мне - ты": тебе + ты: тебе он/она/оно: displayValue: нём/ней/нём title: Пол объекта? From 6359e43ff5c790dc98bf18a1c48a92a3e7ddbb3e Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sat, 21 Feb 2026 16:30:36 +0100 Subject: [PATCH 16/22] Update German contract with missing displayValue fields for declensions --- app/src/main/assets/data-contracts/de.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index efd00ac1..bd106cd5 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -136,12 +136,14 @@ declensions: ich: mich du/Sie: + displayValue: dich/Sie title: Formalität des Subjekts? declensionForms: informell: dich formell: Sie er/sie/es: + displayValue: ihn/sie/es title: Geschlecht des Subjekts? declensionForms: er: ihn @@ -276,12 +278,14 @@ declensions: ich: mir du/Sie: + displayValue: dir/Ihnen title: Formalität des Subjekts? declensionForms: informell: dir formell: Ihnen er/sie/es: + displayValue: ihm/ihr/ihm title: Geschlecht des Subjekts? declensionForms: er: ihm @@ -416,12 +420,14 @@ declensions: ich: meiner du/Sie: + displayValue: deiner/Ihrer title: Formalität des Subjekts? declensionForms: informell: deiner formell: Ihrer er/sie/es: + displayValue: seiner/ihrer/seiner title: Geschlecht des Subjekts? declensionForms: er: seiner From be39d68be1f6f5d993478ec9160c484889f2e9bb Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 22 Feb 2026 01:03:13 +0100 Subject: [PATCH 17/22] Update contracts with fully indexed conjugations and declensions --- app/src/main/assets/data-contracts/de.yaml | 945 +++++++++++++++------ app/src/main/assets/data-contracts/en.yaml | 88 +- app/src/main/assets/data-contracts/es.yaml | 72 +- app/src/main/assets/data-contracts/fr.yaml | 96 ++- app/src/main/assets/data-contracts/it.yaml | 72 +- app/src/main/assets/data-contracts/pt.yaml | 96 ++- app/src/main/assets/data-contracts/ru.yaml | 245 ++++-- app/src/main/assets/data-contracts/sv.yaml | 32 +- 8 files changed, 1213 insertions(+), 433 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index bd106cd5..b01623b8 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -28,12 +28,24 @@ conjugations: 1: tenseTitle: Präsens tenseForms: - ich: indicativePresentFirstPersonSingular - du: indicativePresentSecondPersonSingular - er/sie/es: indicativePresentThirdPersonSingular - wir: indicativePresentFirstPersonPlural - ihr: indicativePresentSecondPersonPlural - sie/Sie: indicativePresentThirdPersonPlural + 1: + label: ich + value: indicativePresentFirstPersonSingular + 2: + label: du + value: indicativePresentSecondPersonSingular + 3: + label: er/sie/es + value: indicativePresentThirdPersonSingular + 4: + label: wir + value: indicativePresentFirstPersonPlural + 5: + label: ihr + value: indicativePresentSecondPersonPlural + 6: + label: sie/Sie + value: indicativePresentThirdPersonPlural 2: sectionTitle: Preterite @@ -41,12 +53,24 @@ conjugations: 1: tenseTitle: Preterite tenseForms: - ich: indicativePreteriteFirstPersonSingular - du: indicativePreteriteFirstPersonPlural - er/sie/es: indicativePreteriteSecondPersonSingular - wir: indicativePreteriteSecondPersonPlural - ihr: indicativePreteriteThirdPersonSingular - sie/Sie: indicativePreteriteThirdPersonPlural + 1: + label: ich + value: indicativePreteriteFirstPersonSingular + 2: + label: du + value: indicativePreteriteSecondPersonSingular + 3: + label: er/sie/es + value: indicativePreteriteThirdPersonSingular + 4: + label: wir + value: indicativePreteriteFirstPersonPlural + 5: + label: ihr + value: indicativePreteriteSecondPersonPlural + 6: + label: sie/Sie + value: indicativePreteriteThirdPersonPlural 3: sectionTitle: Perfekt @@ -54,12 +78,24 @@ conjugations: 1: tenseTitle: Perfekt tenseForms: - ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" - du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" - er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" - wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" - ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" - sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" + 1: + label: ich + value: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" + 2: + label: du + value: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" + 3: + label: er/sie/es + value: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" + 4: + label: wir + value: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" + 5: + label: ihr + value: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" + 6: + label: sie/Sie + value: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" # MARK: Translate @@ -117,425 +153,806 @@ declensions: 1: sectionTitle: Akkusativ Definitpronomen declensionForms: - M: den - F: die - N: das - PL: die + 1: + label: M + value: den + 2: + label: F + value: die + 3: + label: N + value: das + 4: + label: PL + value: die 2: sectionTitle: Akkusativ Indefinitpronomen declensionForms: - M: einen - F: eine - N: ein - PL: welche + 1: + label: M + value: einen + 2: + label: F + value: eine + 3: + label: N + value: ein + 4: + label: PL + value: welche 3: sectionTitle: Akkusativ Personalpronomen declensionForms: - ich: mich + 1: + label: ich + value: mich - du/Sie: + 2: + label: du/Sie displayValue: dich/Sie title: Formalität des Subjekts? declensionForms: - informell: dich - formell: Sie - - er/sie/es: + 1: + label: informell + value: dich + 2: + label: formell + value: Sie + + 3: + label: er/sie/es displayValue: ihn/sie/es title: Geschlecht des Subjekts? declensionForms: - er: ihn - sie: sie - es: es - - wir: uns - - ihr: euch - - sie: sie + 1: + label: er + value: ihn + 2: + label: sie + value: sie + 3: + label: es + value: es + + 4: + label: wir + value: uns + + 5: + label: ihr + value: euch + + 6: + label: sie + value: sie 4: sectionTitle: Akkusativ Possessivpronomen declensionForms: - ich: + 1: + label: ich displayValue: mein* title: Geschlecht des Objekts? declensionForms: - M: meinen - F: meine - N: mein - PL: meine - - du/Sie: + 1: + label: M + value: meinen + 2: + label: F + value: meine + 3: + label: N + value: mein + 4: + label: PL + value: meine + + 2: + label: du/Sie displayValue: dein*/Ihr* title: Formalität des Subjekts? declensionForms: - informell: + 1: + label: informell displayValue: dein* title: Geschlecht des Objekts? declensionForms: - M: deinen - F: deine - N: dein - PL: deine - - formell: + 1: + label: M + value: deinen + 2: + label: F + value: deine + 3: + label: N + value: dein + 4: + label: PL + value: deine + + 2: + label: formell displayValue: Ihr* title: Geschlecht des Objekts? declensionForms: - M: Ihren - F: Ihre - N: Ihr - PL: Ihre - - er/sie/es: + 1: + label: M + value: Ihren + 2: + label: F + value: Ihre + 3: + label: N + value: Ihr + 4: + label: PL + value: Ihre + + 3: + label: er/sie/es displayValue: sein*/ihr*/sein* title: Geschlecht des Subjekts? declensionForms: - er: + 1: + label: er displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seinen - F: seine - N: sein - PL: seine - - sie: + 1: + label: M + value: seinen + 2: + label: F + value: seine + 3: + label: N + value: sein + 4: + label: PL + value: seine + + 2: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihren - F: ihre - N: ihr - PL: ihre - - es: + 1: + label: M + value: ihren + 2: + label: F + value: ihre + 3: + label: N + value: ihr + 4: + label: PL + value: ihre + + 3: + label: es displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seinen - F: seine - N: sein - PL: seine - - wir: + 1: + label: M + value: seinen + 2: + label: F + value: seine + 3: + label: N + value: sein + 4: + label: PL + value: seine + + 4: + label: wir displayValue: unser* title: Geschlecht des Objekts? declensionForms: - M: unsren - F: unsre - N: unser - PL: unsre - - ihr: + 1: + label: M + value: unsren + 2: + label: F + value: unsre + 3: + label: N + value: unser + 4: + label: PL + value: unsre + + 5: + label: ihr displayValue: euer* title: Geschlecht des Objekts? declensionForms: - M: euren - F: eure - N: euer - PL: eure - - sie: + 1: + label: M + value: euren + 2: + label: F + value: eure + 3: + label: N + value: euer + 4: + label: PL + value: eure + + 6: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihren - F: ihre - N: ihr - PL: ihre + 1: + label: M + value: ihren + 2: + label: F + value: ihre + 3: + label: N + value: ihr + 4: + label: PL + value: ihre 5: sectionTitle: Akkusativ Demonstrativpronomen declensionForms: - M: diesen - F: diese - N: dieses - PL: diese + 1: + label: M + value: diesen + 2: + label: F + value: diese + 3: + label: N + value: dieses + 4: + label: PL + value: diese 6: sectionTitle: Dativ Definitpronomen declensionForms: - M: dem - F: der - N: dem - PL: den + 1: + label: M + value: dem + 2: + label: F + value: der + 3: + label: N + value: dem + 4: + label: PL + value: den 7: sectionTitle: Dativ Indefinitpronomen declensionForms: - M: einem - F: einer - N: einem - PL: welchen + 1: + label: M + value: einem + 2: + label: F + value: einer + 3: + label: N + value: einem + 4: + label: PL + value: welchen 8: sectionTitle: Dativ Personalpronomen declensionForms: - ich: mir + 1: + label: ich + value: mir - du/Sie: + 2: + label: du/Sie displayValue: dir/Ihnen title: Formalität des Subjekts? declensionForms: - informell: dir - formell: Ihnen - - er/sie/es: + 1: + label: informell + value: dir + 2: + label: formell + value: Ihnen + + 3: + label: er/sie/es displayValue: ihm/ihr/ihm title: Geschlecht des Subjekts? declensionForms: - er: ihm - sie: ihr - es: ihm - - wir: uns - - ihr: euch - - sie: ihnen + 1: + label: er + value: ihm + 2: + label: sie + value: ihr + 3: + label: es + value: ihm + + 4: + label: wir + value: uns + + 5: + label: ihr + value: euch + + 6: + label: sie + value: ihnen 9: sectionTitle: Dativ Possessivpronomen declensionForms: - ich: + 1: + label: ich displayValue: mein* title: Geschlecht des Objekts? declensionForms: - M: meinem - F: meiner - N: meinem - PL: meinen - - du/Sie: + 1: + label: M + value: meinem + 2: + label: F + value: meiner + 3: + label: N + value: meinem + 4: + label: PL + value: meinen + + 2: + label: du/Sie displayValue: dein*/Ihr* title: Formalität des Subjekts? declensionForms: - informell: + 1: + label: informell displayValue: dein* title: Geschlecht des Objekts? declensionForms: - M: deinem - F: deiner - N: deinem - PL: deinen - - formell: + 1: + label: M + value: deinem + 2: + label: F + value: deiner + 3: + label: N + value: deinem + 4: + label: PL + value: deinen + + 2: + label: formell displayValue: Ihr* title: Geschlecht des Objekts? declensionForms: - M: Ihrem - F: Ihrer - N: Ihrem - PL: Ihren - - er/sie/es: + 1: + label: M + value: Ihrem + 2: + label: F + value: Ihrer + 3: + label: N + value: Ihrem + 4: + label: PL + value: Ihren + + 3: + label: er/sie/es displayValue: sein*/ihr*/sein* title: Geschlecht des Subjekts? declensionForms: - er: + 1: + label: er displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seinem - F: seiner - N: seinem - PL: seinen - - sie: + 1: + label: M + value: seinem + 2: + label: F + value: seiner + 3: + label: N + value: seinem + 4: + label: PL + value: seinen + + 2: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihrem - F: ihrer - N: ihrem - PL: ihren - - es: + 1: + label: M + values: ihrem + 2: + label: F + value: ihrer + 3: + label: N + value: ihrem + 4: + label: PL + value: ihren + + 3: + label: es displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seinem - F: seiner - N: seinem - PL: seinen - - wir: + 1: + label: M + value: seinem + 2: + label: F + value: seiner + 3: + label: N + value: seinem + 4: + label: PL + value: seinen + + 4: + label: wir displayValue: unser* title: Geschlecht des Objekts? declensionForms: - M: unsrem - F: unsrer - N: unsrem - PL: unsren - - ihr: + 1: + label: M + value: unsrem + 2: + label: F + value: unsrer + 3: + label: N + value: unsrem + 4: + label: PL + value: unsren + + 5: + label: ihr displayValue: euer* title: Geschlecht des Objekts? declensionForms: - M: eurem - F: eurer - N: eurem - PL: euren - - sie: + 1: + label: M + value: eurem + 2: + label: F + value: eurer + 3: + label: N + value: eurem + 4: + label: PL + value: euren + + 6: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihrem - F: ihrer - N: ihrem - PL: ihren + 1: + label: M + value: ihrem + 2: + label: F + value: ihrer + 3: + label: N + value: ihrem + 4: + label: PL + value: ihren 10: sectionTitle: Dativ Demonstrativpronomen declensionForms: - M: diesem - F: dieser - N: diesem - PL: diesen + 1: + label: M + value: diesem + 2: + label: F + valaue: dieser + 3: + label: N + value: diesem + 4: + label: PL + value: diesen 11: sectionTitle: Genitiv Definitpronomen declensionForms: - M: des - F: der - N: des - PL: der + 1: + label: M + value: des + 2: + label: F + value: der + 3: + label: N + value: des + 4: + label: PL + value: der 12: sectionTitle: Genitiv Indefinitpronomen declensionForms: - M: eines - F: einer - N: eines - PL: welcher + 1: + label: M + value: eines + 2: + label: F + value: einer + 3: + label: N + value: eines + 4: + label: PL + value: welcher 13: sectionTitle: Genitiv Personalpronomen declensionForms: - ich: meiner + 1: + label: ich + value: meiner - du/Sie: + 2: + label: du/Sie displayValue: deiner/Ihrer title: Formalität des Subjekts? declensionForms: - informell: deiner - formell: Ihrer - - er/sie/es: + 1: + label: informell + value: deiner + 2: + label: formell + value: Ihrer + + 3: + label: er/sie/es displayValue: seiner/ihrer/seiner title: Geschlecht des Subjekts? declensionForms: - er: seiner - sie: ihrer - es: seiner - - wir: unser - - ihr: euer - - sie: ihrer + 1: + label: er + value: seiner + 2: + label: sie + value: ihrer + 3: + label: es + value: seiner + + 4: + label: wir + value: unser + + 5: + label: ihr + value: euer + + 6: + label: sie + value: ihrer 14: sectionTitle: Genitiv Possessivpronomen declensionForms: - ich: + 1: + label: ich displayValue: mein* title: Geschlecht des Objekts? declensionForms: - M: meines - F: meiner - N: meines - PL: meiner - - du/Sie: + 1: + label: M + value: meines + 2: + label: F + value: meiner + 3: + label: N + value: meines + 4: + label: PL + value: meiner + + 2: + label: du/Sie displayValue: dein*/Ihr* title: Formalität des Subjekts? declensionForms: - informell: + 1: + label: informell displayValue: dein* title: Geschlecht des Objekts? declensionForms: - M: deines - F: deiner - N: deines - PL: deiner - - formell: + 1: + label: M + value: deines + 2: + label: F + value: deiner + 3: + label: N + value: deines + 4: + label: PL + value: deiner + + 2: + label: formell displayValue: Ihr* title: Geschlecht des Objekts? declensionForms: - M: Ihres - F: Ihrer - N: Ihres - PL: Ihrer - - er/sie/es: + 1: + label: M + value: Ihres + 2: + label: F + value: Ihrer + 3: + label: N + value: Ihres + 4: + label: PL + value: Ihrer + + 3: + label: er/sie/es displayValue: sein*/ihr*/sein* title: Geschlecht des Subjekts? declensionForms: - er: + 1: + label: er displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seines - F: seiner - N: seines - PL: seiner - - sie: + 1: + label: M + value: seines + 2: + label: F + value: seiner + 3: + label: N + value: seines + 4: + label: PL + value: seiner + + 2: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihres - F: ihr - N: ihres - PL: ihr - - es: + 1: + label: M + value: ihres + 2: + label: F + value: ihr + 3: + label: N + value: ihres + 4: + label: PL + value: ihr + + 3: + label: es displayValue: sein* title: Geschlecht des Objekts? declensionForms: - M: seines - F: seiner - N: seines - PL: seiner - - wir: + 1: + label: M + value: seines + 2: + label: F + value: seiner + 3: + label: N + value: seines + 4: + label: PL + value: seiner + + 4: + label: wir displayValue: unser* title: Geschlecht des Objekts? declensionForms: - M: unsres - F: unsrer - N: unsres - PL: unsrer - - ihr: + 1: + label: M + value: unsres + 2: + label: F + value: unsrer + 3: + label: N + value: unsres + 4: + label: PL + value: unsrer + + 5: + label: ihr displayValue: euer* title: Geschlecht des Objekts? declensionForms: - M: eures - F: eurer - N: eures - PL: eurer - - sie: + 1: + label: M + value: eures + 2: + label: F + value: eurer + 3: + label: N + value: eures + 4: + label: PL + value: eurer + + 6: + label: sie displayValue: ihr* title: Geschlecht des Objekts? declensionForms: - M: ihres - F: ihrer - N: ihres - PL: ihrer + 1: + label: M + value: ihres + 2: + label: F + value: ihrer + 3: + label: N + value: ihres + 4: + label: PL + value: ihrer 15: sectionTitle: Genitiv Demonstrativpronomen declensionForms: - M: dieses - F: dieser - N: dieses - PL: dieser + 1: + label: M + value: dieses + 2: + label: F + value: dieser + 3: + label: N + value: dieses + 4: + label: PL + value: dieser diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index ca4ce817..ae217fa3 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -28,27 +28,45 @@ conjugations: 1: tenseTitle: Pr. Simple tenseForms: - I/you/plural: simplePresent - he/she/it: simplePresentThirdPersonSingular + 1: + label: I/you/plural + value: simplePresent + 2: + label: he/she/it + value: simplePresentThirdPersonSingular 2: tenseTitle: Pr. Perfect tenseForms: - I/you/plural: "[have] pastParticiple" - he/she/it: "[has] pastParticiple" + 1: + label: I/you/plural + value: "[have] pastParticiple" + 2: + label: he/she/it + value: "[has] pastParticiple" 3: tenseTitle: Pr. Continuous tenseForms: - I: "[am] presentParticiple" - you/plural: "[are] presentParticiple" - he/she/it: "[is] presentParticiple" + 1: + label: I + value: "[am] presentParticiple" + 2: + label: you/plural + value: "[are] presentParticiple" + 3: + label: he/she/it + value: "[is] presentParticiple" 4: tenseTitle: Pr. Perf. Continuous tenseForms: - I/you/plural: "[have been] presentParticiple" - he/she/it: "[has been] presentParticiple" + 1: + label: I/you/plural + value: "[have been] presentParticiple" + 2: + label: he/she/it + value: "[has been] presentParticiple" 2: sectionTitle: Past @@ -56,23 +74,33 @@ conjugations: 1: tenseTitle: Past Simple tenseForms: - all: simplePast + 1: + label: all + value: simplePast 2: tenseTitle: Past Perfect tenseForms: - all: "[had] pastParticiple" + 1: + label: all + value: "[had] pastParticiple" 3: tenseTitle: Past Continuous tenseForms: - I/he/she/it: "[was] presentParticiple" - you/plural: "[were] presentParticiple" + 1: + label: I/he/she/it + value: "[was] presentParticiple" + 2: + label: you/plural + value: "[were] presentParticiple" 4: tenseTitle: Past Perf. Continuous tenseForms: - all: "[had been] presentParticiple" + 1: + label: all + value: "[had been] presentParticiple" 3: sectionTitle: Future @@ -80,22 +108,30 @@ conjugations: 1: tenseTitle: Fut. Simple tenseForms: - all: "[will] infinitive" + 1: + label: all + value: "[will] infinitive" 2: tenseTitle: Fut. Perfect tenseForms: - all: "[will have] pastParticiple" + 1: + label: all + value: "[will have] pastParticiple" 3: tenseTitle: Fut. Continuous tenseForms: - all: "[will be] presentParticiple" + 1: + label: all + value: "[will be] presentParticiple" 4: tenseTitle: Fut. Perf. Continuous tenseForms: - all: "[will have been] presentParticiple" + 1: + label: all + value: "[will have been] presentParticiple" 4: sectionTitle: Conditional @@ -103,22 +139,30 @@ conjugations: 1: tenseTitle: Cond. Simple tenseForms: - all: "[would] infinitive" + 1: + label: all + value: "[would] infinitive" 2: tenseTitle: Cond. Perfect tenseForms: - all: "[would have] pastParticiple" + 1: + label: all + value: "[would have] pastParticiple" 3: tenseTitle: Cond. Continuous tenseForms: - all: "[would be] presentParticiple" + 1: + label: all + value: "[would be] presentParticiple" 4: tenseTitle: Cond. Perf. Continuous tenseForms: - all: "[would have been] presentParticiple" + 1: + label: all + value: "[would have been] presentParticiple" # MARK: Translate diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 735a2bad..58d7d1de 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -29,12 +29,24 @@ conjugations: 1: tenseTitle: Presente tenseForms: - yo: indicativePresentFirstPersonSingular - tú: indicativePresentFirstPersonPlural - él/ella/Ud.: indicativePresentSecondPersonSingular - nosotros: indicativePresentSecondPersonPlural - vosotros: indicativePresentThirdPersonSingular - ellos/ellas/Uds.: indicativePresentThirdPersonPlural + 1: + label: yo + value: indicativePresentFirstPersonSingular + 2: + label: tú + value: indicativePresentSecondPersonSingular + 3: + label: él/ella/Ud. + value: indicativePresentThirdPersonSingular + 4: + label: nosotros + value: indicativePresentFirstPersonPlural + 5: + label: vosotros + value: indicativePresentSecondPersonPlural + 6: + label: ellos/ellas/Uds. + value: indicativePresentThirdPersonPlural 2: sectionTitle: Pretérito @@ -42,12 +54,24 @@ conjugations: 1: tenseTitle: Pretérito tenseForms: - yo: preteriteFirstPersonSingular - tú: preteriteFirstPersonPlural - él/ella/Ud.: preteriteSecondPersonSingular - nosotros: preteriteSecondPersonPlural - vosotros: preteriteThirdPersonSingular - ellos/ellas/Uds.: preteriteThirdPersonPlural + 1: + label: yo + value: preteriteFirstPersonSingular + 2: + label: tú + value: preteriteSecondPersonSingular + 3: + label: él/ella/Ud. + value: preteriteThirdPersonSingular + 4: + label: nosotros + value: preteriteFirstPersonPlural + 5: + label: vosotros + value: preteriteSecondPersonPlural + 6: + label: ellos/ellas/Uds. + value: preteriteThirdPersonPlural 3: sectionTitle: Imperfecto @@ -55,12 +79,24 @@ conjugations: 1: tenseTitle: Imperfecto tenseForms: - yo: pastImperfectFirstPersonSingular - tú: pastImperfectFirstPersonPlural - él/ella/Ud.: pastImperfectSecondPersonSingular - nosotros: pastImperfectSecondPersonPlural - vosotros: pastImperfectThirdPersonSingular - ellos/ellas/Uds.: pastImperfectThirdPersonPlural + 1: + label: yo + value: pastImperfectFirstPersonSingular + 2: + label: tú + value: pastImperfectSecondPersonSingular + 3: + label: él/ella/Ud. + value: pastImperfectThirdPersonSingular + 4: + label: nosotros + value: pastImperfectFirstPersonPlural + 5: + label: vosotros + value: pastImperfectSecondPersonPlural + 6: + label: ellos/ellas/Uds. + value: pastImperfectThirdPersonPlural # MARK: Translate diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index 69efd0c2..aede2e98 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -28,12 +28,24 @@ conjugations: 1: tenseTitle: Présent tenseForms: - je: indicativePresentFirstPersonSingular - tu: indicativePresentFirstPersonPlural - il/elle: indicativePresentSecondPersonSingular - nous: indicativePresentSecondPersonPlural - vous: indicativePresentThirdPersonSingular - ils/elles: indicativePresentThirdPersonPlural + 1: + label: je + value: indicativePresentFirstPersonSingular + 2: + label: tu + value: indicativePresentSecondPersonSingular + 3: + label: il/elle + value: indicativePresentThirdPersonSingular + 4: + label: nous + value: indicativePresentFirstPersonPlural + 5: + label: vous + value: indicativePresentSecondPersonPlural + 6: + label: ils/elles + value: indicativePresentThirdPersonPlural 2: sectionTitle: Passé simple @@ -41,12 +53,24 @@ conjugations: 1: tenseTitle: Passé simple tenseForms: - je: indicativePreteriteFirstPersonSingular - tu: indicativePreteriteFirstPersonPlural - il/elle: indicativePreteriteSecondPersonSingular - nous: indicativePreteriteSecondPersonPlural - vous: indicativePreteriteThirdPersonSingular - ils/elles: indicativePreteriteThirdPersonPlural + 1: + label: je + value: indicativePreteriteFirstPersonSingular + 2: + label: tu + value: indicativePreteriteSecondPersonSingular + 3: + label: il/elle + value: indicativePreteriteThirdPersonSingular + 4: + label: nous + value: indicativePreteriteFirstPersonPlural + 5: + label: vous + value: indicativePreteriteSecondPersonPlural + 6: + label: ils/elles + value: indicativePreteriteThirdPersonPlural 3: sectionTitle: Imparfait @@ -54,12 +78,24 @@ conjugations: 1: tenseTitle: Imparfait tenseForms: - je: indicativeImperfectFirstPersonSingular - tu: indicativeImperfectFirstPersonPlural - il/elle: indicativeImperfectSecondPersonSingular - nous: indicativeImperfectSecondPersonPlural - vous: indicativeImperfectThirdPersonSingular - ils/elles: indicativeImperfectThirdPersonPlural + 1: + label: je + value: indicativeImperfectFirstPersonSingular + 2: + label: tu + value: indicativeImperfectSecondPersonSingular + 3: + label: il/elle + value: indicativeImperfectThirdPersonSingular + 4: + label: nous + value: indicativeImperfectFirstPersonPlural + 5: + label: vous + value: indicativeImperfectSecondPersonPlural + 6: + label: ils/elles + value: indicativeImperfectThirdPersonPlural 4: sectionTitle: Futur @@ -67,12 +103,24 @@ conjugations: 1: tenseTitle: Futur tenseForms: - je: indicativeSimpleFutureFirstPersonSingular - tu: indicativeSimpleFutureFirstPersonPlural - il/elle: indicativeSimpleFutureSecondPersonSingular - nous: indicativeSimpleFutureSecondPersonPlural - vous: indicativeSimpleFutureThirdPersonSingular - ils/elles: indicativeSimpleFutureThirdPersonPlural + 1: + label: je + value: indicativeSimpleFutureFirstPersonSingular + 2: + label: tu + value: indicativeSimpleFutureSecondPersonSingular + 3: + label: il/elle + value: indicativeSimpleFutureThirdPersonSingular + 4: + label: nous + value: indicativeSimpleFutureFirstPersonPlural + 5: + label: vous + value: indicativeSimpleFutureSecondPersonPlural + 6: + label: ils/elles + value: indicativeSimpleFutureThirdPersonPlural # MARK: Translate diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index 42db0996..ec210634 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -28,12 +28,24 @@ conjugations: 1: tenseTitle: Presente tenseForms: - io: presentIndicativeFirstPersonSingular - tu: presentIndicativeFirstPersonPlural - lei/lui: presentIndicativeSecondPersonSingular - noi: presentIndicativeSecondPersonPlural - voi: presentIndicativeThirdPersonSingular - loro: presentIndicativeThirdPersonPlural + 1: + label: io + value: presentIndicativeFirstPersonSingular + 2: + label: tu + value: presentIndicativeSecondPersonSingular + 3: + label: lei/lui + value: presentIndicativeThirdPersonSingular + 4: + label: noi + value: presentIndicativeFirstPersonPlural + 5: + label: voi + value: presentIndicativeSecondPersonPlural + 6: + label: loro + value: presentIndicativeThirdPersonPlural 2: sectionTitle: Preterito @@ -41,12 +53,24 @@ conjugations: 1: tenseTitle: Preterito tenseForms: - io: preteriteFirstPersonSingular - tu: preteriteFirstPersonPlural - lei/lui: preteriteSecondPersonSingular - noi: preteriteSecondPersonPlural - voi: preteriteThirdPersonSingular - loro: preteriteThirdPersonPlural + 1: + label: io + value: preteriteFirstPersonSingular + 2: + label: tu + value: preteriteSecondPersonSingular + 3: + label: lei/lui + value: preteriteThirdPersonSingular + 4: + label: noi + value: preteriteFirstPersonPlural + 5: + label: voi + value: preteriteSecondPersonPlural + 6: + label: loro + value: preteriteThirdPersonPlural 3: sectionTitle: Imperfetto @@ -54,12 +78,24 @@ conjugations: 1: tenseTitle: Imperfetto tenseForms: - io: pastImperfectFirstPersonSingular - tu: pastImperfectFirstPersonPlural - lei/lui: pastImperfectSecondPersonSingular - noi: pastImperfectSecondPersonPlural - voi: pastImperfectThirdPersonSingular - loro: pastImperfectThirdPersonPlural + 1: + label: io + value: pastImperfectFirstPersonSingular + 2: + label: tu + value: pastImperfectSecondPersonSingular + 3: + label: lei/lui + value: pastImperfectThirdPersonSingular + 4: + label: noi + value: pastImperfectFirstPersonPlural + 5: + label: voi + value: pastImperfectSecondPersonPlural + 6: + label: loro + value: pastImperfectThirdPersonPlural # MARK: Translate diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index 2f6db0ba..3665c3cd 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -28,12 +28,24 @@ conjugations: 1: tenseTitle: Presente tenseForms: - eu: indicativePresentFirstPersonSingular - tu: indicativePresentFirstPersonPlural - ele/ela/você: indicativePresentSecondPersonSingular - nós: indicativePresentSecondPersonPlural - vós: indicativePresentThirdPersonSingular - eles/elas/vocês: indicativePresentThirdPersonPlural + 1: + label: eu + value: indicativePresentFirstPersonSingular + 2: + label: tu + value: indicativePresentSecondPersonSingular + 3: + label: ele/ela/você + value: indicativePresentThirdPersonSingular + 4: + label: nós + value: indicativePresentFirstPersonPlural + 5: + label: vós + value: indicativePresentSecondPersonPlural + 6: + label: eles/elas/vocês + value: indicativePresentThirdPersonPlural 2: sectionTitle: Pretérito Perfeito @@ -41,12 +53,24 @@ conjugations: 1: tenseTitle: Pretérito Perfeito tenseForms: - eu: indicativePastPerfectFirstPersonSingular - tu: indicativePastPerfectFirstPersonPlural - ele/ela/você: indicativePastPerfectSecondPersonSingular - nós: indicativePastPerfectSecondPersonPlural - vós: indicativePastPerfectThirdPersonSingular - eles/elas/vocês: indicativePastPerfectThirdPersonPlural + 1: + label: eu + value: indicativePastPerfectFirstPersonSingular + 2: + label: tu + value: indicativePastPerfectSecondPersonSingular + 3: + label: ele/ela/você + value: indicativePastPerfectThirdPersonSingular + 4: + label: nós + value: indicativePastPerfectFirstPersonPlural + 5: + label: vós + value: indicativePastPerfectSecondPersonPlural + 6: + label: eles/elas/vocês + value: indicativePastPerfectThirdPersonPlural 3: sectionTitle: Pretérito Imperfeito @@ -54,12 +78,24 @@ conjugations: 1: tenseTitle: Pretérito Imperfeito tenseForms: - eu: indicativePastImperfectFirstPersonSingular - tu: indicativePastImperfectFirstPersonPlural - ele/ela/você: indicativePastImperfectSecondPersonSingular - nós: indicativePastImperfectSecondPersonPlural - vós: indicativePastImperfectThirdPersonSingular - eles/elas/vocês: indicativePastImperfectThirdPersonPlural + 1: + label: eu + value: indicativePastImperfectFirstPersonSingular + 2: + label: tu + value: indicativePastImperfectSecondPersonSingular + 3: + label: ele/ela/você + value: indicativePastImperfectThirdPersonSingular + 4: + label: nós + value: indicativePastImperfectFirstPersonPlural + 5: + label: vós + value: indicativePastImperfectSecondPersonPlural + 6: + label: eles/elas/vocês + value: indicativePastImperfectThirdPersonPlural 4: sectionTitle: Futuro Simples @@ -67,12 +103,24 @@ conjugations: 1: tenseTitle: Futuro Simples tenseForms: - eu: indicativePluperfectFirstPersonSingular - tu: indicativePluperfectFirstPersonPlural - ele/ela/você: indicativePluperfectSecondPersonSingular - nós: indicativePluperfectSecondPersonPlural - vós: indicativePluperfectThirdPersonSingular - eles/elas/vocês: indicativePluperfectThirdPersonPlural + 1: + label: eu + value: indicativePluperfectFirstPersonSingular + 2: + label: tu + value: indicativePluperfectSecondPersonSingular + 3: + label: ele/ela/você + value: indicativePluperfectThirdPersonSingular + 4: + label: nós + value: indicativePluperfectFirstPersonPlural + 5: + label: vós + value: indicativePluperfectSecondPersonPlural + 6: + label: eles/elas/vocês + value: indicativePluperfectThirdPersonPlural # MARK: Translate diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 0677a4c4..ff16b2a8 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -28,12 +28,24 @@ conjugations: 1: tenseTitle: Indicative Present tenseForms: - я: indicativePresentFirstPersonSingular - ты: indicativePresentSecondPersonSingular - он/она/оно: indicativePresentThirdPersonSingular - мы: indicativePresentFirstPersonPlural - вы: indicativePresentSecondPersonPlural - они: indicativePresentThirdPersonPlural + 1: + label: я + value: indicativePresentFirstPersonSingular + 2: + label: ты + value: indicativePresentSecondPersonSingular + 3: + label: он/она/оно + value: indicativePresentThirdPersonSingular + 4: + label: мы + value: indicativePresentFirstPersonPlural + 5: + label: вы + value: indicativePresentSecondPersonPlural + 6: + label: они + value: indicativePresentThirdPersonPlural 2: sectionTitle: Прошедшее @@ -41,10 +53,18 @@ conjugations: 1: tenseTitle: Indicative Past tenseForms: - я/ты/она: feminineIndicativePast - я/ты/он: masculineIndicativePast - оно: neuterIndicativePast - мы/вы/они: indicativePastPlural + 1: + label: я/ты/она + value: feminineIndicativePast + 2: + label: я/ты/он + value: masculineIndicativePast + 3: + label: оно + value: neuterIndicativePast + 4: + label: мы/вы/они + value: indicativePastPlural # MARK: Translate @@ -102,79 +122,194 @@ declensions: 1: title: Винительные местоимения declensionForms: - я: меня - ты: тебя - он/она/оно: + 1: + label: я + value: меня + + 2: + label: ты + value: тебя + + 3: + label: он/она/оно displayValue: его/её/его title: Пол объекта? declensionForms: - он: его - она: её - оно: его - мы: нас - вы: вас - они: их + 1: + label: он + value: его + 2: + label: она + value: её + 3: + label: оно + value: его + + 4: + label: мы + value: нас + + 5: + label: вы + value: вас + + 6: + label: они + value: их 2: title: Дательные местоимения declensionForms: - я: мне - ты: тебе - он/она/оно: + 1: + label: я + value: мне + + 2: + label: ты + value: тебе + + 3: + label: он/она/оно displayValue: ему/ей/ему title: Пол объекта? declensionForms: - он: ему - она: ей - оно: ему - мы: нам - вы: вам - они: им + 1: + label: он + value: ему + + 2: + label: она + value: ей + + 3: + label: оно + value: ему + + 4: + label: мы + value: нам + + 5: + label: вы + value: вам + 6: + label: они + value: им 3: title: Родительные местоимения declensionForms: - я: меня - ты: тебя - он/она/оно: + 1: + label: я + value: меня + + 2: + label: ты + value: тебя + + 3: + label: он/она/оно displayValue: его/её/его title: Пол объекта? declensionForms: - он: его - она: её - оно: его - мы: нас - вы: вас - они: их + 1: + label: он + value: его + + 2: + label: она + value: её + + 3: + label: оно + value: его + + 4: + label: мы + value: нас + + 5: + label: вы + value: вас + + 6: + label: они + value: их 4: title: Творительные местоимения declensionForms: - я: мной - ты: тобой - он/она/оно: + 1: + label: я + value: мной + + 2: + label: ты + value: тобой + + 3: + label: он/она/оно displayValue: им/ей/им title: Пол объекта? declensionForms: - он: им - она: ей - оно: им - мы: нами - вы: вами - они: ими + 1: + label: он + value: им + 2: + label: она + value: ей + 3: + label: оно + value: им + + 4: + label: мы + value: нами + + 5: + label: вы + value: вами + + 6: + label: они + value: ими 5: title: Предложные местоимения declensionForms: - я: мне - ты: тебе - он/она/оно: + 1: + label: я + value: мне + + 2: + label: ты + value: тебе + + 3: + label: он/она/оно displayValue: нём/ней/нём title: Пол объекта? declensionForms: - он: нём - она: ней - оно: нём - мы: нас - вы: вас - они: них + 1: + label: он + value: нём + + 2: + label: она + value: ней + + 3: + label: оно + value: нём + + 4: + label: мы + value: нас + + 5: + label: вы + value: вас + + 6: + label: они + value: них diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index c37972ef..53c1dbb2 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -29,10 +29,18 @@ conjugations: 1: tenseTitle: Aktiv tenseForms: - infinitiv: activeInfinitive - presens: activePresent - preteritum: activePreterite - supinum: activeSupine + 1: + label: infinitiv + value: activeInfinitive + 2: + label: presens + value: activePresent + 3: + label: preteritum + value: activePreterite + 4: + label: supinum + value: activeSupine 2: sectionTitle: Passiv @@ -40,10 +48,18 @@ conjugations: 1: tenseTitle: Passiv tenseForms: - infinitiv: passiveInfinitive - presens: passivePresent - preteritum: passivePreterite - supinum: passiveSupine + 1: + label: infinitiv + value: passiveInfinitive + 2: + label: presens + value: passivePresent + 3: + label: preteritum + value: passivePreterite + 4: + label: supinum + value: passiveSupine # MARK: Translate From 9f67ba6518b66ab363bf48aedd19b7002ca8ccaa Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Tue, 24 Feb 2026 01:06:50 +0100 Subject: [PATCH 18/22] Fixes to DE data contract --- app/src/main/assets/data-contracts/de.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index b01623b8..65bdad8e 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -589,7 +589,7 @@ declensions: declensionForms: 1: label: M - values: ihrem + value: ihrem 2: label: F value: ihrer @@ -680,7 +680,7 @@ declensions: value: diesem 2: label: F - valaue: dieser + value: dieser 3: label: N value: diesem From 670851e8f008b1716a688e55aa87ba41cf128139 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Tue, 24 Feb 2026 15:52:55 +0700 Subject: [PATCH 19/22] fix to fit new indexed contract --- .../java/be/scri/helpers/data/ConjugateDataManager.kt | 6 ++++-- app/src/main/java/be/scri/models/DataContract.kt | 8 +++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt index 159f344f..e4b93db3 100644 --- a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt +++ b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt @@ -38,7 +38,7 @@ class ConjugateDataManager( tenseGroup.tenses.values.forEach { conjugationCategory -> val forms = conjugationCategory.tenseForms.values.map { form -> - getTheValueForTheConjugateWord(word.lowercase(), form, language) + getTheValueForTheConjugateWord(word.lowercase(), form.value, language) } conjugateForms[conjugationCategory.tenseTitle] = forms } @@ -67,7 +67,9 @@ class ConjugateDataManager( val allFormKeys = mutableSetOf() yamlData?.conjugations?.values?.forEach { tenseGroup -> tenseGroup.tenses.values.forEach { conjugationCategory -> - allFormKeys.addAll(conjugationCategory.tenseForms.keys) + conjugationCategory.tenseForms.values.forEach { form -> + allFormKeys.add(form.label) + } } } allFormKeys.add(word) diff --git a/app/src/main/java/be/scri/models/DataContract.kt b/app/src/main/java/be/scri/models/DataContract.kt index 2241026f..250cecf6 100644 --- a/app/src/main/java/be/scri/models/DataContract.kt +++ b/app/src/main/java/be/scri/models/DataContract.kt @@ -45,7 +45,13 @@ data class TenseGroup( @Serializable data class ConjugationCategory( val tenseTitle: String = "", - val tenseForms: Map = emptyMap(), + val tenseForms: Map, +) + +@Serializable +data class TenseForm( + val label: String, + val value: String, ) /** From 44ecb2ecbf58343768c8729963cf61e591bc71bf Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Tue, 24 Feb 2026 17:01:44 +0700 Subject: [PATCH 20/22] feat: "All languages" download action --- app/src/main/java/be/scri/App.kt | 2 ++ .../ui/screens/download/DataDownloadScreen.kt | 17 +++++++++++++++-- .../screens/download/DataDownloadViewModel.kt | 13 +++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index 632f0c43..982cce74 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -81,6 +81,7 @@ fun ScribeApp( val navBackStackEntry by navController.currentBackStackEntryAsState() val downloadStates = downloadViewModel.downloadStates val onDownloadAction = downloadViewModel::handleDownloadAction + val onDownloadAll = downloadViewModel::handleDownloadAllLanguages val inititalizeStates = downloadViewModel::initializeStates val checkAllForUpdates = downloadViewModel::checkAllForUpdates @@ -214,6 +215,7 @@ fun ScribeApp( }, downloadStates = downloadStates, onDownloadAction = onDownloadAction, + onDownloadAll = onDownloadAll, initializeStates = inititalizeStates, checkAllForUpdates = checkAllForUpdates, modifier = Modifier.padding(innerPadding), diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index 0ca440bc..afcc6693 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -57,6 +57,7 @@ fun DownloadDataScreen( modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, + onDownloadAll: () -> Unit = {}, initializeStates: (List) -> Unit = {}, checkAllForUpdates: () -> Unit, ) { @@ -72,6 +73,7 @@ fun DownloadDataScreen( SettingsUtil.getKeyboardLanguages(context) } + // Prepare the list of languages to display, including the "All Languages" option. val languages = remember(installedKeyboardLanguages) { buildList { @@ -97,6 +99,15 @@ fun DownloadDataScreen( } } + // Determine the state of the "All Languages" item based on individual language states. + val allLanguagesState = + when { + downloadStates.filter { it.key != "all" }.values.all { it == DownloadState.Completed } -> DownloadState.Completed + downloadStates.filter { it.key != "all" }.values.all { it == DownloadState.Downloading } -> DownloadState.Downloading + downloadStates.filter { it.key != "all" }.values.all { it == DownloadState.Update } -> DownloadState.Update + else -> DownloadState.Ready + } + LaunchedEffect(languages) { val keys = languages.map { it.first } currentInitializeStates(keys) @@ -177,13 +188,15 @@ fun DownloadDataScreen( Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { languages.forEachIndexed { index, lang -> val (key, title, isDark) = lang - val currentStatus = downloadStates[key] ?: DownloadState.Ready + val currentStatus = if (key == "all") allLanguagesState else (downloadStates[key] ?: DownloadState.Ready) LanguageItemComp( title = title, onClick = { }, onButtonClick = { - if (currentStatus == DownloadState.Ready) { + if (key == "all") { + onDownloadAll() + } else if (currentStatus == DownloadState.Ready) { selectedLanguage.value = lang } else { onDownloadAction(key, false) diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index 38e09082..7d2255bb 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -152,6 +152,19 @@ class DataDownloadViewModel( } } + /** + * Handles the "All languages" download action by initiating downloads for all languages that are not already completed or downloading. + */ + fun handleDownloadAllLanguages() { + val toDownload = + downloadStates.keys.filter { key -> + key != "all" && downloadStates[key] != DownloadState.Completed && downloadStates[key] != DownloadState.Downloading + } + toDownload.forEach { key -> + handleDownloadAction(key) + } + } + /** * Checks for available updates using the data version API. * Sets state to Update if server has newer data. From 453229b0749384d1cb02a212c5acf3b09dc38b82 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 25 Feb 2026 15:25:04 +0700 Subject: [PATCH 21/22] feat: add empty state for download screen --- app/build.gradle.kts | 1 + .../appcomponents/InstallKeyboardButton.kt | 67 +++++ .../ui/screens/download/DataDownloadScreen.kt | 276 ++++++++++++------ .../ui/screens/settings/SettingsScreen.kt | 48 +-- 4 files changed, 253 insertions(+), 139 deletions(-) create mode 100644 app/src/main/java/be/scri/ui/common/appcomponents/InstallKeyboardButton.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ede0a79c..bc581710 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -325,6 +325,7 @@ dependencies { ksp("com.github.bumptech.glide:ksp:4.16.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") implementation("com.charleskorn.kaml:kaml:0.57.0") + implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") } tasks.register("moveFromi18n") { diff --git a/app/src/main/java/be/scri/ui/common/appcomponents/InstallKeyboardButton.kt b/app/src/main/java/be/scri/ui/common/appcomponents/InstallKeyboardButton.kt new file mode 100644 index 00000000..1a240cf3 --- /dev/null +++ b/app/src/main/java/be/scri/ui/common/appcomponents/InstallKeyboardButton.kt @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.ui.common.appcomponents + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import be.scri.R + +/** + * A composable button that prompts the user to install keyboards. + * + * @param onClick The callback to invoke when the button is clicked. + * @param modifier Optional [Modifier] for styling and layout adjustments. + */ +@Composable +fun InstallKeyboardButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + OutlinedButton( + onClick = onClick, + modifier = + modifier + .fillMaxWidth() + .padding(Dimensions.PaddingSmallXL) + .shadow(Dimensions.ElevationSmall, RoundedCornerShape(dimensionResource(id = R.dimen.rounded_corner_radius_standard))), + shape = RoundedCornerShape(dimensionResource(id = R.dimen.rounded_corner_radius_standard)), + colors = + ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.surfaceContainer, + ), + ) { + Text( + text = stringResource(R.string.i18n_app_settings_button_install_keyboards), + fontSize = Dimensions.TextSizeExtraLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onPrimary, + modifier = Modifier.padding(vertical = Dimensions.PaddingLarge), + ) + } +} + +/** + * Defines commonly used dimensions for the Settings screen UI. + * Includes padding, text sizes, and elevation values. + */ +object Dimensions { + val PaddingLarge = 20.dp + val PaddingSmallXL = 12.dp + + val TextSizeExtraLarge = 24.sp + + val ElevationSmall = 4.dp +} diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index afcc6693..386625f3 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -18,11 +18,15 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.Immutable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -30,14 +34,23 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.compose.LocalLifecycleOwner +import androidx.lifecycle.viewmodel.compose.viewModel import be.scri.R import be.scri.helpers.StringUtils import be.scri.ui.common.ScribeBaseScreen import be.scri.ui.common.appcomponents.ConfirmationDialog +import be.scri.ui.common.appcomponents.InstallKeyboardButton import be.scri.ui.common.components.CircleClickableItemComp import be.scri.ui.common.components.LanguageItemComp import be.scri.ui.common.components.SwitchableItemComp import be.scri.ui.screens.settings.SettingsUtil +import be.scri.ui.screens.settings.SettingsViewModel +import be.scri.ui.screens.settings.SettingsViewModelFactory +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList /** * Screen for downloading and managing language data. @@ -54,31 +67,43 @@ import be.scri.ui.screens.settings.SettingsUtil fun DownloadDataScreen( onBackNavigation: () -> Unit, onNavigateToTranslation: (String) -> Unit, + checkAllForUpdates: () -> Unit, modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, onDownloadAll: () -> Unit = {}, initializeStates: (List) -> Unit = {}, - checkAllForUpdates: () -> Unit, + viewModel: SettingsViewModel = + viewModel( + factory = SettingsViewModelFactory(LocalContext.current), + ), ) { val currentInitializeStates by rememberUpdatedState(initializeStates) val scrollState = rememberScrollState() val checkForNewData = remember { mutableStateOf(false) } val regularlyUpdateData = remember { mutableStateOf(true) } - val selectedLanguage = remember { mutableStateOf?>(null) } + val selectedLanguage = remember { mutableStateOf(null) } val context = LocalContext.current val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) - val installedKeyboardLanguages = - remember { - SettingsUtil.getKeyboardLanguages(context) - } + val installedKeyboardLanguages by viewModel.languages.collectAsState() + + val lifecycleOwner = LocalLifecycleOwner.current + DisposableEffect(lifecycleOwner) { + val observer = + LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_RESUME) { + viewModel.refreshSettings(context) + } + } + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { lifecycleOwner.lifecycle.removeObserver(observer) } + } // Prepare the list of languages to display, including the "All Languages" option. - val languages = + val languages: ImmutableList = remember(installedKeyboardLanguages) { buildList { - add(Triple("all", context.getString(R.string.i18n_app_download_menu_ui_download_data_all_languages), false)) - + add(LanguageItem("all", context.getString(R.string.i18n_app_download_menu_ui_download_data_all_languages), false)) installedKeyboardLanguages.forEach { languageCode -> val displayName = when (languageCode.lowercase()) { @@ -92,11 +117,9 @@ fun DownloadDataScreen( "swedish" -> context.getString(R.string.i18n_app__global_swedish) else -> languageCode.replaceFirstChar { it.uppercase() } } - - val key = languageCode.lowercase() - add(Triple(key, displayName, false)) + add(LanguageItem(languageCode.lowercase(), displayName, false)) } - } + }.toImmutableList() } // Determine the state of the "All Languages" item based on individual language states. @@ -109,7 +132,7 @@ fun DownloadDataScreen( } LaunchedEffect(languages) { - val keys = languages.map { it.first } + val keys = languages.map { it.key } currentInitializeStates(keys) } @@ -126,6 +149,7 @@ fun DownloadDataScreen( .verticalScroll(scrollState), verticalArrangement = Arrangement.spacedBy(12.dp), ) { + // Update Data Section Column { Text( text = stringResource(R.string.i18n_app_download_menu_ui_update_data), @@ -143,23 +167,21 @@ fun DownloadDataScreen( color = MaterialTheme.colorScheme.surface, ) { Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { - CircleClickableItemComp( - title = stringResource(R.string.i18n_app_download_menu_ui_update_data_check_new), - onClick = { - checkForNewData.value = !checkForNewData.value - if (checkForNewData.value) { - checkAllForUpdates() - } - }, - isSelected = checkForNewData.value, - ) - - HorizontalDivider( - color = Color.Gray.copy(alpha = 0.3f), - thickness = 1.dp, - modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp), - ) - + if (installedKeyboardLanguages.isNotEmpty()) { + CircleClickableItemComp( + title = stringResource(R.string.i18n_app_download_menu_ui_update_data_check_new), + onClick = { + checkForNewData.value = !checkForNewData.value + if (checkForNewData.value) checkAllForUpdates() + }, + isSelected = checkForNewData.value, + ) + HorizontalDivider( + color = Color.Gray.copy(alpha = 0.3f), + thickness = 1.dp, + modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp), + ) + } SwitchableItemComp( title = stringResource(R.string.i18n_app_download_menu_ui_update_data_regular_update), isChecked = regularlyUpdateData.value, @@ -168,6 +190,8 @@ fun DownloadDataScreen( } } } + + // Download Data Section Column { Text( text = stringResource(R.string.i18n_app_download_menu_ui_download_data_title), @@ -177,72 +201,140 @@ fun DownloadDataScreen( modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 10.dp), ) - Surface( - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp), - shape = RoundedCornerShape(12.dp), - color = MaterialTheme.colorScheme.surface, - ) { - Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { - languages.forEachIndexed { index, lang -> - val (key, title, isDark) = lang - val currentStatus = if (key == "all") allLanguagesState else (downloadStates[key] ?: DownloadState.Ready) - - LanguageItemComp( - title = title, - onClick = { }, - onButtonClick = { - if (key == "all") { - onDownloadAll() - } else if (currentStatus == DownloadState.Ready) { - selectedLanguage.value = lang - } else { - onDownloadAction(key, false) - } - }, - isDarkTheme = isDark, - buttonState = currentStatus, - ) - if (index < languages.lastIndex) { - HorizontalDivider( - color = Color.Gray.copy(alpha = 0.3f), - thickness = 1.dp, - modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp), - ) - } - } - } + if (installedKeyboardLanguages.isEmpty()) { + EmptyStateSection(context) + } else { + LanguagesListSection( + languages = languages, + allLanguagesState = allLanguagesState, + downloadStates = downloadStates, + onLanguageSelect = { selectedLanguage.value = it }, + onDownloadAll = onDownloadAll, + onDownloadAction = onDownloadAction, + ) + } + + Spacer(modifier = Modifier.height(10.dp)) + + selectedLanguage.value?.let { lang -> + val (key, title, _) = lang + val languageId = key.replaceFirstChar { it.uppercase() } + val sourceLang = sharedPref.getString("translation_source_$languageId", "English") ?: "English" + ConfirmationDialog( + text = + StringUtils.stringResourceWithParams( + R.string.i18n_app_download_menu_ui_translation_source_tooltip_download_warning, + sourceLang, + title, + ), + textConfirm = + StringUtils.stringResourceWithParams( + R.string.i18n_app_download_menu_ui_translation_source_tooltip_use_source_language, + sourceLang, + ), + textChange = stringResource(R.string.i18n_app_download_menu_ui_translation_source_tooltip_change_language), + onConfirm = { + onDownloadAction(key, false) + selectedLanguage.value = null + }, + onChange = { onNavigateToTranslation(languageId) }, + onDismiss = { selectedLanguage.value = null }, + ) } } + } + } +} + +@Immutable +data class LanguageItem( + val key: String, + val displayName: String, + val isDark: Boolean, +) - Spacer(modifier = Modifier.height(10.dp)) - - selectedLanguage.value?.let { lang -> - val (key, title, _) = lang - val languageId = key.replaceFirstChar { it.uppercase() } - val sourceLang = sharedPref.getString("translation_source_$languageId", "English") ?: "English" - ConfirmationDialog( - text = - StringUtils.stringResourceWithParams( - R.string.i18n_app_download_menu_ui_translation_source_tooltip_download_warning, - sourceLang, - title, - ), - textConfirm = - StringUtils.stringResourceWithParams( - R.string.i18n_app_download_menu_ui_translation_source_tooltip_use_source_language, - sourceLang, - ), - textChange = stringResource(R.string.i18n_app_download_menu_ui_translation_source_tooltip_change_language), - onConfirm = { - onDownloadAction(key, false) - selectedLanguage.value = null +/** + * Represents empty state when no languages are available for download. + */ +@Composable +private fun EmptyStateSection(context: Context) { + Surface( + modifier = + Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp), + shape = RoundedCornerShape(12.dp), + color = MaterialTheme.colorScheme.surface, + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(R.string.i18n_app_download_menu_ui_no_keyboards_installed), + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f), + fontSize = 16.sp, + ) + } + } + InstallKeyboardButton( + onClick = { SettingsUtil.navigateToKeyboardSettings(context) }, + ) +} + +/** + * Composable function to display the list of languages available for download, along with their respective download states and actions. + * + * @param languages List of [LanguageItem] representing the available languages. + * @param allLanguagesState The overall download state for all languages. + * @param downloadStates Map of individual language keys to their respective [DownloadState]. + * @param onLanguageSelect Callback invoked when a specific language is selected for download. + * @param onDownloadAll Callback invoked when the "All Languages" option is selected for download. + * @param onDownloadAction Callback invoked when a specific language's download action is triggered, with parameters for language key and whether it's an "all" action. + */ +@Composable +private fun LanguagesListSection( + languages: ImmutableList, + allLanguagesState: DownloadState, + downloadStates: Map, + onLanguageSelect: (LanguageItem) -> Unit, + onDownloadAll: () -> Unit, + onDownloadAction: (String, Boolean) -> Unit, +) { + Surface( + modifier = + Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp), + shape = RoundedCornerShape(12.dp), + color = MaterialTheme.colorScheme.surface, + ) { + Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { + languages.forEachIndexed { index, lang -> + val currentStatus = if (lang.key == "all") allLanguagesState else (downloadStates[lang.key] ?: DownloadState.Ready) + + LanguageItemComp( + title = lang.displayName, + onClick = { }, + onButtonClick = { + if (lang.key == "all") { + onDownloadAll() + } else if (currentStatus == DownloadState.Ready) { + onLanguageSelect(lang) + } else { + onDownloadAction(lang.key, false) + } }, - onChange = { onNavigateToTranslation(languageId) }, - onDismiss = { selectedLanguage.value = null }, + isDarkTheme = lang.isDark, + buttonState = currentStatus, ) + if (index < languages.lastIndex) { + HorizontalDivider( + color = Color.Gray.copy(alpha = 0.3f), + thickness = 1.dp, + modifier = Modifier.padding(vertical = 8.dp, horizontal = 12.dp), + ) + } } } } diff --git a/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt index a7fc6c4a..ff53ca5d 100644 --- a/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/settings/SettingsScreen.kt @@ -8,29 +8,21 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.viewmodel.compose.viewModel import be.scri.R import be.scri.ui.common.ScribeBaseScreen +import be.scri.ui.common.appcomponents.InstallKeyboardButton import be.scri.ui.common.components.ItemCardContainerWithTitle import be.scri.ui.models.ScribeItem import be.scri.ui.models.ScribeItemList @@ -139,41 +131,3 @@ fun SettingsScreen( } } } - -@Composable -private fun InstallKeyboardButton(onClick: () -> Unit) { - OutlinedButton( - onClick = onClick, - modifier = - Modifier - .fillMaxWidth() - .padding(Dimensions.PaddingSmallXL) - .shadow(Dimensions.ElevationSmall, RoundedCornerShape(dimensionResource(id = R.dimen.rounded_corner_radius_standard))), - shape = RoundedCornerShape(dimensionResource(id = R.dimen.rounded_corner_radius_standard)), - colors = - ButtonDefaults.outlinedButtonColors( - containerColor = MaterialTheme.colorScheme.surfaceContainer, - ), - ) { - Text( - text = stringResource(R.string.i18n_app_settings_button_install_keyboards), - fontSize = Dimensions.TextSizeExtraLarge, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.onPrimary, - modifier = Modifier.padding(vertical = Dimensions.PaddingLarge), - ) - } -} - -/** - * Defines commonly used dimensions for the Settings screen UI. - * Includes padding, text sizes, and elevation values. - */ -object Dimensions { - val PaddingLarge = 20.dp - val PaddingSmallXL = 12.dp - - val TextSizeExtraLarge = 24.sp - - val ElevationSmall = 4.dp -} From 61c88629434e46b0086511210aa9111447b9bf0f Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sat, 28 Feb 2026 17:16:55 +0100 Subject: [PATCH 22/22] Misc fix of comment --- app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt index fad200aa..14e6df43 100644 --- a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt @@ -142,7 +142,7 @@ fun SelectTranslationSourceLanguageScreen( sharedPref.edit { putString("translation_source_$currentLanguage", selectedLanguage.value) } val downloadKey = currentLanguage.lowercase() - // trigger the download action in the ViewModel. + // Trigger the download action in the ViewModel. onDownloadAction(downloadKey, true) showDialog.value = false // Navigate to the download data screen.