Compose initiative • Eufemia design system • Design system architecture • Building a component library with Compose • Making sure we deliver components with banking level quality • Release & dependency management • Learnings and challenges
architecture • One app had single activity architecture • One app had multiple activity architecture • One app is not part of mono-repo • They all used one design system
EufemiaTypography( val title: TextStyle, val titleDemi: TextStyle, val titleEmphasized: TextStyle, val titleMedium: TextStyle, val titleMediumEmphasized: TextStyle, val titleLarge: TextStyle, *** ** * )
EufemiaShape( public val small: CornerBasedShape = RoundedCornerShape(4.dp), public val medium: CornerBasedShape = RoundedCornerShape(4.dp), public val large: CornerBasedShape = RoundedCornerShape(8.dp), )
Decreases the API surface • Reduces coupling between components • Can become to fl exible @Composable public fun CardPromo( illustration: @Composable () -> Unit, button: @Composable () -> Unit, textContent: @Composable () -> Unit, modifier: Modifier = Modifier, )
Use Showkase from Airbnb • Annotate our component with @Preview or @ShowkaseComposable • Will generate an activity to browse your components • Helps us see which components we have
@Composable public fun CardPromoPreview( @PreviewParameter(LoyaltyProgramParameterProvider::class) params: LoyaltyProgram, ) { EufemiaTheme(loyaltyProgram = params, overlayType = OverlayType.STANDARD) { CardPromo( modifier = Modifier.fillMaxWidth(), title = "DNBs mortgage", description = "A mortgage loan can be a good solution if you want to buy a house. You can calculate how much you can get here!", illustrationDrawable = DrawableData( drawableRes = R.drawable.ic_illustration_example_1, contentDescription = “Mortgage illustration” ), closeOnClicked = {}, primaryButtonText = "Calculate mortgage loan", primaryButtonOnClicked = {}, textButtonText = "Read more about mortgages at dnb.no", textButtonOnClicked = {} ) } }
@Composable public fun CardPromoPreview( @PreviewParameter(LoyaltyProgramParameterProvider::class) params: LoyaltyProgram, ) { EufemiaTheme(loyaltyProgram = params, overlayType = OverlayType.STANDARD) { CardPromo( modifier = Modifier.fillMaxWidth(), title = "DNBs mortgage", description = "A mortgage loan can be a good solution if you want to buy a house. You can calculate how much you can get here!", illustrationDrawable = DrawableData( drawableRes = R.drawable.ic_illustration_example_1, contentDescription = “Mortgage illustration” ), closeOnClicked = {}, primaryButtonText = "Calculate mortgage loan", primaryButtonOnClicked = {}, textButtonText = "Read more about mortgages at dnb.no", textButtonOnClicked = {} ) } } @PreviewParameter(LoyaltyProgramParameterProvider::class) params: LoyaltyProgram,
Locally hosted preview screenshot testing from AGP 8.2+ • Announced at Google IO 2023 • Integrate well with @Preview • Great option to Showkase + Paparazzi
class Preview( val name: String = “", val group: String = “", @IntRange(from = 1) val apiLevel: Int = -1, val widthDp: Int = -1, val heightDp: Int = -1, val locale: String = “", @FloatRange(from = 0.01) val fontScale: Float = 1f, val showSystemUi: Boolean = false, val showBackground: Boolean = false, val backgroundColor: Long = 0, @UiMode val uiMode: Int = 0, @Device val device: String = Devices.DEFAULT, @Wallpaper val wallpaper: Int = Wallpapers.NONE, )
name = "CardPromo dark high font", uiMode = Configuration.UI_MODE_NIGHT_YES, fontScale = 2f, ) @Preview( name = "CardPromo light high font", uiMode = Configuration.UI_MODE_NIGHT_NO, fontScale = 2f, ) @Composable public fun CardPromoPreview( )
name = "CardPromo dark high font", uiMode = Configuration.UI_MODE_NIGHT_YES, fontScale = 2f, ) @Preview( name = "CardPromo light high font", uiMode = Configuration.UI_MODE_NIGHT_NO, fontScale = 2f, ) annotation class HighFontPreviews
fun InputTextField() { var text = mutableStateOf("") TextField(value = text, onValueChange = { text.value = it }) } var text = mutableStateOf("") • Rule violation
fun InputTextField() { var text = remember { mutableStateOf("") } TextField(value = text, onValueChange = { text.value = it }) } var text = remember { mutableStateOf("") }
fun InputTextField() { var text = remember { mutableStateOf("") } TextField(value = text, onValueChange = { text.value = it }) } var text = remember { mutableStateOf("") } • State should be remembered to avoid creating new state instance on each recomposition