diff --git a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialContent.kt b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialContent.kt index f55de975..fb6fe500 100644 --- a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialContent.kt +++ b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialContent.kt @@ -2,6 +2,9 @@ package be.scri.ui.screens.tutorial +import android.content.Context +import be.scri.R + /** * Defines all tutorial chapters and their steps. * Each chapter contains one or more interactive steps that guide the user @@ -12,75 +15,156 @@ object TutorialContent { * Chapter 1: Noun Annotation. * Teaches users about gender tags that appear when typing nouns. */ - val nounAnnotationSteps = - listOf( + fun getNounAnnotationSteps( + languageCode: String, + context: Context, + ): List { + val (fatherWord, fatherTag, fatherGender) = + when (languageCode) { + "es" -> Triple("padre", "M", "Masculino") + "fr" -> Triple("père", "M", "Masculin") + "it" -> Triple("padre", "M", "Maschile") + "pt" -> Triple("pai", "M", "Masculino") + "ru" -> Triple("отец", "M", "Мужской") + "sv" -> Triple("far", "C", "Common") + else -> Triple("Vater", "M", "Maskulin") + } + + val (motherWord, motherTag, motherGender) = + when (languageCode) { + "es" -> Triple("madre", "F", "Femenino") + "fr" -> Triple("mère", "F", "Féminin") + "it" -> Triple("madre", "F", "Femminile") + "pt" -> Triple("mãe", "F", "Feminino") + "ru" -> Triple("мать", "F", "Женский") + "sv" -> Triple("mor", "C", "Common") + else -> Triple("Mutter", "F", "Feminin") + } + + if (languageCode == "en") { + return listOf( + TutorialStep( + instruction = + context + .getString(R.string.i18n_app_keyboard_tutorial_noun_annotation_invalid_language) + .replace("{language}", "English"), + requiresValidation = false, + ), + ) + } + return listOf( TutorialStep( instruction = - "Write the word \"Vater\". Notice the word suggestions " + - "that appear on the keyboard's top bar.\n\n" + - "Then, press space. You will see the word's gender " + - "tag on the keyboard's top bar \u2013 in this case, \"M\" for Maskulin.", - expectedWord = "Vater", + context + .getString(R.string.i18n_app_keyboard_tutorial_noun_annotation_instruction_1) + .replace("{mother_word}", motherWord) + .replace("{mother_tag}", motherTag) + .replace("{mother_gender}", motherGender), + expectedWord = motherWord, ), TutorialStep( instruction = - "Now write the word \"Mutter\" and then press space. " + - "The gender tag will be \"F\", for Feminin.", - expectedWord = "Mutter", + context + .getString(R.string.i18n_app_keyboard_tutorial_noun_annotation_instruction_2) + .replace("{father_word}", fatherWord) + .replace("{father_tag}", fatherTag) + .replace("{father_gender}", fatherGender), + expectedWord = fatherWord, ), ) + } /** * Chapter 2: Word Translation. * Teaches users how to use the Translate command via the Scribe key. */ - val wordTranslationSteps = - listOf( + fun wordTranslationSteps( + languageCode: String, + context: Context, + ): List { + val translation = + when (languageCode) { + "en" -> "Translate" + "es" -> "Traducir" + "fr" -> "Traduire" + "it" -> "Tradurre" + "pt" -> "Traduzir" + "ru" -> "Перевести" + "sv" -> "Översätt" + else -> "Übersetzen" + } + return listOf( TutorialStep( instruction = - "Let's translate! Tap the \u27A1 Scribe key on the top-left " + - "corner of your keyboard, and select \u00DCbersetzen.\n\n" + - "Then write the word you want to translate, press \u25B6, " + - "and the translation will be returned to you.", - hint = "If your second language is not German, change the language in your keyboard.", + context + .getString(R.string.i18n_app_keyboard_tutorial_word_translation_instruction) + .replace("{translate}", translation), requiresValidation = false, ), ) + } - val verbConjugationSteps = - listOf( + fun verbConjugationSteps( + languageCode: String, + context: Context, + ): List { + val conjugation = + when (languageCode) { + "en" -> "Conjugate" + "es" -> "Conjugar" + "fr" -> "Conjuguer" + "it" -> "Coniugare" + "pt" -> "Conjugar" + "ru" -> "Спрягать" + "sv" -> "Konjugera" + else -> "Konjugieren" + } + return listOf( TutorialStep( instruction = - "On to the verbs. Tap the \u27A1 Scribe key on the top-left " + - "corner of your keyboard, and select Konjugieren.\n\n" + - "Write the verb you want to conjugate, press \u25B6, and " + - "you will see a table with all the verb tenses. Select " + - "the one you need and it will be inserted!", - hint = "If your second language is not German, change the language in your keyboard.", + context + .getString(R.string.i18n_app_keyboard_tutorial_verb_conjugation_instruction) + .replace("{conjugate}", conjugation), requiresValidation = false, ), ) + } - val nounPluralsSteps = - listOf( + fun nounPluralsSteps( + languageCode: String, + context: Context, + ): List { + val plural = + when (languageCode) { + "en" -> "Plural" + "es" -> "Plural" + "fr" -> "Pluriel" + "it" -> "Plurale" + "pt" -> "Plural" + "ru" -> "Множ-ое" + "sv" -> "Plural" + else -> "Plural" + } + return listOf( TutorialStep( instruction = - "Finding the plural of a noun with Scribe is easy. Tap " + - "the \u27A1 Scribe key on the top-left corner of your " + - "keyboard, and select Plural.\n\n" + - "Then write the noun you want the plural for, press " + - "\u25B6, and the plural will be returned to you.", - hint = "If your second language is not German, change the language in your keyboard.", + context + .getString(R.string.i18n_app_keyboard_tutorial_noun_plurals_instruction) + .replace("{plural}", plural), requiresValidation = false, ), ) + } /** Returns all chapters as a list of pairs (title, steps). */ - fun getAllChapters(): List>> = + fun getAllChapters( + languageCode: String = "de", + context: Context, + ): List>> = listOf( - "Noun annotation" to nounAnnotationSteps, - "Word translation" to wordTranslationSteps, - "Verb conjugation" to verbConjugationSteps, - "Noun plurals" to nounPluralsSteps, + context.getString(R.string.i18n_app_keyboard_tutorial_noun_annotation) to getNounAnnotationSteps(languageCode, context), + context.getString(R.string.i18n_app_keyboard_tutorial_word_translation) to wordTranslationSteps(languageCode, context), + context.getString(R.string.i18n_app_keyboard_tutorial_verb_conjugation) to verbConjugationSteps(languageCode, context), + context.getString(R.string.i18n_app_keyboard_tutorial_noun_plurals) to nounPluralsSteps(languageCode, context), ) } diff --git a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialHomeScreen.kt b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialHomeScreen.kt index f92e4e42..02755c9b 100644 --- a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialHomeScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialHomeScreen.kt @@ -62,10 +62,10 @@ fun TutorialHomeScreen( val headerColor = MaterialTheme.colorScheme.onBackground val chapters = listOf( - TutorialChapter("Noun annotation", 0), - TutorialChapter("Word translation", 1), - TutorialChapter("Verb conjugation", 2), - TutorialChapter("Noun plurals", 3), + TutorialChapter(stringResource(R.string.i18n_app_keyboard_tutorial_noun_annotation), 0), + TutorialChapter(stringResource(R.string.i18n_app_keyboard_tutorial_word_translation), 1), + TutorialChapter(stringResource(R.string.i18n_app_keyboard_tutorial_verb_conjugation), 2), + TutorialChapter(stringResource(R.string.i18n_app_keyboard_tutorial_noun_plurals), 3), ) Column( @@ -113,9 +113,7 @@ fun TutorialHomeScreen( modifier = Modifier.fillMaxWidth(), ) { Text( - text = - "This quick tutorial will show you how to use Scribe to support writing in your second language. " + - "\nMake sure you select the desired Scribe keyboard by pressing \uD83C\uDF10 when typing.", + text = stringResource(R.string.i18n_app_keyboard_tutorial_description), color = textColor, fontSize = 14.sp, modifier = Modifier.padding(16.dp), @@ -127,7 +125,7 @@ fun TutorialHomeScreen( // MARK: Chapter List Text( - text = "Tutorial chapters", + text = stringResource(R.string.i18n_app_keyboard_tutorial_chapters), color = textColor, fontSize = 18.sp, fontWeight = FontWeight.Bold, @@ -189,7 +187,7 @@ fun TutorialHomeScreen( .height(52.dp), ) { Text( - text = "Start full tutorial", + text = stringResource(R.string.i18n_app_keyboard_tutorial_start_full_tutorial), fontSize = 18.sp, fontWeight = FontWeight.SemiBold, ) diff --git a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialNavigator.kt b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialNavigator.kt index d82d2f0d..ecbadfe8 100644 --- a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialNavigator.kt +++ b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialNavigator.kt @@ -2,14 +2,40 @@ package be.scri.ui.screens.tutorial +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.provider.Settings import androidx.activity.compose.BackHandler import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext + +private fun getCurrentScribeLanguage(context: Context): String { + val currentImeId = + Settings.Secure.getString( + context.contentResolver, + Settings.Secure.DEFAULT_INPUT_METHOD, + ) ?: "" + + return when { + currentImeId.contains("EnglishKeyboardIME") -> "en" + currentImeId.contains("SpanishKeyboardIME") -> "es" + currentImeId.contains("FrenchKeyboardIME") -> "fr" + currentImeId.contains("ItalianKeyboardIME") -> "it" + currentImeId.contains("PortugueseKeyboardIME") -> "pt" + currentImeId.contains("RussianKeyboardIME") -> "ru" + currentImeId.contains("SwedishKeyboardIME") -> "sv" + else -> "de" + } +} /** * The main tutorial navigation controller. @@ -28,7 +54,39 @@ fun TutorialNavigator( var currentStepIndex by remember { mutableIntStateOf(0) } var isFullTutorial by remember { mutableStateOf(false) } - val allChapters = TutorialContent.getAllChapters() + val context = LocalContext.current + + var activeLanguageCode by remember { + mutableStateOf(getCurrentScribeLanguage(context)) + } + + DisposableEffect(context) { + val receiver = + object : BroadcastReceiver() { + override fun onReceive( + context: Context, + intent: Intent, + ) { + if (intent.action == Intent.ACTION_INPUT_METHOD_CHANGED) { + activeLanguageCode = getCurrentScribeLanguage(context) + } + } + } + + context.registerReceiver( + receiver, + IntentFilter(Intent.ACTION_INPUT_METHOD_CHANGED), + ) + + onDispose { + context.unregisterReceiver(receiver) + } + } + + val allChapters = + remember(activeLanguageCode) { + TutorialContent.getAllChapters(activeLanguageCode, context) + } BackHandler { if (currentScreen == "home") { diff --git a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialStepScreen.kt b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialStepScreen.kt index e70242a3..b794b2f5 100644 --- a/app/src/main/java/be/scri/ui/screens/tutorial/TutorialStepScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/tutorial/TutorialStepScreen.kt @@ -79,7 +79,7 @@ enum class InputValidationState { data class TutorialStep( val instruction: String, val expectedWord: String = "", - val hint: String = "If your second language is not German, change the language in your keyboard.", + val hint: String = "", val successMessage: String = "Great! Press Next to continue.", val errorMessage: String = "", val requiresValidation: Boolean = true, @@ -173,7 +173,7 @@ fun TutorialStepScreen( when { !step.requiresValidation -> InputValidationState.CORRECT userInput.isEmpty() -> InputValidationState.EMPTY - userInput.trim().equals(step.expectedWord, ignoreCase = false) -> InputValidationState.CORRECT + userInput.trim().equals(step.expectedWord, ignoreCase = true) -> InputValidationState.CORRECT else -> InputValidationState.INCORRECT } @@ -182,6 +182,7 @@ fun TutorialStepScreen( step.errorMessage } else { stringResource(R.string.i18n_app_keyboard_tutorial_not_quite) + .replace("{expected_word}", step.expectedWord) } Column( @@ -256,19 +257,21 @@ fun TutorialStepScreen( Spacer(modifier = Modifier.height(12.dp)) // Language hint - Row( - verticalAlignment = Alignment.Top, - ) { - Text( - text = "\uD83C\uDF10 ", - fontSize = 14.sp, - ) - Text( - text = step.hint, - color = textSecondaryColor, - fontSize = 13.sp, - lineHeight = 18.sp, - ) + if (step.hint.isNotEmpty()) { + Row( + verticalAlignment = Alignment.Top, + ) { + Text( + text = "\uD83C\uDF10 ", + fontSize = 14.sp, + ) + Text( + text = step.hint, + color = textSecondaryColor, + fontSize = 13.sp, + lineHeight = 18.sp, + ) + } } Spacer(modifier = Modifier.height(16.dp)) @@ -327,7 +330,7 @@ fun TutorialStepScreen( } } - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.height(32.dp)) // Next / Finish button Button( diff --git a/app/src/main/java/be/scri/ui/screens/tutorial/WrongKeyboardScreen.kt b/app/src/main/java/be/scri/ui/screens/tutorial/WrongKeyboardScreen.kt index 03ba5135..a0c27ffc 100644 --- a/app/src/main/java/be/scri/ui/screens/tutorial/WrongKeyboardScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/tutorial/WrongKeyboardScreen.kt @@ -111,7 +111,7 @@ fun WrongKeyboardScreen( // Title Text( - text = "Non-Scribe keyboard", + text = stringResource(R.string.i18n_app_keyboard_tutorial_non_scribe_keyboard), color = headerColor, fontSize = 28.sp, fontWeight = FontWeight.Bold, @@ -134,7 +134,7 @@ fun WrongKeyboardScreen( ) { // Instruction text Text( - text = "Press the \uD83C\uDF10 button to select a Scribe keyboard.", + text = stringResource(R.string.i18n_app_keyboard_tutorial_select_keyboard), color = textColor, fontSize = 15.sp, lineHeight = 22.sp,