refactor BasePromptSettingsScreen to use InspiringSearchField and unify prompt settings across the app

This commit is contained in:
jonasgaudian
2026-02-13 16:54:24 +01:00
parent b5a9f5873a
commit f6fb6e77a8
10 changed files with 57 additions and 90 deletions

View File

@@ -134,7 +134,9 @@ fun AppOutlinedTextField(
fun InspiringSearchField(
value: String,
hints : Array<String>,
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
)
}

View File

@@ -153,7 +153,7 @@ fun AppCard(
if (!title.isNullOrBlank()) {
Text(
text = title,
style = MaterialTheme.typography.headlineMedium,
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface
)
}

View File

@@ -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<ApiProvider>, // Pass the list of providers
providers: List<ApiProvider>,
description: String,
onPromptChanged: (String) -> Unit,
onSaveClicked: () -> Unit,
onModelSelected: (LanguageModel?) -> Unit,
onExamplePromptClicked: (String) -> Unit
hints: Array<String>
) {
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(),
)
}

View File

@@ -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),
)
}
}

View File

@@ -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 {

View File

@@ -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),
)
}
}