Slide 1

Slide 1 text

Google Developers Andromeda - Custom design systems with Compose

Slide 2

Slide 2 text

Android GDE
 🛠 Individual Consultant
 🔊 Speaker
 🌎 Globe Trotter
 🍻 Beer enthusiast 🎯https:/ /androiddev.social/@aditlal 🔗aditlal.dev

Slide 3

Slide 3 text

Make design easier, better and faster.

Slide 4

Slide 4 text

Ever baked a cake?

Slide 5

Slide 5 text

5 Ingredients The famous nani’s recipe Oven of course Time and patience Ever baked a cake?

Slide 6

Slide 6 text

6 Ever baked a cake?

Slide 7

Slide 7 text

7 Ever baked a cake? Yikes

Slide 8

Slide 8 text

8 Ever baked a cake? Phew

Slide 9

Slide 9 text

9 Ever baked a cake?

Slide 10

Slide 10 text

10 Ever baked a cake?

Slide 11

Slide 11 text

11 Ever baked a cake?

Slide 12

Slide 12 text

12 Ingredients The famous nani’s recipe Oven of course Time and patience Assembly line Story and marketing Customer support Ever baked a cake?

Slide 13

Slide 13 text

13 Inconsistent. Slower. Not so Scaleable.

Slide 14

Slide 14 text

14 Components

Slide 15

Slide 15 text

15 Components -> Consistent. Faster. Better.

Slide 16

Slide 16 text

16 Components -> Consistent. Faster. Better. Variety

Slide 17

Slide 17 text

That’s what a Design System is for!

Slide 18

Slide 18 text

A design system is a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications. Design system

Slide 19

Slide 19 text

Style Guide: Colours, Typography, Icons, Illustrations, etc Component Library: Buttons, Forms, Menu, Navigation, etc Content Guide: Principles, Common De fi nitions, Voice and Tone, etc Patterns Guide: User and Business Flows, etc Reference Site: Documentation and Best Practices to use it all correctly Design system

Slide 20

Slide 20 text

Style Guide: Colours, Typography, Icons, Illustrations, etc Component Library: Buttons, Forms, Menu, Navigation, etc Content Guide: Principles, Common De fi nitions, Voice and Tone, etc Patterns Guide: User and Business Flows, etc Reference Site: Documentation and Best Practices to use it all correctly Design system

Slide 21

Slide 21 text

21 Design 
 System Design Guidelines Document Guidelines Design system No Guidelines Chaos 😱 No feedback loop Hard to edit Asset automation
 Feedback loop 🥳

Slide 22

Slide 22 text

“A design system is a set of interconnected patterns and shared practices coherently organised.” “A design system is a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications.” Design system

Slide 23

Slide 23 text

• Consistency • Higher quality • Faster builds, through reusable components and shared rationale. • Improved maintenance and scalability • Stronger focus on product - concentrate on solving user needs • More and better communication between teams Design system Pros

Slide 24

Slide 24 text

• Huge initial effort • Less fl exibility Design system Cons

Slide 25

Slide 25 text

💰 Make designers and developers more productive 😍 Consistent end user experience Design system

Slide 26

Slide 26 text

Planners Can decide on UX fl ow decision faster Can focus on more business goals Design system

Slide 27

Slide 27 text

Designers Can improve design consistency Can improve the productivity of design work Design system

Slide 28

Slide 28 text

Developers Can concentrate on the core logic Can improve UI ef fi ciently and consistently Can decrease the cost of QA Can reduce project size Design system

Slide 29

Slide 29 text

Ultimately Make the Process Shorter should .. Design system

Slide 30

Slide 30 text

Design system Common doubts "Won't it be too restricting?" "I won't be able to explore a new style” "What if something doesn't work?"

Slide 31

Slide 31 text

Design system Preparing should be.. Making a List Getting a buy-in Form a team

Slide 32

Slide 32 text

Making a List Getting a buy-in Form a team Re fl ect back on your recent projects Audit and focus on pain points Components, Principles - de fi ne work fl ows Design system Preparing should be..

Slide 33

Slide 33 text

Making a List Getting a buy-in Form a team Get people excited - may be not so straightforward Identify what’s the reward Do a 1-1 with the team - maybe? Look at other examples Run a quick case study Final Approvals Design system Preparing should be..

Slide 34

Slide 34 text

