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

Introducing Jetpack Compose into your existing app

Introducing Jetpack Compose into your existing app

In this talk I am explaining how to introduce Jetpack Compose into your existing app by following those steps:
- Theme
- Components
- Interop (with the old UI Toolkit)
- Full Screens
- Navigation

Alexander Gherschon

July 18, 2022
Tweet

More Decks by Alexander Gherschon

Other Decks in Programming

Transcript

  1. INTRODUCING JETPACK COMPOSE
    INTO YOUR EXISTING APP
    Alexander Gherschon

    Android Tech Lead @ ONE ZERO Digital Bank

    View full-size slide

  2. TIMELINE
    Theme

    View full-size slide

  3. TIMELINE
    Components
    Theme

    View full-size slide

  4. TIMELINE
    Interop
    Components
    Theme

    View full-size slide

  5. TIMELINE
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  6. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  7. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  8. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  9. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  10. DEFINING OUR THEME

    View full-size slide

  11. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  12. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  13. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  14. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  15. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  16. THEME - DEFINING
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  17. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }

    View full-size slide

  18. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }

    View full-size slide

  19. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }

    View full-size slide

  20. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }

    View full-size slide

  21. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }

    View full-size slide

  22. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  23. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  24. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  25. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  26. THEME - USAGE
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  27. THEME - HOW DOES THIS WORK?
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
    IntroducingComposeTheme {
    GreetingScreen()
    }
    }
    }
    }
    @Composable
    fun GreetingScreen() {
    Surface(
    modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize(),
    color = MaterialTheme.colors.primary
    ) {
    Text(text = "Hello KotlinTLV!")
    }
    }

    View full-size slide

  28. A LOOK AT MATERIAL THEME

    View full-size slide

  29. THEME - MATERIAL THEME
    @Composable
    fun IntroducingComposeTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    val colors = if (darkTheme) DarkColorPalette else LightColorPalette
    MaterialTheme(
    colors = colors,
    typography = Typography,
    shapes = Shapes,
    content = content
    )
    }

    View full-size slide

  30. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }

    View full-size slide

  31. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }

    View full-size slide

  32. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }

    View full-size slide

  33. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }

    View full-size slide

  34. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }

    View full-size slide

  35. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }

    View full-size slide

  36. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }
    internal val LocalColors = staticCompositionLocalOf {
    error("LocalColors was not provided")
    }

    View full-size slide

  37. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }
    internal val LocalColors = staticCompositionLocalOf {
    error("LocalColors was not provided")
    }

    View full-size slide

  38. THEME - MATERIAL THEME
    @Composable
    fun MaterialTheme(
    colors: Colors = MaterialTheme.colors,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    content: @Composable () -> Unit
    ) {
    CompositionLocalProvider(
    LocalColors provides colors,
    // more provided compositionLocals
    content = content
    )
    }
    object MaterialTheme {
    val colors: Colors
    @Composable
    @ReadOnlyComposable
    get() = LocalColors.current
    val typography: Typography
    // same
    val shapes: Shapes
    // same
    }
    internal val LocalColors = staticCompositionLocalOf {
    error("LocalColors was not provided")
    }

    View full-size slide

  39. THEME - COMPOSITIONLOCALS

    View full-size slide

  40. FULLY-CUSTOM THEME

    View full-size slide

  41. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  42. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  43. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  44. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  45. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  46. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  47. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  48. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }

    View full-size slide

  49. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }
    object OZTheme {
    val isDarkMode: Boolean
    @Composable get() = LocalIsDarkMode.current
    val isGeneralMode: Boolean
    @Composable get() = LocalIsGeneralMode.current
    val colors: OZColors
    @Composable get() = LocalOZColors.current
    val generalColors: OZGeneralColors
    @Composable get() = LocalOZGeneralColors.current
    val typography: OZTypography
    @Composable get() = LocalOZTypography.current
    val shapes: OZShapes
    @Composable get() = LocalOZShapes.current
    }

    View full-size slide

  50. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }
    object OZTheme {
    val isDarkMode: Boolean
    @Composable get() = LocalIsDarkMode.current
    val isGeneralMode: Boolean
    @Composable get() = LocalIsGeneralMode.current
    val colors: OZColors
    @Composable get() = LocalOZColors.current
    val generalColors: OZGeneralColors
    @Composable get() = LocalOZGeneralColors.current
    val typography: OZTypography
    @Composable get() = LocalOZTypography.current
    val shapes: OZShapes
    @Composable get() = LocalOZShapes.current
    }

    View full-size slide

  51. THEME - FULLY-CUSTOM THEME
    @Composable
    fun OZTheme(
    isDarkMode: Boolean = isSystemInDarkTheme(),
    isGeneralMode: Boolean = false,
    content: @Composable () -> Unit,
    ) {
    val colors = if (isDarkMode) ozDarkColors else ozLightColors
    val generalColors = ozGeneralColors
    val typography = OZTypography()
    val shapes = OZShapes()
    CompositionLocalProvider(
    LocalOZColors provides colors,
    LocalOZGeneralColors provides generalColors,
    LocalOZTypography provides typography,
    LocalOZShapes provides shapes,
    LocalIsDarkMode provides isDarkMode,
    LocalIsGeneralMode provides isGeneralMode,
    content = content
    )
    }
    object OZTheme {
    val isDarkMode: Boolean
    @Composable get() = LocalIsDarkMode.current
    val isGeneralMode: Boolean
    @Composable get() = LocalIsGeneralMode.current
    val colors: OZColors
    @Composable get() = LocalOZColors.current
    val generalColors: OZGeneralColors
    @Composable get() = LocalOZGeneralColors.current
    val typography: OZTypography
    @Composable get() = LocalOZTypography.current
    val shapes: OZShapes
    @Composable get() = LocalOZShapes.current
    }

    View full-size slide

  52. THEME - CONCLUSION
    • Use Material Theme as your Design System if it’s enough for you
    • Have your designers build your brand aka Design System
    • Translate Your Design System into your own Fully Custom Theme

    View full-size slide

  53. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme
    Questions?

    View full-size slide

  54. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  55. BUILDING A COMPONENT

    View full-size slide

  56. COMPONENTS - STEP PROGRESS BAR

    View full-size slide

  57. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  58. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  59. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  60. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  61. COMPONENTS - STEP PROGRESS BAR
    enum class StepProgressBarVariant(
    val completedStepColor: Color,
    val unCompletedStepColor: Color,
    ) {
    Regular(
    completedStepColor = OZTheme.colors.buttonsPrimaryRegular,
    unCompletedStepColor = OZTheme.colors.systemGrayGray5
    ),
    }

    View full-size slide

  62. COMPONENTS - STEP PROGRESS BAR
    enum class StepProgressBarVariant(
    val completedStepColor: Color,
    val unCompletedStepColor: Color,
    ) {
    Regular(
    completedStepColor = OZTheme.colors.buttonsPrimaryRegular,
    unCompletedStepColor = OZTheme.colors.systemGrayGray5
    ),
    }
    Looks good?

    View full-size slide

  63. COMPONENTS - STEP PROGRESS BAR
    enum class StepProgressBarVariant(
    val completedStepColor: Color,
    val unCompletedStepColor: Color,
    ) {
    Regular(
    completedStepColor = OZTheme.colors.buttonsPrimaryRegular,
    unCompletedStepColor = OZTheme.colors.systemGrayGray5
    ),
    }
    Looks good, but doesn’t work

    View full-size slide

  64. COMPONENTS - STEP PROGRESS BAR

    View full-size slide

  65. COMPONENTS - STEP PROGRESS BAR
    enum class StepProgressBarVariant(
    val completedStepColor: Color,
    val unCompletedStepColor: Color,
    ) {
    Regular(
    completedStepColor = OZTheme.colors.buttonsPrimaryRegular,
    unCompletedStepColor = OZTheme.colors.systemGrayGray5
    ),
    }
    HOW DO WE FIX THIS?

    View full-size slide

  66. COMPONENTS - STEP PROGRESS BAR
    enum class StepProgressBarVariant(
    val completedStepColor: @Composable () -> Color,
    val unCompletedStepColor: @Composable () -> Color,
    ) {
    Regular(
    completedStepColor = { OZTheme.colors.buttonsPrimaryRegular },
    unCompletedStepColor = { OZTheme.colors.systemGrayGray5 }
    ),
    }

    View full-size slide

  67. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  68. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  69. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun StepProgressBar(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    variant: StepProgressBarVariant = StepProgressBarVariant.Regular,
    numberOfSteps: Int,
    currentStep: Int
    ) {
    // some code here
    }

    View full-size slide

  70. COMPONENTS - STEP PROGRESS BAR
    {
    Row(
    modi
    fi
    er = modi
    fi
    er
    .width(230.dp),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.Center,
    ) {
    // more code here
    }
    }

    View full-size slide

  71. COMPONENTS - STEP PROGRESS BAR
    {
    Row(
    modi
    fi
    er = modi
    fi
    er
    .width(230.dp),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.Center,
    ) {
    // more code here
    }
    }

    View full-size slide

  72. COMPONENTS - STEP PROGRESS BAR
    {
    Row(
    modi
    fi
    er = modi
    fi
    er
    .width(230.dp),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.Center,
    ) {
    // more code here
    }
    }

    View full-size slide

  73. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  74. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  75. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  76. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  77. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  78. COMPONENTS - STEP PROGRESS BAR
    for (step in 0 until numberOfSteps) {
    Step(
    completed = step < currentStep,
    completedColor = variant.completedStepColor(),
    unCompletedColor = variant.unCompletedStepColor(),
    modi
    fi
    er = Modi
    fi
    er
    .weight(1F),
    )
    if (step < numberOfSteps - 1) {
    Spacer(modi
    fi
    er = Modi
    fi
    er.width(5.dp))
    }
    }

    View full-size slide

  79. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  80. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  81. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  82. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  83. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  84. COMPONENTS - STEP PROGRESS BAR
    @Composable
    fun Step(
    modi
    fi
    er: Modi
    fi
    er = Modi
    fi
    er,
    completed: Boolean,
    completedColor: Color,
    unCompletedColor: Color
    ) {
    Divider(
    modi
    fi
    er = modi
    fi
    er
    .width(20.dp)
    .clip(OZTheme.shapes.cornerRadius50percent),
    color = if (completed) completedColor else unCompletedColor,
    thickness = 2.dp
    )
    }

    View full-size slide

  85. COMPONENTS - STEP PROGRESS BAR
    @Preview(name = "Step Progress Bar / Light Mode", showBackground = true, uiMode = Con
    fi
    guration.UI_MODE_NIGHT_NO)
    @Preview(name = "Step Progress Bar / Dark Mode", showBackground = true, uiMode = Con
    fi
    guration.UI_MODE_NIGHT_YES)
    @Composable
    fun StepProgressBarPreview() {
    OZTheme {
    StepProgressBar(numberOfSteps = 10, currentStep = 2)
    }
    }
    @Preview(name = "Step Progress Bar / General Mode", showBackground = true, uiMode = Con
    fi
    guration.UI_MODE_NIGHT_YES)
    @Composable
    fun StepProgressBarGeneralPreview() {
    OZTheme(isGeneralMode = true) {
    StepProgressBar(numberOfSteps = 6, currentStep = 3)
    }
    }

    View full-size slide

  86. COMPONENTS - STEP PROGRESS BAR

    View full-size slide

  87. COMPONENTS - TESTING
    https://github.com/cashapp/paparazzi

    View full-size slide

  88. COMPONENTS - TESTING
    class StepProgressBarViewTest {
    @get:Rule
    val paparazzi = Paparazzi(
    theme = "android:Theme.AppCompat",
    deviceCon
    fi
    g = DeviceCon
    fi
    g.NEXUS_5,
    )
    // screenshot tests here
    }

    View full-size slide

  89. COMPONENTS - TESTING
    class StepProgressBarViewTest {
    @get:Rule
    val paparazzi = Paparazzi(
    theme = "android:Theme.AppCompat",
    deviceCon
    fi
    g = DeviceCon
    fi
    g.NEXUS_5,
    )
    // screenshot tests here
    }

    View full-size slide

  90. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  91. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  92. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  93. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  94. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  95. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  96. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  97. COMPONENTS - TESTING
    @Test
    fun sixStepsTwoCompleted() {
    paparazzi.snapshot {
    OZTheme {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    modi
    fi
    er = Modi
    fi
    er
    .
    fi
    llMaxSize()
    .background(backgroundColor),
    ) {
    StepProgressBar(
    modi
    fi
    er = Modi
    fi
    er.background(componentBackgroundColor),
    numberOfSteps = 6,
    currentStep = 2,
    )
    }
    }
    }
    }

    View full-size slide

  98. COMPONENTS - TESTING
    ./gradlew recordPaparazziDebug

    View full-size slide

  99. COMPONENTS - TESTING
    ./gradlew verifyPaparazziDebug

    View full-size slide

  100. COMPONENTS - TESTING
    ./gradlew verifyPaparazziDebug

    View full-size slide

  101. COMPONENTS - TESTING
    ./gradlew verifyPaparazziDebug

    View full-size slide

  102. COMPONENTS - CONCLUSION
    • Translate design needs into the right parameters like a “Variant”
    • We can’t call something @Composable inside enums or classes but
    we can hold a Composable lambda
    • Use cashapp/paparazzi to screenshot-test your components

    View full-size slide

  103. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme
    Questions?

    View full-size slide

  104. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  105. USING COMPONENTS

    View full-size slide

  106. INTEROP - USING COMPONENTS

    View full-size slide

  107. INTEROP - USING COMPONENTS



    android:id="@+id/step_progress_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />


    View full-size slide

  108. INTEROP - USING COMPONENTS



    android:id="@+id/step_progress_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />


    View full-size slide

  109. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  110. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  111. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  112. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  113. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  114. INTEROP - USING COMPONENTS
    binding.stepProgressBar.setOZContent(forceLtr = false) {
    Column(
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
    ) {
    StepProgressBar(
    numberOfSteps = numberOfSteps,
    currentStep = currentStep
    )
    }
    }

    View full-size slide

  115. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  116. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  117. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  118. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  119. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  120. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  121. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  122. INTEROP - USING COMPONENTS
    fun ComposeView.setOZContent(
    forceLtr: Boolean = true,
    content: @Composable () -> Unit,
    ) {
    setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
    setContent {
    OZTheme {
    val direction = if (forceLtr) LayoutDirection.Ltr else LocalLayoutDirection.current
    CompositionLocalProvider(
    LocalLayoutDirection provides direction,
    content = content
    )
    }
    }
    }

    View full-size slide

  123. INTEROP - CONCLUSION
    • Build your helper functions to make it easy to use
    • Do not forget setViewCompositionStrategy()

    View full-size slide

  124. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme
    Questions?

    View full-size slide

  125. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  126. COMPOSE BASE FRAGMENTS

    View full-size slide

  127. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  128. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  129. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  130. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  131. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  132. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  133. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  134. FULL SCREENS - BASE FRAGMENTS
    abstract class ComposeFragment : Fragment() {
    protected open val isThemeInGeneralMode: Boolean = false
    override fun onCreateView(in
    fl
    ater: LayoutIn
    fl
    ater, c: ViewGroup?, sub: Bundle?): View? {
    return setOZContent(isThemeInGeneralMode) { ComposeContent() }
    }
    @Composable
    protected abstract fun ComposeContent()
    }

    View full-size slide

  135. USING BASE FRAGMENT

    View full-size slide

  136. FULL SCREENS - USING BASE FRAGMENT
    class SomeComposeFragment: ComposeFragment() {
    @Composable
    override fun ComposeContent() {
    TestComposeScreen()
    }
    }

    View full-size slide

  137. FULL SCREENS - USING BASE FRAGMENT
    class SomeComposeFragment: ComposeFragment() {
    @Composable
    override fun ComposeContent() {
    TestComposeScreen()
    }
    }

    View full-size slide

  138. FULL SCREENS - USING BASE FRAGMENT
    class SomeComposeFragment: ComposeFragment() {
    @Composable
    override fun ComposeContent() {
    TestComposeScreen()
    }
    }

    View full-size slide

  139. FULL SCREENS - USING BASE FRAGMENT
    class SomeComposeFragment: ComposeFragment() {
    @Composable
    override fun ComposeContent() {
    TestComposeScreen()
    }
    }

    View full-size slide

  140. FULL SCREENS - USING BASE FRAGMENT
    fun TestComposeScreen(testViewModel: TestMVIViewModel = viewModel()) {
    val uiState by testViewModel.uiState.collectAsState()
    Column(modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize()) {
    when (uiState) {
    TestUiState.Initial -> Text("Initial State")
    TestUiState.SecondState -> Text("Second State")
    }
    }
    }

    View full-size slide

  141. FULL SCREENS - USING BASE FRAGMENT
    fun TestComposeScreen(testViewModel: TestMVIViewModel = viewModel()) {
    val uiState by testViewModel.uiState.collectAsState()
    Column(modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize()) {
    when (uiState) {
    TestUiState.Initial -> Text("Initial State")
    TestUiState.SecondState -> Text("Second State")
    }
    }
    }

    View full-size slide

  142. FULL SCREENS - USING BASE FRAGMENT
    fun TestComposeScreen(testViewModel: TestMVIViewModel = viewModel()) {
    val uiState by testViewModel.uiState.collectAsState()
    Column(modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize()) {
    when (uiState) {
    TestUiState.Initial -> Text("Initial State")
    TestUiState.SecondState -> Text("Second State")
    }
    }
    }

    View full-size slide

  143. FULL SCREENS - USING BASE FRAGMENT
    fun TestComposeScreen(testViewModel: TestMVIViewModel = viewModel()) {
    val uiState by testViewModel.uiState.collectAsState()
    Column(modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize()) {
    when (uiState) {
    TestUiState.Initial -> Text("Initial State")
    TestUiState.SecondState -> Text("Second State")
    }
    }
    }

    View full-size slide

  144. FULL SCREENS - USING BASE FRAGMENT
    fun TestComposeScreen(testViewModel: TestMVIViewModel = viewModel()) {
    val uiState by testViewModel.uiState.collectAsState()
    Column(modi
    fi
    er = Modi
    fi
    er.
    fi
    llMaxSize()) {
    when (uiState) {
    TestUiState.Initial -> Text("Initial State")
    TestUiState.SecondState -> Text("Second State")
    }
    }
    }

    View full-size slide

  145. FULL SCREENS - USING BASE FRAGMENT
    class SomeComposeFragment: ComposeFragment() {
    @Composable
    override fun ComposeContent() {
    TestComposeScreen()
    }
    }

    View full-size slide

  146. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme
    Questions?

    View full-size slide

  147. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  148. NAVIGATION
    • Jetpack Navigation for Compose
    • Compose-destinations by Rafael Costa (1.3k stars on Github)
    • Voyager by Adiel Café (659 stars on Github)

    View full-size slide

  149. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme
    Questions?

    View full-size slide

  150. TIMELINE
    Navigation
    Full Screens
    Interop
    Components
    Theme

    View full-size slide

  151. THANK YOU!
    Alexander Gherschon

    Android Tech Lead @ ONE ZERO Digital Bank
    Blog - https://galex.co.il/
    Twitter - https://twitter.com/galex
    Github - https://github.com/galex
    Linkedin - https://www.linkedin.com/in/agherschon/

    View full-size slide