Refactor hint management by replacing @Composable lambda hint content with a structured Hint type and updating UI components to support it.
This commit is contained in:
@@ -115,7 +115,7 @@ fun AppAlertDialog(
|
||||
title: @Composable (() -> Unit)? = null,
|
||||
text: @Composable (() -> Unit)? = null,
|
||||
properties: DialogProperties = DialogProperties(),
|
||||
hintContent: @Composable (() -> Unit)? = null,
|
||||
hintContent:Hint? = null,
|
||||
) {
|
||||
val sheetState = rememberModalBottomSheetState()
|
||||
var showBottomSheet by remember { mutableStateOf(false) }
|
||||
@@ -142,11 +142,13 @@ fun AppAlertDialog(
|
||||
)
|
||||
|
||||
if (showBottomSheet) {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = { showBottomSheet = false },
|
||||
sheetState = sheetState,
|
||||
content = hintContent
|
||||
)
|
||||
hintContent?.let {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = { showBottomSheet = false },
|
||||
sheetState = sheetState,
|
||||
content = it
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +214,7 @@ private fun DialogHeader(
|
||||
@Composable
|
||||
private fun DialogTitleWithHint(
|
||||
title: @Composable () -> Unit,
|
||||
hintContent: @Composable (() -> Unit)?,
|
||||
hintContent: Hint? = null,
|
||||
onHintClick: () -> Unit
|
||||
) {
|
||||
val showHints = LocalShowHints.current
|
||||
@@ -424,7 +426,6 @@ fun AppAlertDialogPreview() {
|
||||
},
|
||||
title = { Text("Alert Dialog Title") },
|
||||
text = { Text("This is the alert dialog text.") },
|
||||
hintContent = { Text("This is a hint for the alert dialog.") }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -492,7 +493,6 @@ fun AppAlertDialogLongTextPreview() {
|
||||
Text("Third paragraph with additional information that users need to be aware of.")
|
||||
}
|
||||
},
|
||||
hintContent = { Text("This hint explains the terms in more detail.") }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -115,16 +115,17 @@ fun AppTopAppBar(
|
||||
)
|
||||
|
||||
if (showBottomSheet) {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = {
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
showBottomSheet = false
|
||||
},
|
||||
sheetState = sheetState,
|
||||
content = {
|
||||
hintContent?.Render()
|
||||
}
|
||||
)
|
||||
hintContent?.let {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = {
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
showBottomSheet = false
|
||||
},
|
||||
sheetState = sheetState,
|
||||
content = it
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CheckboxDefaults
|
||||
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
|
||||
@@ -36,6 +37,7 @@ import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.SwitchDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -56,6 +58,9 @@ import eu.gaudian.translator.R
|
||||
import eu.gaudian.translator.ui.theme.ThemePreviews
|
||||
import eu.gaudian.translator.ui.theme.semanticColors
|
||||
import eu.gaudian.translator.view.composable.ComponentDefaults.DefaultElevation
|
||||
import eu.gaudian.translator.view.hints.Hint
|
||||
import eu.gaudian.translator.view.hints.HintBottomSheet
|
||||
import eu.gaudian.translator.view.hints.LocalShowHints
|
||||
|
||||
|
||||
object ComponentDefaults {
|
||||
@@ -97,14 +102,16 @@ object ComponentDefaults {
|
||||
fun AppCard(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String? = null,
|
||||
icon: ImageVector? = null, // New optional icon parameter
|
||||
icon: ImageVector? = null,
|
||||
text: String? = null,
|
||||
expandable: Boolean = false,
|
||||
initiallyExpanded: Boolean = false,
|
||||
onClick: (() -> Unit)? = null,
|
||||
hintContent : Hint? = null,
|
||||
content: @Composable ColumnScope.() -> Unit,
|
||||
) {
|
||||
var isExpanded by remember { mutableStateOf(initiallyExpanded) }
|
||||
val showHints = LocalShowHints.current
|
||||
|
||||
val rotationState by animateFloatAsState(
|
||||
targetValue = if (isExpanded) 180f else 0f,
|
||||
@@ -116,6 +123,20 @@ fun AppCard(
|
||||
val hasHeader = title != null || text != null || expandable || icon != null
|
||||
val canClickHeader = expandable || onClick != null
|
||||
|
||||
var showBottomSheet by remember { mutableStateOf(false) }
|
||||
|
||||
if (showBottomSheet) {
|
||||
hintContent?.let {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = { showBottomSheet = false },
|
||||
content = it,
|
||||
sheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Surface(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
@@ -146,6 +167,7 @@ fun AppCard(
|
||||
) {
|
||||
// 1. Optional Icon on the left
|
||||
if (icon != null) {
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
@@ -179,6 +201,16 @@ fun AppCard(
|
||||
}
|
||||
}
|
||||
|
||||
if (showHints && hintContent != null) {
|
||||
IconButton(onClick = { showBottomSheet = true }) {
|
||||
Icon(
|
||||
imageVector = AppIcons.Help,
|
||||
contentDescription = stringResource(R.string.show_hint),
|
||||
tint = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Expand Chevron (Far right)
|
||||
if (expandable) {
|
||||
Icon(
|
||||
@@ -189,6 +221,7 @@ fun AppCard(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --- Content Area ---
|
||||
|
||||
@@ -109,7 +109,7 @@ fun ImportDialogContent(
|
||||
AppDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(descriptionText) },
|
||||
hintContent = HintDefinition.IMPORT.hint(),
|
||||
hintContent = HintDefinition.VOCABULARY_GENERATE_AI.hint(),
|
||||
content = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -21,7 +21,7 @@ enum class HintDefinition(
|
||||
CATEGORY("category_hint", R.string.category_hint_intro),
|
||||
DICTIONARY_OPTIONS("dictionary_hint", R.string.label_dictionary_options),
|
||||
EXERCISE("exercise_hint", R.string.label_exercise),
|
||||
IMPORT("import_hint", R.string.hint_how_to_generate_vocabulary_with_ai),
|
||||
VOCABULARY_GENERATE_AI("import_hint", R.string.hint_how_to_generate_vocabulary_with_ai),
|
||||
LEARNING_STAGES("learning_stages_hint", R.string.learning_stages_title),
|
||||
REVIEW("review_hint", R.string.review_intro),
|
||||
SORTING("sorting_hint", R.string.sorting_hint_title),
|
||||
|
||||
@@ -32,7 +32,7 @@ import kotlinx.coroutines.launch
|
||||
fun HintBottomSheet(
|
||||
onDismissRequest: () -> Unit,
|
||||
sheetState: SheetState,
|
||||
content: @Composable (() -> Unit)?
|
||||
content: Hint,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
ModalBottomSheet(
|
||||
@@ -50,7 +50,7 @@ fun HintBottomSheet(
|
||||
.weight(1f, fill = false)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
content?.invoke()
|
||||
content.Render()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
@@ -16,7 +15,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.gaudian.translator.R
|
||||
import eu.gaudian.translator.view.composable.AppIcons
|
||||
@@ -39,8 +37,8 @@ val LocalShowHints = compositionLocalOf { false }
|
||||
*/
|
||||
@Composable
|
||||
fun WithHint(
|
||||
hintContent: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
hintContent: Hint? = null,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val showHints = LocalShowHints.current
|
||||
@@ -69,27 +67,16 @@ fun WithHint(
|
||||
}
|
||||
|
||||
if (showBottomSheet) {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = {
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
showBottomSheet = false
|
||||
},
|
||||
sheetState = sheetState,
|
||||
hintContent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun WithHintPreview() {
|
||||
androidx.compose.runtime.CompositionLocalProvider(LocalShowHints provides true) {
|
||||
WithHint(
|
||||
hintContent = {
|
||||
Text(stringResource(R.string.this_is_a_hint))
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.this_is_the_main_content))
|
||||
hintContent?.let {
|
||||
HintBottomSheet(
|
||||
onDismissRequest = {
|
||||
@Suppress("AssignedValueIsNeverRead")
|
||||
showBottomSheet = false
|
||||
},
|
||||
sheetState = sheetState,
|
||||
content = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ fun HintsOverviewScreen(
|
||||
val showExperimental = LocalShowExperimentalFeatures.current
|
||||
|
||||
// Get hints using the new function-based approach
|
||||
val importHint = HintDefinition.IMPORT.hint()
|
||||
val importHint = HintDefinition.VOCABULARY_GENERATE_AI.hint()
|
||||
val addModelScanHint = HintDefinition.ADD_MODEL_SCAN.hint()
|
||||
val dictionaryOptionsHint = HintDefinition.DICTIONARY_OPTIONS.hint()
|
||||
val translationScreenHint = HintDefinition.TRANSLATION.hint()
|
||||
|
||||
@@ -113,7 +113,7 @@ fun NavGraphBuilder.settingsGraph(navController: NavController) {
|
||||
HintScreen(navController, HintDefinition.DICTIONARY_OPTIONS)
|
||||
}
|
||||
composable(SettingsRoutes.HINTS_IMPORT) {
|
||||
HintScreen(navController, HintDefinition.IMPORT)
|
||||
HintScreen(navController, HintDefinition.VOCABULARY_GENERATE_AI)
|
||||
}
|
||||
composable(SettingsRoutes.HINTS_SORTING) {
|
||||
HintScreen(navController, HintDefinition.SORTING)
|
||||
|
||||
@@ -37,6 +37,7 @@ import eu.gaudian.translator.R
|
||||
import eu.gaudian.translator.view.composable.AppIcons
|
||||
import eu.gaudian.translator.view.composable.SourceLanguageDropdown
|
||||
import eu.gaudian.translator.view.composable.TargetLanguageDropdown
|
||||
import eu.gaudian.translator.view.hints.Hint
|
||||
import eu.gaudian.translator.view.hints.WithHint
|
||||
import eu.gaudian.translator.viewmodel.LanguageViewModel
|
||||
|
||||
@@ -71,7 +72,7 @@ fun TopBarActions(
|
||||
languageViewModel: LanguageViewModel,
|
||||
onSettingsClick: () -> Unit,
|
||||
onNavigateBack: (() -> Unit)? = null,
|
||||
hintContent: (@Composable () -> Unit)? = null
|
||||
hintContent: Hint? = null
|
||||
) {
|
||||
|
||||
ActionBar(modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp)) {
|
||||
|
||||
@@ -177,7 +177,7 @@ private fun LoadedTranslationContent(
|
||||
languageViewModel = languageViewModel,
|
||||
onSettingsClick = onSettingsClick,
|
||||
onNavigateBack = onNavigateBack,
|
||||
hintContent = { HintDefinition.TRANSLATION.Render() }
|
||||
hintContent = HintDefinition.TRANSLATION.hint()
|
||||
)
|
||||
|
||||
AppCard(modifier = Modifier.padding(8.dp, end = 8.dp, bottom = 8.dp, top = 0.dp)) {
|
||||
|
||||
@@ -70,6 +70,7 @@ import eu.gaudian.translator.view.composable.AppTopAppBar
|
||||
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.HintDefinition
|
||||
import eu.gaudian.translator.view.library.VocabularyCard
|
||||
import eu.gaudian.translator.viewmodel.LanguageViewModel
|
||||
import eu.gaudian.translator.viewmodel.VocabularyViewModel
|
||||
@@ -445,26 +446,17 @@ fun AIGeneratorCard(
|
||||
onGenerate: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
|
||||
val icon = Icons.Default.AutoAwesome
|
||||
val hints = stringArrayResource(R.array.vocabulary_hints)
|
||||
AppCard(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
title = "AI Generator",
|
||||
icon = icon,
|
||||
hintContent = HintDefinition.VOCABULARY_GENERATE_AI.hint(),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(24.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.AutoAwesome,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = "AI Generator",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
Column(modifier = Modifier.padding(8.dp)) {
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.text_search_term),
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
|
||||
Reference in New Issue
Block a user