Making a List Getting a buy-in Form a team Designers - de fi ne the visual components Front-end developers - Coders duh!! Product Managers - align with requirements, and set up necessary steps to help the team. Researchers - to discover user needs Quality Engineers - smooth tested system. Leaders - align the vision and allocate resources. Design system Preparing should be..

Slide 35

Slide 35 text

Compose goodness Less code Intuitive Accelerate development Powerful framework

Slide 36

Slide 36 text

36 Where to start?

Slide 37

Slide 37 text

Runtime UI Foundation Material Design Compose

Slide 38

Slide 38 text

Basic Structure of Design System

Slide 39

Slide 39 text

Andromeda

Slide 40

Slide 40 text

• Always keep users’ expectations in mind and focus on patterns to build a clean design. • Clear primary task - Users want to USE an app if the design is simple yet effective, so make it clear. • Find the best middle ground! • Give enough controls Andromeda - Design Principles

Slide 41

Slide 41 text

Andromeda

Slide 42

Slide 42 text

Andromeda AndromedaTheme { } composeContent()

Slide 43

Slide 43 text

Andromeda AndromedaTheme( colors = if (isLightTheme) customLightColors() else customDarkColors(), fontFamily = CustomAppFonts ){ composeContent() }

Slide 44

Slide 44 text

Breakdown

Slide 45

Slide 45 text

AndromedaTheme - defining the base theme @Composable fun AndromedaTheme( shapes: AndromedaShapes = DefaultShapes.default, fontFamily: FontFamily = AndromedaFonts, colors: AndromedaColors = AndromedaTheme.colors, typography: AndromedaTypography = textStyles(fontFamily = fontFamily), content: @Composable () - > Unit, ) { CompositionLocalProvider( LocalColors provides colors, LocalTypography provides typography, LocalShapes provides shapes, LocalContentEmphasis provides ContentEmphasis.Normal, ) { content() } }

Slide 46

Slide 46 text

AndromedaTheme - defining the base theme @Composable fun AndromedaTheme( shapes: AndromedaShapes = DefaultShapes.default, fontFamily: FontFamily = AndromedaFonts, colors: AndromedaColors = AndromedaTheme.colors, typography: AndromedaTypography = textStyles(fontFamily = fontFamily), content: @Composable () - > Unit, ) { CompositionLocalProvider( LocalColors provides colors, LocalTypography provides typography, LocalShapes provides shapes, LocalContentEmphasis provides ContentEmphasis.Normal, ) { content() } }

Slide 47

Slide 47 text

AndromedaTheme - defining the base theme @Composable fun AndromedaTheme( shapes: AndromedaShapes = DefaultShapes.default, fontFamily: FontFamily = AndromedaFonts, colors: AndromedaColors = AndromedaTheme.colors, typography: AndromedaTypography = textStyles(fontFamily = fontFamily), content: @Composable () - > Unit, ) { CompositionLocalProvider( LocalColors provides colors, LocalTypography provides typography, LocalShapes provides shapes, LocalContentEmphasis provides ContentEmphasis.Normal, ) { content() } }

Slide 48

Slide 48 text

AndromedaTheme - important bits @Composable fun AndromedaTheme( shapes: AndromedaShapes = DefaultShapes.default, fontFamily: FontFamily = AndromedaFonts, colors: AndromedaColors = AndromedaTheme.colors, typography: AndromedaTypography = textStyles(fontFamily = fontFamily), content: @Composable () - > Unit, ) { CompositionLocalProvider( LocalColors provides colors, LocalTypography provides typography, LocalShapes provides shapes, LocalContentEmphasis provides ContentEmphasis.Normal, ) { content() } }

Slide 49

Slide 49 text

AndromedaTheme object AndromedaTheme { public val colors: AndromedaColors @Composable @ReadOnlyComposable get() = LocalColors.current public val typography: AndromedaTypography @Composable @ReadOnlyComposable get() = LocalTypography.current public val shapes: AndromedaShapes @Composable @ReadOnlyComposable get() = LocalShapes.current }

Slide 50

Slide 50 text

AndromedaTheme object AndromedaTheme { public val colors: AndromedaColors @Composable @ReadOnlyComposable get() = LocalColors.current public val typography: AndromedaTypography @Composable @ReadOnlyComposable get() = LocalTypography.current public val shapes: AndromedaShapes @Composable @ReadOnlyComposable get() = LocalShapes.current }

