Refactor the hint system by consolidating hint definitions into a central HintDefinition enum and migrating individual hint files to a markdown-based approach.

This commit is contained in:
jonasgaudian
2026-02-15 21:46:11 +01:00
parent 7d18f8eb04
commit 8e610259ca
31 changed files with 117 additions and 1098 deletions

View File

@@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-02-15T17:06:55.070074900Z"> <DropdownSelection timestamp="2026-02-15T19:51:37.987601800Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\jonas\.android\avd\Pixel_Tablet.avd" /> <DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\jonas\.android\avd\Medium_Phone_28.avd" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@@ -1,87 +0,0 @@
# How to Scan for AI Models
# TODO REWRITE
This guide explains how to use the **Scan** feature to discover and add AI models to your app.
## How Scanning Works
The scan feature searches for available AI models on your device or network.
> **Note:** Results depend on your API key permissions.
### Key Points
- Only public models are shown by default
- Private models require additional setup
- Try again if no models are found
## Why Some Models Are Missing
Some models may not appear in the scan results due to:
| Reason | Description | Icon |
|--------|-------------|------|
| Restricted access | Model requires special permissions | 🔒 |
| Not suitable | Model type not supported | ⚠️ |
| Text only | Only text-based models are supported | ✓ |
### Model Tiers
We recommend these tiers for optimal performance:
- **Nano** - Fastest, for simple tasks
- **Mini** - Balanced speed and capability
- **Small** - Good for most tasks
- **Medium** - More capable, slower
- **Large** - Most capable, paid only
## Tips for Success
1. **Verify your API key** is active and has correct permissions
2. **Select the correct organization** from your account
3. **Type model names manually** if scanning doesn't find them
4. **Prefer instruct or chat models** for text generation
```kotlin
// Example: Manual model addition
val model = Model(
name = "llama3.2",
type = ModelType.TEXT,
provider = "ollama"
)
```
## Visual Guide
### Step 1: Initiate Scan
Click the scan button to search for available models.
### Step 2: Select Model Type
Choose between different model categories:
- **Text Chat** - For conversational AI
- **Instruct** - For direct instructions
- **Complete** - For text completion
### Step 3: Add & Validate
Add the selected model and validate it works correctly.
---
## Can't Find Your Model?
If your model doesn't appear in the scan results:
1. Check if the model is running locally or accessible via API
2. Verify network connectivity
3. Try adding it manually by entering the model details
> **Pro Tip:** You can always add models manually by clicking the "+" button in the models screen.
---
*Last updated: 2024-01-15*
*For more help, visit our documentation website.*

View File

