rename AppTextField to AppOutlinedTextField and implement InspiringSearchField
This commit is contained in:
@@ -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<String>,
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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)) },
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
<item>Make it informal.</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="vocabulary_hints">
|
||||
<item>Basic greetings</item>
|
||||
<item>Irregular verbs</item>
|
||||
<item>Vocabulary at the airport</item>
|
||||
<item>How to order a coffee</item>
|
||||
<item>Idiomatic expressions</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="changelog_entries">
|
||||
<item>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)</item>
|
||||
<item>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</item>
|
||||
|
||||
Reference in New Issue
Block a user