Slide 51

Slide 51 text

51 Colors `

Slide 52

Slide 52 text

Andromeda Foundation Common colour library with consistent labels Colors `

Slide 53

Slide 53 text

Andromeda Foundation @Stable class AndromedaColors( val primaryColors: PrimaryColors, val secondaryColors: SecondaryColors, val tertiaryColors: TertiaryColors, val borderColors: BorderColors, val iconColors: IconColors, val contentColors: ContentColors, isDark: Boolean ) { var isDark: Boolean by mutableStateOf(isDark, structuralEqualityPolicy()) internal set fun copy( . . ) : AndromedaColors = AndromedaColors( . . ) } Colors

Slide 54

Slide 54 text

Andromeda Foundation Colors @Stable class AndromedaColors( val primaryColors: PrimaryColors, val secondaryColors: SecondaryColors, val tertiaryColors: TertiaryColors, val borderColors: BorderColors, val iconColors: IconColors, val contentColors: ContentColors, isDark: Boolean ) { var isDark: Boolean by mutableStateOf(isDark, structuralEqualityPolicy()) internal set fun copy( . . ) : AndromedaColors = AndromedaColors( . . ) }

Slide 55

Slide 55 text

Andromeda Foundation - Fill Colors import androidx.compose.ui.graphics.Color as ComposeColor interface FillColors { val background: ComposeColor val active: ComposeColor val error: ComposeColor val mute: ComposeColor val pressed: ComposeColor val alt: ComposeColor }

Slide 56

Slide 56 text

Andromeda Foundation - Fill Colors import androidx.compose.ui.graphics.Color as ComposeColor interface FillColors { val background: ComposeColor val active: ComposeColor val error: ComposeColor val mute: ComposeColor val pressed: ComposeColor val alt: ComposeColor }

Slide 57

Slide 57 text

Andromeda Foundation - Primary Fill Colors @Stable class PrimaryColors( background: ComposeColor, active: ComposeColor, error: ComposeColor, mute: ComposeColor, pressed: ComposeColor, alt: ComposeColor ) : FillColors { override var background: ComposeColor by mutableStateOf(background, structuralEqualityPolicy()) internal set override var active: ComposeColor by mutableStateOf(active, structuralEqualityPolicy()) internal set override var error: ComposeColor by mutableStateOf(error, structuralEqualityPolicy()) internal set override var mute: ComposeColor by mutableStateOf(mute, structuralEqualityPolicy()) internal set override var pressed: ComposeColor by mutableStateOf(pressed, structuralEqualityPolicy()) internal set override var alt: ComposeColor by mutableStateOf(alt, structuralEqualityPolicy()) internal set fun copy(…) }

Slide 58

Slide 58 text

Andromeda Foundation - Primary Fill Colors @Stable class PrimaryColors( background: ComposeColor, active: ComposeColor, error: ComposeColor, mute: ComposeColor, pressed: ComposeColor, alt: ComposeColor ) : FillColors { override var background: ComposeColor by mutableStateOf(background, structuralEqualityPolicy()) internal set override var active: ComposeColor by mutableStateOf(active, structuralEqualityPolicy()) internal set override var error: ComposeColor by mutableStateOf(error, structuralEqualityPolicy()) internal set override var mute: ComposeColor by mutableStateOf(mute, structuralEqualityPolicy()) internal set override var pressed: ComposeColor by mutableStateOf(pressed, structuralEqualityPolicy()) internal set override var alt: ComposeColor by mutableStateOf(alt, structuralEqualityPolicy()) internal set fun copy(…) }

Slide 59

Slide 59 text

Andromeda Foundation - Primary Fill Colors @Stable class PrimaryColors( background: ComposeColor, active: ComposeColor, error: ComposeColor, mute: ComposeColor, pressed: ComposeColor, alt: ComposeColor ) : FillColors { override var background: ComposeColor by mutableStateOf(background, structuralEqualityPolicy()) internal set override var active: ComposeColor by mutableStateOf(active, structuralEqualityPolicy()) internal set override var error: ComposeColor by mutableStateOf(error, structuralEqualityPolicy()) internal set override var mute: ComposeColor by mutableStateOf(mute, structuralEqualityPolicy()) internal set override var pressed: ComposeColor by mutableStateOf(pressed, structuralEqualityPolicy()) internal set override var alt: ComposeColor by mutableStateOf(alt, structuralEqualityPolicy()) internal set fun copy(…) }