@@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import eu.gaudian.translator.R import eu.gaudian.translator.R
import eu.gaudian.translator.view.hints.Hint
import eu.gaudian.translator.view.hints.HintBottomSheet import eu.gaudian.translator.view.hints.HintBottomSheet
import eu.gaudian.translator.view.hints.LocalShowHints import eu.gaudian.translator.view.hints.LocalShowHints
@@ -48,7 +49,7 @@ import eu.gaudian.translator.view.hints.LocalShowHints
fun AppDialog( fun AppDialog(
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
title: (@Composable () -> Unit)? = null, title: (@Composable () -> Unit)? = null,
hintContent: @Composable (() -> Unit)? = null, hintContent: Hint? = null,
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
// 1. Swipe Resistance: Prevent accidental dismissal // 1. Swipe Resistance: Prevent accidental dismissal
@@ -98,7 +99,7 @@ fun AppDialog(
if (showBottomSheet) { if (showBottomSheet) {
EnhancedHintBottomSheet( EnhancedHintBottomSheet(
onDismissRequest = { showBottomSheet = false }, onDismissRequest = { showBottomSheet = false },
content = hintContent, content = {hintContent?.Render()},
parentTitle = title parentTitle = title
) )
} }
@@ -156,7 +157,7 @@ fun AppAlertDialog(
@Composable @Composable
private fun DialogHeader( private fun DialogHeader(
title: (@Composable () -> Unit)?, title: (@Composable () -> Unit)?,
hintContent: @Composable (() -> Unit)?, hintContent: Hint? = null,
onHintClick: () -> Unit, onHintClick: () -> Unit,
onCloseClick: () -> Unit onCloseClick: () -> Unit
) { ) {
@@ -327,7 +328,6 @@ fun AppDialogPreview() {
AppDialog( AppDialog(
onDismissRequest = {}, onDismissRequest = {},
title = { Text("Dialog Title") }, title = { Text("Dialog Title") },
hintContent = { Text("This is a hint.") },
content = { content = {
Column { Column {
Text("Content line 1") Text("Content line 1")
@@ -378,7 +378,6 @@ fun AppDialogLongContentPreview() {
AppDialog( AppDialog(
onDismissRequest = {}, onDismissRequest = {},
title = { Text("Long Content Dialog") }, title = { Text("Long Content Dialog") },
hintContent = { Text("Hint for long content dialog") },
content = { content = {
Column { Column {
Text("This is a long content dialog to test scrolling") Text("This is a long content dialog to test scrolling")

View File

@@ -48,7 +48,7 @@ import eu.gaudian.translator.view.composable.AppDialog
import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppIcons
import eu.gaudian.translator.view.composable.AppOutlinedTextField import eu.gaudian.translator.view.composable.AppOutlinedTextField
import eu.gaudian.translator.view.composable.MultipleLanguageDropdown import eu.gaudian.translator.view.composable.MultipleLanguageDropdown
import eu.gaudian.translator.view.hints.CategoryHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.viewmodel.CategoryViewModel import eu.gaudian.translator.viewmodel.CategoryViewModel
import eu.gaudian.translator.viewmodel.LanguageViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel
@@ -80,7 +80,7 @@ fun AddCategoryDialog(
AppDialog( AppDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.label_add_category)) }, title = { Text(stringResource(R.string.label_add_category)) },
hintContent = { CategoryHint() }, hintContent = HintDefinition.CATEGORY.hint(),
content = { content = {
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {

View File

@@ -44,7 +44,7 @@ import eu.gaudian.translator.view.composable.DialogButton
import eu.gaudian.translator.view.composable.InspiringSearchField import eu.gaudian.translator.view.composable.InspiringSearchField
import eu.gaudian.translator.view.composable.SourceLanguageDropdown 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.ImportVocabularyHint import eu.gaudian.translator.view.hints.HintDefinition
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
@@ -109,7 +109,7 @@ fun ImportDialogContent(
AppDialog( AppDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
title = { Text(descriptionText) }, title = { Text(descriptionText) },
hintContent = { ImportVocabularyHint() }, hintContent = HintDefinition.IMPORT.hint(),
content = { content = {
Column( Column(
modifier = Modifier modifier = Modifier

View File

@@ -34,7 +34,7 @@ import eu.gaudian.translator.view.composable.AppButton
import eu.gaudian.translator.view.composable.AppCheckbox import eu.gaudian.translator.view.composable.AppCheckbox
import eu.gaudian.translator.view.composable.AppScaffold import eu.gaudian.translator.view.composable.AppScaffold
import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.AppTopAppBar
import eu.gaudian.translator.view.hints.getVocabularyReviewHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.viewmodel.CategoryViewModel import eu.gaudian.translator.viewmodel.CategoryViewModel
import eu.gaudian.translator.viewmodel.VocabularyViewModel import eu.gaudian.translator.viewmodel.VocabularyViewModel
@@ -66,7 +66,7 @@ fun VocabularyReviewScreen(
topBar = { topBar = {
AppTopAppBar( AppTopAppBar(
title = { Text(stringResource(R.string.found_items)) }, title = { Text(stringResource(R.string.found_items)) },
hintContent = getVocabularyReviewHint() hintContent = HintDefinition.REVIEW.hint()
) )
}, },
) { paddingValues -> ) { paddingValues ->

View File

@@ -1,30 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated AddModelScanHint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getAddModelScanHint(): Hint {
return Hint(
titleRes = R.string.hint_scan_hint_title,
elements = listOf(
HintElement.LocalizedMarkdown("example_hint")
)
)
}
@Preview
@Composable
fun AddModelScanHintPreview() {
getAddModelScanHint().Render()
}
@Composable
fun AddModelScanHint() {
getAddModelScanHint().Render()
}

View File

@@ -0,0 +1,55 @@
@file:Suppress("HardCodedStringLiteral")
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import eu.gaudian.translator.R
/**
* Hint metadata mapping Markdown filenames to their string resource titles.
* All hint-related operations are available as functions on each enum entry.
*/
@Suppress("HardCodedStringLiteral")
enum class HintDefinition(
val markdownFile: String,
val titleRes: Int
) {
ADD_MODEL_SCAN("find_ai_model", R.string.hint_scan_hint_title),
API_KEY("api_key_hint", R.string.hint_how_to_connect_to_an_ai),
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),
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),
TRANSLATION("translation_hint", R.string.hint_translate_how_it_works),
VOCABULARY_PROGRESS("vocabulary_progress_hint", R.string.hint_vocabulary_progress_hint_title);
/** Creates the Hint data class for this hint definition. */
@Composable
fun hint() = Hint(titleRes = titleRes, elements = listOf(HintElement.LocalizedMarkdown(markdownFile)))
/** Renders this hint's content. */
@Composable
fun Render() = hint().Render()
}
@Composable
fun hint(definition: HintDefinition): Hint = definition.hint()
@Composable fun HintContent(definition: HintDefinition) = definition.Render()
@Composable fun HintScreen(navController: NavController, definition: HintDefinition) = HintScreen(
navController = navController,
title = stringResource(definition.titleRes),
content = { definition.Render() }
)

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated API Key hint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getApiKeyHint() = Hint (
titleRes = R.string.hint_how_to_connect_to_an_ai,
elements = listOf(
HintElement.LocalizedMarkdown("api_key_hint")
)
)
@Composable
fun ApiKeyHint() {
getApiKeyHint().Render()
}
@Preview
@Composable
fun ApiKeyHintPreview() {
MaterialTheme {
ApiKeyHint()
}
}

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated Category hint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getCategoryHint(): Hint {
return Hint(
titleRes = R.string.category_hint_intro,
elements = listOf(
HintElement.LocalizedMarkdown("category_hint")
)
)
}
@Composable
fun CategoryHint() {
getCategoryHint().Render()
}
@Preview
@Composable
fun CategoryHintPreview() {
MaterialTheme {
CategoryHint()
}
}

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated Category Hint Screen using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getCategoryHintScreen(): Hint {
return Hint(
titleRes = R.string.category_hint_intro,
elements = listOf(
HintElement.LocalizedMarkdown("category_hint")
)
)
}
@Composable
fun CategoryHintScreen() {
getCategoryHintScreen().Render()
}
@Preview
@Composable
fun CategoryHintScreenPreview() {
MaterialTheme {
CategoryHintScreen()
}
}

View File

@@ -1,25 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated DictionaryOptionsHint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getDictionaryOptionsHint(): Hint {
return Hint(
titleRes = R.string.label_dictionary_options,
elements = listOf(
HintElement.LocalizedMarkdown("dictionary_hint")
)
)
}
@Preview
@Composable
fun DictionaryOptionsHint() {
getDictionaryOptionsHint().Render()
}

View File

@@ -1,145 +0,0 @@
package eu.gaudian.translator.view.hints
import android.content.Context
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Example of a migrated hint using the new markdown-based approach.
*
* This demonstrates how to migrate from the old LegacyHint format to the new
* markdown-based format.
*
* Benefits:
* - Easier to manage and translate (no code changes needed)
* - Better separation of concerns
* - Consistent styling across all hints
* - Support for rich formatting (tables, code blocks, etc.)
*/
/**
* Example 1: Loading markdown content from string (simple).
*/
@Composable
fun getApiKeyMarkdownHint(): String {
return """
# How to Connect to an AI Model
This guide explains how to connect your app to an AI model using an API key.
## Getting Started
To use AI models in your app, you need to provide a valid API key.
> **Note:** Keep your API key secure and never share it publicly.
## Key Status Indicators
| Status | Icon | Meaning |
|--------|------|---------|
| Active | ✅ | Key is valid and working |
| Missing | ⚠️ | Key is not set |
## Troubleshooting
1. Verify the key is correct
2. Ensure proper permissions
3. Check your quota
```json
{
"api_key": "sk-xxxxxxxxxxxx"
}
```
""".trimIndent()
}
@Composable
fun ApiKeyMarkdownHint() {
val content = getApiKeyMarkdownHint()
MarkdownHint(
markdownContent = content,
title = stringResource(R.string.hint_how_to_connect_to_an_ai)
)
}
/**
* Example 2: Loading markdown from assets file (recommended for production).
*/
@Composable
fun loadMarkdownFromAssets(fileName: String): String {
val context = LocalContext.current
return try {
context.assets.open("hints/$fileName").bufferedReader().use { it.readText() }
} catch (e: Exception) {
"Error loading markdown file: ${e.message}"
}
}
/**
* Data class for programmatic hint loading.
*/
data class MarkdownHintDefinition(
val fileName: String,
val titleRes: Int
) {
fun loadContent(context: Context): String {
return context.assets.open("hints/$fileName").bufferedReader().use { it.readText() }
}
}
/**
* Pre-defined hints ready for migration.
*/
object MarkdownHints {
val API_KEY = MarkdownHintDefinition(
fileName = "api_key_hint.md",
titleRes = R.string.hint_how_to_connect_to_an_ai
)
val CATEGORY = MarkdownHintDefinition(
fileName = "category_hint.md",
titleRes = R.string.category_hint_intro
)
val LEARNING_STAGES = MarkdownHintDefinition(
fileName = "learning_stages_hint.md",
titleRes = R.string.learning_stages_title
)
val SORTING = MarkdownHintDefinition(
fileName = "sorting_hint.md",
titleRes = R.string.sorting_hint_title
)
val VOCABULARY_PROGRESS = MarkdownHintDefinition(
fileName = "vocabulary_progress_hint.md",
titleRes = R.string.hint_vocabulary_progress_hint_title
)
}
/**
* Preview for the migrated API Key hint.
*/
@Preview
@Composable
fun ApiKeyMarkdownHintPreview() {
MaterialTheme {
ApiKeyMarkdownHint()
}
}
/**
* Preview for loading from assets.
*/
@Preview
@Composable
fun LoadFromAssetsPreview() {
MaterialTheme {
val content = loadMarkdownFromAssets("example_hint.md")
MarkdownHint(
markdownContent = content,
title = stringResource(R.string.hint_title_hints_overview)
)
}
}

View File

@@ -1,7 +0,0 @@
package eu.gaudian.translator.view.hints
/**
* This file is kept for reference only.
* All hints are now migrated to markdown-based format.
* See individual hint files for implementations.
*/

View File

@@ -1,3 +1,5 @@
@file:Suppress("HardCodedStringLiteral")
package eu.gaudian.translator.view.hints package eu.gaudian.translator.view.hints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -9,9 +11,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.jeziellago.compose.markdowntext.MarkdownText import dev.jeziellago.compose.markdowntext.MarkdownText
import eu.gaudian.translator.utils.Log
private const val TAG = "MarkdownHint" private const val TAG = "MarkdownHint"
@@ -25,7 +27,7 @@ sealed class HintElement {
data class UIElement(val composable: @Composable () -> Unit) : HintElement() data class UIElement(val composable: @Composable () -> Unit) : HintElement()
/** /**
* A localized markdown file element. * A localized Markdown file element.
* The file is loaded from assets based on the current device locale. * The file is loaded from assets based on the current device locale.
* Follows Android's locale-qualified resource pattern: * Follows Android's locale-qualified resource pattern:
* - assets/hints/ - Default (English) * - assets/hints/ - Default (English)
@@ -56,7 +58,7 @@ fun RenderHintElement(element: HintElement) {
androidx.compose.foundation.layout.Row( androidx.compose.foundation.layout.Row(
modifier = Modifier.padding(top = 4.dp) modifier = Modifier.padding(top = 4.dp)
) { ) {
androidx.compose.material3.Text( Text(
text = "[DEBUG: ${element.fileName}]", text = "[DEBUG: ${element.fileName}]",
style = MaterialTheme.typography.labelSmall, style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error color = MaterialTheme.colorScheme.error
@@ -68,7 +70,7 @@ fun RenderHintElement(element: HintElement) {
} }
/** /**
* Composable to render localized markdown content. * Composable to render localized Markdown content.
* Automatically loads the correct locale version based on device settings. * Automatically loads the correct locale version based on device settings.
* Falls back to English default if localized version is not available. * Falls back to English default if localized version is not available.
*/ */
@@ -85,23 +87,23 @@ fun LocalizedMarkdownContent(
// Try localized version (folder has suffix, filename doesn't) // Try localized version (folder has suffix, filename doesn't)
val localizedPath = "hints$suffix/$fileName.md" val localizedPath = "hints$suffix/$fileName.md"
android.util.Log.d(TAG, "Loading hint: $fileName") Log.d(TAG, "Loading hint: $fileName")
android.util.Log.d(TAG, "Device locale: ${locale.language}_${locale.country}") Log.d(TAG, "Device locale: ${locale.language}_${locale.country}")
android.util.Log.d(TAG, "Localized path: $localizedPath") Log.d(TAG, "Localized path: $localizedPath")
val localized = MarkdownHintLoader.loadFromAssets(context, localizedPath) val localized = MarkdownHintLoader.loadFromAssets(context, localizedPath)
if (localized != null) { if (localized != null) {
android.util.Log.d(TAG, "Found localized version at: $localizedPath") Log.d(TAG, "Found localized version at: $localizedPath")
localized localized
} else { } else {
// Fall back to English default in hints folder // Fall back to English default in hints folder
val defaultPath = "hints/$fileName.md" val defaultPath = "hints/$fileName.md"
android.util.Log.d(TAG, "Localized not found, trying default: $defaultPath") Log.d(TAG, "Localized not found, trying default: $defaultPath")
val default = MarkdownHintLoader.loadFromAssets(context, defaultPath) val default = MarkdownHintLoader.loadFromAssets(context, defaultPath)
if (default != null) { if (default != null) {
android.util.Log.d(TAG, "Found default version at: $defaultPath") Log.d(TAG, "Found default version at: $defaultPath")
} else { } else {
android.util.Log.e(TAG, "No hint found for: $fileName (tried: $localizedPath, $defaultPath)") Log.e(TAG, "No hint found for: $fileName (tried: $localizedPath, $defaultPath)")
} }
default default
} }
@@ -125,22 +127,3 @@ fun LocalizedMarkdownContent(
} }
@Suppress("HardCodedStringLiteral")
@Preview
@Composable
fun UIElementPreview() {
RenderHintElement(
HintElement.UIElement {
Text("Custom UI Element")
}
)
}
@Suppress("HardCodedStringLiteral")
@Preview
@Composable
fun LocalizedMarkdownElementPreview() {
RenderHintElement(
HintElement.LocalizedMarkdown("example_hint")
)
}

View File

@@ -1,123 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import eu.gaudian.translator.R
/**
* Wrapper for Category Hint Screen
*/
@Composable
fun CategoryHintScreenWrapper(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.category_hint_intro)
) {
CategoryHint()
}
}
/**
* Dictionary Hint Screen
*/
@Composable
fun DictionaryHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.label_dictionary_options)
) {
getDictionaryOptionsHint().Render()
}
}
/**
* Import Hint Screen
*/
@Composable
fun ImportHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.hint_how_to_generate_vocabulary_with_ai)
) {
getImportVocabularyHint()
}
}
/**
* Sorting Hint Screen
*/
@Composable
fun SortingHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.sorting_hint_title)
) {
SortingScreenHint()
}
}
/**
* Stages Hint Screen
*/
@Composable
fun StagesHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.learning_stages_title)
) {
LearningStagesHint()
}
}
/**
* Translation Hint Screen
*/
@Composable
fun TranslationHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.hint_translate_how_it_works)
) {
getTranslationScreenHint().Render()
}
}
/**
* Scan Hint Screen
*/
@Composable
fun ScanHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.hint_scan_hint_title)
) {
AddModelScanHint()
}
}
/**
* API Hint Screen
*/
@Composable
fun ApiHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.hint_how_to_connect_to_an_ai)
) {
ApiKeyHint()
}
}
/**
* Vocabulary Progress Hint Screen
*/
@Composable
fun VocabularyProgressHintScreen(navController: NavController) {
HintScreen(
navController = navController,
title = stringResource(R.string.hint_vocabulary_progress_hint_title)
) {
VocabularyProgressHint()
}
}

View File

@@ -18,9 +18,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
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.view.LocalShowExperimentalFeatures import eu.gaudian.translator.view.LocalShowExperimentalFeatures
import eu.gaudian.translator.view.composable.AppCard import eu.gaudian.translator.view.composable.AppCard
import eu.gaudian.translator.view.composable.AppIcons import eu.gaudian.translator.view.composable.AppIcons
@@ -42,15 +40,16 @@ fun HintsOverviewScreen(
val showExperimental = LocalShowExperimentalFeatures.current val showExperimental = LocalShowExperimentalFeatures.current
// Get hints using the new function-based approach // Get hints using the new function-based approach
val importHint = getImportVocabularyHint() val importHint = HintDefinition.IMPORT.hint()
val addModelScanHint = getAddModelScanHint() val addModelScanHint = HintDefinition.ADD_MODEL_SCAN.hint()
val dictionaryOptionsHint = getDictionaryOptionsHint() val dictionaryOptionsHint = HintDefinition.DICTIONARY_OPTIONS.hint()
val translationScreenHint = getTranslationScreenHint() val translationScreenHint = HintDefinition.TRANSLATION.hint()
val categoryHint = getCategoryHint() val categoryHint = HintDefinition.CATEGORY.hint()
val learningStagesHint = getLearningStagesHint() val learningStagesHint = HintDefinition.LEARNING_STAGES.hint()
val sortingScreenHint = getSortingScreenHint() val sortingScreenHint = HintDefinition.SORTING.hint()
val vocabularyProgressHint = getVocabularyProgressHint() val vocabularyProgressHint = HintDefinition.VOCABULARY_PROGRESS.hint()
val apiKeyHint = getApiKeyHint() val apiKeyHint = HintDefinition.API_KEY.hint()
val hintGroups = remember(showExperimental, importHint, addModelScanHint, dictionaryOptionsHint, translationScreenHint) { val hintGroups = remember(showExperimental, importHint, addModelScanHint, dictionaryOptionsHint, translationScreenHint) {
val allGroups = listOf( val allGroups = listOf(
@@ -133,11 +132,7 @@ fun HintsOverviewScreen(
} }
} }
@ThemePreviews
@Composable
fun HintsOverviewScreenPreview() {
HintsOverviewScreen(navController = rememberNavController())
}
@Composable @Composable
private fun HintHeader( private fun HintHeader(
@@ -176,12 +171,4 @@ private fun HintListItem(
) )
} }
@ThemePreviews
@Composable
fun HintListItemPreview() {
HintListItem(
title = stringResource(R.string.category_hint_intro),
icon = AppIcons.Category,
onClick = {}
)
}

View File

@@ -1,45 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated ImportVocabularyHint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getImportVocabularyHint(): Hint {
return Hint(
titleRes = R.string.hint_how_to_generate_vocabulary_with_ai,
elements = listOf(
HintElement.LocalizedMarkdown("import_hint")
)
)
}
@Preview
@Composable
fun ImportVocabularyHint() {
getImportVocabularyHint().Render()
}
/**
* Migrated VocabularyReviewHint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getVocabularyReviewHint(): Hint {
return Hint(
titleRes = R.string.review_intro,
elements = listOf(
HintElement.LocalizedMarkdown("review_hint")
)
)
}
@Composable
fun VocabularyReviewHint() {
getVocabularyReviewHint()
}

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated Learning Stages hint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getLearningStagesHint(): Hint {
return Hint(
titleRes = R.string.learning_stages_title,
elements = listOf(
HintElement.LocalizedMarkdown("learning_stages_hint")
)
)
}
@Composable
fun LearningStagesHint() {
getLearningStagesHint().Render()
}
@Preview
@Composable
fun LearningStagesHintPreview() {
MaterialTheme {
LearningStagesHint()
}
}

View File

@@ -1,147 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.foundation.layout.Column
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.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
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 dev.jeziellago.compose.markdowntext.MarkdownText
import eu.gaudian.translator.R
/**
* Markdown-styled hint content using the jeziellago compose-markdown library.
* This provides beautiful, consistent rendering of markdown content with
* support for headings, lists, tables, code blocks, and more.
*
* Usage:
* - Create a .md file in assets/hints/ (e.g., "api_key_hint.md")
* - Load it using context.assets.open() or pass raw markdown string
* - Use MarkdownHint composable for styled rendering
*
* Supported markdown:
* - Headings (# ## ###)
* - Bold (**text**) and italic (*text*)
* - Lists (- item, 1. item)
* - Tables (| col | col |)
* - Code blocks (```code```)
* - Blockquotes (> quote)
* - Links ([text](url))
*/
@Composable
fun MarkdownHint(
markdownContent: String,
modifier: Modifier = Modifier,
title: String? = null
) {
val scrollState = rememberScrollState()
Column(
modifier = modifier
.fillMaxWidth()
.verticalScroll(scrollState)
.padding(16.dp)
) {
// Optional title with icon header
title?.let {
HeaderWithIcon(
title = it,
subtitle = null
)
Spacer(modifier = Modifier.height(16.dp))
}
// Render markdown
MarkdownText(
markdown = markdownContent,
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.bodyMedium.copy(
color = MaterialTheme.colorScheme.onSurface
)
)
}
}
/**
* Preview for MarkdownHint with sample content.
*/
@Preview
@Composable
fun MarkdownHintPreview() {
val sampleMarkdown = """
# Welcome to the Hint System
This is a **markdown-based** hint that provides _beautiful_ and consistent styling.
## Features
- **Rich text formatting** - bold, italic, strikethrough
- **Headings** - H1 through H6 levels
- **Lists** - ordered and unordered
- **Code blocks** - with syntax highlighting
- **Tables** - for structured data
- **Links** - styled clickable references
- **Blockquotes** - for highlighted content
## How to Use
1. Create a `.md` file in `assets/hints/`
2. Load it using `context.assets.open("hints/your_hint.md")`
3. Pass the content to `MarkdownHint()`
> **Tip:** You can also embed UI elements by combining markdown with HintElements!
## Code Example
```kotlin
val markdown = loadMarkdownFromAssets("hints/scan_hint.md")
MarkdownHint(
markdownContent = markdown,
title = "Scan Hint"
)
```
## Table Example
| Feature | Status | Priority |
|---------|--------|----------|
| Headings | ✅ | High |
| Lists | ✅ | High |
| Tables | ✅ | Medium |
---
*Last updated: 2024-01-15*
""".trimIndent()
MaterialTheme {
MarkdownHint(
markdownContent = sampleMarkdown,
title = stringResource(R.string.hint_title_hints_overview)
)
}
}
/**
* Data class for loading markdown content from assets.
*/
data class MarkdownHintData(
val fileName: String,
val titleRes: Int
) {
/**
* Load and return the markdown content as a string.
*/
fun loadContent(androidContext: android.content.Context): String {
return androidContext.assets.open("hints/$fileName")
.bufferedReader()
.use { it.readText() }
}
}

View File

@@ -4,7 +4,7 @@ import android.content.Context
import java.util.Locale import java.util.Locale
/** /**
* Internationalization system for markdown hints. * Internationalization system for Markdown hints.
* *
* This follows Android's locale-qualified resource pattern: * This follows Android's locale-qualified resource pattern:
* - assets/hints/ - Default (English) * - assets/hints/ - Default (English)
@@ -18,131 +18,22 @@ import java.util.Locale
*/ */
object MarkdownHintLoader { object MarkdownHintLoader {
/**
* Load markdown content with automatic locale detection.
*
* @param context The context for accessing assets
* @param hintFileName The base filename without locale suffix (e.g., "api_key_hint")
* @return The markdown content as a string, or null if not found
*/
fun loadHint(context: Context, hintFileName: String): String? {
val locale = getCurrentLocale(context)
val suffix = getLocaleSuffix(locale)
// Try localized version (folder has suffix, filename doesn't)
val localizedPath = "hints$suffix/$hintFileName.md"
val localizedContent = loadFromAssets(context, localizedPath)
if (localizedContent != null) {
return localizedContent
}
// Try with just language code (e.g., hints-pt/ instead of hints-pt-rBR/)
val languageSuffix = if (locale.country.isNotEmpty()) "-${locale.language}" else ""
val languageOnlyPath = "hints$languageSuffix/$hintFileName.md"
val languageContent = loadFromAssets(context, languageOnlyPath)
if (languageContent != null) {
return languageContent
}
// Fall back to default (English) in hints folder
val defaultPath = "hints/$hintFileName.md"
val defaultContent = loadFromAssets(context, defaultPath)
if (defaultContent != null) {
return defaultContent
}
return null
}
/**
* Get the localized file path for a hint.
*
* @param hintFileName The base filename (e.g., "api_key_hint")
* @return The full path including locale folder (e.g., "hints-de-rDE/api_key_hint.md")
*/
fun getHintPath(hintFileName: String): String {
val locale = Locale.getDefault()
val localeSuffix = getLocaleSuffix(locale)
return "hints$localeSuffix/$hintFileName.md"
}
/**
* Get the localized file name for a hint.
*
* @param hintFileName The base filename (e.g., "api_key_hint")
* @param locale The target locale
* @return The file name with locale suffix (e.g., "api_key_hint-de-rDE.md")
*/
fun getLocalizedFileName(hintFileName: String, locale: Locale): String {
val localeSuffix = getLocaleSuffix(locale)
return "$hintFileName$localeSuffix.md"
}
/**
* Get the file name with language-only suffix.
*
* @param hintFileName The base filename
* @param locale The target locale
* @return The file name with language suffix (e.g., "api_key_hint-de.md")
*/
private fun getLanguageOnlyFileName(hintFileName: String, locale: Locale): String {
val languageCode = locale.language
return "$hintFileName-$languageCode.md"
}
fun getCurrentLocale(context: Context): Locale { fun getCurrentLocale(context: Context): Locale {
return context.resources.configuration.locale return context.resources.configuration.locale
} }
/**
* Get all supported locales for hints.
*/
fun getSupportedLocales(): List<Locale> {
return listOf(
Locale.ENGLISH, // Default
Locale.GERMAN, // de-rDE
Locale("pt", "BR"), // pt-rBR
Locale.FRENCH, // fr-rFR
Locale("es", "ES"), // es-rES
Locale.ITALIAN, // it-rIT
Locale("nl", "NL"), // nl-rNL
Locale("hr", "HR") // hr-rHR
)
}
/**
* Check if a localized version exists for the given locale.
*/
fun localizedVersionExists(context: Context, hintFileName: String, locale: Locale): Boolean {
val localizedFileName = getLocalizedFileName(hintFileName, locale)
val suffix = getLocaleSuffix(locale)
return assetExists(context, "hints$suffix/$localizedFileName")
}
/** /**
* Load content from assets. * Load content from assets.
*/ */
fun loadFromAssets(context: Context, fileName: String): String? { fun loadFromAssets(context: Context, fileName: String): String? {
return try { return try {
context.assets.open(fileName).bufferedReader().use { it.readText() } context.assets.open(fileName).bufferedReader().use { it.readText() }
} catch (e: Exception) { } catch (_: Exception) {
null null
} }
} }
/**
* Check if an asset file exists.
*/
private fun assetExists(context: Context, path: String): Boolean {
return try {
context.assets.open(path).close()
true
} catch (e: Exception) {
false
}
}
/** /**
* Get the locale suffix string. * Get the locale suffix string.
*/ */
@@ -163,55 +54,3 @@ object MarkdownHintLoader {
} }
} }
/**
* Extension function to get localized hint content.
*/
fun Context.loadLocalizedHint(hintFileName: String): String? {
return MarkdownHintLoader.loadHint(this, hintFileName)
}
/**
* Data class for localized hint information.
*/
data class LocalizedHint(
val fileName: String,
val locale: Locale,
val isDefault: Boolean = false
)
/**
* Hint localization manager that tracks available translations.
*/
object HintLocalizationManager {
/**
* Get all available translations for a hint.
*/
fun getAvailableTranslations(context: Context, baseFileName: String): List<LocalizedHint> {
val available = mutableListOf<LocalizedHint>()
val defaultLocale = MarkdownHintLoader.getCurrentLocale(context)
// Check each supported locale
MarkdownHintLoader.getSupportedLocales().forEach { locale ->
val fileName = MarkdownHintLoader.getLocalizedFileName(baseFileName, locale)
val path = "hints${MarkdownHintLoader.getLocaleSuffix(locale)}/$fileName"
if (MarkdownHintLoader.loadFromAssets(context, path) != null) {
available.add(LocalizedHint(
fileName = fileName,
locale = locale,
isDefault = locale.language == "en" && locale.country.isEmpty()
))
}
}
return available.sortedBy { it.locale.language }
}
/**
* Get the best available translation for current locale.
*/
fun getBestTranslation(context: Context, baseFileName: String): String? {
return MarkdownHintLoader.loadHint(context, baseFileName)
}
}

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated Sorting Screen hint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getSortingScreenHint(): Hint {
return Hint(
titleRes = R.string.sorting_hint_title,
elements = listOf(
HintElement.LocalizedMarkdown("sorting_hint")
)
)
}
@Composable
fun SortingScreenHint() {
getSortingScreenHint()
}
@Preview
@Composable
fun SortingScreenHintPreview() {
MaterialTheme {
SortingScreenHint()
}
}

View File

@@ -1,28 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated TranslationScreenHint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getTranslationScreenHint() = Hint(
titleRes = R.string.hint_translate_how_it_works,
elements = listOf(
HintElement.LocalizedMarkdown("translation_hint")
)
)
@Composable
fun TranslationScreenHint() {
getTranslationScreenHint().Render()
}
@Preview
@Composable
fun TranslationScreenHintPreview() {
getTranslationScreenHint().Render()
}

View File

@@ -1,33 +0,0 @@
package eu.gaudian.translator.view.hints
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import eu.gaudian.translator.R
/**
* Migrated Vocabulary Progress hint using markdown-based format.
* Content is loaded from localized assets/hints based on device locale.
*/
@Composable
fun getVocabularyProgressHint(): Hint {
return Hint(
titleRes = R.string.hint_vocabulary_progress_hint_title,
elements = listOf(
HintElement.LocalizedMarkdown("vocabulary_progress_hint")
)
)
}
@Composable
fun VocabularyProgressHint() {
getVocabularyProgressHint().Render()
}
@Preview
@Composable
fun VocabularyProgressHintPreview() {
MaterialTheme {
VocabularyProgressHint()
}
}

View File

@@ -58,8 +58,7 @@ import eu.gaudian.translator.view.composable.AppScaffold
import eu.gaudian.translator.view.composable.AppSwitch import eu.gaudian.translator.view.composable.AppSwitch
import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.AppTopAppBar
import eu.gaudian.translator.view.composable.ModelBadges import eu.gaudian.translator.view.composable.ModelBadges
import eu.gaudian.translator.view.hints.AddModelScanHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.hints.getAddModelScanHint
import eu.gaudian.translator.viewmodel.ApiViewModel import eu.gaudian.translator.viewmodel.ApiViewModel
@Composable @Composable
@@ -141,7 +140,7 @@ fun AddModelScreen(navController: NavController, providerKey: String) {
Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back)) Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back))
} }
}, },
hintContent = getAddModelScanHint() hintContent = HintDefinition.ADD_MODEL_SCAN.hint()
) )
}, },
) { paddingValues -> ) { paddingValues ->

View File

@@ -80,7 +80,7 @@ import eu.gaudian.translator.view.composable.ClickableText
import eu.gaudian.translator.view.composable.PrimaryButton import eu.gaudian.translator.view.composable.PrimaryButton
import eu.gaudian.translator.view.composable.SecondaryButton import eu.gaudian.translator.view.composable.SecondaryButton
import eu.gaudian.translator.view.composable.TabItem import eu.gaudian.translator.view.composable.TabItem
import eu.gaudian.translator.view.hints.getApiKeyHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.viewmodel.ApiKeyManagementState import eu.gaudian.translator.viewmodel.ApiKeyManagementState
import eu.gaudian.translator.viewmodel.ApiViewModel import eu.gaudian.translator.viewmodel.ApiViewModel
import eu.gaudian.translator.viewmodel.ProviderState import eu.gaudian.translator.viewmodel.ProviderState
@@ -121,7 +121,7 @@ fun ApiKeyScreen(navController: NavController) {
Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back)) Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back))
} }
}, },
hintContent = getApiKeyHint() hintContent = HintDefinition.API_KEY.hint()
) )
} }
) { paddingValues -> ) { paddingValues ->

View File

@@ -36,7 +36,7 @@ import eu.gaudian.translator.view.composable.AppScaffold
import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.AppTopAppBar
import eu.gaudian.translator.view.composable.OptionItemSwitch import eu.gaudian.translator.view.composable.OptionItemSwitch
import eu.gaudian.translator.view.dictionary.DictionaryManagerContent import eu.gaudian.translator.view.dictionary.DictionaryManagerContent
import eu.gaudian.translator.view.hints.getDictionaryOptionsHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.viewmodel.ApiViewModel import eu.gaudian.translator.viewmodel.ApiViewModel
import eu.gaudian.translator.viewmodel.DictionaryViewModel import eu.gaudian.translator.viewmodel.DictionaryViewModel
import eu.gaudian.translator.viewmodel.SettingsViewModel import eu.gaudian.translator.viewmodel.SettingsViewModel
@@ -72,7 +72,7 @@ fun DictionaryOptionsScreen(
Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back)) Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back))
} }
}, },
hintContent = getDictionaryOptionsHint() hintContent = HintDefinition.DICTIONARY_OPTIONS.hint()
) )
} }
) { paddingValues -> ) { paddingValues ->

View File

@@ -7,16 +7,9 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.navigation import androidx.navigation.navigation
import eu.gaudian.translator.view.composable.Screen import eu.gaudian.translator.view.composable.Screen
import eu.gaudian.translator.view.hints.ApiHintScreen import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.hints.CategoryHintScreenWrapper import eu.gaudian.translator.view.hints.HintScreen
import eu.gaudian.translator.view.hints.DictionaryHintScreen
import eu.gaudian.translator.view.hints.HintsOverviewScreen import eu.gaudian.translator.view.hints.HintsOverviewScreen
import eu.gaudian.translator.view.hints.ImportHintScreen
import eu.gaudian.translator.view.hints.ScanHintScreen
import eu.gaudian.translator.view.hints.SortingHintScreen
import eu.gaudian.translator.view.hints.StagesHintScreen
import eu.gaudian.translator.view.hints.TranslationHintScreen
import eu.gaudian.translator.view.hints.VocabularyProgressHintScreen
// Defines the routes for the settings graph to avoid using raw strings // Defines the routes for the settings graph to avoid using raw strings
object SettingsRoutes { object SettingsRoutes {
@@ -114,31 +107,31 @@ fun NavGraphBuilder.settingsGraph(navController: NavController) {
HintsOverviewScreen(navController = navController) HintsOverviewScreen(navController = navController)
} }
composable(SettingsRoutes.HINTS_CATEGORIES) { composable(SettingsRoutes.HINTS_CATEGORIES) {
CategoryHintScreenWrapper(navController = navController) HintScreen(navController, HintDefinition.CATEGORY)
} }
composable(SettingsRoutes.HINTS_DICTIONARY) { composable(SettingsRoutes.HINTS_DICTIONARY) {
DictionaryHintScreen(navController = navController) HintScreen(navController, HintDefinition.DICTIONARY_OPTIONS)
} }
composable(SettingsRoutes.HINTS_IMPORT) { composable(SettingsRoutes.HINTS_IMPORT) {
ImportHintScreen(navController = navController) HintScreen(navController, HintDefinition.IMPORT)
} }
composable(SettingsRoutes.HINTS_SORTING) { composable(SettingsRoutes.HINTS_SORTING) {
SortingHintScreen(navController = navController) HintScreen(navController, HintDefinition.SORTING)
} }
composable(SettingsRoutes.HINTS_STAGES) { composable(SettingsRoutes.HINTS_STAGES) {
StagesHintScreen(navController = navController) HintScreen(navController, HintDefinition.LEARNING_STAGES)
} }
composable(SettingsRoutes.HINTS_TRANSLATION) { composable(SettingsRoutes.HINTS_TRANSLATION) {
TranslationHintScreen(navController = navController) HintScreen(navController, HintDefinition.TRANSLATION)
} }
composable(SettingsRoutes.HINTS_SCAN) { composable(SettingsRoutes.HINTS_SCAN) {
ScanHintScreen(navController = navController) HintScreen(navController, HintDefinition.ADD_MODEL_SCAN)
} }
composable(SettingsRoutes.HINTS_API) { composable(SettingsRoutes.HINTS_API) {
ApiHintScreen(navController = navController) HintScreen(navController, HintDefinition.API_KEY)
} }
composable(SettingsRoutes.HINTS_VOCABULARY_PROGRESS) { composable(SettingsRoutes.HINTS_VOCABULARY_PROGRESS) {
VocabularyProgressHintScreen(navController = navController) HintScreen(navController, HintDefinition.VOCABULARY_PROGRESS)
} }
} }
} }

