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