This Day In History Jetpack Compose App - Languages Screen
Objective:
Build our Languages Screen and connect it to a mock SettingsViewModel. At the end of this exercise, the Languages Screen will look like below. It will require more work to style it correctly, but that will be done later. We will take care of the functionality first.

Languages Screen functionalities
The Languages screen will do the following:
- Display App Logo at the top.
- Display languages supported by the app for the user to choose any available language as an in-app chosen language.
Code
Tag Constants
Add the following constants to the ui.constants package. We will need them for unit tests.
package com.coroutines.thisdayinhistory.ui.constants
//add this entry:
const val LANGUAGE_SELECTION_TEXT_TAG = "languageSelectionText"
Preview Providers
And ThisDayInHistoryThemeEnumProvider to the ui.previewProviders package.
package com.coroutines.thisdayinhistory.ui.previewProviders
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.coroutines.thisdayinhistory.ui.theme.ThisDayInHistoryThemeEnum
class ThisDayInHistoryThemeEnumProvider : PreviewParameterProvider<ThisDayInHistoryThemeEnum> {
override val values = listOf(
ThisDayInHistoryThemeEnum.Dark,
ThisDayInHistoryThemeEnum.Light
).asSequence()
}
Languages Screen Composables
First, we need LanguageSelection composable, which will server as a fundamental block for language selection.
@Composable
fun LanguageSelection(
language: LangEnum,
modifier: Modifier,
onLangSelection: (language: LangEnum) -> Unit
)
{
Text(modifier = modifier
.testTag(LANGUAGE_SELECTION_TEXT_TAG)
.sizeIn(
minWidth = 48.dp,
minHeight = 48.dp
)
.padding(0.dp, 10.dp)
.semantics {
contentDescription = language.langName
}
.clickable(enabled = true) {
onLangSelection(language)
},
text = language.langNativeName,
lineHeight = 20.sp,
style = MaterialTheme.typography.bodyMedium
)
}
@Composable
@Preview
fun LanguageSelectionPreview(
@PreviewParameter(ThisDayInHistoryThemeEnumProvider::class)
thisDayInHistoryThemeEnum: ThisDayInHistoryThemeEnum
) {
val settingsViewModel = SettingsViewModelMock(thisDayInHistoryThemeEnum)
ThisDayInHistoryTheme(
settingsViewModel
) {
val appThemeColor = MaterialTheme.colorScheme.background
Surface(
modifier = Modifier.background(appThemeColor)
) {
LanguageSelection(language = LangEnum.GERMAN,
modifier = Modifier, onLangSelection = {} )
}
}
}
And now the Languages Screen Composable itself, together with the preview function.
@Composable
fun LanguageScreen(
modifier: Modifier = Modifier,
navController: NavController,
viewModel: ISettingsViewModel = SettingsViewModelMock(),
languagePrompt: String = ""
){
val settings by viewModel.appConfigurationState.collectAsStateWithLifecycle()
Column(
modifier = modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CatLogo(settings)
Spacer(modifier = Modifier.height(30.dp))
Text(languagePrompt)
Spacer(modifier = Modifier.height(30.dp))
val scope = rememberCoroutineScope()
for (language in LangEnum.entries){
Row {
LanguageSelection(
language = language,
modifier = Modifier
){
scope.launch {
viewModel.setOnboarded()
viewModel.setAppLanguage(language)
navController.navigate(NavRoutes.MainRoute.name) {
popUpTo(NavRoutes.MainRoute.name)
}
}
}
}
}
Spacer(modifier = Modifier.height(30.dp))
}
}
@Composable
@Preview(locale = "es")
fun LanguageScreenPreview(
@PreviewParameter(ThisDayInHistoryThemeEnumProvider::class)
historyCatThemeEnum: ThisDayInHistoryThemeEnum
) {
val navController = rememberNavController()
val settingsViewModel = SettingsViewModelMock(historyCatThemeEnum)
ThisDayInHistoryTheme(
settingsViewModel
) {
val appThemeColor = MaterialTheme.colorScheme.background
Surface(
modifier = Modifier.background(appThemeColor)
) {
LanguageScreen(
navController = navController,
viewModel = settingsViewModel,
languagePrompt = stringResource(id = R.string.language_prompt)
)
}
}
}