Slide 60

Slide 60 text

Andromeda Foundation - Secondary Colors @Stable class SecondaryColors( background: ComposeColor, active: ComposeColor, error: ComposeColor, mute: ComposeColor, pressed: ComposeColor, alt: ComposeColor ) : FillColors { override var background: ComposeColor by mutableStateOf(background, structuralEqualityPolicy()) internal set override var active: ComposeColor by mutableStateOf(active, structuralEqualityPolicy()) internal set override var error: ComposeColor by mutableStateOf(error, structuralEqualityPolicy()) internal set override var mute: ComposeColor by mutableStateOf(mute, structuralEqualityPolicy()) internal set override var pressed: ComposeColor by mutableStateOf(pressed, structuralEqualityPolicy()) internal set override var alt: ComposeColor by mutableStateOf(alt, structuralEqualityPolicy()) internal set fun copy() }

Slide 61

Slide 61 text

Andromeda Foundation - Content Colors @Stable class ContentColors( normal: ComposeColor, minor: ComposeColor, subtle: ComposeColor, disabled: ComposeColor, ) { var normal: ComposeColor by mutableStateOf(normal, structuralEqualityPolicy()) internal set var minor: ComposeColor by mutableStateOf(minor, structuralEqualityPolicy()) internal set var subtle: ComposeColor by mutableStateOf(subtle, structuralEqualityPolicy()) internal set var disabled: ComposeColor by mutableStateOf(disabled, structuralEqualityPolicy()) internal set fun copy() : ContentColors }

Slide 62

Slide 62 text

fun customLightColors( primaryColors: PrimaryColors = customPrimaryLightColors(), secondaryColors: SecondaryColors = customSecondaryLightColors(), tertiaryColors: TertiaryColors = customTertiaryLightColors(), borderColors: BorderColors = customBorderLightColors(), iconColors: IconColors = customtIconsLightColors(), contentColors: ContentColors = customContentLightColors() ) : AndromedaColors = AndromedaColors( primaryColors = primaryColors, secondaryColors = secondaryColors, tertiaryColors = tertiaryColors, borderColors = borderColors, iconColors = iconColors, contentColors = contentColors, isDark = false ) Andromeda Foundation - Colors

Slide 63

Slide 63 text

fun customLightColors( primaryColors: PrimaryColors = customPrimaryLightColors(), secondaryColors: SecondaryColors = customSecondaryLightColors(), tertiaryColors: TertiaryColors = customTertiaryLightColors(), borderColors: BorderColors = customBorderLightColors(), iconColors: IconColors = customtIconsLightColors(), contentColors: ContentColors = customContentLightColors() ) : AndromedaColors = AndromedaColors( primaryColors = primaryColors, secondaryColors = secondaryColors, tertiaryColors = tertiaryColors, borderColors = borderColors, iconColors = iconColors, contentColors = contentColors, isDark = false ) Andromeda Foundation - Colors

Slide 64

Slide 64 text

64 Typography

Slide 65

Slide 65 text

Andromeda - Common typography styles library with consistent specs. Typography

Slide 66

Slide 66 text

val AndromedaFonts = FontFamily( Font(R.font.andromeda_black, FontWeight.Black), Font(R.font.andromeda_bold, FontWeight.Bold), Font(R.font.andromeda_extrabold, FontWeight.ExtraBold), Font(R.font.andromeda_light, FontWeight.Light), Font(R.font.andromeda_medium, FontWeight.Medium), Font(R.font.andromeda_regular, FontWeight.W400), Font(R.font.andromeda_semibold, FontWeight.SemiBold), Font(R.font.andromeda_thin, FontWeight.Thin) ) Andromeda Foundation - Fonts

Slide 67

Slide 67 text

