Compare commits
4 Commits
858c73fd0d
...
77b86208c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77b86208c3 | ||
|
|
03e9aeedae | ||
|
|
05a1b2b71a | ||
|
|
18474b072e |
@@ -1,53 +1,70 @@
|
||||
# How to Connect to an AI Model
|
||||
## What is an API Key?
|
||||
|
||||
This guide explains how to connect your app to an AI model using an API key.
|
||||
An API key is like a password that lets your app talk to AI services. You need one to use an AI provider like OpenAI (ChatGPT), Anthropic, Mistral, or DeepSeek.
|
||||
|
||||
## Getting Started
|
||||
## Getting an API Key
|
||||
|
||||
To use AI models in your app, you need to provide a valid API key. This key authenticates your requests and tracks your usage.
|
||||
Some providers offer a limited free use of their API, which should be sufficient for most functions of this app; however, it is recommended to use a faster and better-paid service.
|
||||
|
||||
> **Note:** Keep your API key secure and never share it publicly.
|
||||
### For Cloud Providers
|
||||
|
||||
## Key Status Indicators
|
||||
1. Create an account on the provider's website
|
||||
2. Choose a plan or billing option or free tier if available
|
||||
3. Create a new key and copy it
|
||||
4. Paste it into this app
|
||||
|
||||
Your API key can be in one of two states:
|
||||
### For Local AI Servers
|
||||
|
||||
| Status | Icon | Meaning |
|
||||
|--------|------|---------|
|
||||
| Active | ✅ | Key is valid and working |
|
||||
| Missing | ⚠️ | Key is not set or was cleared |
|
||||
Running a local AI server (like Ollama or LM Studio), you don't need an API key. Just add a custom provider:
|
||||
|
||||
### Active Key
|
||||
1. Tap **"Add Custom Provider"**
|
||||
2. Enter your local server IP and endpoint
|
||||
3. Tap **"Check Availability"** to test the connection
|
||||
|
||||
When your API key is active, you can use all available AI models. The system will display a checkmark indicator next to the key status.
|
||||
## Choosing a Model
|
||||
|
||||
### Missing Key
|
||||
### What are Models?
|
||||
|
||||
If the key is missing or cleared, you won't be able to make API requests. You'll see a warning indicator, and any attempt to use AI features will prompt you to add a valid key.
|
||||
A model is a specific AI brain. Different models have different strengths:
|
||||
- **Smaller models**: Faster and cheaper
|
||||
- **Larger models**: Smarter but slower and more expensive
|
||||
|
||||
## Connecting Your AI Model
|
||||
For pre-configured providers, some models are already added by default and proven to work with this app.
|
||||
|
||||
1. **Navigate to Settings** → API Key section
|
||||
2. **Enter your API key** in the provided field
|
||||
3. **Save** the configuration
|
||||
4. **Verify** the connection is successful
|
||||
### Adding Models
|
||||
|
||||
## Troubleshooting
|
||||
1. Open a provider's details
|
||||
2. Tap **Add Model**
|
||||
3. Choose **Scan for Models** to find available ones automatically
|
||||
4. Select the models you want to use
|
||||
|
||||
If you're having issues with your API key:
|
||||
### Assigning Models to Tasks
|
||||
|
||||
1. **Verify the key is correct** - Check for typos or extra spaces
|
||||
2. **Ensure the key has proper permissions** - Some models require additional access
|
||||
3. **Check your quota** - You may have exceeded your usage limits
|
||||
4. **Try regenerating the key** - If all else fails, generate a new key from your provider
|
||||
You can use different models for different features:
|
||||
|
||||
```json
|
||||
// Example API key format
|
||||
{
|
||||
"api_key": "sk-xxxxxxxxxxxxxxxxxxxx"
|
||||
}
|
||||
```
|
||||
1. Go to the **Tasks** tab
|
||||
2. Select which model to use for:
|
||||
- **Translation**: Translates text between languages
|
||||
- **Exercises**: Creates practice exercises
|
||||
- **Vocabulary**: Generates vocabulary and synonyms
|
||||
- **Dictionary**: Looks up definitions
|
||||
|
||||
---
|
||||
## Common Problems
|
||||
|
||||
**Need more help?** Check our documentation or contact support.
|
||||
### "Invalid API Key"
|
||||
- Check for typos or extra spaces
|
||||
- Make sure your key is still active and valid on the provider's website
|
||||
|
||||
|
||||
### "No Models Available"
|
||||
- Make sure your API key is valid first
|
||||
- If on a local network, make sure that your connection and endpoint is configured correctly
|
||||
|
||||
### Slow Responses
|
||||
- Try a faster provider, you might need to choose a paid option
|
||||
- Use a smaller model (look for names with "small" "light" "fast" "nano")
|
||||
|
||||
### Local Server Not Working
|
||||
- Make sure your local server is running
|
||||
- Check that the URL is correct
|
||||
- Your phone and computer might need to be on the same WiFi for local servers.
|
||||
|
||||
@@ -1,30 +1,25 @@
|
||||
# Understanding Categories
|
||||
|
||||
Learn how to use categories to organize and filter your vocabulary effectively.
|
||||
|
||||
## What Are Categories?
|
||||
|
||||
Categories help you organize your vocabulary into meaningful groups. You can use them to track words by topic, difficulty, or any custom system that works for you.
|
||||
Categories help you organize your vocabulary into meaningful groups. You can use them to track words by topic, language, stage, or any custom system that works for you.
|
||||
|
||||
## Two Types of Categories
|
||||
|
||||
### List Categories
|
||||
|
||||
List categories are simple groupings of vocabulary items. Words in a list category stay together regardless of their learning stage.
|
||||
List categories are simple groupings of vocabulary items. You can simply just add words to a list and they stay there forever.
|
||||
|
||||
**Use cases:**
|
||||
- Group words by topic (e.g., "Food", "Travel", "Business")
|
||||
- Create custom decks for specific purposes
|
||||
- Organize words by source (e.g., "Book: Harry Potter")
|
||||
|
||||
### Filter Categories
|
||||
|
||||
Filter categories automatically include all vocabulary items that match certain criteria. Words are dynamically added based on the filter rules.
|
||||
Filter categories automatically include all vocabulary items that match certain criteria. Words are dynamically added or removed based on the filter rules.
|
||||
|
||||
**Use cases:**
|
||||
- Filter by learning stage (e.g., "Words I'm learning")
|
||||
- Filter by mastery level (e.g., "Words I need to review")
|
||||
- Combine multiple criteria for complex filtering
|
||||
- Filter by language
|
||||
- Combine multiple criteria for complex filtering (e.g., "Words in Spanish that I know already")
|
||||
|
||||
## Creating Categories
|
||||
|
||||
@@ -36,14 +31,10 @@ Filter categories automatically include all vocabulary items that match certain
|
||||
|
||||
## Managing Categories
|
||||
|
||||
- **Edit** - Tap a category to modify its settings
|
||||
- **Delete** - Swipe left and tap delete (words are not deleted)
|
||||
- **Reorder** - Drag to change display order
|
||||
- **Edit** - Enter a category to modify its settings
|
||||
|
||||
## Tips
|
||||
|
||||
> **Pro Tip:** Use filter categories for learning stages to automatically track progress across all words at a certain level.
|
||||
|
||||
---
|
||||
|
||||
*Need more help? Check our documentation.*
|
||||
- Use filter categories for learning stages to automatically track progress across all words at a certain level.
|
||||
- The same vocabulary card can appear in several categories
|
||||
- You can also use categories to manage large groups of vocabulary items at once by using the "selct all" feature inside a category
|
||||
@@ -1,4 +1,5 @@
|
||||
# Dictionary Options
|
||||
# TODO REWRITE
|
||||
|
||||
Learn how to configure and use the dictionary options for better translations.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# 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.
|
||||
|
||||
|
||||
81
app/src/main/assets/hints/exercise_hint.md
Normal file
81
app/src/main/assets/hints/exercise_hint.md
Normal file
@@ -0,0 +1,81 @@
|
||||
## What Are Exercises?
|
||||
|
||||
Exercises help you practice and memorize your vocabulary through interactive activities. You can practice with flashcards, test your spelling, or challenge yourself with word puzzles.
|
||||
|
||||
## Exercise Types
|
||||
|
||||
### Flashcard Mode
|
||||
|
||||
A simple card shows one word, and you guess the translation. Tap to flip and reveal the answer, then mark it as correct or wrong.
|
||||
|
||||
### Spelling Practice
|
||||
|
||||
A word appears and you must type the translation yourself. This is great for memorizing spelling and reinforcing what you've learned.
|
||||
|
||||
### Multiple Choice
|
||||
|
||||
Four answer options are shown and you pick the correct translation. Good for quick recognition practice.
|
||||
|
||||
### Word Jumble
|
||||
|
||||
Letters are scrambled and you must click them in the correct order to spell the word. Excellent for mastering spelling.
|
||||
|
||||
## Starting an Exercise
|
||||
|
||||
1. **From the Dashboard** - Tap the Start Exercise button
|
||||
2. **From a Category** - Open any category and tap Start
|
||||
3. **From the Main Screen** - Tap the floating action button
|
||||
|
||||
## Before You Start
|
||||
|
||||
You can customize your exercise:
|
||||
|
||||
- **How many cards** - Use the slider to pick 1 to 100+ cards
|
||||
- **Quick select** - Tap 10, 25, 50, or 100 for fast selection
|
||||
- **Language direction** - Choose which language to translate from and to
|
||||
- **Exercise types** - Pick one type or mix several together
|
||||
- **Shuffle cards** - Randomize the order
|
||||
- **Shuffle languages** - Randomize which side (word/translation) is shown
|
||||
- **Training mode** - Practice without affecting your progress
|
||||
- **Due today only** - Only practice items scheduled for today
|
||||
|
||||
## Training Mode
|
||||
|
||||
When training mode is ON:
|
||||
- Your answers won't affect your progress stages
|
||||
- No statistics are recorded
|
||||
- Perfect for casual practice or testing yourself
|
||||
|
||||
When training mode is OFF (default):
|
||||
- Correct answers may advance items to higher stages
|
||||
- Progress is saved and tracked
|
||||
- Affects your learning statistics
|
||||
|
||||
## During an Exercise
|
||||
|
||||
The progress bar at the top shows:
|
||||
- **Green** - How many you've gotten right
|
||||
- **Red** - How many you've gotten wrong
|
||||
- **Total** - How many cards in this session
|
||||
|
||||
Tap the close button anytime to exit (you'll be asked to confirm).
|
||||
|
||||
## After Finishing
|
||||
|
||||
Your results screen shows:
|
||||
- Your overall score as a percentage
|
||||
- How many you got right and wrong
|
||||
- Total cards practiced
|
||||
|
||||
You can then:
|
||||
- **Start Over** - Begin a fresh exercise
|
||||
- **Repeat Wrong** - Practice only the cards you missed
|
||||
- **Finish** - Return to the main screen
|
||||
|
||||
## Tips
|
||||
|
||||
- **Mix it up** - Combine different exercise types for variety
|
||||
- **Daily practice** - Use "Due Today Only" for regular reviews
|
||||
- **Focus on mistakes** - Use "Repeat Wrong" to learn from errors
|
||||
- **Start small** - Begin with 10-25 cards and increase over time
|
||||
- **Use training mode** - When you want to practice without pressure
|
||||
@@ -1,4 +1,5 @@
|
||||
# Import Vocabulary with AI
|
||||
# TODO REWRITE
|
||||
|
||||
Generate vocabulary lists automatically using AI assistance.
|
||||
|
||||
|
||||
@@ -1,53 +1,44 @@
|
||||
# Learning Stages
|
||||
|
||||
Understand how vocabulary progresses through different learning stages to optimize your study sessions.
|
||||
|
||||
## The Learning Stages
|
||||
|
||||
Your vocabulary items move through these stages as you learn:
|
||||
Your vocabulary items move through these stages as you learn. In "daily" exercises you get presented with vocabulary items according to their interval.
|
||||
|
||||
| Stage | Name | Interval | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| 🌟 | New | - | Just added vocabulary |
|
||||
| 📅 | Stage 1 | 1 day | Recently learned |
|
||||
| 📅 | Stage 2 | 3 days | Reinforcement |
|
||||
| 📅 | Stage 3 | 1 week | Consolidation |
|
||||
| 📅 | Stage 4 | 2 weeks | Deep learning |
|
||||
| 📅 | Stage 5 | 1 month | Mastery |
|
||||
| ✅ | Learned | ∞ | Fully learned |
|
||||
| Stage | Interval | Description |
|
||||
|------|----------|-------------|
|
||||
| New | 1 day | Just added vocabulary |
|
||||
| Stage 1 | 3 days | Recently learned |
|
||||
| Stage 2 | 1 week | Reinforcement |
|
||||
| Stage 3 | 2 weeks | Consolidation |
|
||||
| Stage 4 | 1 month | Deep learning |
|
||||
| Stage 5 | 2 month | Mastery |
|
||||
| Learned | 3 months | Fully learned |
|
||||
|
||||
## How It Works
|
||||
|
||||
### Answer Correctly ✅
|
||||
### Answer Correctly
|
||||
|
||||
When you correctly identify a word during review:
|
||||
When you correctly identify a word during an exercise:
|
||||
- The word **moves forward** to the next stage
|
||||
- The interval until next review **increases**
|
||||
- This helps you focus on words that need more practice
|
||||
|
||||
### Answer Incorrectly ❌
|
||||
### Answer Incorrectly
|
||||
|
||||
When you make a mistake:
|
||||
- The word **moves back** one or more stages
|
||||
- The word **moves back** one stage
|
||||
- The review interval **decreases**
|
||||
- This ensures you practice challenging words more often
|
||||
|
||||
## Customization
|
||||
|
||||
All intervals and rules can be customized in Settings:
|
||||
All intervals and rules can be customized:
|
||||
|
||||
- **Adjust intervals** for each stage
|
||||
- **Change how many stages** to regress on errors
|
||||
- **Skip stages** for certain word types
|
||||
- **Enable/disable** specific stages
|
||||
- **Change how many attempts** it takes to move up a stage or get demoted
|
||||
- **Skip stages** You can also manually move items to a stage
|
||||
|
||||
## Visual Progress
|
||||
|
||||
The app displays your progress visually:
|
||||
In the dashboard, the app displays your progress visually:
|
||||
- Stage indicators show current status
|
||||
- Progress bars track advancement
|
||||
- Statistics display overall mastery
|
||||
|
||||
---
|
||||
|
||||
*Tip: Consistent daily practice is key to moving words through all stages!*
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Review Vocabulary
|
||||
# TODO REWRITE
|
||||
|
||||
Master your vocabulary through systematic review sessions.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Sorting Vocabulary
|
||||
# TODO REWRITE
|
||||
|
||||
Learn how to efficiently sort and organize new vocabulary as you add them.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Translation Features
|
||||
# TODO REWRITE
|
||||
|
||||
Discover the powerful translation capabilities of this app.
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# Vocabulary Progress Tracking
|
||||
# TODO REWRITE
|
||||
|
||||
Monitor your vocabulary learning journey with detailed progress statistics.
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ package eu.gaudian.translator.model.repository
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import eu.gaudian.translator.R
|
||||
import eu.gaudian.translator.model.Language
|
||||
import eu.gaudian.translator.model.parseLanguagesFromResources
|
||||
import eu.gaudian.translator.model.repository.DataStoreKeys.LANGUAGE_INIT_METADATA_KEY
|
||||
@@ -88,13 +89,12 @@ class LanguageRepository(private val context: Context) {
|
||||
// Check if we already have default languages saved
|
||||
val savedDefaultLanguages = loadLanguages(LanguageListType.DEFAULT).firstOrNull() ?: emptyList()
|
||||
|
||||
// Check if we need to re-parse languages (first run, version change, or language change)
|
||||
// Check if we need to reparse languages (first run, version change, or language change)
|
||||
val shouldReparse = shouldReparseLanguages(savedDefaultLanguages)
|
||||
|
||||
if (shouldReparse) {
|
||||
Log.d("LanguageRepository", "Parsing languages from resources")
|
||||
val parsedLanguages = parseLanguagesFromResources(context)
|
||||
wipeHistoryAndFavorites()
|
||||
saveLanguages(LanguageListType.DEFAULT, parsedLanguages)
|
||||
// Save the current app version and locale to detect changes next time
|
||||
saveLanguageInitializationMetadata()
|
||||
@@ -112,8 +112,11 @@ class LanguageRepository(private val context: Context) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if the number of languages matches expected count (51)
|
||||
if (savedLanguages.size != 51) {
|
||||
// Get expected language count from resources dynamically
|
||||
val expectedCount = context.resources.getStringArray(R.array.language_codes).size
|
||||
|
||||
// Check if the number of languages matches expected count from resources
|
||||
if (savedLanguages.size != expectedCount) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -167,15 +170,22 @@ class LanguageRepository(private val context: Context) {
|
||||
val customLanguages = loadLanguages(LanguageListType.CUSTOM).first()
|
||||
val master = (defaultLanguages + customLanguages).distinctBy { it.nameResId }
|
||||
|
||||
// Sanitize existing enabled IDs and initialize if empty
|
||||
// Get existing enabled IDs
|
||||
val existingEnabled: List<Int> = try {
|
||||
context.dataStore.loadObjectList<Int>(DataStoreKeys.ALL_LANGUAGES_KEY).firstOrNull() ?: emptyList()
|
||||
} catch (_: Exception) {
|
||||
emptyList()
|
||||
}
|
||||
val masterIds = master.map { it.nameResId }.toSet()
|
||||
val sanitized = existingEnabled.filter { it in masterIds }
|
||||
val finalIds = sanitized.ifEmpty { master.filter { it.isSelected == true }.map { it.nameResId } }
|
||||
|
||||
// Sanitize existing enabled IDs (remove any that are no longer valid)
|
||||
val existingValidIds = existingEnabled.filter { it in masterIds }.toSet()
|
||||
|
||||
// Add any new languages from master that aren't already enabled
|
||||
val newLanguageIds = masterIds - existingValidIds
|
||||
|
||||
// Combine: keep existing enabled + add new languages
|
||||
val finalIds = (existingValidIds + newLanguageIds).toList()
|
||||
|
||||
context.dataStore.saveObjectList(DataStoreKeys.ALL_LANGUAGES_KEY, finalIds)
|
||||
|
||||
|
||||
@@ -480,16 +480,32 @@ class VocabularyRepository private constructor(context: Context) {
|
||||
correctCount: Int, incorrectCount: Int,
|
||||
criteriaCorrect: Int, criteriaWrong: Int
|
||||
): VocabularyStage {
|
||||
val readyToAdvance = if (isCorrect) correctCount >= criteriaCorrect else incorrectCount >= criteriaWrong
|
||||
if (!readyToAdvance) return currentStage
|
||||
return when (currentStage) {
|
||||
VocabularyStage.NEW -> VocabularyStage.STAGE_1
|
||||
VocabularyStage.STAGE_1 -> VocabularyStage.STAGE_2
|
||||
VocabularyStage.STAGE_2 -> VocabularyStage.STAGE_3
|
||||
VocabularyStage.STAGE_3 -> VocabularyStage.STAGE_4
|
||||
VocabularyStage.STAGE_4 -> VocabularyStage.STAGE_5
|
||||
VocabularyStage.STAGE_5 -> VocabularyStage.LEARNED
|
||||
VocabularyStage.LEARNED -> VocabularyStage.LEARNED
|
||||
if (isCorrect) {
|
||||
// Correct answer: advance to next stage if criteria met
|
||||
val readyToAdvance = correctCount >= criteriaCorrect
|
||||
if (!readyToAdvance) return currentStage
|
||||
return when (currentStage) {
|
||||
VocabularyStage.NEW -> VocabularyStage.STAGE_1
|
||||
VocabularyStage.STAGE_1 -> VocabularyStage.STAGE_2
|
||||
VocabularyStage.STAGE_2 -> VocabularyStage.STAGE_3
|
||||
VocabularyStage.STAGE_3 -> VocabularyStage.STAGE_4
|
||||
VocabularyStage.STAGE_4 -> VocabularyStage.STAGE_5
|
||||
VocabularyStage.STAGE_5 -> VocabularyStage.LEARNED
|
||||
VocabularyStage.LEARNED -> VocabularyStage.LEARNED
|
||||
}
|
||||
} else {
|
||||
// Incorrect answer: demote to previous stage if criteria met
|
||||
val readyToDemote = incorrectCount >= criteriaWrong
|
||||
if (!readyToDemote) return currentStage
|
||||
return when (currentStage) {
|
||||
VocabularyStage.LEARNED -> VocabularyStage.STAGE_5
|
||||
VocabularyStage.STAGE_5 -> VocabularyStage.STAGE_4
|
||||
VocabularyStage.STAGE_4 -> VocabularyStage.STAGE_3
|
||||
VocabularyStage.STAGE_3 -> VocabularyStage.STAGE_2
|
||||
VocabularyStage.STAGE_2 -> VocabularyStage.STAGE_1
|
||||
VocabularyStage.STAGE_1 -> VocabularyStage.STAGE_1
|
||||
VocabularyStage.NEW -> VocabularyStage.NEW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ val LANGUAGE_STRING_IDS: IntArray = intArrayOf(
|
||||
R.string.language_49,
|
||||
R.string.language_50,
|
||||
R.string.language_51,
|
||||
R.string.language_52,
|
||||
|
||||
R.string.native_language_1,
|
||||
R.string.native_language_2,
|
||||
@@ -112,6 +113,7 @@ val LANGUAGE_STRING_IDS: IntArray = intArrayOf(
|
||||
R.string.native_language_49,
|
||||
R.string.native_language_50,
|
||||
R.string.native_language_51,
|
||||
R.string.native_language_52,
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ fun MainSettingsScreen(
|
||||
Setting(R.string.settings_title_voice, AppIcons.TextToSpeech, SettingsRoutes.TTS_OPTIONS),
|
||||
Setting(R.string.label_logs, AppIcons.Log, SettingsRoutes.LOGS),
|
||||
Setting(R.string.label_languages, AppIcons.Language, SettingsRoutes.LANGUAGE_OPTIONS),
|
||||
//Setting(R.string.hint_settings_title_hints, AppIcons.Info, SettingsRoutes.HINTS_OVERVIEW)
|
||||
Setting(R.string.hint_settings_title_hints, AppIcons.Info, SettingsRoutes.HINTS_OVERVIEW)
|
||||
|
||||
),
|
||||
R.string.settings_header_translator to listOf(
|
||||
|
||||
@@ -77,7 +77,8 @@ fun VocabularyExerciseHostScreen(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
|
||||
// Reset exercise state when starting fresh
|
||||
exerciseViewModel.resetExercise()
|
||||
|
||||
vocabularyViewModel.prepareExercise(
|
||||
categoryIdsAsJson,
|
||||
@@ -249,7 +250,15 @@ private fun ExerciseScreen(
|
||||
}
|
||||
|
||||
LaunchedEffect(currentExerciseState, score, wrongAnswers) {
|
||||
if (currentExerciseState == null && (score + wrongAnswers) >= totalItems && totalItems > 0) {
|
||||
// Only trigger completion when:
|
||||
// 1. Current exercise state is null (no more items to show)
|
||||
// 2. We have answered all items (score + wrong = total)
|
||||
// 3. We have at least one item to process
|
||||
// 4. We're not already in a completed state (prevent duplicate triggers)
|
||||
if (currentExerciseState == null &&
|
||||
(score + wrongAnswers) >= totalItems &&
|
||||
totalItems > 0 &&
|
||||
(score + wrongAnswers) > 0) {
|
||||
onFinish(score, wrongAnswers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,38 +240,12 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
else -> if (shuffleLanguages) Random.nextBoolean() else false
|
||||
}
|
||||
|
||||
_exerciseState.value = when (randomType) {
|
||||
VocabularyExerciseType.GUESSING -> VocabularyExerciseState.Guessing(
|
||||
item = itemToUse,
|
||||
isSwitched = isSwitched
|
||||
)
|
||||
VocabularyExerciseType.SPELLING -> VocabularyExerciseState.Spelling(
|
||||
item = itemToUse,
|
||||
isSwitched = isSwitched
|
||||
)
|
||||
VocabularyExerciseType.MULTIPLE_CHOICE -> {
|
||||
val correctAnswer = if (isSwitched) itemToUse.wordFirst else itemToUse.wordSecond
|
||||
val options = generateMultipleChoiceOptions(correctAnswer, isSwitched)
|
||||
VocabularyExerciseState.MultipleChoice(
|
||||
item = itemToUse,
|
||||
isSwitched = isSwitched,
|
||||
options = options
|
||||
)
|
||||
}
|
||||
VocabularyExerciseType.WORD_JUMBLE -> {
|
||||
val wordToJumble = if (isSwitched) itemToUse.wordFirst else itemToUse.wordSecond
|
||||
VocabularyExerciseState.WordJumble(
|
||||
item = itemToUse,
|
||||
isSwitched = isSwitched,
|
||||
jumbledLetters = wordToJumble.toList().mapIndexed { index, char -> Pair(char, index) }.shuffled()
|
||||
)
|
||||
}
|
||||
}
|
||||
@Suppress("HardCodedStringLiteral")
|
||||
Log.d("ExerciseDebug", "Item: ${itemToUse.wordFirst} (${itemToUse.languageFirstId}) / ${itemToUse.wordSecond} (${itemToUse.languageSecondId}), Switched: $isSwitched")
|
||||
@Suppress("HardCodedStringLiteral")
|
||||
Log.d("ExerciseDebug", "Origin Lang: ${config.originLanguageId}, Target Lang: ${config.targetLanguageId}")
|
||||
|
||||
// Set the exercise state based on the random type
|
||||
_exerciseState.value = when (randomType) {
|
||||
VocabularyExerciseType.GUESSING -> VocabularyExerciseState.Guessing(
|
||||
item = itemToUse,
|
||||
@@ -344,18 +318,16 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAnswer(answer: Any) {
|
||||
viewModelScope.launch {
|
||||
val state = _exerciseState.value ?: return@launch
|
||||
private suspend fun checkAnswer(answer: Any) {
|
||||
val state = _exerciseState.value ?: return
|
||||
val correctAnswer = if (state.isSwitched) state.item.wordFirst else state.item.wordSecond
|
||||
|
||||
// Check if the state is a Spelling type before proceeding with specific logic
|
||||
val isCorrect = when (state) {
|
||||
is VocabularyExerciseState.Spelling -> {
|
||||
val userAnswer = (answer as String).trim()
|
||||
val languageId = if (state.isSwitched) state.item.languageFirstId else state.item.languageSecondId
|
||||
val language = languageRepository.getLanguageById(languageId ?: 0)
|
||||
?: return@launch
|
||||
?: return
|
||||
|
||||
// Get articles for the language
|
||||
val articles = languageConfigRepository.getArticlesForLanguage(language.code)
|
||||
@@ -405,7 +377,6 @@ class VocabularyExerciseViewModel @Inject constructor(
|
||||
is VocabularyExerciseState.WordJumble -> state.copy(isCorrect = isCorrect, isRevealed = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateJumbledWord(assembledWord: List<Pair<Char, Int>>) {
|
||||
_exerciseState.value = when (val state = _exerciseState.value) {
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<item>cz,CZ,49</item>
|
||||
<item>he,IL,50</item>
|
||||
<item>hr,HR,51</item>
|
||||
<item>fil,PH,52</item>
|
||||
</string-array>
|
||||
|
||||
<string name="language_1">Englisch</string>
|
||||
@@ -105,6 +106,7 @@
|
||||
<string name="language_49">Tschechisch</string>
|
||||
<string name="language_50">Hebräisch</string>
|
||||
<string name="language_51">Kroatisch</string>
|
||||
<string name="language_52">Filipino</string>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -52,6 +52,7 @@
|
||||
<item>cz,CZ,49</item>
|
||||
<item>he,IL,50</item>
|
||||
<item>hr,HR,51</item>
|
||||
<item>fil,PH,52</item>
|
||||
</string-array>
|
||||
|
||||
<string name="language_1">Inglês</string>
|
||||
@@ -105,6 +106,7 @@
|
||||
<string name="language_49">Tcheco</string>
|
||||
<string name="language_50">Hebraico</string>
|
||||
<string name="language_51">Croata</string>
|
||||
<string name="language_52">Filipino</string>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -52,6 +52,7 @@
|
||||
<item>cz,CZ,49</item>
|
||||
<item>he,IL,50</item>
|
||||
<item>hr,HR,51</item>
|
||||
<item>fil,PH,52</item>
|
||||
</string-array>
|
||||
|
||||
<string name="language_1">English</string>
|
||||
@@ -105,6 +106,7 @@
|
||||
<string name="language_49">Czech</string>
|
||||
<string name="language_50">Hebrew</string>
|
||||
<string name="language_51">Croatian</string>
|
||||
<string name="language_52">Filipino</string>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -52,4 +52,5 @@
|
||||
<string name="native_language_49" translatable="false">Čeština</string>
|
||||
<string name="native_language_50" translatable="false">עברית</string>
|
||||
<string name="native_language_51" translatable="false">Hrvatski</string>
|
||||
<string name="native_language_52" translatable="false">Filipino</string>
|
||||
</resources>
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
<string name="label_amount_models">%1$d models</string>
|
||||
<string name="label_analyze_grammar">Analyze Grammar</string>
|
||||
<string name="label_appearance">Appearance</string>
|
||||
<string name="hint_settings_title_hints">Help</string>
|
||||
<string name="label_apply_filters">Apply Filters</string>
|
||||
<string name="label_article">Article</string>
|
||||
<string name="label_backup_and_restore">Backup and Restore</string>
|
||||
|
||||
270
docs/EXERCISES.md
Normal file
270
docs/EXERCISES.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Vocabulary Exercises Documentation
|
||||
|
||||
This document explains how the exercise system works in the Polly vocabulary learning app.
|
||||
|
||||
## Overview
|
||||
|
||||
The exercise system allows users to practice vocabulary through various interactive exercise types. Users can configure and start exercises from different screens, track their progress, and review their results.
|
||||
|
||||
## Exercise Types
|
||||
|
||||
The app supports four different exercise types:
|
||||
|
||||
### 1. Guessing Exercise (Flashcard Mode)
|
||||
|
||||
**How it works:**
|
||||
- A vocabulary card is displayed with one side (word or translation)
|
||||
- The user sees only one side of the card initially
|
||||
- The user guesses the answer before flipping the card
|
||||
|
||||
**User actions:**
|
||||
- Tap "Flip Card" to reveal the answer
|
||||
- Mark as "Wrong" or "Correct" after revealing
|
||||
- The card advances when "Next" is tapped
|
||||
|
||||
**Use case:** Ideal for quick recognition practice and memorization.
|
||||
|
||||
---
|
||||
|
||||
### 2. Spelling Exercise
|
||||
|
||||
**How it works:**
|
||||
- A vocabulary word is displayed as a prompt
|
||||
- The user must type the translation manually
|
||||
- The app checks if the typed answer is correct
|
||||
|
||||
**User actions:**
|
||||
- Type the translation in the text field
|
||||
- Tap "Check" to submit the answer
|
||||
- See immediate feedback on correctness
|
||||
- Tap "Next" to proceed to the next card
|
||||
|
||||
**Use case:** Excellent for practicing proper spelling and reinforcing memory through active recall.
|
||||
|
||||
---
|
||||
|
||||
### 3. Multiple Choice Exercise
|
||||
|
||||
**How it works:**
|
||||
- A word is displayed with four answer options
|
||||
- Only one option is the correct translation
|
||||
- The user selects their answer
|
||||
|
||||
**User actions:**
|
||||
- Tap one of the four options
|
||||
- The correct answer is highlighted after selection
|
||||
- Visual feedback shows if the choice was right or wrong
|
||||
- Tap "Next" to continue
|
||||
|
||||
**Use case:** Good for recognition practice with immediate feedback.
|
||||
|
||||
---
|
||||
|
||||
### 4. Word Jumble Exercise
|
||||
|
||||
**How it works:**
|
||||
- A word's letters are scrambled and displayed
|
||||
- The user must click letters in the correct order to form the word
|
||||
- Letters can be moved between the "available" and "assembled" areas
|
||||
|
||||
**User actions:**
|
||||
- Click a letter from the available pool to add it to the assembly area
|
||||
- Click an assembled letter to return it to the pool
|
||||
- Tap "Check" when the word is assembled
|
||||
- The correct answer is revealed if incorrect
|
||||
|
||||
**Use case:** Great for reinforcing spelling through active manipulation of letter order.
|
||||
|
||||
---
|
||||
|
||||
## Starting an Exercise
|
||||
|
||||
### Entry Points
|
||||
|
||||
1. **Dashboard Widget:** Tap "Start Exercise" from the ModernStartButtons widget
|
||||
2. **Category Detail Screen:** Tap "Start" on a specific category
|
||||
3. **Main Vocabulary Screen:** Tap the FAB (Floating Action Button)
|
||||
4. **Daily Exercise:** Access from the dashboard for daily review
|
||||
|
||||
### Configuration Options
|
||||
|
||||
Before starting an exercise, users can configure:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| **Number of Cards** | Slider to select how many cards to practice (1 to total available) |
|
||||
| **Quick Select** | Preset buttons for 10, 25, 50, or 100 cards |
|
||||
| **Language Direction** | Choose origin and target languages |
|
||||
| **Exercise Types** | Select which exercise types to include (can combine multiple) |
|
||||
| **Shuffle Cards** | Randomize card order |
|
||||
| **Shuffle Languages** | Randomize which side (word/translation) is shown |
|
||||
| **Training Mode** | Practice without affecting progress/stages |
|
||||
| **Due Today Only** | Limit to items scheduled for today |
|
||||
|
||||
---
|
||||
|
||||
## Exercise Flow
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ START SCREEN │
|
||||
│ (Configuration) │
|
||||
└────────┬────────┘
|
||||
│ Tap "Start Exercise"
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ EXERCISE │
|
||||
│ PROGRESS │
|
||||
│ INDICATOR │
|
||||
├─────────────────┤
|
||||
│ CARD/QUESTION │
|
||||
│ DISPLAY │
|
||||
├─────────────────┤
|
||||
│ CONTROLS │
|
||||
│ (Reveal/Check) │
|
||||
└────────┬────────┘
|
||||
│ Complete all cards
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ RESULT SCREEN │
|
||||
│ (Score, │
|
||||
│ Retry, │
|
||||
│ Start Over) │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercise Progress Indicator
|
||||
|
||||
During an exercise, a progress bar shows:
|
||||
|
||||
- **Green section:** Number of correct answers
|
||||
- **Red section:** Number of wrong answers
|
||||
- **Total:** Total cards in the exercise
|
||||
- **Close button:** Exit the exercise (shows confirmation dialog)
|
||||
|
||||
The progress bar animates as the user advances through cards.
|
||||
|
||||
---
|
||||
|
||||
## Exercise State Management
|
||||
|
||||
The app uses a state machine to manage exercise progress:
|
||||
|
||||
### States
|
||||
|
||||
| State | Description |
|
||||
|-------|-------------|
|
||||
| `START` | Configuration screen before starting |
|
||||
| `EXERCISE` | Active exercise in progress |
|
||||
| `RESULT` | Exercise completed, showing results |
|
||||
|
||||
### State Transitions
|
||||
|
||||
```
|
||||
START → EXERCISE (user taps "Start")
|
||||
EXERCISE → RESULT (all cards completed)
|
||||
RESULT → START (user taps "Start Over")
|
||||
RESULT → EXERCISE (user taps "Retry Wrong")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exercise Actions
|
||||
|
||||
The following user actions are available during exercises:
|
||||
|
||||
| Action | Description |
|
||||
|--------|-------------|
|
||||
| `Reveal` | Show the answer (Guessing exercise) |
|
||||
| `Submit` | Submit an answer (Spelling, Multiple Choice, Word Jumble) |
|
||||
| `Next` | Move to the next card |
|
||||
| `UpdateWordJumble` | Modify assembled letters (Word Jumble) |
|
||||
|
||||
---
|
||||
|
||||
## Results Screen
|
||||
|
||||
After completing an exercise, users see:
|
||||
|
||||
### Displayed Information
|
||||
- **Percentage Score:** Overall performance as a circular progress indicator
|
||||
- **Correct/Wrong Count:** Detailed breakdown of answers
|
||||
- **Total Items:** Number of cards practiced
|
||||
|
||||
### Available Actions
|
||||
- **Start Over:** Begin a new exercise from scratch
|
||||
- **Repeat Wrong:** Retry only the incorrectly answered cards
|
||||
- **Finish:** Return to the main screen
|
||||
|
||||
---
|
||||
|
||||
## Training Mode
|
||||
|
||||
When Training Mode is enabled:
|
||||
- Answers are not recorded for progress tracking
|
||||
- No stage progression occurs
|
||||
- Useful for casual practice or testing knowledge
|
||||
|
||||
When disabled (default):
|
||||
- Correct answers may advance item stages
|
||||
- Progress is saved for statistics
|
||||
- Affects due dates and learning progress
|
||||
|
||||
---
|
||||
|
||||
## Technical Architecture
|
||||
|
||||
### Key Components
|
||||
|
||||
1. **VocabularyExerciseHostScreen.kt**
|
||||
- Main container managing exercise flow
|
||||
- Handles screen states (START, EXERCISE, RESULT)
|
||||
- Coordinates between configuration and exercise screens
|
||||
|
||||
2. **VocabularyExercise.kt**
|
||||
- Defines exercise types (enum)
|
||||
- State classes for each exercise type
|
||||
- Action sealed class for user interactions
|
||||
|
||||
3. **VocabularyExerciseRenderer.kt**
|
||||
- Renders the appropriate UI based on exercise state
|
||||
- Handles display logic for each exercise type
|
||||
|
||||
4. **ExerciseControls.kt**
|
||||
- Input field and buttons for user interaction
|
||||
- Different controls based on exercise type
|
||||
|
||||
5. **ExerciseProgressIndicator.kt**
|
||||
- Visual progress bar during exercises
|
||||
- Animated updates for correct/wrong counts
|
||||
|
||||
---
|
||||
|
||||
## Related Screens
|
||||
|
||||
| Screen | Purpose |
|
||||
|--------|---------|
|
||||
| `StartScreen` | Configure exercise settings before starting |
|
||||
| `ResultScreen` | Show final score and options to continue |
|
||||
| `CategoryDetailScreen` | Start exercise for a specific category |
|
||||
| `DashboardContent` | Main dashboard with exercise shortcuts |
|
||||
|
||||
---
|
||||
|
||||
## Tips for Users
|
||||
|
||||
1. **Combine exercise types:** Mix Guessing, Spelling, and Word Jumble for variety
|
||||
2. **Use Training Mode:** For casual practice without affecting progress
|
||||
3. **Start small:** Use 10-25 cards initially, increase as comfortable
|
||||
4. **Review wrong answers:** Use "Repeat Wrong" to focus on difficult items
|
||||
5. **Daily exercises:** Use "Due Today Only" for spaced repetition practice
|
||||
|
||||
---
|
||||
|
||||
## Navigation During Exercise
|
||||
|
||||
- **Close button:** Exit exercise (confirms before closing)
|
||||
- **Back button:** Also triggers exit confirmation
|
||||
- Results screen options: Continue practicing or return to dashboard
|
||||
Reference in New Issue
Block a user