implement conditional AI generator UI and improve "No Connection" handling

This commit is contained in:
jonasgaudian
2026-02-19 22:50:25 +01:00
parent 95dfd3c7eb
commit c94b29073f
10 changed files with 194 additions and 137 deletions

View File

@@ -16,13 +16,18 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import eu.gaudian.translator.R import eu.gaudian.translator.R
import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppButton
import eu.gaudian.translator.view.composable.AppTopAppBar
@Composable @Composable
fun NoConnectionScreen(onSettingsClick: () -> Unit) { fun NoConnectionScreen(onSettingsClick: () -> Unit, navController: NavController) {
AppTopAppBar(
title = "No Connection",
onNavigateBack = {navController.popBackStack()},
)
Column( Column(
modifier = Modifier.fillMaxSize().padding(24.dp), modifier = Modifier.fillMaxSize().padding(24.dp),
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
@@ -41,7 +46,7 @@ fun NoConnectionScreen(onSettingsClick: () -> Unit) {
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
AppButton(onClick = onSettingsClick, modifier = Modifier.padding(top = 16.dp)) { AppButton(onClick = onSettingsClick, modifier = Modifier.padding(top = 16.dp)) {
Text(text = stringResource(id = R.string.settings_title_connection)) Text(text = "Configure Connection")
} }
} }
} }

View File

@@ -17,13 +17,10 @@ import androidx.navigation.compose.rememberNavController
import eu.gaudian.translator.R import eu.gaudian.translator.R
import eu.gaudian.translator.ui.theme.ThemePreviews import eu.gaudian.translator.ui.theme.ThemePreviews
import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.utils.findActivity
import eu.gaudian.translator.view.LocalConnectionConfigured
import eu.gaudian.translator.view.NoConnectionScreen
import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppIcons
import eu.gaudian.translator.view.composable.AppTabLayout import eu.gaudian.translator.view.composable.AppTabLayout
import eu.gaudian.translator.view.composable.Screen import eu.gaudian.translator.view.composable.Screen
import eu.gaudian.translator.view.composable.TabItem import eu.gaudian.translator.view.composable.TabItem
import eu.gaudian.translator.view.settings.SettingsRoutes
import eu.gaudian.translator.viewmodel.CorrectionViewModel import eu.gaudian.translator.viewmodel.CorrectionViewModel
import eu.gaudian.translator.viewmodel.DictionaryViewModel import eu.gaudian.translator.viewmodel.DictionaryViewModel
import eu.gaudian.translator.viewmodel.LanguageViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel
@@ -52,12 +49,6 @@ fun MainDictionaryScreen(
val languageViewModel: LanguageViewModel = hiltViewModel(viewModelStoreOwner = activity) val languageViewModel: LanguageViewModel = hiltViewModel(viewModelStoreOwner = activity)
val dictionaryTabs = getDictionaryTabs() val dictionaryTabs = getDictionaryTabs()
val connectionConfigured = LocalConnectionConfigured.current
if (!connectionConfigured) {
NoConnectionScreen(onSettingsClick = {navController.navigate(SettingsRoutes.API_KEY)})
return
}
var selectedTab by remember { mutableStateOf(dictionaryTabs[0]) } var selectedTab by remember { mutableStateOf(dictionaryTabs[0]) }
Column { Column {

View File

@@ -337,6 +337,7 @@ fun AllCardsView(
onItemLongClick: (VocabularyItem) -> Unit, onItemLongClick: (VocabularyItem) -> Unit,
onDeleteClick: (VocabularyItem) -> Unit, onDeleteClick: (VocabularyItem) -> Unit,
listState: LazyListState, listState: LazyListState,
onAddClick: (() -> Unit)? = null,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
if (vocabularyItems.isEmpty()) { if (vocabularyItems.isEmpty()) {
@@ -359,6 +360,21 @@ fun AllCardsView(
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
if (onAddClick != null) {
Spacer(modifier = Modifier.height(24.dp))
androidx.compose.material3.Button(
onClick = onAddClick,
modifier = Modifier.fillMaxWidth(0.6f)
) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(text = stringResource(R.string.label_add_vocabulary))
}
}
} }
} else { } else {
LazyColumn( LazyColumn(

View File

@@ -266,6 +266,7 @@ fun LibraryScreen(
selection = selection, selection = selection,
stageMapping = stageMapping, stageMapping = stageMapping,
listState = lazyListState, listState = lazyListState,
onAddClick = { navController.navigate(NavigationRoutes.NEW_WORD) },
onItemClick = { item -> onItemClick = { item ->
if (isInSelectionMode) { if (isInSelectionMode) {
selection = if (selection.contains(item.id.toLong())) { selection = if (selection.contains(item.id.toLong())) {

View File

@@ -6,6 +6,7 @@ import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Configuration
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode import androidx.compose.animation.core.RepeatMode
@@ -58,6 +59,7 @@ import eu.gaudian.translator.view.LocalConnectionConfigured
import eu.gaudian.translator.view.NoConnectionScreen import eu.gaudian.translator.view.NoConnectionScreen
import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppCard
import eu.gaudian.translator.view.composable.AppOutlinedCard import eu.gaudian.translator.view.composable.AppOutlinedCard
import eu.gaudian.translator.view.composable.Screen
import eu.gaudian.translator.view.dialogs.AddVocabularyDialog import eu.gaudian.translator.view.dialogs.AddVocabularyDialog
import eu.gaudian.translator.view.hints.HintDefinition import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.settings.SettingsRoutes import eu.gaudian.translator.view.settings.SettingsRoutes
@@ -88,7 +90,10 @@ fun TranslationScreen(
if (isInitializationComplete && !connectionConfigured) { if (isInitializationComplete && !connectionConfigured) {
NoConnectionScreen(onSettingsClick = { navController.navigate(SettingsRoutes.API_KEY) }) NoConnectionScreen(
onSettingsClick = { navController.navigate(SettingsRoutes.API_KEY) },
navController = navController
)
return return
} }
@@ -108,7 +113,7 @@ fun TranslationScreen(
onSettingsClick = onSettingsClick, onSettingsClick = onSettingsClick,
onNavigateBack = { onNavigateBack = {
if (!navController.popBackStack()) { if (!navController.popBackStack()) {
navController.navigate(eu.gaudian.translator.view.composable.Screen.Home.route) { navController.navigate(Screen.Home.route) {
launchSingleTop = true launchSingleTop = true
restoreState = false restoreState = false
} }
@@ -182,7 +187,7 @@ private fun LoadedTranslationContent(
AppCard(modifier = Modifier.padding(8.dp, end = 8.dp, bottom = 8.dp, top = 0.dp)) { AppCard(modifier = Modifier.padding(8.dp, end = 8.dp, bottom = 8.dp, top = 0.dp)) {
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
val isLandscape = configuration.orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
if (isLandscape) { if (isLandscape) {
Row(modifier = Modifier.fillMaxSize()) { Row(modifier = Modifier.fillMaxSize()) {

View File

@@ -563,12 +563,6 @@ fun ExplorePacksScreen(
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text(
manifestError ?: "",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { vocabPacksViewModel.loadManifest() }) { Button(onClick = { vocabPacksViewModel.loadManifest() }) {
Text(stringResource(R.string.label_retry)) Text(stringResource(R.string.label_retry))

View File

@@ -22,6 +22,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AutoAwesome import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material.icons.filled.DriveFolderUpload import androidx.compose.material.icons.filled.DriveFolderUpload
import androidx.compose.material.icons.filled.EditNote import androidx.compose.material.icons.filled.EditNote
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
@@ -56,6 +57,7 @@ import eu.gaudian.translator.model.VocabularyItem
import eu.gaudian.translator.utils.StatusMessageId import eu.gaudian.translator.utils.StatusMessageId
import eu.gaudian.translator.utils.StatusMessageService import eu.gaudian.translator.utils.StatusMessageService
import eu.gaudian.translator.utils.findActivity import eu.gaudian.translator.utils.findActivity
import eu.gaudian.translator.view.LocalConnectionConfigured
import eu.gaudian.translator.view.NavigationRoutes import eu.gaudian.translator.view.NavigationRoutes
import eu.gaudian.translator.view.composable.AppButton import eu.gaudian.translator.view.composable.AppButton
import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppCard
@@ -71,6 +73,7 @@ import eu.gaudian.translator.view.composable.SourceLanguageDropdown
import eu.gaudian.translator.view.composable.TargetLanguageDropdown import eu.gaudian.translator.view.composable.TargetLanguageDropdown
import eu.gaudian.translator.view.hints.HintDefinition import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.library.VocabularyCard import eu.gaudian.translator.view.library.VocabularyCard
import eu.gaudian.translator.view.settings.SettingsRoutes
import eu.gaudian.translator.viewmodel.LanguageViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel
import eu.gaudian.translator.viewmodel.VocabularyViewModel import eu.gaudian.translator.viewmodel.VocabularyViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -247,6 +250,7 @@ fun NewWordScreen(
} }
} }
}, },
navController = navController,
) )
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
@@ -437,108 +441,156 @@ fun AIGeneratorCard(
languageViewModel: LanguageViewModel, languageViewModel: LanguageViewModel,
isGenerating: Boolean, isGenerating: Boolean,
onGenerate: () -> Unit, onGenerate: () -> Unit,
navController: NavHostController,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val icon = Icons.Default.AutoAwesome val connectionConfigured = LocalConnectionConfigured.current
val hints = stringArrayResource(R.array.vocabulary_hints)
AppCard(
modifier = modifier.fillMaxWidth(),
title = stringResource(R.string.label_ai_generator),
icon = icon,
hintContent = HintDefinition.VOCABULARY_GENERATE_AI.hint(),
) {
Column(modifier = Modifier.padding(8.dp)) {
Text( if (connectionConfigured) {
text = stringResource(R.string.text_search_term), // Show the normal AI generator card
style = MaterialTheme.typography.labelLarge, val icon = Icons.Default.AutoAwesome
fontWeight = FontWeight.SemiBold val hints = stringArrayResource(R.array.vocabulary_hints)
) AppCard(
Spacer(modifier = Modifier.height(8.dp)) modifier = modifier.fillMaxWidth(),
InspiringSearchField( title = stringResource(R.string.label_ai_generator),
value = category, icon = icon,
hints = hints, hintContent = HintDefinition.VOCABULARY_GENERATE_AI.hint(),
onValueChange = onCategoryChange ) {
) Column(modifier = Modifier.padding(8.dp)) {
Spacer(modifier = Modifier.height(24.dp))
Text( Text(
text = stringResource(R.string.text_select_languages), text = stringResource(R.string.text_search_term),
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
fontWeight = FontWeight.SemiBold fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f))
.padding(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
SourceLanguageDropdown(
modifier = Modifier.weight(1f),
languageViewModel = languageViewModel,
iconEnabled = false,
noBorder = true
) )
TargetLanguageDropdown( Spacer(modifier = Modifier.height(8.dp))
modifier = Modifier.weight(1f), InspiringSearchField(
languageViewModel = languageViewModel, value = category,
iconEnabled = false, hints = hints,
noBorder = true onValueChange = onCategoryChange
) )
} Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.height(24.dp)) Text(
Text( text = stringResource(R.string.text_select_languages),
text = stringResource(R.string.text_select_amount), style = MaterialTheme.typography.labelLarge,
style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.SemiBold
fontWeight = FontWeight.SemiBold )
) Spacer(modifier = Modifier.height(8.dp))
Spacer(modifier = Modifier.height(8.dp))
AppSlider(
value = amount,
onValueChange = onAmountChange,
valueRange = 1f..25f,
steps = 24,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(R.string.text_amount_2d, amount.toInt()),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 8.dp)
)
Spacer(modifier = Modifier.height(32.dp))
if (isGenerating) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
horizontalArrangement = Arrangement.Center .fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f))
.padding(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
CircularProgressIndicator() SourceLanguageDropdown(
} modifier = Modifier.weight(1f),
Spacer(modifier = Modifier.height(16.dp)) languageViewModel = languageViewModel,
} iconEnabled = false,
noBorder = true
AppButton(
onClick = onGenerate,
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
enabled = category.isNotBlank() && !isGenerating
) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Icon(imageVector = Icons.Default.AutoAwesome, contentDescription = null, modifier = Modifier.size(20.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.text_generate),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
) )
TargetLanguageDropdown(
modifier = Modifier.weight(1f),
languageViewModel = languageViewModel,
iconEnabled = false,
noBorder = true
)
}
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(R.string.text_select_amount),
style = MaterialTheme.typography.labelLarge,
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.height(8.dp))
AppSlider(
value = amount,
onValueChange = onAmountChange,
valueRange = 1f..25f,
steps = 24,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(R.string.text_amount_2d, amount.toInt()),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 8.dp)
)
Spacer(modifier = Modifier.height(32.dp))
if (isGenerating) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
CircularProgressIndicator()
}
Spacer(modifier = Modifier.height(16.dp))
}
AppButton(
onClick = onGenerate,
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
enabled = category.isNotBlank() && !isGenerating
) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Icon(imageVector = Icons.Default.AutoAwesome, contentDescription = null, modifier = Modifier.size(20.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.text_generate),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
}
}
}
}
} else {
// Show the "configure connection" card when not configured
AppCard(
modifier = modifier.fillMaxWidth(),
title = stringResource(R.string.label_ai_generator),
icon = Icons.Default.AutoAwesome,
hintContent = HintDefinition.VOCABULARY_GENERATE_AI.hint(),
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(R.string.text_ai_generator_requires_configuration),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(16.dp))
AppButton(
onClick = { navController.navigate(SettingsRoutes.API_KEY) },
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Icon(imageVector = Icons.Default.Settings, contentDescription = null, modifier = Modifier.size(20.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.label_configure),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
}
} }
} }
} }

View File

@@ -547,7 +547,6 @@
<string name="sorting_hint_title">Vokabeln sortieren</string> <string name="sorting_hint_title">Vokabeln sortieren</string>
<string name="text_optional">" (optional)"</string> <string name="text_optional">" (optional)"</string>
<string name="text_check_availability">Verfügbarkeit prüfen</string> <string name="text_check_availability">Verfügbarkeit prüfen</string>
<string name="text_no_valid_api_configuration_could_be_found">Keine gültige API-Konfiguration gefunden. Bitte konfiguriere zuerst einen API-Anbieter in den Einstellungen.</string>
<string name="text_try_wiktionary_first">Zuerst Wiktionary versuchen</string> <string name="text_try_wiktionary_first">Zuerst Wiktionary versuchen</string>
<string name="text_try_first_finding_the_word_on">Versuche zuerst, das Wort auf Wiktionary zu finden, bevor eine KI-Antwort generiert wird.</string> <string name="text_try_first_finding_the_word_on">Versuche zuerst, das Wort auf Wiktionary zu finden, bevor eine KI-Antwort generiert wird.</string>
<string name="text_question_of">Frage %1$d von %2$d</string> <string name="text_question_of">Frage %1$d von %2$d</string>

View File

@@ -8,7 +8,6 @@
<string name="label_translate">Traduzir</string> <string name="label_translate">Traduzir</string>
<string name="label_add">Adicionar</string> <string name="label_add">Adicionar</string>
<string name="label_close">Fechar</string> <string name="label_close">Fechar</string>
<string name="label_cancel">Cancelar</string>
<string name="label_confirm">Confirmar</string> <string name="label_confirm">Confirmar</string>
<string name="label_select">Selecionar</string> <string name="label_select">Selecionar</string>
<string name="label_done">Concluído</string> <string name="label_done">Concluído</string>
@@ -90,7 +89,6 @@
<string name="text_widget_title_weekly_activity">Atividade Semanal</string> <string name="text_widget_title_weekly_activity">Atividade Semanal</string>
<string name="text_loading_3d">Carregando…</string> <string name="text_loading_3d">Carregando…</string>
<string name="text_show_loading">Mostrar Carregamento</string> <string name="text_show_loading">Mostrar Carregamento</string>
<string name="text_cancel_loading">Cancelar Carregamento</string>
<string name="text_show_info_message">Mostrar Mensagem Informativa</string> <string name="text_show_info_message">Mostrar Mensagem Informativa</string>
<string name="text_show_error_message">Mostrar Mensagem de Erro</string> <string name="text_show_error_message">Mostrar Mensagem de Erro</string>
<string name="text_reset_intro">Resetar Introdução</string> <string name="text_reset_intro">Resetar Introdução</string>
@@ -543,7 +541,6 @@
<string name="sorting_hint_title">Organização de Vocabulário</string> <string name="sorting_hint_title">Organização de Vocabulário</string>
<string name="text_optional">" (opcional)"</string> <string name="text_optional">" (opcional)"</string>
<string name="text_check_availability">Verificar disponibilidade</string> <string name="text_check_availability">Verificar disponibilidade</string>
<string name="text_no_valid_api_configuration_could_be_found">Nenhuma configuração de API válida foi encontrada. Antes de usar o app, configure pelo menos um provedor de API.</string>
<string name="text_try_wiktionary_first">Tentar Wikcionário Primeiro</string> <string name="text_try_wiktionary_first">Tentar Wikcionário Primeiro</string>
<string name="text_try_first_finding_the_word_on">Tente primeiro encontrar a palavra no Wikcionário antes de gerar uma resposta de IA</string> <string name="text_try_first_finding_the_word_on">Tente primeiro encontrar a palavra no Wikcionário antes de gerar uma resposta de IA</string>
<string name="text_question_of">Pergunta %1$d de %2$d</string> <string name="text_question_of">Pergunta %1$d de %2$d</string>
@@ -620,11 +617,9 @@
<string name="text_do_you_want_to_minimize_the_app">Quer minimizar o app?</string> <string name="text_do_you_want_to_minimize_the_app">Quer minimizar o app?</string>
<string name="text_error_deleting_dictionaries">Erro ao excluir dicionários: %1$s</string> <string name="text_error_deleting_dictionaries">Erro ao excluir dicionários: %1$s</string>
<string name="text_error_deleting_dictionary">Erro ao excluir dicionário: %1$s</string> <string name="text_error_deleting_dictionary">Erro ao excluir dicionário: %1$s</string>
<string name="text_error_deleting_orphaned_file">Erro ao deletar arquivo órfão: %1$s</string>
<string name="text_error_downloading_dictionary">Erro ao baixar dicionário: %1$s</string> <string name="text_error_downloading_dictionary">Erro ao baixar dicionário: %1$s</string>
<string name="text_error_loading_stored_values">Erro ao carregar valores armazenados: %1$s</string> <string name="text_error_loading_stored_values">Erro ao carregar valores armazenados: %1$s</string>
<string name="text_error_saving_entry">Erro ao salvar entrada: %1$s</string> <string name="text_error_saving_entry">Erro ao salvar entrada: %1$s</string>
<string name="text_failed_to_delete_dictionary">Falha ao deletar dicionário: %1$s</string>
<string name="text_failed_to_delete_orphaned_file">Falhou ao excluir arquivo órfão: %1$s</string> <string name="text_failed_to_delete_orphaned_file">Falhou ao excluir arquivo órfão: %1$s</string>
<string name="text_failed_to_delete_some_dictionaries">Falhou ao excluir alguns dicionários</string> <string name="text_failed_to_delete_some_dictionaries">Falhou ao excluir alguns dicionários</string>
<string name="text_failed_to_download_dictionary">Falhou ao baixar dicionário: %1$s</string> <string name="text_failed_to_download_dictionary">Falhou ao baixar dicionário: %1$s</string>
@@ -771,8 +766,6 @@
<string name="text_use_downloaded_dictionary">Usar dicionário baixado</string> <string name="text_use_downloaded_dictionary">Usar dicionário baixado</string>
<string name="text_watch_video_again">Assistir ao Vídeo Novamente</string> <string name="text_watch_video_again">Assistir ao Vídeo Novamente</string>
<string name="text_dialog_delete_provider">Tem certeza que deseja excluir o provedor "%1$s"? Isso também removerá todos os modelos associados a este provedor. Esta ação não pode ser desfeita.</string> <string name="text_dialog_delete_provider">Tem certeza que deseja excluir o provedor "%1$s"? Isso também removerá todos os modelos associados a este provedor. Esta ação não pode ser desfeita.</string>
<string name="label_delete_model">Deletar Modelo</string>
<string name="text_dialog_delete_model">Tem certeza que deseja deletar o modelo "%1$s" de %2$s? Essa ação não pode ser desfeita.</string>
<string name="label_task_model_assignments">Atribuições do Modelo de Tarefa</string> <string name="label_task_model_assignments">Atribuições do Modelo de Tarefa</string>
<string name="text_configure_which_ai_model_to_use_for_each_task_type">Configurar qual modelo de IA usar para cada tipo de tarefa</string> <string name="text_configure_which_ai_model_to_use_for_each_task_type">Configurar qual modelo de IA usar para cada tipo de tarefa</string>
<string name="label_custom">Personalizado</string> <string name="label_custom">Personalizado</string>
@@ -785,7 +778,6 @@
<string name="text_translation_will_appear_here">A tradução vai aparecer aqui</string> <string name="text_translation_will_appear_here">A tradução vai aparecer aqui</string>
<string name="label_delete_key">Apagar Chave</string> <string name="label_delete_key">Apagar Chave</string>
<string name="text_dialog_delete_key">Tem certeza que quer apagar a Chave desse Fornecedor?</string> <string name="text_dialog_delete_key">Tem certeza que quer apagar a Chave desse Fornecedor?</string>
<string name="text_delete_all_providers_and_models">Deletar todos os provedores e modelos</string>
<string name="label_dictionary_content">Conteúdo do Dicionário</string> <string name="label_dictionary_content">Conteúdo do Dicionário</string>
<string name="tab_ai_definition">Definição de IA</string> <string name="tab_ai_definition">Definição de IA</string>
<string name="tab_downloaded">Baixado</string> <string name="tab_downloaded">Baixado</string>

View File

@@ -128,7 +128,7 @@
<string name="existing_item_id_d">Existing Item (ID: %1$d)</string> <string name="existing_item_id_d">Existing Item (ID: %1$d)</string>
<string name="experimental_features">Experimental Features</string> <string name="experimental_features">Experimental Features</string>
<string name="experimental_features_description">Enable experimental features that are not yet ready for production.</string> <string name="experimental_features_description">Enable experimental features that arent yet ready for production.</string>
<string name="export_vocabulary_data">Export Vocabulary Data</string> <string name="export_vocabulary_data">Export Vocabulary Data</string>
@@ -238,6 +238,8 @@
<string name="label_adverb">Adverb</string> <string name="label_adverb">Adverb</string>
<string name="label_ai_configuration">AI Configuration</string> <string name="label_ai_configuration">AI Configuration</string>
<string name="label_ai_generator">AI Generator</string> <string name="label_ai_generator">AI Generator</string>
<string name="text_ai_generator_requires_configuration">In order to generate vocabulary with AI, you have to configure a connection to an AI service.</string>
<string name="label_configure">Configure</string>
<string name="label_ai_model">AI Model</string> <string name="label_ai_model">AI Model</string>
<string name="label_ai_model_and_prompt"><![CDATA[AI Model & Prompt]]></string> <string name="label_ai_model_and_prompt"><![CDATA[AI Model & Prompt]]></string>
<string name="label_all_cards">All Cards</string> <string name="label_all_cards">All Cards</string>
@@ -511,7 +513,7 @@
<string name="message_error_api_key_missing">API Key is missing or invalid.</string> <string name="message_error_api_key_missing">API Key is missing or invalid.</string>
<string name="message_error_articles_remove_failed">Error removing articles: %1$s</string> <string name="message_error_articles_remove_failed">Error removing articles: %1$s</string>
<string name="message_error_category_update_failed">Error updating category: %1$s</string> <string name="message_error_category_update_failed">Error updating category: %1$s</string>
<string name="message_error_excel_not_supported">Excel is not supported. Use CSV instead.</string> <string name="message_error_excel_not_supported">Excel isnt supported. Use CSV instead.</string>
<string name="message_error_file_picker_not_initialized">Save File Launcher not initialized.</string> <string name="message_error_file_picker_not_initialized">Save File Launcher not initialized.</string>
<string name="message_error_file_save_cancelled">File save cancelled or failed.</string> <string name="message_error_file_save_cancelled">File save cancelled or failed.</string>
<string name="message_error_file_save_failed">Error saving file: %1$s</string> <string name="message_error_file_save_failed">Error saving file: %1$s</string>
@@ -869,7 +871,7 @@
<string name="text_assemble_the_word_here">Bring the letters into the right order</string> <string name="text_assemble_the_word_here">Bring the letters into the right order</string>
<string name="text_assign_a_different_language_items">Assign a different language to these items.</string> <string name="text_assign_a_different_language_items">Assign a different language to these items.</string>
<string name="text_assign_these_items_2d">Assign these items:</string> <string name="text_assign_these_items_2d">Assign these items:</string>
<string name="text_authentication_is_required_and_has_failed">Authentication is required and has failed or has not yet been provided.</string> <string name="text_authentication_is_required_and_has_failed">Authentication is required and has failed or hasnt yet been provided.</string>
<string name="text_automatically_discover_models_from">Automatically discover models from %1$s</string> <string name="text_automatically_discover_models_from">Automatically discover models from %1$s</string>
<string name="text_available_dictionaries">Available Dictionaries</string> <string name="text_available_dictionaries">Available Dictionaries</string>
<string name="text_available_models">Available Models:</string> <string name="text_available_models">Available Models:</string>
@@ -915,8 +917,8 @@
<string name="text_description_dictionary_prompt">Set a model for generating dictionary content and give optional instructions.</string> <string name="text_description_dictionary_prompt">Set a model for generating dictionary content and give optional instructions.</string>
<string name="text_developed_by_jonas_gaudian">Developed by Jonas Gaudian\n</string> <string name="text_developed_by_jonas_gaudian">Developed by Jonas Gaudian\n</string>
<string name="text_dialog_delete_key">Are you sure you want to delete the Key for this Provider?</string> <string name="text_dialog_delete_key">Are you sure you want to delete the Key for this Provider?</string>
<string name="text_dialog_delete_model">Are you sure you want to delete the model \"%1$s\" from %2$s? This action cannot be undone.</string> <string name="text_dialog_delete_model">Are you sure you want to delete the model \"%1$s\" from %2$s? This action cant be undone.</string>
<string name="text_dialog_delete_provider">Are you sure you want to delete the provider \"%1$s\"? This will also remove all models associated with this provider. This action cannot be undone.</string> <string name="text_dialog_delete_provider">Are you sure you want to delete the provider \"%1$s\"? This will also remove all models associated with this provider. This action cant be undone.</string>
<string name="text_dictionary_deleted_successfully">Dictionary deleted successfully</string> <string name="text_dictionary_deleted_successfully">Dictionary deleted successfully</string>
<string name="text_dictionary_downloaded_successfully">Dictionary downloaded successfully</string> <string name="text_dictionary_downloaded_successfully">Dictionary downloaded successfully</string>
<string name="text_dictionary_manager_description">You can download dictionaries for certain languages which can be used insteaf of AI generation for dictionary content.</string> <string name="text_dictionary_manager_description">You can download dictionaries for certain languages which can be used insteaf of AI generation for dictionary content.</string>
@@ -987,7 +989,7 @@
<string name="text_language_direction_disabled_with_pairs">Clear language pair selection to choose a direction.</string> <string name="text_language_direction_disabled_with_pairs">Clear language pair selection to choose a direction.</string>
<string name="text_language_direction_explanation">You can set an optional preference which language should come first or second.</string> <string name="text_language_direction_explanation">You can set an optional preference which language should come first or second.</string>
<string name="text_language_options">Language Options</string> <string name="text_language_options">Language Options</string>
<string name="text_language_settings_description">Set what languages you want to use in the app. Languages that are not activated will not appear in this app. You can also add your own language to the list, or change an existing language (region/locale)</string> <string name="text_language_settings_description">Set what languages you want to use in the app. Languages that arent activated wont appear in this app. You can also add your own language to the list, or change an existing language (region/locale)</string>
<string name="text_last_7_days">Last 7 Days</string> <string name="text_last_7_days">Last 7 Days</string>
<string name="text_light">Light</string> <string name="text_light">Light</string>
<string name="text_list">List</string> <string name="text_list">List</string>
@@ -1011,7 +1013,7 @@
<string name="text_no_key">No Key</string> <string name="text_no_key">No Key</string>
<string name="text_no_models_found">No models found</string> <string name="text_no_models_found">No models found</string>
<string name="text_no_packs_match_search">No packs match your search.</string> <string name="text_no_packs_match_search">No packs match your search.</string>
<string name="text_no_valid_api_configuration_could_be_found">No valid API configuration could be found in the settings. Before using this app, you have to configure at least one API provider.</string> <string name="text_no_valid_api_configuration_could_be_found">No valid LLM API configuration could be found in the settings. Before using this function, you have to configure at least one API provider.</string>
<string name="text_no_vocabulary_available">No vocabulary available.</string> <string name="text_no_vocabulary_available">No vocabulary available.</string>
<string name="text_no_vocabulary_due_today">No Vocabulary Due Today</string> <string name="text_no_vocabulary_due_today">No Vocabulary Due Today</string>
<string name="text_none">None</string> <string name="text_none">None</string>
@@ -1020,7 +1022,7 @@
<string name="text_optional">" (optional)"</string> <string name="text_optional">" (optional)"</string>
<string name="text_optional_describe_what_this_model_is_good_for">Optional: Describe what this model is good for</string> <string name="text_optional_describe_what_this_model_is_good_for">Optional: Describe what this model is good for</string>
<string name="text_orphaned_file_deleted_successfully">Orphaned file deleted successfully</string> <string name="text_orphaned_file_deleted_successfully">Orphaned file deleted successfully</string>
<string name="text_orphaned_file_description">This file exists locally but is not in the server manifest or missing assets. It may be from an older version or a failed download.</string> <string name="text_orphaned_file_description">This file exists locally but isnt in the server manifest or missing assets. It may be from an older version or a failed download.</string>
<string name="text_paste_or_open_a_">Paste or open a YouTube link to see its subtitles here.</string> <string name="text_paste_or_open_a_">Paste or open a YouTube link to see its subtitles here.</string>
<string name="text_please_select_a_dictionary_language_first">Please select a dictionary language first.</string> <string name="text_please_select_a_dictionary_language_first">Please select a dictionary language first.</string>
<string name="text_question">Question</string> <string name="text_question">Question</string>
@@ -1064,7 +1066,7 @@
<string name="text_shuffle_card_order">Shuffle card order</string> <string name="text_shuffle_card_order">Shuffle card order</string>
<string name="text_shuffle_card_order_description">Shuffle Card Order</string> <string name="text_shuffle_card_order_description">Shuffle Card Order</string>
<string name="text_shuffle_languages">Shuffle Languages</string> <string name="text_shuffle_languages">Shuffle Languages</string>
<string name="text_shuffle_languages_description">Shuffle what language comes first. Does not affect language direction preferences.</string> <string name="text_shuffle_languages_description">Shuffle what language comes first. Doesnt affect language direction preferences.</string>
<string name="text_shuffle_languages_disabled_by_direction">Disable language direction preference to enable shuffling.</string> <string name="text_shuffle_languages_disabled_by_direction">Disable language direction preference to enable shuffling.</string>
<string name="text_some_items_are_in_the_wrong_category">Some items are in the wrong category.</string> <string name="text_some_items_are_in_the_wrong_category">Some items are in the wrong category.</string>
<string name="text_stage_2d">Stage %1$s</string> <string name="text_stage_2d">Stage %1$s</string>
@@ -1076,9 +1078,9 @@
<string name="text_the_correct_sentence_was_2d">The correct sentence was: %1$s</string> <string name="text_the_correct_sentence_was_2d">The correct sentence was: %1$s</string>
<string name="text_the_correct_translation_is_2d">The correct translation is: %1$s</string> <string name="text_the_correct_translation_is_2d">The correct translation is: %1$s</string>
<string name="text_theme_preview">Theme Preview</string> <string name="text_theme_preview">Theme Preview</string>
<string name="text_these_files_exist_locally">These files exist locally but are not in the server manifest. They may be from older versions.</string> <string name="text_these_files_exist_locally">These files exist locally but arent in the server manifest. They may be from older versions.</string>
<string name="text_this_must_match_the_provider_s_model_name_exactly">This must match the provider\'s model name exactly</string> <string name="text_this_must_match_the_provider_s_model_name_exactly">This must match the provider\'s model name exactly</string>
<string name="text_this_will_remove_all">This will remove all configured API providers, models, and stored API keys. This action cannot be undone.</string> <string name="text_this_will_remove_all">This will remove all configured API providers, models, and stored API keys. This action cant be undone.</string>
<string name="text_too_many_requests">Too Many Requests: The user has sent too many requests in a given amount of time.</string> <string name="text_too_many_requests">Too Many Requests: The user has sent too many requests in a given amount of time.</string>
<string name="text_total_learned_words">Total Learned Words</string> <string name="text_total_learned_words">Total Learned Words</string>
<string name="text_training_mode">Training Mode</string> <string name="text_training_mode">Training Mode</string>
@@ -1104,13 +1106,13 @@
<string name="text_youtube_link">YouTube Link</string> <string name="text_youtube_link">YouTube Link</string>
<string name="the_request_was_successful">The request was successful.</string> <string name="the_request_was_successful">The request was successful.</string>
<string name="the_requested_resource_could_not_be_found">The requested resource could not be found.</string> <string name="the_requested_resource_could_not_be_found">The requested resource couldnt be found.</string>
<string name="the_server_could_not_understand_the_request">The server could not understand the request.</string> <string name="the_server_could_not_understand_the_request">The server couldnt understand the request.</string>
<string name="the_server_understood_the_request_but_is_refusing_to_authorize_it">The server understood the request, but is refusing to authorize it.</string> <string name="the_server_understood_the_request_but_is_refusing_to_authorize_it">The server understood the request, but is refusing to authorize it.</string>
<string name="this_is_a_sample_output_text">This is a sample output text.</string> <string name="this_is_a_sample_output_text">This is a sample output text.</string>
<string name="this_is_the_content_inside_the_card">This is the content inside the card.</string> <string name="this_is_the_content_inside_the_card">This is the content inside the card.</string>
<string name="this_mode_will_not_affect_your_progress_in_stages">This mode will not affect your progress in stages.</string> <string name="this_mode_will_not_affect_your_progress_in_stages">This mode wont affect your progress in stages.</string>
<string name="timeout">Timeout</string> <string name="timeout">Timeout</string>