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

Jetpack Compose — Next Gen Kotlin UI Toolkit for Android

Jetpack Compose — Next Gen Kotlin UI Toolkit for Android

https://info.jetbrains.com/kotlin-everywhere-bangalore-2019.html

The Android UI toolkit's API surface has remained the same for the past decade. With applications and UI becoming more and more demanding, we need a new programming model to handle this complexity. With Kotlin bringing in DSLs, functional programming, and compiler plugin capabilities - the Android UI Toolkit team is taking a new direction with Jetpack Compose.

This shift in API design also demands a shift in thinking about UI and app architecture. In this talk, we’ll see how Jetpack Compose is radically different from the existing Android UI framework and look at various examples to build reactive Android apps.

Ragunath Jawahar

June 22, 2019
Tweet

More Decks by Ragunath Jawahar

Other Decks in Programming

Transcript

  1. • Unbundled UI Toolkit • React, Litho, Vue.js & Flutter

    • Declarative • Composition over inheritance • Kotlin only • “Pre-Alpha” ⛔
  2. FRAMEWORKS ARE NOT TOOLS FOR ORGANISING YOUR CODE, THEY ARE

    TOOLS FOR ORGANISING YOUR MIND – Rick Hickey
  3. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  4. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  5. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  6. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  7. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  8. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  9. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  10. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  11. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  12. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  13. // Android framework val textView = TextView(context) println(textView=>class.java) // AB

    android.widget.TextView // Jetpack Compose val text = Text(text = "Hello World!") println(text=>class.java) // AB kotlin.Unit No more reference to views
  14. @Composable fun Text( text: String, style: TextStyle? = null, textAlign:

    TextAlign = DefaultTextAlign, // More parameters… ) { // More code… } Composable functions
  15. @Composable fun Text( text: String, style: TextStyle? = null, textAlign:

    TextAlign = DefaultTextAlign, // More parameters… ) { // More code… } Composable functions
  16. @Composable fun Text( text: String, style: TextStyle? = null, textAlign:

    TextAlign = DefaultTextAlign, // More parameters… ) { // More code… } Composable functions
  17. @Composable fun Text( text: String, style: TextStyle? = null, textAlign:

    TextAlign = DefaultTextAlign, // More parameters… ) { // More code… } Composable functions
  18. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  19. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  20. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  21. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  22. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  23. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  24. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  25. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  26. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  27. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  28. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  29. @Model data class Fruit( val name: String, val price: Double

    = 2.0, var quantity: Int = 0 ) { val totalPrice: Double get() = quantity * price }
  30. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  31. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  32. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  33. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  34. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  35. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  36. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  37. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  38. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  39. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  40. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  41. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  42. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  43. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  44. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  45. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  46. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  47. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  48. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  49. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  50. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  51. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  52. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  53. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  54. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  55. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  56. @Composable fun Stepper(count: Int, onCountChange: (Int) ^> Unit) { val

    onRemoveOne = { onCountChange(count - 1) } val onAddOne = { onCountChange(count + 1) } Row { Button(text = "-", onClick = if (count > 0) onRemoveOne else null) WidthSpacer(8.dp) Container(width = 24.dp) { Text(text = "$count", style = +themeTextStyle { body1 }) } WidthSpacer(8.dp) Button(text = "+", onClick = onAddOne) } }
  57. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  58. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  59. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  60. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  61. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  62. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  63. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  64. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  65. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  66. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  67. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  68. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  69. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  70. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  71. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  72. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  73. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  74. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  75. @Composable fun FruitRow(fruit: Fruit) { Padding(padding = EdgeInsets(left = 16.dp,

    right = 16.dp)) { FlexRow { expanded(1.0f) { Text(text = "${fruit.name} ($${fruit.totalPrice})", style = +themeTextStyle { h6 }) } inflexible { Stepper(fruit.quantity, onCountChange = { fruit.quantity = it }) } } } }
  76. Future • Increased productivity • Higher-level of abstraction • Wider

    use of existing of skillset • Collaboration • Design • Product • Other platforms?