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

Material 3 やめました / Good-bye M3 design system

Yuki Anzai
September 15, 2023

Material 3 やめました / Good-bye M3 design system

Yuki Anzai

September 15, 2023
Tweet

More Decks by Yuki Anzai

Other Decks in Technology

Transcript

  1. .BUFSJBM΍Ί·ͨ͠
    :VLJ"O[BJ !ZBO[N

    %SPJE,BJHJ
    Good-bye M3 design system

    View Slide

  2. :VLJ"O[BJ
    w (PPHMF%FWFMPQFS&YQFSUGPS"OESPJE
    w 9 UXJUUFS
    !ZBO[N
    w CMPHZBO[NCMPHTQPUDPN
    w V1IZDB*OD

    View Slide

  3. %SPJE,BJHJ

    View Slide

  4. (PPECZF
    .BUFSJBMEFTJHOTZTUFN

    View Slide

  5. Why
    What use instead of
    (PPECZF
    .BUFSJBMEFTJHOTZTUFN

    View Slide

  6. "HFOEB
    w 8IZ
    w 3FWJFX.BUFSJBM
    w 1BJOQPJOUPG.EFTJHOTZTUFN
    w *OTUFBEPG
    w )PXUPDSFBUFDVTUPNEFTJHOTZTUFN
    w )PXUPJNQMFNFOUDVTUPNEFTJHOTZTUFN

    View Slide

  7. 3FWJFX.BUFSJBM

    View Slide

  8. .BUFSJBM%FTJHO
    w BOBEBQUBCMFTZTUFNPGHVJEFMJOFT DPNQPOFOUT BOEUPPMTUIBU
    TVQQPSUUIFCFTUQSBDUJDFTPGVTFSJOUFSGBDFEFTJHO
    .BUFSJBM%FTJHO
    .

    ʙ
    .BUFSJBM%FTJHO
    .

    ʙ
    .BUFSJBM5IFNJOH
    .BUFSJBM$PNQPOFOUTJNQMFNFOUBUJPO
    .BUFSJBM%FTJHO
    .

    ʙ
    .BUFSJBM:PV
    %ZOBNJDDPMPS

    View Slide

  9. %FTJHO5PLFOT

    View Slide

  10. %FTJHO5PLFOT
    w "EFTJHOWBMVFEF
    fi
    OFEXJUIBOBNFBWBSJBCMFUIBUIPMETUIFEFTJHO
    WBMVF
    w 6TF%FTJHO5PLFOTBDSPTTEFTJHO DPEF UPPMT BOEQMBUGPSNT
    w 1MBUGPSNJOEFQFOEFOUGPSNBU
    w DBOCFBQQMJFEDPOTJTUFOUMZ
    w 1MBDFTUIBUSFGFSUPUIFTBNF%FTJHO5PLFOXJMMIBWFUIFTBNFWBMVF

    View Slide

  11. /BNFPG%FTJHO5PLFOT
    w "OBNFPGEFTJHOTZTUFN
    w #UZQFPG%FTJHO5PLFO
    w $BEFTDSJQUJWFOBNFUP
    DPNNVOJDBUFUIFUPLFO`T
    SPMF
    w TFQBSBUPS
    w MFGUˠSJHIU(FOFSBMJOGPSNBUJPOˠ4QFDJ
    fi
    DJOGPSNBUJPO

    View Slide

  12. 5ZQFTPG%FTJHO5PLFOT
    w 3FGFSFODF5PLFO
    w 4ZTUFN5PLFO
    w $PNQPOFOU5PLFO

    View Slide

  13. 3FGFSFODF5PLFO
    w "MMBWBJMBCMFUPLFOTXJUI
    BTTPDJBUFEWBMVFT
    w NESFG
    w %PFTOPUDIBOHFEFQFOEJOH
    PODPOUFYUT
    w DPOUFYUTFH
    EFWJDFGPSN
    GBDUPST EBSLUIFNF EQJ

    View Slide

  14. 4ZTUFN5PLFO
    w %FDJTJPOTBOESPMFTUIBUHJWF
    UIFEFTJHOTZTUFNJUT
    DIBSBDUFS
    w NETZT
    w 1PJOUTUPEJ
    ff
    FSFOU
    3FGFSFODF5PLFOT
    EFQFOEJOHPODPOUFYUT

    View Slide

  15. DPOUFYUTBXBSFUPLFO
    w 5IFTDSFFOCBDLHSPVOEˠNETZTDPMPSCBDLHSPVOE
    w NETZTDPMPSCBDLHSPVOEˠEJ
    ff
    FSFOUSFGFSFODFUPLFOTGPSMJHIUPS
    EBSL

    View Slide

  16. $PNQPOFOU5PLFO
    w 5IFEFTJHOBUUSJCVUFTBTTJHOFE
    UPFMFNFOUTJOBDPNQPOFOU
    w FHʣDPMPS BUUSJCVUF
    PG
    DPOUBJOFS FMFNFOU
    JO'"#
    ʢDPNQPOFOUʣ
    w NEDPNQ

    View Slide

  17. .BUFSJBMEFTJHOTZTUFN
    w %FTJHO5PLFOT
    w 3FGFSFODF5PLFO
    w 4ZTUFN5PLFO
    w $PNQPOFOU5PLFO

    View Slide

  18. .BUFSJBMEFTJHOTZTUFN
    w %FTJHO5PLFOT
    w 3FGFSFODF5PLFO
    w 4ZTUFN5PLFO
    w $PNQPOFOU5PLFO
    w 4ZTUFN5PLFO

    View Slide

  19. .BUFSJBMEFTJHOTZTUFN
    w %FTJHO5PLFOT
    w 3FGFSFODF5PLFO
    w 4ZTUFN5PLFO
    w $PNQPOFOU5PLFO
    w 4ZTUFN5PLFO
    w DPMPS DPMPS4DIFNF

    w UZQPHSBQIZ
    w TIBQF

    View Slide

  20. $PMPSPG.

    View Slide

  21. ,FZDPMPST
    w LFZDPMPS

    View Slide

  22. 5POBMQBMFUUF
    w "UPOBMQBMFUUF
    DPOTJTUTPGUIJSUFFO
    UPOFT
    w UPOF#MBDL
    w UPOF8IJUF

    View Slide

  23. 5POBMQBMFUUFTPGLFZDPMPST
    IUUQTNNBUFSJBMJPUIFNFCVJMEFSDVTUPN

    View Slide

  24. QJDLDPMPSTGSPNUPOBMQBMFUUF
    w 5POBMQBMFUUFPG1SJNBSZ,FZDPMPSˠ$PMPS3PMFTPG1SJNBSZ
    1SJNBSZ 0O1SJNBSZ
    1SJNBSZ$POUBJOFS
    0O1SJNBSZ$POUBJOFS

    View Slide

  25. "DDFOUSPMFT

    View Slide

  26. /FVUSBMSPMFT

    View Slide

  27. &SSPSSPMFT

    View Slide

  28. $PMPSPG.
    w DPMPSTDIFNF
    w LFZDPMPSFSSPS
    w QJDLDPMPSTGSPNUPOBMQBMFUUFˠ3PMF
    w $PMPS3PMFT
    w 1SJNBSZ PO1SJNBSZ 4FDPOEBSZ ʜ

    View Slide

  29. 5ZQPHSBQIZPG.

    View Slide

  30. 5ZQPHSBQIZPG.
    w 3PMFT
    w %JTQMBZ
    w )FBEMJOF
    w 5JUMF
    w #PEZ
    w -BCFM
    w TDBMFTQFS3PMF
    w -BSHF
    w .FEJVN
    w 4NBMM

    View Slide

  31. 4IBQFPG.

    View Slide

  32. 4IBQFPG.
    w MFWFMTEFQFOEJOHPOUIFTDBMFPGTIBQF
    w /POF &YUSBTNBMM 4NBMM .FEJVN
    -BSHF &YUSBMBSHF 'VMM

    View Slide

  33. 1BJOQPJOUPG
    .EFTJHOTZTUFN

    View Slide

  34. 5IFNPTUDSJUJDBMQBJOQPJOUJTʜ

    View Slide

  35. 5IFNPTUDSJUJDBMQBJOQPJOUJTʜ
    $PMPS

    View Slide

  36. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS

    View Slide

  37. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS
    https://m3.material.io/theme-builder#/custom
    ˌBF
    ˌEB

    View Slide

  38. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS
    w .BOVBMMZBEKVTUJOHUIFDPMPSTPOUIF.JTEJ
    ff i
    DVMU

    View Slide

  39. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS
    w .BOVBMMZBEKVTUJOHUIFDPMPSTPOUIF.JTEJ
    ff i
    DVMU
    w /PUFOPVHIDPMPS
    w "EEJOHDVTUPNDPMPSEPFTOPUTVQQPSU%ZOBNJD$PMPS

    View Slide

  40. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS
    w .BOVBMMZBEKVTUJOHUIFDPMPSTPOUIF.JTEJ
    ff i
    DVMU
    w /PUFOPVHIDPMPS
    w "EEJOHDVTUPNDPMPSEPFTOPUTVQQPSU%ZOBNJD$PMPS
    w "EEJOHDVTUPNDPMPSBMTPEPFTOPUTVQQPSU%BSL.PEF

    View Slide

  41. $VTUPNDPMPSPG.
    val Colors.container: Color
    get() = if (isLight) Color.Blue else Color.Red

    View Slide

  42. $VTUPNDPMPSPG.
    val ColorScheme.container: Color
    @Composable
    get() = if (!isSystemInDarkTheme()) Color.Blue else Color.Red

    View Slide

  43. MyM3Theme {
    Surface {
    Row {
    Spacer(
    modifier = Modifier

    .background(MaterialTheme.colorScheme.container)
    )
    Box {
    MyM3Theme(darkTheme = true) {
    Surface {
    Spacer(
    modifier = Modifier

    .background(MaterialTheme.colorScheme.container)
    )
    }
    }
    }
    }
    }
    }
    M2
    M3
    isSystemInDarkTheme()TUJMMGBMTF
    MJHIU
    EBSL

    View Slide

  44. 1BJOQPJOUPG.DPMPS
    w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS
    w .BOVBMMZBEKVTUJOHUIFDPMPSTPOUIF.JTEJ
    ff i
    DVMU
    w /PUFOPVHIDPMPS
    w "EEJOHDVTUPNDPMPSEPFTOPUTVQQPSU%ZOBNJD$PMPS
    w "EEJOHDVTUPNDPMPSBMTPEPFTOPUTVQQPSU%BSL.PEF
    #FUUFSUPVTFBMMZPVSPXODPMPSEF
    fi
    OJUJPOT

    View Slide

  45. )PXUPDSFBUFDVTUPN
    EFTJHOTZTUFN

    View Slide

  46. $VTUPNEFTJHOTZTUFN
    w 6UJMJ[JOH.EFTJHOUPLFONFDIBOJTN
    w 3FGFSFODF5PLFO
    w 4ZTUFN5PLFO
    w $PNQPOFOU5PLFO

    View Slide

  47. 3FBTPOGPSOPUVTJOH$PNQPOFOU5PLFO
    w $PNQPOFOU5PLFOJTVTFEJOTPNFDPNQPOFOUTPG. CVUUIF
    SFGFSFODFTBSFEFFQBOEEJ
    ffi
    DVMUUPGPMMPX
    w 8FEPOUOFFEUIBUNVDIBCTUSBDUJPO

    View Slide

  48. 3FBTPOGPSOPUVTJOH$PNQPOFOU5PLFO
    w $PNQPOFOU5PLFOJTVTFEJOTPNFDPNQPOFOUTPG. CVUUIF
    SFGFSFODFTBSFEFFQBOEEJ
    ffi
    DVMUUPGPMMPX
    w 8FEPOUOFFEUIBUNVDIBCTUSBDUJPO
    w %FTJHO5PLFOJTQMBUGPSNJOEFQFOEFOU CVUDPNQPOFOUTBSFQMBUGPSN
    EFQFOEFOU "OESPJEJ048FC

    View Slide

  49. @Composable
    fun buttonColors(
    containerColor: Color = FilledButtonTokens.ContainerColor.toColor(),

    ): ButtonColors = ButtonColors(
    containerColor = containerColor,

    )
    .
    $PNQPOFOU5PLFO

    View Slide

  50. @Composable
    fun buttonColors(
    containerColor: Color = FilledButtonTokens.ContainerColor.toColor(),

    ): ButtonColors = ButtonColors(
    containerColor = containerColor,

    )
    internal object FilledButtonTokens {
    val ContainerColor = ColorSchemeKeyTokens.Primary

    }
    .

    View Slide

  51. internal enum class ColorSchemeKeyTokens {

    Primary,

    }
    @Composable
    fun buttonColors(
    containerColor: Color = FilledButtonTokens.ContainerColor.toColor(),

    ): ButtonColors = ButtonColors(
    containerColor = containerColor,

    )
    internal object FilledButtonTokens {
    val ContainerColor = ColorSchemeKeyTokens.Primary

    }
    .

    View Slide

  52. @Composable
    fun buttonColors(
    containerColor: Color = FilledButtonTokens.ContainerColor.toColor(),

    ): ButtonColors = ButtonColors(
    containerColor = containerColor,

    )
    @ReadOnlyComposable
    @Composable
    internal fun ColorSchemeKeyTokens.toColor(): Color {
    return MaterialTheme.colorScheme.fromToken(this)
    }
    internal fun ColorScheme.fromToken(value: ColorSchemeKeyTokens): Color {
    return when (value) {

    ColorSchemeKeyTokens.Primary -> primary

    }
    }
    .

    View Slide

  53. 8JUIPVU$PNQPOFOU5PLFO
    @Composable
    fun buttonColors(
    containerColor: Color = MyTheme.colorScheme.primary,

    ): ButtonColors = ButtonColors(
    containerColor = containerColor,

    )

    View Slide

  54. )PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO

    View Slide

  55. )PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO
    w .DPMPS UZQPHSBQIZ TIBQF

    View Slide

  56. )PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO
    w $BOXFHFUIFMQGSPNBEFTJHOFS
    w ZFT
    w *EFOUJGZUIFUZQFTPGTZTUFNUPLFOZPVXJMMOFFEBOEUIFO
    JNQMFNFOUJU
    w OP
    w 1SFQBSFPOMZUIFDPMPSBOEUZQPHSBQIZBTTZTUFNUPLFO BEEBOE
    NBJOUBJOUIFOFDFTTBSZJUFNTXIJMFJNQMFNFOUJOHUIFBQQ

    View Slide

  57. )PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO
    w $BOXFHFUIFMQGSPNBEFTJHOFS
    w ZFT
    w *EFOUJGZUIFUZQFTPGTZTUFNUPLFOZPVXJMMOFFEBOEUIFO
    JNQMFNFOUJU
    w OP
    w 1SFQBSFPOMZUIFDPMPSBOEUZQPHSBQIZBTTZTUFNUPLFO BEEBOE
    NBJOUBJOUIFOFDFTTBSZJUFNTXIJMFJNQMFNFOUJOHUIFBQQ

    View Slide

  58. 4ZTUFN5PLFO3FDPNNFOEFE
    *OJUJBM4FUUJOHT

    View Slide

  59. 4ZTUFN5PLFO*OJUJBM4FUUJOHT
    w $PMPS
    w CBDLHSPVOE
    w GPSDPOUFOUT UFYUDPMPS
    w FHPO#BDLHSPVOE PO#BDLHSPVOE7BSJBOU
    w FHUFYU1SJNBSZ UFYU4FDPOEBSZ
    w FHDPOUFOU)JHI DPOUFOU.JE
    w QSJNBSZʢPQUJPOBMʣ

    View Slide

  60. 4ZTUFN5PLFO*OJUJBM4FUUJOHT
    w 5ZQPHSBQIZ
    w CPEZ-BSHF
    w CPEZ.FEJVN

    View Slide

  61. 0QUJPOBM
    w %JNFOTJPO
    w TQBDJOHʢEQ EQ ʜʣ
    w SBEJVT

    View Slide

  62. *NQMFNFOUBUJPOPGDVTUPN
    EFTJHOTZTUFN

    View Slide

  63. .PEVMFGPSEFTJHOTZTUFN
    w NPEVMFOBNFJTPQUJPOBM
    w FH
    DPSFEFTJHOTZTUFN
    w TFUVQDPNQPTF

    View Slide

  64. android {

    buildFeatures {
    compose = true
    }
    composeOptions {
    kotlinCompilerExtensionVersion = "1.5.1"
    }
    }
    dependencies {

    implementation(platform("androidx.compose:compose-bom:2023.08.00"))
    implementation("androidx.compose.material3:material3")
    }
    CVJMEHSBEMFLUT DPSFEFTJHOTZTUFN

    View Slide


  65. dependencies {
    implementation(project(":core:design-system"))
    implementation(platform("androidx.compose:compose-bom:2023.08.00"))
    implementation("androidx.compose.foundation:foundation")

    }
    CVJMEHSBEMFLUT BQQ

    View Slide

  66. $PMPS

    View Slide

  67. $PMPS5PLFOT
    internal object MyColorLightTokens {
    val Primary = Color(0xFF3D6A00)
    val Background = Color(0xffffffff)
    val OnBackground = Color(0xde000000)
    }
    internal object MyColorDarkTokens {
    val Primary = Color(0xFF95D94A)
    val Background = Color(0xff141816)
    val OnBackground = Color(0xffffffff)
    }
    DPSFEFTJHOTZTUFN

    View Slide

  68. $VTUPN$PMPSDMBTT
    @Stable
    class MyColor(
    primary: Color,
    background: Color,
    onBackground: Color,
    ) {
    var primary by mutableStateOf(primary, structuralEqualityPolicy())
    internal set
    var background by mutableStateOf(background, structuralEqualityPolicy())
    internal set
    var onBackground by mutableStateOf(onBackground, structuralEqualityPolicy())
    internal set

    }
    DPSFEFTJHOTZTUFN

    View Slide

  69. fun lightMyColor(
    primary: Color = MyColorLightTokens.Primary,
    background: Color = MyColorLightTokens.Background,
    onBackground: Color = MyColorLightTokens.OnBackground,
    ): MyColor = MyColor(

    )
    fun darkMyColor(
    primary: Color = MyColorDarkTokens.Primary,
    background: Color = MyColorDarkTokens.Background,
    onBackground: Color = MyColorDarkTokens.OnBackground,
    ): MyColor = MyColor(

    )

    internal val LocalMyColor = staticCompositionLocalOf { lightMyColor() }
    DPSFEFTJHOTZTUFN

    View Slide

  70. $PNQPTJUJPO-PDBM
    My blog article → https://y-anz-m.blogspot.com/2021/04/jetpack-compose-composition-local.html

    View Slide

  71. $PNQPTJUJPO-PDBM
    My blog article → https://y-anz-m.blogspot.com/2021/04/jetpack-compose-composition-local.html
    val MyLocalColor = staticCompositionLocalOf { Color.Red }

    View Slide

  72. $PNQPTJUJPO-PDBM
    My blog article → https://y-anz-m.blogspot.com/2021/04/jetpack-compose-composition-local.html
    val MyLocalColor = staticCompositionLocalOf { Color.Red }
    Text(
    text = "hello",
    color = MyLocalColor.current, // Color.Red
    )

    View Slide

  73. $PNQPTJUJPO-PDBM
    My blog article → https://y-anz-m.blogspot.com/2021/04/jetpack-compose-composition-local.html
    val MyLocalColor = staticCompositionLocalOf { Color.Red }
    Text(
    text = "hello",
    color = MyLocalColor.current, // Color.Red
    )
    CompositionLocalProvider(MyLocalColor provides Color.Blue) {
    Text(
    text = "hello",
    color = MyLocalColor.current, // Color.Blue
    )
    }

    View Slide

  74. 5ZQPHSBQIZ

    View Slide

  75. 5ZQPHSBQIZ5PLFOT
    internal object MyTypographyTokens {
    val BodyLarge = TextStyle(
    fontFamily = FontFamily.SansSerif,
    fontWeight = FontWeight.Normal,
    fontSize = 16.sp,
    lineHeight = 24.0.sp,
    letterSpacing = 0.5.sp,
    )
    val BodyMedium = TextStyle(
    fontFamily = FontFamily.SansSerif,
    fontWeight = FontWeight.Normal,
    fontSize = 14.sp,
    lineHeight = 20.0.sp,
    letterSpacing = 0.2.sp,
    )
    }
    DPSFEFTJHOTZTUFN

    View Slide

  76. $VTUPN5ZQPHSBQIZDMBTT
    @Immutable
    data class MyTypography(
    val bodyLarge: TextStyle = MyTypographyTokens.BodyLarge,
    val bodyMedium: TextStyle = MyTypographyTokens.BodyMedium,
    )
    internal val LocalMyTypography = staticCompositionLocalOf { MyTypography() }
    DPSFEFTJHOTZTUFN

    View Slide

  77. .Z5IFNFDPNQPTBCMF

    View Slide

  78. .Z5IFNFPCKFDU
    object MyTheme {
    val color: MyColor
    @Composable
    @ReadOnlyComposable
    get() = LocalMyColor.current
    val typography: MyTypography
    @Composable
    @ReadOnlyComposable
    get() = LocalMyTypography.current
    }
    DPSFEFTJHOTZTUFN

    View Slide

  79. 5IFNFDPNQPTBCMFGPSEFTJHOTZTUFN
    w FRVJWBMFOUUP.BUFSJBM5IFNFDPNQPTBCMF
    w JOUFSOBM

    View Slide

  80. @Composable
    internal fun BaseMyTheme(
    color: MyColor = MyTheme.color,
    typography: MyTypography = MyTheme.typography,
    content: @Composable () -> Unit,
    ) {
    val rememberedColors = remember {
    color.copy()
    }.apply {
    updateMyColorFrom(color)
    }
    val selectionColors = rememberTextSelectionColors(rememberedColors)
    CompositionLocalProvider(
    LocalIndication provides rememberRipple(),
    LocalRippleTheme provides MaterialRippleTheme,
    LocalTextSelectionColors provides selectionColors,
    LocalMyColor provides rememberedColors,
    LocalMyTypography provides typography,
    ) {
    ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
    }
    DPSFEFTJHOTZTUFN

    View Slide

  81. @Composable
    internal fun BaseMyTheme(
    color: MyColor = MyTheme.color,
    typography: MyTypography = MyTheme.typography,
    content: @Composable () -> Unit,
    ) {
    val rememberedColors = remember {
    color.copy()
    }.apply {
    updateMyColorFrom(color)
    }
    val selectionColors = rememberTextSelectionColors(rememberedColors)
    CompositionLocalProvider(
    LocalIndication provides rememberRipple(),
    LocalRippleTheme provides MaterialRippleTheme,
    LocalTextSelectionColors provides selectionColors,
    LocalMyColor provides rememberedColors,
    LocalMyTypography provides typography,
    ) {
    ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
    }
    DPSFEFTJHOTZTUFN

    View Slide

  82. @Composable
    internal fun BaseMyTheme(
    color: MyColor = MyTheme.color,
    typography: MyTypography = MyTheme.typography,
    content: @Composable () -> Unit,
    ) {
    val rememberedColors = remember {
    color.copy()
    }.apply {
    updateMyColorFrom(color)
    }
    val selectionColors = rememberTextSelectionColors(rememberedColors)
    CompositionLocalProvider(
    LocalIndication provides rememberRipple(),
    LocalRippleTheme provides MaterialRippleTheme,
    LocalTextSelectionColors provides selectionColors,
    LocalMyColor provides rememberedColors,
    LocalMyTypography provides typography,
    ) {
    ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
    }
    DPSFEFTJHOTZTUFN

    View Slide

  83. @Composable
    internal fun BaseMyTheme(
    color: MyColor = MyTheme.color,
    typography: MyTypography = MyTheme.typography,
    content: @Composable () -> Unit,
    ) {

    CompositionLocalProvider(
    LocalIndication provides rememberRipple(),
    LocalRippleTheme provides MaterialRippleTheme,

    ) {
    ProvideTextStyle(value = typography.bodyLarge, content = content)
    }
    }
    @Immutable
    private object MaterialRippleTheme : RippleTheme {
    @Composable
    override fun defaultColor() = LocalContentColor.current
    @Composable
    override fun rippleAlpha() = RippleAlpha(…)
    }
    DPSFEFTJHOTZTUFN

    View Slide

  84. VTFSFNFNCFS3JQQMF
    JOBQQNPEVMF
    Box(
    modifier = Modifier…
    .clickable(
    onClick = onClick,
    role = Role.Button,
    interactionSource = remember { MutableInteractionSource() },
    indication = rememberRipple(
    bounded = false,
    radius = 24.dp,
    )
    ),
    ) {

    View Slide

  85. VTFSFNFNCFS3JQQMF
    JOBQQNPEVMF
    w JNQMFNFOUBXSBQQFSNFUIPEJOEFTJHOTZTUFNNPEVMF
    @Composable
    fun rememberRipple(
    bounded: Boolean = true,
    radius: Dp = Dp.Unspecified,
    color: Color = Color.Unspecified
    ): Indication {
    return androidx.compose.material.ripple.rememberRipple(
    bounded = bounded,
    radius = radius,
    color = color,
    )
    }
    DPSFEFTJHOTZTUFN

    View Slide

  86. VTFSFNFNCFS3JQQMF
    JOBQQNPEVMF
    w JNQMFNFOUBXSBQQFSNFUIPEJOEFTJHOTZTUFNNPEVMF
    w BEElNBUFSJBMSJQQMFMJCSBSZUPBQQNPEVMF
    dependencies {

    implementation(platform("androidx.compose:compose-bom:2023.08.00"))
    implementation("androidx.compose.foundation:foundation")
    implementation("androidx.compose.material:material-ripple")

    }
    BQQ

    View Slide

  87. 5IFNFDPNQPTBCMFGPSBQQ
    w FRVJWBMFOUUPUIFUIFNFBVUPNBUJDBMMZDSFBUFEXIFODSFBUJOHBQSPKFDU
    w QVCMJD
    @Composable
    fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    BaseMyTheme(
    color = if (!darkTheme) lightMyColor() else darkMyColor(),
    typography = MyTypography(),
    content = content
    )
    }
    DPSFEFTJHOTZTUFN

    View Slide

  88. .JHSBUJOHGSPN. PS.

    @Composable
    fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
    ) {
    BaseMyTheme(
    color = if (!darkTheme) lightMyColor() else darkMyColor(),
    typography = MyTypography(),
    ) {
    MaterialTheme(
    colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme,
    content = content
    )
    }
    }
    DPSFEFTJHOTZTUFN

    View Slide

  89. *NQMFNFOUBUJPOPG
    DPNQPOFOUT

    View Slide

  90. *NQMFNFOUBUJPOPGDPNQPOFOUT
    w .DPNQPOFOUTDBOOPUCFVTFEBTJT

    View Slide

  91. *NQMFNFOUBUJPOPGDPNQPOFOUT
    w .DPNQPOFOUTDBOOPUCFVTFEBTJT
    @Preview
    @Composable
    private fun Preview() {
    MyTheme {
    androidx.compose.material3.Checkbox(
    checked = true,
    onCheckedChange = {}
    )
    }
    }

    View Slide

  92. object CheckboxDefaults {
    @Composable
    fun colors(
    checkedColor: Color =
    MaterialTheme.colorScheme.fromToken(CheckboxTokens.SelectedContainerColor)

    ): CheckboxColors = CheckboxColors(
    checkedBoxColor = checkedColor,

    )
    }
    object MaterialTheme {
    val colorScheme: ColorScheme
    @Composable
    @ReadOnlyComposable
    get() = LocalColorScheme.current

    }
    ColorSchemeKeyTokens.Primary
    .

    View Slide

  93. @Composable
    fun MaterialTheme(
    colorScheme: ColorScheme = MaterialTheme.colorScheme,

    ) {

    CompositionLocalProvider(
    LocalColorScheme provides rememberedColorScheme,

    ) { … }
    }
    object MaterialTheme {
    val colorScheme: ColorScheme
    @Composable
    @ReadOnlyComposable
    get() = LocalColorScheme.current

    }
    .

    View Slide

  94. @Preview
    @Composable
    private fun Preview() {
    MaterialTheme(
    colorScheme = lightColorScheme(
    primary = Color.Blue
    )
    ) {
    androidx.compose.material3.Checkbox(
    checked = true,
    onCheckedChange = {}
    )
    }
    }

    View Slide

  95. $PNQPOFOUTPGDVTUPNEFTJHOTZTUFN
    w XSBQQFSPG.DPNQPOFOUT
    w DPNQPOFOUTXJUIDVTUPNJNQMFNFOUBUJPO

    View Slide

  96. $PNQPOFOUTPGDVTUPNEFTJHOTZTUFN
    w OBNFPGDPNQPOFOUT
    w DVSSFOUMZBQQVTFT.
    w /PˠOPQSF
    fi
    YFHʣ$IFDLCPY
    w :FTˠXJUIQSF
    fi
    YFHʣ.Z$IFDLCPY
    w BWPJEUIFNJTUBLFPGJNQPSUJOH.DPNQPOFOUT
    w SFOBNFBGUFSSFNPWJOH.EFQFOEFODJFTGSPNBQQNPEVMF

    View Slide

  97. @Composable
    fun Checkbox(
    checked: Boolean,
    onCheckedChange: ((Boolean) -> Unit)?,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
    ) {
    TODO()
    }
    $VTUPN

    View Slide

  98. @Composable
    fun Checkbox(

    ) {
    val borderColor = MyTheme.color.onBackground.copy(alpha = 0.4f)
    val disabledBorderColor = borderColor.let { it.copy(alpha = it.alpha *
    DisabledAlpha) }
    androidx.compose.material3.Checkbox(
    checked = checked,
    onCheckedChange = onCheckedChange,
    modifier = modifier,
    enabled = enabled,
    colors = CheckboxDefaults.colors(
    checkedColor = MyTheme.color.primary,
    uncheckedColor = borderColor,
    checkmarkColor = MyTheme.color.background,
    disabledCheckedColor = disabledBorderColor,
    disabledUncheckedColor = disabledBorderColor,
    disabledIndeterminateColor = disabledBorderColor
    ),
    interactionSource = interactionSource,
    )
    }
    $VTUPN

    View Slide

  99. @Composable
    fun Checkbox(

    ) {
    val borderColor = MyTheme.color.onBackground.copy(alpha = 0.4f)
    val disabledBorderColor = borderColor.let { it.copy(alpha = it.alpha *
    DisabledAlpha) }
    androidx.compose.material3.Checkbox(
    checked = checked,
    onCheckedChange = onCheckedChange,
    modifier = modifier,
    enabled = enabled,
    colors = CheckboxDefaults.colors(
    checkedColor = MyTheme.color.primary,
    uncheckedColor = borderColor,
    checkmarkColor = MyTheme.color.background,
    disabledCheckedColor = disabledBorderColor,
    disabledUncheckedColor = disabledBorderColor,
    disabledIndeterminateColor = disabledBorderColor
    ),
    interactionSource = interactionSource,
    )
    }
    $VTUPN

    View Slide

  100. @Composable
    fun Checkbox(

    ) {
    val borderColor = MyTheme.color.onBackground.copy(alpha = 0.4f)
    val disabledBorderColor = borderColor.let { it.copy(alpha = it.alpha *
    DisabledAlpha) }
    androidx.compose.material3.Checkbox(
    checked = checked,
    onCheckedChange = onCheckedChange,
    modifier = modifier,
    enabled = enabled,
    colors = CheckboxDefaults.colors(
    checkedColor = MyTheme.color.primary,
    uncheckedColor = borderColor,
    checkmarkColor = MyTheme.color.background,
    disabledCheckedColor = disabledBorderColor,
    disabledUncheckedColor = disabledBorderColor,
    disabledIndeterminateColor = disabledBorderColor
    ),
    interactionSource = interactionSource,
    )
    }
    $VTUPN

    View Slide

  101. internal object MyColorLightTokens {
    val Primary = Color(0xFF3D6A00)
    val Background = Color(0xffffffff)
    val OnBackground = Color(0xde000000)
    val Border = Color(0x66000000)
    }
    internal object MyColorDarkTokens {
    val Primary = Color(0xFF95D94A)
    val Background = Color(0xff141816)
    val OnBackground = Color(0xffffffff)
    val Border = Color(0x66ffffff)
    }
    $VTUPN

    View Slide

  102. @Stable
    class MyColor(
    primary: Color,

    border: Color,
    ) {

    var border by mutableStateOf(border, structuralEqualityPolicy())
    internal set
    fun copy(

    border: Color = this.border,
    ): MyColor =
    MyColor(

    border = border,
    )
    }
    $VTUPN

    View Slide

  103. fun lightMyColor(

    border: Color = MyColorLightTokens.Border,
    ): MyColor = MyColor(

    border = border,
    )
    fun darkMyColor(

    border: Color = MyColorDarkTokens.Border,
    ): MyColor = MyColor(

    border = border,
    )
    $VTUPN

    View Slide

  104. @Composable
    fun Checkbox(

    ) {
    val borderColor = MyTheme.color.border
    val disabledBorderColor = borderColor.let { it.copy(alpha = it.alpha *
    DisabledAlpha) }
    androidx.compose.material3.Checkbox(
    checked = checked,
    onCheckedChange = onCheckedChange,
    modifier = modifier,
    enabled = enabled,
    colors = CheckboxDefaults.colors(
    checkedColor = MyTheme.color.primary,
    uncheckedColor = borderColor,
    checkmarkColor = MyTheme.color.background,
    disabledCheckedColor = disabledBorderColor,
    disabledUncheckedColor = disabledBorderColor,
    disabledIndeterminateColor = disabledBorderColor
    ),
    interactionSource = interactionSource,
    )
    }
    $VTUPN

    View Slide

  105. @Composable
    fun Divider(
    modifier: Modifier = Modifier,
    ) {
    androidx.compose.material3.Divider(
    modifier = modifier,
    thickness = 1.dp,
    color = MyTheme.color.border,
    )
    }
    $VTUPN

    View Slide

  106. $PNQPOFOUTXJUI4UBUF

    View Slide

  107. $PNQPOFOUTXJUI4UBUF
    w .PEBM#PUUPN4IFFUBOE4IFFU4UBUF
    w 4OBDLCBS)PTUBOE4OBDLCBS)PTU4UBUF
    w .PEBM/BWJHBUJPO%SBXFSBOE%SBXFS4UBUF
    w ʜ
    w OFFEBXSBQQFSGPS4UBUF

    View Slide

  108. FH
    4OBDLCBS

    View Slide

  109. FH
    4OBDLCBS
    w 4OBDLCBS%BUB
    w 4OBDLCBS3FTVMU
    w 4OBDLCBS%VSBUJPO
    w 4OBDLCBS)PTU4UBUF
    w 4OBDLCBS

    w 4OBDLCBS)PTU

    w SFNFNCFS4OBDLCBS)PTU4UBUF

    View Slide

  110. @JvmInline
    value class SnackbarData(val delegate: androidx.compose.material3.SnackbarData)
    $VTUPN

    View Slide

  111. enum class SnackbarResult {
    Dismissed,
    ActionPerformed,
    }
    enum class SnackbarDuration {
    Short,
    Long,
    Indefinite
    }
    @JvmInline
    value class SnackbarData(val delegate: androidx.compose.material3.SnackbarData)
    $VTUPN

    View Slide

  112. @Composable
    fun Snackbar(
    snackbarData: SnackbarData,
    modifier: Modifier = Modifier,
    actionOnNewLine: Boolean = false,
    ) {
    androidx.compose.material3.Snackbar(
    snackbarData = snackbarData.delegate,
    modifier = modifier,
    actionOnNewLine = actionOnNewLine,
    shape = RoundedCornerShape(4.dp),
    containerColor = MyTheme.color.onBackground.copy(alpha = 0.9f)
    .compositeOver(MyTheme.color.background),
    contentColor = MyTheme.color.background,
    actionColor = MyTheme.color.background,
    actionContentColor = MyTheme.color.background,
    dismissActionContentColor = MyTheme.color.background,
    )
    }
    $VTUPN

    View Slide

  113. @Composable
    fun Snackbar(
    snackbarData: SnackbarData,
    modifier: Modifier = Modifier,
    actionOnNewLine: Boolean = false,
    ) {
    androidx.compose.material3.Snackbar(
    snackbarData = snackbarData.delegate,
    modifier = modifier,
    actionOnNewLine = actionOnNewLine,
    shape = RoundedCornerShape(4.dp),
    containerColor = MyTheme.color.onBackground.copy(alpha = 0.9f)
    .compositeOver(MyTheme.color.background),
    contentColor = MyTheme.color.background,
    actionColor = MyTheme.color.background,
    actionContentColor = MyTheme.color.background,
    dismissActionContentColor = MyTheme.color.background,
    )
    }
    $VTUPN

    View Slide

  114. @Stable
    class SnackbarHostState(val delegate: androidx.compose.material3.SnackbarHostState) {
    suspend fun showSnackbar(
    message: String,
    actionLabel: String? = null,
    withDismissAction: Boolean = false,
    duration: SnackbarDuration = …
    ): SnackbarResult {
    val result = delegate.showSnackbar(
    message = message,
    actionLabel = actionLabel,
    withDismissAction = withDismissAction,
    duration = when (duration) {
    SnackbarDuration.Short -> androidx.compose.material3.SnackbarDuration.Short

    },
    )
    return when (result) {
    androidx.compose.material3.SnackbarResult.Dismissed -> SnackbarResult.Dismissed

    }
    }
    }
    $VTUPN

    View Slide

  115. @Stable
    class SnackbarHostState(val delegate: androidx.compose.material3.SnackbarHostState) {
    suspend fun showSnackbar(
    message: String,
    actionLabel: String? = null,
    withDismissAction: Boolean = false,
    duration: SnackbarDuration = …
    ): SnackbarResult {
    val result = delegate.showSnackbar(
    message = message,
    actionLabel = actionLabel,
    withDismissAction = withDismissAction,
    duration = when (duration) {
    SnackbarDuration.Short -> androidx.compose.material3.SnackbarDuration.Short

    },
    )
    return when (result) {
    androidx.compose.material3.SnackbarResult.Dismissed -> SnackbarResult.Dismissed

    }
    }
    }
    $VTUPN

    View Slide

  116. @Composable
    fun SnackbarHost(
    hostState: SnackbarHostState,
    modifier: Modifier = Modifier,
    snackbar: @Composable (SnackbarData) -> Unit = { Snackbar(it) }
    ) {
    androidx.compose.material3.SnackbarHost(
    hostState = hostState.delegate,
    modifier = modifier,
    snackbar = { snackbar(SnackbarData(it)) },
    )
    }
    $VTUPN

    View Slide

  117. @Composable
    fun rememberSnackbarHostState(): SnackbarHostState {
    return remember {
    SnackbarHostState(androidx.compose.material3.SnackbarHostState())
    }
    }
    $VTUPN

    View Slide

  118. val snackbarHostState = rememberSnackbarHostState()
    LaunchedEffect(Unit) {
    snackbarHostState.showSnackbar(message = "message")
    }
    Scaffold(
    snackbarHost = {
    SnackbarHost(
    hostState = snackbarHostState,
    )
    }
    ) {

    }
    BQQ

    View Slide

  119. -PDBM$POUFOU$PMPS
    5FYU*DPODPNQPTBCMF

    View Slide

  120. XSBQQFSPG5FYUDPNQPTBCMF
    w %FGBVMUWBMVFPGDPMPSTIPVMECF$PMPS6OTQFDJ
    fi
    FE
    @Composable
    fun Text(

    color: Color = Color.Unspecified,

    ) {
    androidx.compose.material3.Text(

    color = color,

    )
    }
    0,
    = MyTheme.color.onBackground, /(
    $VTUPN

    View Slide

  121. -PDBM$POUFOU$PMPS
    @Composable
    fun Text(

    color: Color = Color.Unspecified,

    style: TextStyle = LocalTextStyle.current
    ) {
    val textColor = color.takeOrElse {
    style.color.takeOrElse {
    LocalContentColor.current
    }
    }

    BasicText(

    )
    }
    UIFDPMPSTQFDJ
    fi
    FECZUIF
    DPMPSBSHVNFOU
    UIFDPMPSTQFDJ
    fi
    FEJOTUZMF
    UIFDPMPSPG
    -PDBM$POUFOU$PMPS
    .

    View Slide

  122. @Composable
    fun Button(

    colors: ButtonColors = ButtonDefaults.buttonColors(),
    …,
    ) {
    val containerColor = colors.containerColor(enabled).value
    val contentColor = colors.contentColor(enabled).value

    Surface(

    ) {
    CompositionLocalProvider(LocalContentColor provides contentColor) {
    ProvideTextStyle(value = MaterialTheme.typography.labelLarge) {
    Row(

    verticalAlignment = Alignment.CenterVertically,
    content = content
    )
    }
    }
    }
    }
    .

    View Slide

  123. Button(
    onClick = { },
    ) {
    Text(
    text = "button",
    )
    }
    Button(
    onClick = { },
    enabled = false,
    ) {
    Text(
    text = "button",
    )
    }
    .

    View Slide

  124. Button(
    onClick = { },
    ) {
    Text(
    text = "button",
    color = MyTheme.color.onBackground,
    )
    }
    Button(
    onClick = { },
    enabled = false,
    ) {
    Text(
    text = "button",
    color = MyTheme.color.onBackground,
    )
    }
    /(
    /(

    View Slide

  125. XSBQQFSPG*DPODPNQPTBCMF
    w %FGBVMUWBMVFPGUJOUTIPVMECF-PDBM$POUFOU$PMPSDVSSFOU
    @Composable
    fun Icon(

    tint: Color = LocalContentColor.current,
    ) {
    androidx.compose.material3.Icon(

    tint = tint,
    )
    }
    0,
    = MyTheme.color.onBackground, /(
    $VTUPN

    View Slide

  126. -PDBM5FYU4UZMFQSPCMFN

    View Slide

  127. -PDBM5FYU4UZMF
    @Composable
    fun Text(

    color: Color = Color.Unspecified,

    style: TextStyle = LocalTextStyle.current
    ) {

    val mergedStyle = style.merge(

    )
    BasicText(

    mergedStyle,

    )
    }
    .

    View Slide

  128. 5PQ"QQ#BS
    @Composable
    fun TopAppBar(
    title: @Composable () -> Unit,

    ) {
    SingleRowTopAppBar(

    titleTextStyle =
    MaterialTheme.typography.fromToken(TopAppBarSmallTokens.HeadlineFont),

    )
    }
    val HeadlineFont = TypographyKeyTokens.TitleLarge
    .

    View Slide

  129. @Composable
    private fun SingleRowTopAppBar(

    titleTextStyle: TextStyle,

    ) {

    Surface(…) {

    TopAppBarLayout(

    titleTextStyle = titleTextStyle,

    )
    }
    }
    .

    View Slide

  130. @Composable
    private fun TopAppBarLayout(

    title: @Composable () -> Unit,
    titleTextStyle: TextStyle,

    ) {
    Layout(
    {

    Box(
    Modifier
    .layoutId("title")

    ) {
    ProvideTextStyle(value = titleTextStyle) {
    CompositionLocalProvider(
    LocalContentColor provides titleContentColor,
    content = title
    )
    }
    }

    }
    .

    View Slide

  131. @Composable
    private fun TopAppBarLayout(

    title: @Composable () -> Unit,
    titleTextStyle: TextStyle,

    ) {
    Layout(
    {

    Box(
    Modifier
    .layoutId("title")

    ) {
    ProvideTextStyle(value = titleTextStyle) {
    CompositionLocalProvider(
    LocalContentColor provides titleContentColor,
    content = title
    )
    }
    }

    }
    @Composable
    fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit) {
    val mergedStyle = LocalTextStyle.current.merge(value)
    CompositionLocalProvider(LocalTextStyle provides mergedStyle, content = content)
    }
    .

    View Slide

  132. TopAppBar(
    title = {
    Text("title")
    }
    )
    LocalTextStyle : MaterialTheme.typography.titleLarge
    MaterialTheme.typography.titleLarge
    .

    View Slide

  133. -PDBM5FYU4UZMFQSPCMFN

    View Slide

  134. -PDBM5FYU4UZMFQSPCMFN
    TopAppBar(
    title = {
    Text("title")
    }
    )
    MaterialTheme.typography.titleLarge
    0,
    /(
    TopAppBar(
    title = {
    Text(
    text = "title",
    style = MyTheme.typography.titleLarge
    )
    }
    )

    View Slide

  135. @Composable
    fun TopAppBar(
    title: String,

    ) {
    androidx.compose.material3.TopAppBar(
    title = {
    Text(
    text = title,
    style = MyTheme.typography.titleLarge
    )
    },

    )
    }
    $VTUPN

    View Slide

  136. %FTJHO5PLFOPG#

    View Slide

  137. 4ZTUFN5PLFOTPG#
    w DPMPS
    w UZQPHSBQIZ
    w EJNFOTJPO
    w EF
    fi
    OFTJ[FT TQBDJOH CPSEFSXJEUI SBEJVT

    w PQBDJUZ
    w EF
    fi
    OFBMQIBXIFOEJTBCMFE
    https://blog.smartbank.co.jp/entry/2023/06/19/095816

    View Slide

  138. (SPVQJOH
    @Immutable
    class B43Color(
    backgroundColors: BackgroundColors,

    ) {
    var backgroundColors by mutableStateOf(backgroundColors, structuralEqualityPolicy())
    internal set

    @Immutable
    data class BackgroundColors(
    val defaultBase: Color,
    val defaultAccent: Color,
    val inverseBase: Color,
    )

    }

    View Slide

  139. fun b43LightColor(
    backgroundColors: B43Color.BackgroundColors = B43Color.BackgroundColors(
    defaultBase = B43ColorBackgroundTokensLight.DefaultBase,
    defaultAccent = B43ColorBackgroundTokensLight.DefaultAccent,
    inverseBase = B43ColorBackgroundTokensLight.InverseBase,
    ),

    ): B43Color = B43Color(
    backgroundColors = backgroundColors,

    )
    @Composable
    fun TopAppBar(

    containerColor: Color = B43Theme.color.backgroundColors.defaultBase,

    ) {

    View Slide

  140. %JNFOTJPO
    @Immutable
    data class B43Dimension(
    val border: B43DimensionBorder = B43DimensionBorder(),
    val radius: B43DimensionRadius = B43DimensionRadius(),
    val spacing: B43DimensionSpacing = B43DimensionSpacing(),
    )
    @Immutable
    data class B43DimensionSpacing(

    val small: Dp = B43DimensionSpacingTokens.Small,
    val medium: Dp = B43DimensionSpacingTokens.Medium,
    val large: Dp = B43DimensionSpacingTokens.Large,

    )
    Column(
    verticalArrangement = Arrangement.spacedBy(B43Theme.dimension.spacing.large),
    ) {

    View Slide

  141. 4VNNBSZ
    w *UJTEJ
    ffi
    DVMUUPVTF.TEFTJHOTZTUFNGPSBQQTUIBUIBWFB
    fi
    YFE
    CSBOEDPMPS
    w 5IFSFJTBXBZUPDSFBUFZPVSPXOEFTJHOTZTUFN
    w 1SFQBSFBNPEVMFGPSUIFDVTUPNEFTJHOTZTUFNBOEJNQMFNFOUUIF
    EFTJHOTZTUFNBOEDPNQPOFOUT
    w $PODFBM.JOTJEFUIFEFTJHOTZTUFNNPEVMF
    w 8FXBOUDPNQPOFOUTUIBUJOEFQFOEFOUPGUIF.EFTJHOTZTUFN

    View Slide

  142. 5IBOLZPV

    View Slide