Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Migrating Your Design System to Jetpack Compose

Adam Bennett
November 25, 2020

Migrating Your Design System to Jetpack Compose

Jetpack Compose represents a paradigm shift in how Android developers approach building their UI, but how do you get started, and how do you transition a complex app - and your team - to this new model? In this talk, Adam discusses how Cuvva has approached this migration, the tools that are available, and offers practical advice on the steps to take in your team.

Adam Bennett

November 25, 2020
Tweet

More Decks by Adam Bennett

Other Decks in Programming

Transcript

  1. • What is a design system? • Planning your approach

    • How to migrate • Tips, tricks and advice
  2. A design system is a collection of reusable components, guided

    by clear standards, that can be assembled together to build any number of applications
  3. class ButtonView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) { enum class Mode { GO_ELEVATED, GO_ELEVATED_MUTED, SECONDARY_ELEVATED, SECONDARY_ELEVATED_MUTED, DESTRUCTIVE_ELEVATED, DESTRUCTIVE_ELEVATED_MUTED, GO_UNELEVATED, GO_UNELEVATED_MUTED, SECONDARY_UNELEVATED, SECONDARY_UNELEVATED_MUTED, DESTRUCTIVE_UNELEVATED, DESTRUCTIVE_UNELEVATED_MUTED, OUTLINED, TEXT } // ... }
  4. Planning your approach • Create a design app if you

    haven’t already • Get your team onboard
  5. Hack Day • A chance for everyone to finally explore

    Compose • Pool together learning resources • Spend the morning learning at your own speed • Spend the afternoon hacking • Show and tell the next day • Discuss pros, cons, likes and dislikes in the team • Credit to SnappMobile
  6. Planning your approach • Create a design app if you

    haven’t already • Get your team onboard! • Think about decoupling your components • Think about your data flow • Consider testing • Consider gathering metrics
  7. @Composable fun MyTheme( isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable ()

    -> Unit ) { val myColors = if (isDarkTheme) lightColors(...) else darkColors(...) MaterialTheme( colors = myColors, content = content, typography = Typography, shapes = Shapes ) }
  8. val lightPalette = lightColors( primary = // ..., primaryVariant =

    // ..., onPrimary = // ..., secondary = // ..., secondaryVariant = // ..., onSecondary = // ..., onSurface = // ..., onBackground = // ..., error = // ..., onError = // ... )
  9. val lightPalette = CuvvaColors( primaryFill = // ..., primaryFillFaded =

    // ..., secondaryFill = // ..., secondaryFillFaded = // ..., tertiaryFill = // ..., tertiaryFillFaded = // ..., surfaceFill = // ..., surfaceFillFaded = // ..., accentFill = // ..., accentFillFaded = // ..., blankFill = // ..., blankFillFaded = // ..., alertFill = // ..., alertFillFaded = // ..., // ... )
  10. @Composable fun MyTheme( isDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable ()

    -> Unit ) { val myColors = if (isDarkTheme) MyColors(...) else MyColors(…) MaterialTheme( colors = myColors, content = content, typography = Typography, shapes = Shapes ) }
  11. object CuvvaTheme { @Composable val colors: CuvvaColors get() = AmbientCuvvaColors.current

    } private val AmbientCuvvaColors = staticAmbientOf<CuvvaColors> { error("No CuvvaColors provided") }
  12. @Composable fun CuvvaTheme( content: @Composable () -> Unit ) {

    Providers(AmbientCuvvaColors provides semanticColors) { MaterialTheme( colors = debugColors(), content = content, ) } }
  13. <co.cuvva.design.title.sub.button.view.TitleSubButtonView android:id="@+id/help_button" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/divider" app:layout_constraintTop_toBottomOf="@id/resolve_payment" app:icon="@drawable/ic_phone_outline_24dp" app:mode="destructive" />

    <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/help_button" /> </androidx.constraintlayout.widget.ConstraintLayout>
  14. class SubscriptionView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null,

    defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr, defStyleRes) { // ... private val composeView by view<ComposeView>(R.id.compose_view) init { inflate(R.layout.view_subscription) composeView.setContent { CuvvaTheme { CardButton( // ... ) } } }
  15. class SimpleUiTest : ScreenshotTest { @get:Rule val composeTestRule = createComposeRule()

    @Test fun example_test() { composeTestRule.setContent { MyTheme { AndroidView(::MyButtonView) { button -> button.text = "Hello, world!" } } } compareScreenshot(composeRule) } }
  16. class SimpleUiTest : ScreenshotTest { @get:Rule val composeTestRule = createComposeRule()

    @Test fun example_test() { composeTestRule.setContent { MyTheme { MyButton(text = "Hello, world!") } } compareScreenshot(composeRule) } }
  17. class SimpleUiTest : ScreenshotTest { @get:Rule val composeTestRule = createComposeRule()

    @Test fun example_test_with_very_long_text() { composeTestRule.setContent { MyTheme { MyButton(text = "Hello, world! Are you still there?”) } } compareScreenshot(composeRule) } }
  18. data class CuvvaColors( val textColors: TextColors(...), val backgroundColors: BackgroundColors(...), //

    ... ) setContent { MyButton( text = "Hello, world!", backgroundColor = CuvvaTheme.colors.backgroundColors.primary, textColor = CuvvaTheme.colors.textColors.textOnSurface ) }
  19. @Composable fun PrimaryButton( text: String ) { MyButton( text =

    text, backgroundColor = CuvvaTheme.colors.backgroundColors.primary, textColor = CuvvaTheme.colors.textColors.textOnSurface ) } @Composable private fun MyButton( text: String, backgroundColor: Color, textColor: Color ) { Button(...) }
  20. • Worth investigating now - in parallel • Approach it

    with a plan • Use it to overhaul your design system
  21. • Still in the early stages • Learnt a lot

    about big migrations • We’re really enjoying it! • Expect more content from us • github.com/cuvva