View File

@@ -49,8 +49,7 @@ import eu.gaudian.translator.view.composable.AppIcons
import eu.gaudian.translator.view.composable.AppScaffold import eu.gaudian.translator.view.composable.AppScaffold
import eu.gaudian.translator.view.composable.AppSlider import eu.gaudian.translator.view.composable.AppSlider
import eu.gaudian.translator.view.composable.AppTopAppBar import eu.gaudian.translator.view.composable.AppTopAppBar
import eu.gaudian.translator.view.hints.VocabularyProgressHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.hints.getVocabularyProgressHint
import eu.gaudian.translator.viewmodel.SettingsViewModel import eu.gaudian.translator.viewmodel.SettingsViewModel
import eu.gaudian.translator.viewmodel.VocabularyViewModel import eu.gaudian.translator.viewmodel.VocabularyViewModel
import kotlin.math.exp import kotlin.math.exp
@@ -86,7 +85,7 @@ fun VocabularyProgressOptionsScreen(
} }
}, },
// Here is the new hint content // Here is the new hint content
hintContent = getVocabularyProgressHint() hintContent = HintDefinition.VOCABULARY_PROGRESS.hint()
) )
} }
) { paddingValues -> ) { paddingValues ->

View File

@@ -59,7 +59,7 @@ 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.dialogs.AddVocabularyDialog import eu.gaudian.translator.view.dialogs.AddVocabularyDialog
import eu.gaudian.translator.view.hints.TranslationScreenHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.view.settings.SettingsRoutes import eu.gaudian.translator.view.settings.SettingsRoutes
import eu.gaudian.translator.viewmodel.LanguageViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel
import eu.gaudian.translator.viewmodel.SettingsViewModel import eu.gaudian.translator.viewmodel.SettingsViewModel
@@ -167,7 +167,7 @@ private fun LoadedTranslationContent(
TopBarActions( TopBarActions(
languageViewModel = languageViewModel, languageViewModel = languageViewModel,
onSettingsClick = onSettingsClick, onSettingsClick = onSettingsClick,
hintContent = { TranslationScreenHint() } hintContent = { HintDefinition.TRANSLATION.Render() }
) )
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)) {

View File

@@ -74,7 +74,7 @@ import eu.gaudian.translator.view.composable.AppTopAppBar
import eu.gaudian.translator.view.composable.SingleLanguageDropDown import eu.gaudian.translator.view.composable.SingleLanguageDropDown
import eu.gaudian.translator.view.dialogs.CategoryDropdown import eu.gaudian.translator.view.dialogs.CategoryDropdown
import eu.gaudian.translator.view.dialogs.CreateCategoryListDialog import eu.gaudian.translator.view.dialogs.CreateCategoryListDialog
import eu.gaudian.translator.view.hints.getSortingScreenHint import eu.gaudian.translator.view.hints.HintDefinition
import eu.gaudian.translator.viewmodel.CategoryViewModel import eu.gaudian.translator.viewmodel.CategoryViewModel
import eu.gaudian.translator.viewmodel.LanguageConfigViewModel import eu.gaudian.translator.viewmodel.LanguageConfigViewModel
import eu.gaudian.translator.viewmodel.LanguageViewModel import eu.gaudian.translator.viewmodel.LanguageViewModel
@@ -236,7 +236,7 @@ fun VocabularySortingScreen(
Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back)) Icon(AppIcons.ArrowBack, contentDescription = stringResource(R.string.cd_back))
} }
}, },
hintContent = getSortingScreenHint() hintContent = HintDefinition.SORTING.hint()
) )
}, },