Skip to content
160 changes: 122 additions & 38 deletions app/src/main/java/be/scri/ui/screens/tutorial/TutorialContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<TutorialStep> {
val (fatherWord, fatherTag, fatherGender) =
Comment on lines +18 to +22

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some languages could u verify wheather the nouns have gender in the db. If not we could have them checked on why the aren't present.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to get mother in english for example

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mother in English shouldn't have a gender. If the user just has English installed, then we should maybe disable that tutorial option. If the user has say German and English, then we should have an option for no noun annotations for English. We should similarly have this for languages where verb conjugation isn't a thing 😊

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")
}

Comment on lines +22 to +43

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you correct the chracter we use to indicate the feminine neutral and masucline in case of certain languages like russian within the copy thats shown to user in noun suggestion.

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<TutorialStep> {
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),
Comment on lines 80 to +101

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do the same as above for this and check as well

requiresValidation = false,
),
)
}

val verbConjugationSteps =
listOf(
fun verbConjugationSteps(
languageCode: String,
context: Context,
): List<TutorialStep> {
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<TutorialStep> {
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<Pair<String, List<TutorialStep>>> =
fun getAllChapters(
languageCode: String = "de",
context: Context,
): List<Pair<String, List<TutorialStep>>> =
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),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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),
Expand All @@ -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,
Expand Down Expand Up @@ -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,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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") {
Expand Down
Loading
Loading