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 index 997b3e0..7b47628 100644 --- a/app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt +++ b/app/src/main/java/eu/gaudian/translator/view/composable/AppOutlinedTextField.kt @@ -134,7 +134,9 @@ fun AppOutlinedTextField( fun InspiringSearchField( value: String, hints : Array, - onValueChange: (String) -> Unit + onValueChange: (String) -> Unit, + minLines: Int = 1, + maxLines: Int = 1 ) { var currentHintIndex by remember { mutableIntStateOf(0) } @@ -166,14 +168,14 @@ fun InspiringSearchField( Text( text = hint, color = Color.Gray.copy(alpha = 0.6f), - maxLines = 1, + //maxLines = 1, overflow = TextOverflow.Ellipsis ) } }, singleLine = true, - minLines = 1, - maxLines = 1 + minLines = minLines, + maxLines = maxLines ) } 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 7d77f7e..3fed94a 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 @@ -153,7 +153,7 @@ fun AppCard( if (!title.isNullOrBlank()) { Text( text = title, - style = MaterialTheme.typography.headlineMedium, + style = MaterialTheme.typography.headlineSmall, color = MaterialTheme.colorScheme.onSurface ) } 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 08bdb55..87af3ef 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 @@ -1,7 +1,6 @@ package eu.gaudian.translator.view.settings import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -9,7 +8,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -32,6 +30,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import eu.gaudian.translator.R @@ -42,7 +41,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.AppOutlinedTextField +import eu.gaudian.translator.view.composable.InspiringSearchField import eu.gaudian.translator.view.composable.ModelBadges data class PromptSettingsState( @@ -55,13 +54,14 @@ data class PromptSettingsState( @Composable fun BasePromptSettingsScreen( state: PromptSettingsState, - providers: List, // Pass the list of providers + providers: List, description: String, onPromptChanged: (String) -> Unit, onSaveClicked: () -> Unit, onModelSelected: (LanguageModel?) -> Unit, - onExamplePromptClicked: (String) -> Unit + hints: Array ) { + AppCard { Column( modifier = Modifier .fillMaxWidth() @@ -73,16 +73,15 @@ fun BasePromptSettingsScreen( modifier = Modifier.padding(vertical = 16.dp) ) - AppCard( - modifier = Modifier.fillMaxWidth(), - ) { + Column(Modifier.padding(16.dp)) { - AppOutlinedTextField( + InspiringSearchField( value = state.customPrompt, onValueChange = onPromptChanged, - modifier = Modifier.fillMaxWidth(), - label = { Text(stringResource(id = R.string.text_enter_your_custom_prompt)) }, - minLines = 3 + //label = { Text(stringResource(id = R.string.text_enter_your_custom_prompt)) }, + minLines = 3, + maxLines = 5, + hints = hints, ) Row( @@ -109,26 +108,9 @@ fun BasePromptSettingsScreen( } } } - } - Spacer(modifier = Modifier.height(24.dp)) - Text( - text = stringResource(R.string.text_example_prompts), - style = MaterialTheme.typography.titleMedium, - modifier = Modifier.padding(bottom = 8.dp) - ) - - state.examplePrompts.forEach { prompt -> - Text( - text = prompt, - modifier = Modifier - .fillMaxWidth() - .clickable { onExamplePromptClicked(prompt) } - .padding(vertical = 8.dp) - ) - HorizontalDivider() - } + } } } @@ -274,7 +256,7 @@ fun ApiModelDropDown( Text( text = providerName, style = MaterialTheme.typography.labelMedium, - fontWeight = androidx.compose.ui.text.font.FontWeight.Medium, + fontWeight = FontWeight.Medium, color = if (isActive) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) ) Text( @@ -305,7 +287,7 @@ fun ApiModelDropDown( text = model.displayName, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f), - fontWeight = if (model == selectedModel) androidx.compose.ui.text.font.FontWeight.Medium else androidx.compose.ui.text.font.FontWeight.Normal + fontWeight = if (model == selectedModel) FontWeight.Medium else FontWeight.Normal ) Spacer(modifier = Modifier.width(8.dp)) ModelBadges( @@ -387,5 +369,6 @@ fun BasePromptSettingsScreenPreview() { onPromptChanged = {}, onSaveClicked = {}, onModelSelected = {}, - onExamplePromptClicked = {}) + hints = listOf("test1", "test2").toTypedArray(), + ) } diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/CustomPromptScreens.kt b/app/src/main/java/eu/gaudian/translator/view/settings/CustomPromptScreens.kt index 3c952a4..0555413 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/CustomPromptScreens.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/CustomPromptScreens.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue 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.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -82,7 +83,7 @@ fun CustomVocabularyPromptScreen( onPromptChanged = { tempPrompt = it }, onSaveClicked = { settingsViewModel.saveCustomVocabularyPrompt(tempPrompt) }, onModelSelected = { apiViewModel.setVocabularyModel(it) }, - onExamplePromptClicked = { tempPrompt = it } + hints = stringArrayResource(R.array.vocabulary_example_prompts), ) } } 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 36e7fc5..b47f4c7 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 @@ -4,14 +4,12 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -34,11 +32,9 @@ 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.AppTopAppBar import eu.gaudian.translator.view.composable.OptionItemSwitch -import eu.gaudian.translator.view.composable.PrimaryButton import eu.gaudian.translator.view.dictionary.DictionaryManagerContent import eu.gaudian.translator.view.hints.getDictionaryOptionsHint import eu.gaudian.translator.viewmodel.ApiViewModel @@ -113,51 +109,32 @@ fun DictionaryOptionsScreen( } item { - AppCard { - Column( - modifier = Modifier.padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - Text( - stringResource(R.string.text_ai_model_custom_prompt), - style = MaterialTheme.typography.titleMedium - ) - ApiModelDropDown( - models = availableModels, - providers = allProviders, - selectedModel = selectedModel, - onModelSelected = { model -> - apiViewModel.setDictionaryModel(model) - }, - ) - AppOutlinedTextField( - value = tempPrompt, - onValueChange = { tempPrompt = it }, - label = { Text(stringResource(R.string.text_custom_dictionary_prompt)) }, - modifier = Modifier.defaultMinSize(minHeight = 120.dp) - ) - PrimaryButton( - onClick = { settingsViewModel.saveCustomPromptDictionary(tempPrompt) }, - text = stringResource(R.string.text_save_prompt), - modifier = Modifier.align(Alignment.End) - ) - } - } + val screenState = PromptSettingsState( + availableModels = availableModels, + selectedModel = selectedModel, + customPrompt = tempPrompt, + examplePrompts = emptyList() + ) + + BasePromptSettingsScreen( + state = screenState, + providers = allProviders, + description = stringResource(R.string.text_description_dictionary_prompt), + onPromptChanged = { tempPrompt = it }, + onSaveClicked = { settingsViewModel.saveCustomPromptDictionary(tempPrompt) }, + onModelSelected = { apiViewModel.setDictionaryModel(it) }, + hints = emptyArray(), //TODO + ) } item { - AppCard { - - AppCard ( + AppCard( title = stringResource(R.string.label_dictionary_content), text = stringResource(R.string.text_select_the_content_dictionary), expandable = true, initiallyExpanded = false, - - ){ + ) { Column(Modifier.padding(0.dp)) { - - dictionaryOptionKeys.zip(dictionaryOptionLabels).forEach { (key, label) -> val isChecked = dictionarySwitches.contains(key) || dictionarySwitches.contains(label) @@ -182,7 +159,6 @@ fun DictionaryOptionsScreen( } } } - } } item { diff --git a/app/src/main/java/eu/gaudian/translator/view/settings/TranslationSettings.kt b/app/src/main/java/eu/gaudian/translator/view/settings/TranslationSettings.kt index 8d8ea8f..0d68bff 100644 --- a/app/src/main/java/eu/gaudian/translator/view/settings/TranslationSettings.kt +++ b/app/src/main/java/eu/gaudian/translator/view/settings/TranslationSettings.kt @@ -104,11 +104,11 @@ fun TranslationSettingsScreen( BasePromptSettingsScreen( state = screenState, providers = allProviders, - description = stringResource(R.string.text_here_you_can_set), + description = stringResource(R.string.text_translation_instructions), onPromptChanged = { tempPrompt = it }, onSaveClicked = { settingsViewModel.saveCustomPrompt(tempPrompt) }, onModelSelected = { apiViewModel.setTranslationModel(it) }, - onExamplePromptClicked = { tempPrompt = it } + hints = context.resources.getStringArray(R.array.example_prompts), ) } } diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 4614a9b..af6f137 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -155,11 +155,9 @@ Korrigierten Text kopieren Korrekt Erklärung - Hier kannst du einen benutzerdefinierten Prompt für das KI-Übersetzungsmodell festlegen, um den Übersetzungsstil anzupassen. Vokabular-Prompt Hier kannst du einen benutzerdefinierten Prompt festlegen, um zu definieren, wie neue Vokabeln erstellt werden. Wähle die Inhalte aus, die für einen Wörterbucheintrag erstellt werden sollen. - Benutzerdefinierter Wörterbuch-Prompt Prompt speichern Hell diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6e4a3be..f5ba5f0 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -153,11 +153,9 @@ Copiar texto corrigido Correto Explicação - Aqui você pode definir um prompt personalizado para o modelo de tradução de IA, ajustando o estilo da tradução. Prompt de Vocabulário Aqui você pode definir um prompt personalizado para definir como novos itens de vocabulário são gerados. Selecione o conteúdo a ser gerado para uma entrada de dicionário. - Prompt Personalizado do Dicionário Salvar Prompt Claro diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 3d722cc..43b7be0 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -49,12 +49,21 @@ Idiomatic expressions + + Use Latin American Spanish + Avoid long words + Avoid sentences + Include many verbs and adjectives + Use informal language + + + 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 - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e6ba8b7..fc47f97 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -713,7 +713,6 @@ Add to favorites AI failed to create the exercise. AI generation failed with an exception - All dictionaries deleted successfully All items completed! All Languages @@ -833,7 +832,7 @@ Generate Exercise with AI Generating questions from video… Get API Key at %1$s - Here you can set a custom prompt for the AI translation model. This allows you to fine-tune the translation style. + Set model for translation and give optional instructions on how to translate. Here you can set a custom prompt for the AI vocabulary model. This allows you to define how new vocabulary entries are generated. Hint Hint: You can search for any term, e.g. \"Things to do at the zoo\" or \"irregular verbs\"! @@ -1050,4 +1049,5 @@ Regenerate Read Aloud All Categories + Set a model for generating dictionary content and give optional instructions.