From b3e73db95661803d303a7ce7b66068894eb2796e Mon Sep 17 00:00:00 2001 From: jonasgaudian <43753916+jonasgaudian@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:15:16 +0100 Subject: [PATCH] rename `AppTextField` to `AppOutlinedTextField` and implement `InspiringSearchField` --- .../view/composable/AppOutlinedTextField.kt | 231 ++++++++++++++++++ .../view/composable/ComponentLibrary.kt | 101 -------- .../view/dialogs/AddCategoryDialog.kt | 4 +- .../view/dialogs/AddCostumLanguageDialog.kt | 22 +- .../view/dialogs/AddVocabularyDialog.kt | 8 +- .../view/dialogs/CategoryDropdown.kt | 4 +- .../view/dialogs/CreateCategoryListDialog.kt | 4 +- .../view/dialogs/EditCategoryDialog.kt | 4 +- .../view/dialogs/EditLanguageDialog.kt | 8 +- .../view/dialogs/ImportVocabularyDialog.kt | 39 ++- .../view/dictionary/EtymologyScreen.kt | 4 +- .../MainDictionaryScreenComponents.kt | 5 +- .../view/exercises/GenerateExerciseDialog.kt | 4 +- .../translator/view/exercises/QuestionUIs.kt | 8 +- .../view/exercises/YouTubeExerciseDialog.kt | 8 +- .../view/hints/ImportVocabularyHints.kt | 4 +- .../view/hints/SortingScreenHint.kt | 6 +- .../view/settings/AddModelScreen.kt | 12 +- .../translator/view/settings/ApiKeyScreen.kt | 33 +-- .../view/settings/BasePromptSettingsScreen.kt | 4 +- .../view/settings/DictionaryOptionsScreen.kt | 4 +- .../view/settings/ExerciseSettingsScreen.kt | 4 +- .../view/vocabulary/ExerciseControls.kt | 4 +- .../vocabulary/VocabularySortingScreen.kt | 6 +- .../view/vocabulary/card/GrammarComponents.kt | 8 +- app/src/main/res/values/arrays.xml | 8 + 26 files changed, 344 insertions(+), 203 deletions(-) create mode 100644 app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt diff --git a/app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt b/app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt new file mode 100644 index 0000000..997b3e0 --- /dev/null +++ b/app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt @@ -0,0 +1,231 @@ +package eu.gaudian.translator.view.composable + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +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.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import eu.gaudian.translator.R +import kotlinx.coroutines.delay + +/** + * Helper composable for consistent OutlinedTextField colors. + */ +@Composable +private fun appTextFieldColors() = OutlinedTextFieldDefaults.colors( + focusedBorderColor = MaterialTheme.colorScheme.primary, + unfocusedBorderColor = MaterialTheme.colorScheme.onSurface.copy(alpha = ComponentDefaults.ALPHA_LOW), + focusedLabelColor = MaterialTheme.colorScheme.primary, + cursorColor = MaterialTheme.colorScheme.primary +) + +/** + * A styled text input field. + * + * @param value The input text to be shown in the text field. + * @param onValueChange The callback that is triggered when the input service updates the text. + * @param modifier The modifier to be applied to the text field. + * @param label A composable lambda for the label to be displayed inside the text field. + * @param trailingIcon A composable lambda for the trailing icon. + * @param paste Controls the visibility of the paste icon. + * @param clear Controls the visibility of the clear icon. + */ +@Composable +fun AppOutlinedTextField( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: @Composable (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, + singleLine: Boolean = false, + minLines: Int = 1, + maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE, + placeholder: @Composable (() -> Unit)? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + leadingIcon: @Composable (() -> Unit)? = null, + paste: Boolean = false, + clear: Boolean = false, + supportingText: @Composable (() -> Unit)? = null, +) { + val clipboardManager = LocalClipboardManager.current + + val finalTrailingIcon: @Composable (() -> Unit)? = if (paste || clear || trailingIcon != null) { + { + Row(verticalAlignment = Alignment.CenterVertically) { + if (paste && value.isEmpty()) { + IconButton(onClick = { onValueChange(clipboardManager.getText()?.text ?: "") }) { + Icon( + imageVector = AppIcons.Paste, + contentDescription = stringResource(R.string.cd_paste), + tint = MaterialTheme.colorScheme.primary + ) + } + } + if (clear && value.isNotEmpty()) { + IconButton(onClick = { onValueChange("") }) { + Icon( + imageVector = AppIcons.Clear, + contentDescription = stringResource(R.string.label_clear), + tint = MaterialTheme.colorScheme.primary + ) + } + } + if (trailingIcon != null) { + trailingIcon() + } + } + } + } else { + null + } + + OutlinedTextField( + value = value, + onValueChange = onValueChange, + modifier = modifier.fillMaxWidth(), + label = label, + trailingIcon = finalTrailingIcon, + shape = ComponentDefaults.DefaultShape, + colors = appTextFieldColors(), + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + leadingIcon = leadingIcon, + minLines = minLines, + maxLines = maxLines, + supportingText = supportingText, + ) +} + +@Composable +fun InspiringSearchField( + value: String, + hints : Array, + onValueChange: (String) -> Unit +) { + + var currentHintIndex by remember { mutableIntStateOf(0) } + + // Start rotating immediately when the dialog appears + LaunchedEffect(hints) { + if (hints.isNotEmpty()) { + while (true) { + delay(2800) + currentHintIndex = (currentHintIndex + 1) % hints.size + } + } + } + + AppOutlinedTextField( + value = value, + onValueChange = onValueChange, + //label = { Text(stringResource(R.string.text_search_term)) }, + modifier = Modifier.fillMaxWidth(), + placeholder = { + AnimatedContent( + targetState = if (hints.isNotEmpty()) hints[currentHintIndex] else "", + transitionSpec = { + (fadeIn(tween(400)) + slideInVertically { it / 2 }) + .togetherWith(fadeOut(tween(400)) + slideOutVertically { -it / 2 }) + }, + label = "HintAnimation" + ) { hint -> + Text( + text = hint, + color = Color.Gray.copy(alpha = 0.6f), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + }, + singleLine = true, + minLines = 1, + maxLines = 1 + ) +} + +@Suppress("HardCodedStringLiteral") +@Preview +@Composable +fun AppOutlinedTextFieldPreview() { + var text by remember { mutableStateOf("Test") } + AppOutlinedTextField( + value = text, + onValueChange = { }, + label = { Text(stringResource(R.string.email_address)) } + ) +} + +@Suppress("HardCodedStringLiteral") +@Preview(showBackground = true, name = "Search Field Preview") +@Composable +fun PreviewInspiringSearchField() { + MaterialTheme { + Surface( + modifier = Modifier.fillMaxWidth(), + color = Color(0xFFF8F9FA) // Light gray background like in your screenshot + ) { + Column( + modifier = Modifier + .padding(24.dp) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Text( + text = "Deixe a IA encontrar\nvocabulário para você!", + style = MaterialTheme.typography.headlineSmall, + fontWeight = FontWeight.Bold + ) + + // Our animated component + InspiringSearchField( + value = "Test", + hints = listOf("test1", "test2", "test3").toTypedArray(), + onValueChange = {} + ) + + // Placeholder for the rest of your UI + Button( + onClick = { }, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(8.dp) + ) { + Text("Continuar") + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/gaudian/translator/view/composable/ComponentLibrary.kt b/app/src/main/java/eu/gaudian/translator/view/composable/ComponentLibrary.kt index 22e3618..73761db 100644 --- a/app/src/main/java/eu/gaudian/translator/view/composable/ComponentLibrary.kt +++ b/app/src/main/java/eu/gaudian/translator/view/composable/ComponentLibrary.kt @@ -30,12 +30,9 @@ import androidx.compose.material3.Checkbox import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.FabPosition import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Scaffold import androidx.compose.material3.ScaffoldDefaults import androidx.compose.material3.Surface @@ -57,7 +54,6 @@ import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -449,106 +445,9 @@ fun SecondaryButtonInversePreview() { SecondaryButton(onClick = { }, text = stringResource(R.string.secondary_inverse), icon = AppIcons.Add, inverse = true) } -/** - * Helper composable for consistent OutlinedTextField colors. - */ -@Composable -private fun appTextFieldColors() = OutlinedTextFieldDefaults.colors( - focusedBorderColor = MaterialTheme.colorScheme.primary, - unfocusedBorderColor = MaterialTheme.colorScheme.onSurface.copy(alpha = ComponentDefaults.ALPHA_LOW), - focusedLabelColor = MaterialTheme.colorScheme.primary, - cursorColor = MaterialTheme.colorScheme.primary -) -/** - * A styled text input field. - * - * @param value The input text to be shown in the text field. - * @param onValueChange The callback that is triggered when the input service updates the text. - * @param modifier The modifier to be applied to the text field. - * @param label A composable lambda for the label to be displayed inside the text field. - * @param trailingIcon A composable lambda for the trailing icon. - * @param paste Controls the visibility of the paste icon. - * @param clear Controls the visibility of the clear icon. - */ -@Composable -fun AppTextField( - value: String, - onValueChange: (String) -> Unit, - modifier: Modifier = Modifier, - label: @Composable (() -> Unit)? = null, - trailingIcon: @Composable (() -> Unit)? = null, - singleLine: Boolean = false, - minLines: Int = 1, - maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE, - placeholder: @Composable (() -> Unit)? = null, - enabled: Boolean = true, - readOnly: Boolean = false, - leadingIcon: @Composable (() -> Unit)? = null, - paste: Boolean = false, - clear: Boolean = false, - supportingText: @Composable (() -> Unit)? = null, -) { - val clipboardManager = LocalClipboardManager.current - val finalTrailingIcon: @Composable (() -> Unit)? = if (paste || clear || trailingIcon != null) { - { - Row(verticalAlignment = Alignment.CenterVertically) { - if (paste && value.isEmpty()) { - IconButton(onClick = { onValueChange(clipboardManager.getText()?.text ?: "") }) { - Icon( - imageVector = AppIcons.Paste, - contentDescription = stringResource(R.string.cd_paste), - tint = MaterialTheme.colorScheme.primary - ) - } - } - if (clear && value.isNotEmpty()) { - IconButton(onClick = { onValueChange("") }) { - Icon( - imageVector = AppIcons.Clear, - contentDescription = stringResource(R.string.label_clear), - tint = MaterialTheme.colorScheme.primary - ) - } - } - if (trailingIcon != null) { - trailingIcon() - } - } - } - } else { - null - } - OutlinedTextField( - value = value, - onValueChange = onValueChange, - modifier = modifier.fillMaxWidth(), - label = label, - trailingIcon = finalTrailingIcon, - shape = ComponentDefaults.DefaultShape, - colors = appTextFieldColors(), - placeholder = placeholder, - enabled = enabled, - readOnly = readOnly, - leadingIcon = leadingIcon, - minLines = minLines, - maxLines = maxLines, - supportingText = supportingText, - ) -} - -@Preview -@Composable -fun AppTextFieldPreview() { - var text by remember { mutableStateOf("") } - AppTextField( - value = text, - onValueChange = { text = it }, - label = { Text(stringResource(R.string.email_address)) } - ) -} @Composable diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCategoryDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCategoryDialog.kt index ac5d079..9acea63 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCategoryDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCategoryDialog.kt @@ -46,7 +46,7 @@ import eu.gaudian.translator.model.VocabularyStage import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppDialog import eu.gaudian.translator.view.composable.AppIcons -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.MultipleLanguageDropdown import eu.gaudian.translator.view.hints.CategoryHint import eu.gaudian.translator.viewmodel.CategoryViewModel @@ -96,7 +96,7 @@ fun AddCategoryDialog( Spacer(modifier = Modifier.height(16.dp)) - AppTextField( + AppOutlinedTextField( value = categoryName, onValueChange = { categoryName = it }, label = { Text(stringResource(R.string.text_category_name)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCostumLanguageDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCostumLanguageDialog.kt index 63a1206..859b12a 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCostumLanguageDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddCostumLanguageDialog.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp import eu.gaudian.translator.R import eu.gaudian.translator.model.Language import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DialogButton @Composable @@ -56,33 +56,37 @@ fun AddCustomLanguageDialog( modifier = Modifier.padding(bottom = 8.dp) ) - AppTextField( + AppOutlinedTextField( value = languageCode, onValueChange = { languageCode = it }, label = { Text(text = stringResource(R.string.text_language_code)) }, placeholder = { Text(text = stringResource(R.string.text_e_g_en)) }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + singleLine = true ) - AppTextField( + AppOutlinedTextField( value = languageRegion, onValueChange = { languageRegion = it }, label = { Text(text = stringResource(R.string.text_region)) }, placeholder = { Text(text = stringResource(R.string.text_e_g_us)) }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + singleLine = true ) - AppTextField( + AppOutlinedTextField( value = languageName, onValueChange = { languageName = it }, label = { Text(text = stringResource(R.string.text_name_of_the_language)) }, placeholder = { Text(text = stringResource(R.string.text_e_g_english)) }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + singleLine = true ) - AppTextField( + AppOutlinedTextField( value = englishName, onValueChange = { englishName = it }, label = { Text(text = stringResource(R.string.name_in_english)) }, placeholder = { Text(text = stringResource(R.string.text_e_g_english)) }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + singleLine = true ) Row( diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddVocabularyDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddVocabularyDialog.kt index ebddd0f..34e302b 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/AddVocabularyDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/AddVocabularyDialog.kt @@ -46,7 +46,7 @@ import eu.gaudian.translator.view.LocalConnectionConfigured import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCheckbox import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.SourceLanguageDropdown import eu.gaudian.translator.view.composable.TargetLanguageDropdown import eu.gaudian.translator.viewmodel.LanguageViewModel @@ -136,7 +136,7 @@ fun AddVocabularyDialog( } if (selectedTab != VocabularyDialogTab.TEXT) { - AppTextField( + AppOutlinedTextField( value = word, onValueChange = { word = it }, label = { Text(stringResource(R.string.text_label_word)) }, @@ -165,7 +165,7 @@ fun AddVocabularyDialog( modifier = Modifier.fillMaxWidth() ) { Text(stringResource(R.string.label_translate)) } } - AppTextField( + AppOutlinedTextField( value = singleTranslation, onValueChange = { singleTranslation = it }, label = { Text(stringResource(R.string.text_translation)) }, @@ -238,7 +238,7 @@ fun AddVocabularyDialog( Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { Text(stringResource(R.string.text_enter_a_text_to_extract)) Box(Modifier.fillMaxWidth().padding(0.dp).heightIn(max = 300.dp)){ - AppTextField( + AppOutlinedTextField( value = word, onValueChange = { word = it }, label = { Text(stringResource(R.string.label_enter_a_text)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/CategoryDropdown.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/CategoryDropdown.kt index 26c43cc..6f0ffb0 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/CategoryDropdown.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/CategoryDropdown.kt @@ -35,7 +35,7 @@ import eu.gaudian.translator.view.composable.AppCheckbox import eu.gaudian.translator.view.composable.AppDropdownMenuItem import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppOutlinedButton -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.viewmodel.CategoryViewModel @@ -180,7 +180,7 @@ fun CategoryDropdown( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { - AppTextField( + AppOutlinedTextField( value = newCategoryName, onValueChange = { newCategoryName = it }, modifier = Modifier.weight(1f), diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/CreateCategoryListDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/CreateCategoryListDialog.kt index f8666f3..9d94442 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/CreateCategoryListDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/CreateCategoryListDialog.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp import eu.gaudian.translator.R import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField @Composable fun CreateCategoryListDialog( @@ -57,7 +57,7 @@ fun CreateCategoryListDialog( modifier = Modifier.padding(bottom = 8.dp) ) - AppTextField( + AppOutlinedTextField( value = categoryName, onValueChange = { categoryName = it }, label = { Text(stringResource(R.string.text_category_name)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/EditCategoryDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/EditCategoryDialog.kt index 0e3ef79..2621c63 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/EditCategoryDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/EditCategoryDialog.kt @@ -26,7 +26,7 @@ import eu.gaudian.translator.model.VocabularyCategory import eu.gaudian.translator.model.VocabularyFilter import eu.gaudian.translator.model.VocabularyStage import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.MultipleLanguageDropdown import eu.gaudian.translator.viewmodel.CategoryViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel @@ -84,7 +84,7 @@ fun EditCategoryDialog( .fillMaxWidth() .padding(bottom = 16.dp) ) { - AppTextField( + AppOutlinedTextField( value = categoryName, onValueChange = { categoryName = it }, label = { Text(stringResource(R.string.text_category_name)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/EditLanguageDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/EditLanguageDialog.kt index a3e70a2..bcd2851 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/EditLanguageDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/EditLanguageDialog.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.unit.dp import eu.gaudian.translator.R import eu.gaudian.translator.model.Language import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DialogButton @Composable @@ -54,7 +54,7 @@ fun EditLanguageDialog( ) // Language name: editable only for custom languages - AppTextField( + AppOutlinedTextField( value = name, onValueChange = { if (language.isCustom == true) name = it }, enabled = language.isCustom == true, @@ -62,14 +62,14 @@ fun EditLanguageDialog( modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = code, onValueChange = { code = it }, label = { Text(text = stringResource(R.string.text_language_code)) }, placeholder = { Text(text = stringResource(R.string.text_e_g_en)) }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = region, onValueChange = { region = it }, label = { Text(text = stringResource(R.string.text_region)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dialogs/ImportVocabularyDialog.kt b/app/src/main/java/eu/gaudian/translator/view/dialogs/ImportVocabularyDialog.kt index 1e11a87..5aaca35 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dialogs/ImportVocabularyDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dialogs/ImportVocabularyDialog.kt @@ -9,7 +9,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.width import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -25,6 +25,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringArrayResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -39,8 +40,8 @@ import eu.gaudian.translator.R import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppDialog import eu.gaudian.translator.view.composable.AppSlider -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.DialogButton +import eu.gaudian.translator.view.composable.InspiringSearchField import eu.gaudian.translator.view.composable.SourceLanguageDropdown import eu.gaudian.translator.view.composable.TargetLanguageDropdown import eu.gaudian.translator.view.hints.getImportVocabularyHint @@ -117,27 +118,26 @@ fun ImportDialogContent( ) { if (isGenerating) { Box( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), + modifier = Modifier.fillMaxWidth().padding(16.dp), contentAlignment = Alignment.Center ) { CircularProgressIndicator() } } else { - AppTextField( - value = category, - onValueChange = { category = it }, - label = { Text(stringResource(R.string.text_search_term)) }, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 16.dp) - ) Text( - text = stringResource(R.string.text_hint_you_can_search), - style = MaterialTheme.typography.bodyMedium, - modifier = Modifier.fillMaxWidth() + text = stringResource(R.string.text_search_term), + style = MaterialTheme.typography.labelLarge, + modifier = Modifier.padding(bottom = 8.dp) ) + // Modern rotating field using XML resource array + InspiringSearchField( + value = category, + hints = stringArrayResource(R.array.vocabulary_hints), + onValueChange = { category = it } + ) + + // The "Dica" string has been removed to keep the interface clean + Spacer(modifier = Modifier.height(16.dp)) Text( text = stringResource(R.string.text_select_languages), @@ -172,14 +172,11 @@ fun ImportDialogContent( Text( text = stringResource(R.string.text_amount_2d, amount.toInt()), style = MaterialTheme.typography.bodyMedium, - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp) + modifier = Modifier.fillMaxWidth().padding(top = 8.dp) ) Spacer(modifier = Modifier.height(8.dp)) } - // Action buttons Spacer(modifier = Modifier.height(16.dp)) Row( modifier = Modifier.fillMaxWidth(), @@ -190,7 +187,7 @@ fun ImportDialogContent( content = { Text(stringResource(R.string.label_cancel)) } ) if (category.isNotBlank() && !isGenerating) { - Spacer(modifier = Modifier.widthIn(8.dp)) + Spacer(modifier = Modifier.width(8.dp)) DialogButton(onClick = { coroutineScope.launch { vocabularyViewModel.generateVocabularyItems(category, amount.toInt()) diff --git a/app/src/main/java/eu/gaudian/translator/view/dictionary/EtymologyScreen.kt b/app/src/main/java/eu/gaudian/translator/view/dictionary/EtymologyScreen.kt index b48ca4f..7ea83fa 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dictionary/EtymologyScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dictionary/EtymologyScreen.kt @@ -29,7 +29,7 @@ import eu.gaudian.translator.R import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppOutlinedCard -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DictionaryLanguageDropDown import eu.gaudian.translator.viewmodel.DictionaryViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel @@ -49,7 +49,7 @@ fun EtymologyScreen( modifier = Modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - AppTextField( + AppOutlinedTextField( value = searchQuery, onValueChange = { searchQuery = it }, label = { Text(stringResource(R.string.search_for_a_word_s_origin)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/dictionary/MainDictionaryScreenComponents.kt b/app/src/main/java/eu/gaudian/translator/view/dictionary/MainDictionaryScreenComponents.kt index 97cfb7b..ad0b03b 100644 --- a/app/src/main/java/eu/gaudian/translator/view/dictionary/MainDictionaryScreenComponents.kt +++ b/app/src/main/java/eu/gaudian/translator/view/dictionary/MainDictionaryScreenComponents.kt @@ -54,7 +54,7 @@ import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppOutlinedButton -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DictionaryLanguageDropDown import eu.gaudian.translator.view.composable.OptionItemSwitch import eu.gaudian.translator.viewmodel.DictionaryViewModel @@ -243,11 +243,10 @@ private fun SearchFieldWithSuggestions( expanded = expanded && suggestions.isNotEmpty(), onExpandedChange = { expanded = !expanded } ) { - AppTextField( + AppOutlinedTextField( value = searchQuery, onValueChange = { onSearchQueryChange(it) - // Using ViewModel's fetchSuggestions with debounce lastJob?.cancel() lastJob = scope.launch { delay(100) diff --git a/app/src/main/java/eu/gaudian/translator/view/exercises/GenerateExerciseDialog.kt b/app/src/main/java/eu/gaudian/translator/view/exercises/GenerateExerciseDialog.kt index f2f19ec..e149083 100644 --- a/app/src/main/java/eu/gaudian/translator/view/exercises/GenerateExerciseDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/exercises/GenerateExerciseDialog.kt @@ -42,8 +42,8 @@ import eu.gaudian.translator.R import eu.gaudian.translator.model.Question import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppDialog +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppSlider -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.DialogButton import eu.gaudian.translator.view.composable.SourceLanguageDropdown import eu.gaudian.translator.view.composable.TargetLanguageDropdown @@ -94,7 +94,7 @@ fun GenerateExerciseDialog( color = MaterialTheme.colorScheme.onSurface, modifier = Modifier.padding(bottom = 8.dp) ) - AppTextField( + AppOutlinedTextField( value = category, onValueChange = { category = it }, label = { Text(stringResource(R.string.text_category_prompt)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/exercises/QuestionUIs.kt b/app/src/main/java/eu/gaudian/translator/view/exercises/QuestionUIs.kt index 6810ddb..bc96582 100644 --- a/app/src/main/java/eu/gaudian/translator/view/exercises/QuestionUIs.kt +++ b/app/src/main/java/eu/gaudian/translator/view/exercises/QuestionUIs.kt @@ -49,7 +49,7 @@ import eu.gaudian.translator.utils.TextToSpeechHelper import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppIcons -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.viewmodel.SettingsViewModel import kotlinx.coroutines.launch import java.util.Locale @@ -102,7 +102,7 @@ fun FillInTheBlankQuestionUi( } } } - AppTextField( + AppOutlinedTextField( value = selectedAnswer, onValueChange = onAnswerSelect, placeholder = { Text(placeholder) }, @@ -337,7 +337,7 @@ fun ListeningComprehensionQuestionUi( if (maskedHint.isNotBlank()) { Text(maskedHint, style = MaterialTheme.typography.bodyMedium) } - AppTextField( + AppOutlinedTextField( value = selectedAnswer, onValueChange = onAnswerSelect, label = { Text(stringResource(R.string.type_what_you_hear)) }, @@ -482,7 +482,7 @@ fun VocabularyTestQuestionUi( text = stringResource(R.string.translate_the_following_d, question.languageDirection), style = MaterialTheme.typography.bodyMedium ) - AppTextField( + AppOutlinedTextField( value = selectedAnswer, onValueChange = onAnswerSelect, label = { Text(stringResource(R.string.label_your_translation)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/exercises/YouTubeExerciseDialog.kt b/app/src/main/java/eu/gaudian/translator/view/exercises/YouTubeExerciseDialog.kt index 1c5b780..867312c 100644 --- a/app/src/main/java/eu/gaudian/translator/view/exercises/YouTubeExerciseDialog.kt +++ b/app/src/main/java/eu/gaudian/translator/view/exercises/YouTubeExerciseDialog.kt @@ -29,7 +29,7 @@ import eu.gaudian.translator.R import eu.gaudian.translator.model.Language import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DialogButton import eu.gaudian.translator.view.composable.SourceLanguageDropdown import eu.gaudian.translator.view.composable.TargetLanguageDropdown @@ -64,12 +64,14 @@ fun YouTubeExerciseDialog( ) if (!languageOnly) { - AppTextField( + AppOutlinedTextField( value = youtubeUrl, onValueChange = { youtubeUrl = it }, label = { Text(stringResource(R.string.text_youtube_link)) }, placeholder = { Text("https://www.youtube.com/watch?v=...") }, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + singleLine = true, + paste = true, ) } diff --git a/app/src/main/java/eu/gaudian/translator/view/hints/ImportVocabularyHints.kt b/app/src/main/java/eu/gaudian/translator/view/hints/ImportVocabularyHints.kt index 656d3b4..2efe788 100644 --- a/app/src/main/java/eu/gaudian/translator/view/hints/ImportVocabularyHints.kt +++ b/app/src/main/java/eu/gaudian/translator/view/hints/ImportVocabularyHints.kt @@ -16,8 +16,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import eu.gaudian.translator.R import eu.gaudian.translator.view.composable.AppCheckbox +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppSlider -import eu.gaudian.translator.view.composable.AppTextField /** * Provides the migrated Hint for ImportVocabulary. @@ -38,7 +38,7 @@ fun getImportVocabularyHint(): Hint { description = stringResource(R.string.text_hint_you_can_search), trailing = { // The AppTextField is wrapped in the VisualStep's trailing composable - AppTextField( + AppOutlinedTextField( value = stringResource(R.string.search_term_placeholder), onValueChange = {}, label = { Text(stringResource(R.string.text_search_term)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/hints/SortingScreenHint.kt b/app/src/main/java/eu/gaudian/translator/view/hints/SortingScreenHint.kt index ddede6e..c300826 100644 --- a/app/src/main/java/eu/gaudian/translator/view/hints/SortingScreenHint.kt +++ b/app/src/main/java/eu/gaudian/translator/view/hints/SortingScreenHint.kt @@ -36,7 +36,7 @@ import androidx.compose.ui.unit.sp import eu.gaudian.translator.R import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppIcons -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField object SortingScreenHint : LegacyHint() { override val titleRes: Int = R.string.sorting_hint_title @@ -56,7 +56,7 @@ object SortingScreenHint : LegacyHint() { HintSection(title = stringResource(R.string.sorting_hint_intro_text)) { @Suppress("HardCodedStringLiteral") - AppTextField( + AppOutlinedTextField( value = "der Hund", onValueChange = {}, label = { Text(stringResource(R.string.label_word)) }, @@ -64,7 +64,7 @@ object SortingScreenHint : LegacyHint() { enabled = false ) @Suppress("HardCodedStringLiteral") - AppTextField( + AppOutlinedTextField( value = "the dog", onValueChange = {}, label = { Text(stringResource(R.string.label_translation)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/AddModelScreen.kt b/app/src/main/java/eu/gaudian/translator/view/settings/AddModelScreen.kt index 66fe226..3597728 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/AddModelScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/AddModelScreen.kt @@ -53,9 +53,9 @@ import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppDialog import eu.gaudian.translator.view.composable.AppIcons +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppScaffold import eu.gaudian.translator.view.composable.AppSwitch -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.ModelBadges import eu.gaudian.translator.view.hints.AddModelScanHint @@ -272,7 +272,7 @@ fun AddModelScreen(navController: NavController, providerKey: String) { } Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { - AppTextField( + AppOutlinedTextField( value = displayName, onValueChange = { displayName = it }, label = { Text(stringResource(R.string.label_display_name)) }, @@ -289,7 +289,7 @@ fun AddModelScreen(navController: NavController, providerKey: String) { } } ) - AppTextField( + AppOutlinedTextField( value = modelId, onValueChange = { modelId = it }, label = { Text(stringResource(R.string.label_model_id_star)) }, @@ -312,7 +312,7 @@ fun AddModelScreen(navController: NavController, providerKey: String) { } } ) - AppTextField( + AppOutlinedTextField( value = description, onValueChange = { description = it }, label = { Text(stringResource(R.string.label_description)) }, @@ -430,7 +430,7 @@ private fun EnhancedScannedModelsDialog( if (showSearch || hasFreeModels) { Column(Modifier.padding(horizontal = 8.dp)) { if (showSearch) { - AppTextField( + AppOutlinedTextField( value = searchQuery, onValueChange = { searchQuery = it }, modifier = Modifier.fillMaxWidth(), @@ -474,7 +474,7 @@ private fun EnhancedScannedModelsDialog( ) } } else { - itemsIndexed(filteredModels, key = { index, model -> "${model.modelId}_${model.providerKey}_${model.displayName}_$index" }) { index, model -> + itemsIndexed(filteredModels, key = { index, model -> "${model.modelId}_${model.providerKey}_${model.displayName}_$index" }) { _, model -> var expanded by remember { mutableStateOf(false) } var canExpand by remember { mutableStateOf(false) } val secondary = buildString { diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/ApiKeyScreen.kt b/app/src/main/java/eu/gaudian/translator/view/settings/ApiKeyScreen.kt index ca570b0..2986605 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/ApiKeyScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/ApiKeyScreen.kt @@ -71,9 +71,9 @@ import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppDialog import eu.gaudian.translator.view.composable.AppIcons +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppScaffold import eu.gaudian.translator.view.composable.AppTabLayout -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.ClickableText import eu.gaudian.translator.view.composable.PrimaryButton @@ -1006,11 +1006,12 @@ private fun ApiKeyInput( ) { Column(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp)) { val clipboard = LocalClipboardManager.current - AppTextField( + AppOutlinedTextField( value = apiKey, onValueChange = onApiKeyChanged, label = { Text(stringResource(R.string.text_enter_api_key)) }, modifier = Modifier.fillMaxWidth(), + maxLines = 3, trailingIcon = { IconButton( onClick = { @@ -1066,20 +1067,20 @@ fun AddProviderDialog(onDismiss: () -> Unit, onConfirm: (ApiProvider) -> Unit) { modifier = Modifier.padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { - AppTextField( + AppOutlinedTextField( value = displayName, onValueChange = { newValue: String -> displayName = newValue }, label = { Text(stringResource(R.string.display_name) + " *") }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = baseUrl, onValueChange = { newValue: String -> baseUrl = newValue }, label = { Text(stringResource(R.string.text_base_url_and_example) + " *") }, modifier = Modifier.fillMaxWidth(), maxLines = 2 ) - AppTextField( + AppOutlinedTextField( value = endpoint, onValueChange = { newValue: String -> endpoint = newValue }, label = { Text(buildString { @@ -1088,7 +1089,7 @@ fun AddProviderDialog(onDismiss: () -> Unit, onConfirm: (ApiProvider) -> Unit) { }) }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = websiteUrl, onValueChange = { newValue: String -> websiteUrl = newValue }, label = { Text(buildString { @@ -1189,19 +1190,19 @@ fun EditProviderDialog( modifier = Modifier.padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - AppTextField( + AppOutlinedTextField( value = displayName, onValueChange = { displayName = it }, label = { Text(stringResource(R.string.display_name) + " *") }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = baseUrl, onValueChange = { baseUrl = it }, label = { Text(stringResource(R.string.text_base_url_and_example) + " *") }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = endpoint, onValueChange = { endpoint = it }, label = { Text(buildString { @@ -1210,7 +1211,7 @@ fun EditProviderDialog( }) }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = websiteUrl, onValueChange = { websiteUrl = it }, label = { Text(buildString { @@ -1324,14 +1325,14 @@ fun AddModelDialog( } // Manual entry - AppTextField( + AppOutlinedTextField( value = displayName, onValueChange = { newValue: String -> displayName = newValue }, label = { Text(stringResource(R.string.display_name)) }, enabled = !isLoading, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = modelId, onValueChange = { newValue: String -> modelId = newValue }, label = { Text(stringResource(R.string.model_id)) }, @@ -1339,7 +1340,7 @@ fun AddModelDialog( modifier = Modifier.fillMaxWidth(), maxLines = 2 ) - AppTextField( + AppOutlinedTextField( value = description, onValueChange = { newValue: String -> description = newValue }, label = { Text(stringResource(R.string.description)) }, @@ -1429,19 +1430,19 @@ fun EditModelDialog( modifier = Modifier.padding(24.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - AppTextField( + AppOutlinedTextField( value = displayName, onValueChange = { displayName = it }, label = { Text(stringResource(R.string.display_name)) }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = modelId, onValueChange = { modelId = it }, label = { Text(stringResource(R.string.model_id)) }, modifier = Modifier.fillMaxWidth() ) - AppTextField( + AppOutlinedTextField( value = description, onValueChange = { description = it }, label = { Text(stringResource(R.string.description)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/BasePromptSettingsScreen.kt b/app/src/main/java/eu/gaudian/translator/view/settings/BasePromptSettingsScreen.kt index c23a824..08bdb55 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/BasePromptSettingsScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/BasePromptSettingsScreen.kt @@ -42,7 +42,7 @@ import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppOutlinedButton -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.ModelBadges data class PromptSettingsState( @@ -77,7 +77,7 @@ fun BasePromptSettingsScreen( modifier = Modifier.fillMaxWidth(), ) { Column(Modifier.padding(16.dp)) { - AppTextField( + AppOutlinedTextField( value = state.customPrompt, onValueChange = onPromptChanged, modifier = Modifier.fillMaxWidth(), diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/DictionaryOptionsScreen.kt b/app/src/main/java/eu/gaudian/translator/view/settings/DictionaryOptionsScreen.kt index 2de8588..36e7fc5 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/DictionaryOptionsScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/DictionaryOptionsScreen.kt @@ -34,8 +34,8 @@ import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.LocalShowExperimentalFeatures import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppIcons +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppScaffold -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.OptionItemSwitch import eu.gaudian.translator.view.composable.PrimaryButton @@ -130,7 +130,7 @@ fun DictionaryOptionsScreen( apiViewModel.setDictionaryModel(model) }, ) - AppTextField( + AppOutlinedTextField( value = tempPrompt, onValueChange = { tempPrompt = it }, label = { Text(stringResource(R.string.text_custom_dictionary_prompt)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/ExerciseSettingsScreen.kt b/app/src/main/java/eu/gaudian/translator/view/settings/ExerciseSettingsScreen.kt index 82e8762..f976913 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/ExerciseSettingsScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/ExerciseSettingsScreen.kt @@ -31,8 +31,8 @@ import eu.gaudian.translator.R import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppIcons +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppScaffold -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.PrimaryButton import eu.gaudian.translator.view.composable.SecondaryButton @@ -114,7 +114,7 @@ fun ExerciseSettingsScreen( apiViewModel.setExerciseModel(model) }, ) - AppTextField( + AppOutlinedTextField( value = tempPrompt, onValueChange = { tempPrompt = it }, label = { Text(stringResource(R.string.custom_exercise_prompt)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/ExerciseControls.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/ExerciseControls.kt index eeb85d5..2b62941 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/ExerciseControls.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/ExerciseControls.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.unit.dp import eu.gaudian.translator.R import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppOutlinedButton -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.CorrectButton import eu.gaudian.translator.view.composable.WrongButton @@ -43,7 +43,7 @@ fun ExerciseControls( Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)) { // Input field for spelling, only shown before the answer is revealed. if (!isRevealed && state is VocabularyExerciseState.Spelling) { - AppTextField( + AppOutlinedTextField( value = spellingAnswer, onValueChange = { spellingAnswer = it }, label = { Text(stringResource(R.string.type_the_translation)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularySortingScreen.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularySortingScreen.kt index 79e84a6..6f4bd84 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularySortingScreen.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/VocabularySortingScreen.kt @@ -68,8 +68,8 @@ import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppDialog import eu.gaudian.translator.view.composable.AppIcons +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppScaffold -import eu.gaudian.translator.view.composable.AppTextField import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.SingleLanguageDropDown import eu.gaudian.translator.view.dialogs.CategoryDropdown @@ -455,7 +455,7 @@ fun VocabularySortingItem( } Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - AppTextField( + AppOutlinedTextField( value = wordFirst, onValueChange = { wordFirst = it }, label = { Text(stringResource(R.string.label_word)) }, @@ -469,7 +469,7 @@ fun VocabularySortingItem( } Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - AppTextField( + AppOutlinedTextField( value = wordSecond, onValueChange = { wordSecond = it }, label = { Text(stringResource(R.string.label_translation)) }, diff --git a/app/src/main/java/eu/gaudian/translator/view/vocabulary/card/GrammarComponents.kt b/app/src/main/java/eu/gaudian/translator/view/vocabulary/card/GrammarComponents.kt index 5130717..d441739 100644 --- a/app/src/main/java/eu/gaudian/translator/view/vocabulary/card/GrammarComponents.kt +++ b/app/src/main/java/eu/gaudian/translator/view/vocabulary/card/GrammarComponents.kt @@ -45,7 +45,7 @@ import eu.gaudian.translator.model.grammar.formatGrammarDetails import eu.gaudian.translator.utils.Log import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.view.composable.AppDialog -import eu.gaudian.translator.view.composable.AppTextField +import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.DialogButton import eu.gaudian.translator.viewmodel.LanguageConfigViewModel @@ -185,7 +185,7 @@ private fun GuidedEditTabContent( expanded = isCategoryDropdownExpanded, onExpandedChange = { isCategoryDropdownExpanded = !isCategoryDropdownExpanded } ) { - AppTextField( + AppOutlinedTextField( modifier = Modifier .menuAnchor(ExposedDropdownMenuAnchorType.PrimaryEditable, enabled = true) .fillMaxWidth(), @@ -247,7 +247,7 @@ private fun DynamicField( when (fieldConfig.type) { "text" -> { - AppTextField( + AppOutlinedTextField( value = currentValue ?: "", onValueChange = { onValueChange(it.ifEmpty { null }) }, label = { Text(label) }, @@ -262,7 +262,7 @@ private fun DynamicField( isExpanded = !isExpanded } ) { - AppTextField( + AppOutlinedTextField( modifier = Modifier .menuAnchor(ExposedDropdownMenuAnchorType.PrimaryEditable, enabled = true) .fillMaxWidth(), diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 51e6531..3d722cc 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -41,6 +41,14 @@ Make it informal. + + Basic greetings + Irregular verbs + Vocabulary at the airport + How to order a coffee + Idiomatic expressions + + Version 0.3.0 \n• Enabled CSV Import for Vocabulary\n• Option to use a translation server for translations instead of AI models for some supported langugaes\n• UI bug fixes \n• Show word frequency \n• Performance optimizations \n• Improved translations (German and Portuguese) Version 0.4.0 \n• Added dictionary download (beta) \n• UI enhancements \n• Bugfixes \n• Re-designed vocabulary card with improved UI \n• More pre-configured providers \n• Improved performance