/** * Contains all the typography we provide for our components. * * / class AndromedaTypography( val titleHeroTextStyle: TextStyle, val titleModerateBoldTextStyle: TextStyle, val titleModerateDemiTextStyle: TextStyle, val titleSmallDemiTextStyle: TextStyle, val bodyModerateDefaultTypographyStyle: TextStyle, val bodySmallDefaultTypographyStyle: TextStyle, val captionModerateBookDefaultTypographyStyle: TextStyle, val captionModerateDemiDefaultTypographyStyle: TextStyle ) Andromeda Foundation - Text Styles

Slide 68

Slide 68 text

/** * Builds the default typography set for our theme. * * / @Composable fun textStyles(fontFamily: FontFamily) : AndromedaTypography { return AndromedaTypography( titleHeroTextStyle = TitleHeroTypographyStyle(fontFamily) .getComposeTextStyle(), titleModerateBoldTextStyle = TitleModerateBoldTypographyStyle(fontFamily) .getComposeTextStyle(), titleModerateDemiTextStyle = TitleModerateDemiTypographyStyle(fontFamily) .getComposeTextStyle(), titleSmallDemiTextStyle = TitleSmallDemiTypographyStyle(fontFamily) .getComposeTextStyle(), bodyModerateDefaultTypographyStyle = BodyModerateTypographyStyle(fontFamily) .getComposeTextStyle(), bodySmallDefaultTypographyStyle = BodySmallTypographyStyle(fontFamily) .getComposeTextStyle(), captionModerateBookDefaultTypographyStyle = CaptionModerateBookTypographyStyle(fontFamily) .getComposeTextStyle(), captionModerateDemiDefaultTypographyStyle = CaptionModerateDemiTypographyStyle(fontFamily) .getComposeTextStyle() ) } Andromeda Foundation - Text Styles

Slide 69

Slide 69 text

/** * Builds the default typography set for our theme. * * / @Composable fun textStyles(fontFamily: FontFamily) : AndromedaTypography { return AndromedaTypography( titleHeroTextStyle = TitleHeroTypographyStyle(fontFamily) .getComposeTextStyle(), titleModerateBoldTextStyle = TitleModerateBoldTypographyStyle(fontFamily) .getComposeTextStyle(), titleModerateDemiTextStyle = TitleModerateDemiTypographyStyle(fontFamily) .getComposeTextStyle(), titleSmallDemiTextStyle = TitleSmallDemiTypographyStyle(fontFamily) .getComposeTextStyle(), bodyModerateDefaultTypographyStyle = BodyModerateTypographyStyle(fontFamily) .getComposeTextStyle(), bodySmallDefaultTypographyStyle = BodySmallTypographyStyle(fontFamily) .getComposeTextStyle(), captionModerateBookDefaultTypographyStyle = CaptionModerateBookTypographyStyle(fontFamily) .getComposeTextStyle(), captionModerateDemiDefaultTypographyStyle = CaptionModerateDemiTypographyStyle(fontFamily) .getComposeTextStyle() ) } Andromeda Foundation - Text Styles

Slide 70

Slide 70 text

interface BaseTypography { val fontFamily: FontFamily val fontSize: TextUnit val fontWeight: FontWeight val lineHeight: TextUnit } Andromeda Foundation - Typography

Slide 71

Slide 71 text

private fun toTextStyle(typographyStyle: BaseTypography) : TextStyle { return TextStyle( fontSize = typographyStyle.fontSize, fontFamily = typographyStyle.fontFamily, lineHeight = typographyStyle.lineHeight, fontWeight = typographyStyle.fontWeight, ) } fun BaseTypography.getComposeTextStyle() : TextStyle { return toTextStyle(this) } internal val LocalTypography = compositionLocalOf { error( "No typography provided! Make sure to wrap all usages of components in a " + "AndromedaTheme." ) } Andromeda Foundation - Text Styles

Slide 72

Slide 72 text

private fun toTextStyle(typographyStyle: BaseTypography) : TextStyle { return TextStyle( fontSize = typographyStyle.fontSize, fontFamily = typographyStyle.fontFamily, lineHeight = typographyStyle.lineHeight, fontWeight = typographyStyle.fontWeight, ) } fun BaseTypography.getComposeTextStyle() : TextStyle { return toTextStyle(this) } internal val LocalTypography = compositionLocalOf { error( "No typography provided! Make sure to wrap all usages of components in a " + "AndromedaTheme." ) } Andromeda Foundation - Text Styles

Slide 73

Slide 73 text

private fun toTextStyle(typographyStyle: BaseTypography) : TextStyle { return TextStyle( fontSize = typographyStyle.fontSize, fontFamily = typographyStyle.fontFamily, lineHeight = typographyStyle.lineHeight, fontWeight = typographyStyle.fontWeight, ) } fun BaseTypography.getComposeTextStyle() : TextStyle { return toTextStyle(this) } internal val LocalTypography = compositionLocalOf { error( "No typography provided! Make sure to wrap all usages of components in a " + "AndromedaTheme." ) } Andromeda Foundation - Text Styles

Slide 74

Slide 74 text

private fun toTextStyle(typographyStyle: BaseTypography) : TextStyle { return TextStyle( fontSize = typographyStyle.fontSize, fontFamily = typographyStyle.fontFamily, lineHeight = typographyStyle.lineHeight, fontWeight = typographyStyle.fontWeight, ) } fun BaseTypography.getComposeTextStyle() : TextStyle { return toTextStyle(this) } internal val LocalTypography = compositionLocalOf { error( "No typography provided! Make sure to wrap all usages of components in a " + "AndromedaTheme." ) } Andromeda Foundation - Text Styles

Slide 75

Slide 75 text

AndromedaTheme - typography provider /** * Useful static object to access currently conf i gured Theme properties. * / object AndromedaTheme { /** * These represent the default ease - of - use accessors for colors, typography. * * / public val colors: AndromedaColors @Composable @ReadOnlyComposable get() = LocalColors.current public val typography: AndromedaTypography @Composable @ReadOnlyComposable get() = LocalTypography.current public val shapes: AndromedaShapes @Composable @ReadOnlyComposable get() = LocalShapes.current }

Slide 76

Slide 76 text

76 Building blocks 
 & Components

Slide 77

Slide 77 text

Andromeda - Icons Crafted Icons with general use

Slide 78

Slide 78 text

Icons @Composable public fun Icon( painter: Painter, contentDescription: String?, modif i er: Modif i er = Modif i er, onClick: IconClickHandler? = null, emphasis: ContentEmphasis = LocalContentEmphasis.current, tint: Color = AndromedaTheme.colors.contentColors.normal.applyEmphasis(emphasis), ) { val colorFilter = if (tint = = Color.Unspecif i ed) null else ColorFilter.tint(tint) val semantics = if (contentDescription ! = null) { Modif i er.semantics { this.contentDescription = contentDescription this.role = Role.Image } } else { Modif i er } val iconClickRipple = rememberRipple(

Slide 79

Slide 79 text

Icons @Composable public fun Icon( painter: Painter, contentDescription: String?, modif i er: Modif i er = Modif i er, onClick: IconClickHandler? = null, emphasis: ContentEmphasis = LocalContentEmphasis.current, tint: Color = AndromedaTheme.colors.contentColors.normal.applyEmphasis(emphasis), ) { . . . } @Composable public fun Icon( painter: Painter, contentDescription: String?, modif onClick: IconClickHandler? = null, emphasis: ContentEmphasis = LocalContentEmphasis.current, tint: Color = AndromedaTheme.colors.contentColors.normal.applyEmphasis(emphasis), ) { val colorFilter = if (tint val semantics = if (contentDescription Modif this.contentDescription = contentDescription this.role = Role.Image } } else { Modif }

Slide 80

Slide 80 text

Icons @Composable public fun Icon( painter: Painter, contentDescription: String?, modif i er: Modif i er = Modif i er, onClick: IconClickHandler? = null, emphasis: ContentEmphasis = LocalContentEmphasis.current, tint: Color = AndromedaTheme.colors.contentColors.normal.applyEmphasis(emphasis), ) { . . . }

Slide 81

Slide 81 text

Icons @Composable public fun Icon( painter: Painter, contentDescription: String?, modif i er: Modif i er = Modif i er, onClick: IconClickHandler? = null, emphasis: ContentEmphasis = LocalContentEmphasis.current, tint: Color = AndromedaTheme.colors.contentColors.normal.applyEmphasis(emphasis), ) { . . . }

Slide 82

Slide 82 text

Icons @Composable public fun Icon( . . ) { val colorFilter = if (tint = = Color.Unspecif i ed) null else ColorFilter.tint(tint) val semantics = if (contentDescription ! = null) { Modif i er.semantics { this.contentDescription = contentDescription this.role = Role.Image } } else { Modif i er } . . . }

Slide 83

Slide 83 text

Icons @Composable public fun Icon( . . ) { val colorFilter = if (tint = = Color.Unspecif i ed) null else ColorFilter.tint(tint) val semantics = if (contentDescription ! = null) { Modif i er.semantics { this.contentDescription = contentDescription this.role = Role.Image } } else { Modif i er } . . . }

Slide 84

Slide 84 text

Andromeda - Buttons Design and code synced reusable components 
 
 Bu tt ons are vital for almost every screen.

Slide 85

Slide 85 text

Buttons @Composable fun Button( onClick: () - > Unit, modif i er: Modif i er = Modif i er, backgroundColor: ComposeColor = AndromedaTheme.colors.primaryColors.active, contentColor: ComposeColor = contentColorFor(backgroundColor = backgroundColor), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, elevation: ButtonElevation = ButtonDefaults.elevation(), shape: Shape = AndromedaTheme.shapes.small, border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() - > Unit ) { Surface( modif i er = modif i er, shape = shape, color = backgroundColor, contentColor = contentColor, border = border,

Slide 86

Slide 86 text

Buttons @Composable fun Button( onClick: () - > Unit, modif i er: Modif i er = Modif i er, backgroundColor: ComposeColor = AndromedaTheme.colors.primaryColors.active, contentColor: ComposeColor = contentColorFor(backgroundColor = backgroundColor), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, elevation: ButtonElevation = ButtonDefaults.elevation(), shape: Shape = AndromedaTheme.shapes.small, border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() - > Unit ) { . . . } @Composable fun Button( onClick: () modif backgroundColor: ComposeColor = AndromedaTheme.colors.primaryColors.active, contentColor: ComposeColor = contentColorFor(backgroundColor = backgroundColor), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, elevation: ButtonElevation = ButtonDefaults.elevation(), shape: Shape = AndromedaTheme.shapes.small, border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() ) { Surface( modif shape = shape, color = backgroundColor, contentColor = contentColor, border = border,

Slide 87

Slide 87 text

Buttons @Composable fun Button( onClick: () - > Unit, modif i er: Modif i er = Modif i er, backgroundColor: ComposeColor = AndromedaTheme.colors.primaryColors.active, contentColor: ComposeColor = contentColorFor(backgroundColor = backgroundColor), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, elevation: ButtonElevation = ButtonDefaults.elevation(), shape: Shape = AndromedaTheme.shapes.small, border: BorderStroke? = null, contentPadding: PaddingValues = ButtonDefaults.ContentPadding, content: @Composable RowScope.() - > Unit ) { . . . }

Slide 88

Slide 88 text

ButtonsDefaults public object ButtonDefaults { private val ButtonHorizontalPadding = 16.dp private val ButtonVerticalPadding = 8.dp public val ContentPadding: PaddingValues = PaddingValues( horizontal = ButtonHorizontalPadding, vertical = ButtonVerticalPadding ) public val MinWidth: Dp = 64.dp public val MinHeight: Dp = 44.dp @Composable public fun elevation( defaultElevation: Dp = 2.dp,

Slide 89

Slide 89 text

ButtonsDefaults private val ButtonHorizontalPadding = 16.dp private val ButtonVerticalPadding = 8.dp public val ContentPadding: PaddingValues = PaddingValues( horizontal = ButtonHorizontalPadding, vertical = ButtonVerticalPadding ) public val MinWidth: Dp = 64.dp public val MinHeight: Dp = 44.dp @Composable public fun elevation( defaultElevation: Dp = 2.dp, pressedElevation: Dp = 8.dp, / / focused: Dp = 4.dp, / / hovered: Dp = 4.dp, disabledElevation: Dp = 0.dp ) : ButtonElevation { return remember(defaultElevation, pressedElevation, disabledElevation) { DefaultButtonElevation( defaultElevation = defaultElevation, pressedElevation = pressedElevation, disabledElevation = disabledElevation ) } } }

Slide 90

Slide 90 text

Elevation @Stable interface ButtonElevation { /** * Contract to help build Button Elevation based on button's [enabled] and [interactionSource]. * * @param enabled - to decide if button is enabled. * @param interactionSource - [InteractionSource] for the given button. * / @Composable fun elevation(enabled: Boolean, interactionSource: InteractionSource) : State }

Slide 91

Slide 91 text

import androidx.compose.foundation.shape.CornerBasedShape import androidx.compose.ui.graphics.Shape interface BasicShapes { val small: CornerBasedShape val normal: CornerBasedShape val large: CornerBasedShape } interface AndromedaShapes : BasicShapes { val bottomSheet: Shape val buttonShape: Shape val dialogShape: Shape } Andromeda - Shapes

Slide 92

Slide 92 text

public class DefaultShapes( override val bottomSheet: Shape, override val buttonShape: Shape, override val dialogShape: Shape, override val small: CornerBasedShape, override val normal: CornerBasedShape, override val large: CornerBasedShape, ) : AndromedaShapes { public companion object { public val default: AndromedaShapes = DefaultShapes( bottomSheet = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), buttonShape = RoundedCornerShape(8.dp), dialogShape = RoundedCornerShape(8.dp), small = RoundedCornerShape(4.dp), normal = RoundedCornerShape(6.dp), large = RoundedCornerShape(12.dp), ) } } /** * Local providers for shapes in [AndromedaTheme]. * * / internal val LocalShapes = compositionLocalOf { error( "No shapes provided! Make sure to wrap all usages of Andromeda components in a " + "AndromedaTheme." ) } Andromeda - Shapes

Slide 93

Slide 93 text

object AndromedaTheme { /** * These represent the default ease - of - use accessors for colors, typography. * * / public val colors: AndromedaColors @Composable @ReadOnlyComposable get() = LocalColors.current public val typography: AndromedaTypography @Composable @ReadOnlyComposable get() = LocalTypography.current public val shapes: AndromedaShapes @Composable @ReadOnlyComposable get() = LocalShapes.current } Andromeda - Shapes

Slide 94

Slide 94 text

94 Code structure

Slide 95

Slide 95 text

setContent { ProvideWindowInsets { var isLightTheme by remember { mutableStateOf(true) } CircularReveal( targetState = isLightTheme, animationSpec = tween(2500) ) { localTheme - > CatalogTheme(isLightTheme = localTheme) { NavGraph( onToggleTheme = { isLightTheme = !isLightTheme }, ) } } } } Andromeda - Result

Slide 96

Slide 96 text

setContent { ProvideWindowInsets { var isLightTheme by remember { mutableStateOf(true) } CircularReveal( targetState = isLightTheme, animationSpec = tween(2500) ) { localTheme - > CatalogTheme(isLightTheme = localTheme) { NavGraph( onToggleTheme = { isLightTheme = !isLightTheme }, ) } } } } Andromeda - Result

Slide 97

Slide 97 text

@Composable fun CatalogTheme( isLightTheme: Boolean = true, content: @Composable () - > Unit ) { AndromedaTheme( colors = if (isLightTheme) defaultLightColors() else defaultDarkColors(), fontFamily = CatalogAppFonts ) { content() } } val CatalogAppFonts = FontFamily( Font(R.font.catalog_black, FontWeight.Black), Font(R.font.catalog_bold, FontWeight.Bold), Font(R.font.catalog_extrabold, FontWeight.ExtraBold), Font(R.font.catalog_extralight, FontWeight.Light), Font(R.font.catalog_medium, FontWeight.Medium), Font(R.font.catalog_regular, FontWeight.W400), Font(R.font.catalog_semibold, FontWeight.SemiBold), Font(R.font.catalog_thin, FontWeight.Thin) ) Andromeda - Custom Theme extended

Slide 98

Slide 98 text

98 Results

Slide 99

Slide 99 text

99 Runtime UI Foundation Material Design Results

Slide 100

Slide 100 text

100 Runtime UI Foundation Material Design Results Our Design System

Slide 101

Slide 101 text

Check out https://github.com/aldefy/Andromeda 
 https://bit.ly/3Nic0JF - Sample catalog app 
 
 Andromeda is an open-source Jetpack Compose design system. A collection of guidelines and components can be used to create amazing compose app user experiences. Foundations introduce Andromeda tokens and principles while Components provide the bolts and nuts that make Andromeda Compose wrapped apps tick.

Slide 102

Slide 102 text

102 Tips Just do it Scope appropriately Iterate Make it usable Keep it lean Encourage whole-team ownership

Slide 103

Slide 103 text

103

Slide 104

Slide 104 text

https:/ /plasterdesignsystem.com https:/ /github.com/Skyscanner/backpack-android https:/ /github.com/alexpate/awesome- design-systems Examples

Slide 105

Slide 105 text

GOAT- http:/ /bit.ly/3FkrYjA https:/ /airbnb.design/ https:/ /www.kickstartds.com - Starter pack https:/ /mobile.ant.design/ https:/ /thedesignsystem.guide/ Examples

Slide 106

Slide 106 text

Thats all folks! https://linktr.ee/aldefy