Slide 1

Slide 1 text

.BUFSJBM΍Ί·ͨ͠ :VLJ"O[BJ !ZBO[N %SPJE,BJHJ Good-bye M3 design system

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

%SPJE,BJHJ

Slide 4

Slide 4 text

(PPECZF .BUFSJBMEFTJHOTZTUFN

Slide 5

Slide 5 text

Why What use instead of (PPECZF .BUFSJBMEFTJHOTZTUFN

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

3FWJFX.BUFSJBM

Slide 8

Slide 8 text

.BUFSJBM%FTJHO w BOBEBQUBCMFTZTUFNPGHVJEFMJOFT DPNQPOFOUT BOEUPPMTUIBU TVQQPSUUIFCFTUQSBDUJDFTPGVTFSJOUFSGBDFEFTJHO .BUFSJBM%FTJHO . ʙ .BUFSJBM%FTJHO . ʙ .BUFSJBM5IFNJOH .BUFSJBM$PNQPOFOUTJNQMFNFOUBUJPO .BUFSJBM%FTJHO . ʙ .BUFSJBM:PV %ZOBNJDDPMPS

Slide 9

Slide 9 text

%FTJHO5PLFOT

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

$PMPSPG.

Slide 21

Slide 21 text

,FZDPMPST w LFZDPMPS

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

5POBMQBMFUUFTPGLFZDPMPST IUUQTNNBUFSJBMJPUIFNFCVJMEFSDVTUPN

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

"DDFOUSPMFT

Slide 26

Slide 26 text

/FVUSBMSPMFT

Slide 27

Slide 27 text

&SSPSSPMFT

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

5ZQPHSBQIZPG.

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

4IBQFPG.

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

1BJOQPJOUPG .EFTJHOTZTUFN

Slide 34

Slide 34 text

5IFNPTUDSJUJDBMQBJOQPJOUJTʜ

Slide 35

Slide 35 text

5IFNPTUDSJUJDBMQBJOQPJOUJTʜ $PMPS

Slide 36

Slide 36 text

1BJOQPJOUPG.DPMPS w 8FXBOUUPVTFCSBOEDPMPSOPUUPOBMQBMFUUFDPMPS

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

)PXUPDSFBUFDVTUPN EFTJHOTZTUFN

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

@Composable fun buttonColors( containerColor: Color = FilledButtonTokens.ContainerColor.toColor(), … ): ButtonColors = ButtonColors( containerColor = containerColor, … ) . $PNQPOFOU5PLFO

Slide 50

Slide 50 text

@Composable fun buttonColors( containerColor: Color = FilledButtonTokens.ContainerColor.toColor(), … ): ButtonColors = ButtonColors( containerColor = containerColor, … ) internal object FilledButtonTokens { val ContainerColor = ColorSchemeKeyTokens.Primary … } .

Slide 51

Slide 51 text

internal enum class ColorSchemeKeyTokens { … Primary, … } @Composable fun buttonColors( containerColor: Color = FilledButtonTokens.ContainerColor.toColor(), … ): ButtonColors = ButtonColors( containerColor = containerColor, … ) internal object FilledButtonTokens { val ContainerColor = ColorSchemeKeyTokens.Primary … } .

Slide 52

Slide 52 text

@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 … } } .

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

)PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO

Slide 55

Slide 55 text

)PXUPEFDJEFUIFUZQFPG4ZTUFN5PLFO w .DPMPS UZQPHSBQIZ TIBQF

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

4ZTUFN5PLFO3FDPNNFOEFE *OJUJBM4FUUJOHT

Slide 59

Slide 59 text

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ʣ

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

*NQMFNFOUBUJPOPGDVTUPN EFTJHOTZTUFN

Slide 63

Slide 63 text

.PEVMFGPSEFTJHOTZTUFN w NPEVMFOBNFJTPQUJPOBM w FH DPSFEFTJHOTZTUFN w TFUVQDPNQPTF

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

… dependencies { implementation(project(":core:design-system")) implementation(platform("androidx.compose:compose-bom:2023.08.00")) implementation("androidx.compose.foundation:foundation") … } CVJMEHSBEMFLUT BQQ

Slide 66

Slide 66 text

$PMPS

Slide 67

Slide 67 text

$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

Slide 68

Slide 68 text

$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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

$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 )

Slide 73

Slide 73 text

$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 ) }

Slide 74

Slide 74 text

5ZQPHSBQIZ

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

.Z5IFNFDPNQPTBCMF

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

5IFNFDPNQPTBCMFGPSEFTJHOTZTUFN w FRVJWBMFOUUP.BUFSJBM5IFNFDPNQPTBCMF w JOUFSOBM

Slide 80

Slide 80 text

@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

Slide 81

Slide 81 text

@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

Slide 82

Slide 82 text

@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

Slide 83

Slide 83 text

@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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

.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

Slide 89

Slide 89 text

*NQMFNFOUBUJPOPG DPNQPOFOUT

Slide 90

Slide 90 text

*NQMFNFOUBUJPOPGDPNQPOFOUT w .DPNQPOFOUTDBOOPUCFVTFEBTJT

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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 .

Slide 93

Slide 93 text

@Composable fun MaterialTheme( colorScheme: ColorScheme = MaterialTheme.colorScheme, … ) { … CompositionLocalProvider( LocalColorScheme provides rememberedColorScheme, … ) { … } } object MaterialTheme { val colorScheme: ColorScheme @Composable @ReadOnlyComposable get() = LocalColorScheme.current … } .

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

$PNQPOFOUTPGDVTUPNEFTJHOTZTUFN w XSBQQFSPG.DPNQPOFOUT w DPNQPOFOUTXJUIDVTUPNJNQMFNFOUBUJPO

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

@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

Slide 99

Slide 99 text

@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

Slide 100

Slide 100 text

@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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

@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

Slide 103

Slide 103 text

fun lightMyColor( … border: Color = MyColorLightTokens.Border, ): MyColor = MyColor( … border = border, ) fun darkMyColor( … border: Color = MyColorDarkTokens.Border, ): MyColor = MyColor( … border = border, ) $VTUPN

Slide 104

Slide 104 text

@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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

$PNQPOFOUTXJUI4UBUF

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

FH 4OBDLCBS

Slide 109

Slide 109 text

FH 4OBDLCBS w 4OBDLCBS%BUB w 4OBDLCBS3FTVMU w 4OBDLCBS%VSBUJPO w 4OBDLCBS)PTU4UBUF w 4OBDLCBS w 4OBDLCBS)PTU w SFNFNCFS4OBDLCBS)PTU4UBUF

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

@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

Slide 113

Slide 113 text

@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

Slide 114

Slide 114 text

@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

Slide 115

Slide 115 text

@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

Slide 116

Slide 116 text

@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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

-PDBM$POUFOU$PMPS 5FYU*DPODPNQPTBCMF

Slide 120

Slide 120 text

XSBQQFSPG5FYUDPNQPTBCMF w %FGBVMUWBMVFPGDPMPSTIPVMECF$PMPS6OTQFDJ fi FE @Composable fun Text( … color: Color = Color.Unspecified, … ) { androidx.compose.material3.Text( … color = color, … ) } 0, = MyTheme.color.onBackground, /( $VTUPN

Slide 121

Slide 121 text

-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 .

Slide 122

Slide 122 text

@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 ) } } } } .

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

-PDBM5FYU4UZMFQSPCMFN

Slide 127

Slide 127 text

-PDBM5FYU4UZMF @Composable fun Text( … color: Color = Color.Unspecified, … style: TextStyle = LocalTextStyle.current ) { … val mergedStyle = style.merge( … ) BasicText( … mergedStyle, … ) } .

Slide 128

Slide 128 text

5PQ"QQ#BS @Composable fun TopAppBar( title: @Composable () -> Unit, … ) { SingleRowTopAppBar( … titleTextStyle = MaterialTheme.typography.fromToken(TopAppBarSmallTokens.HeadlineFont), … ) } val HeadlineFont = TypographyKeyTokens.TitleLarge .

Slide 129

Slide 129 text

@Composable private fun SingleRowTopAppBar( … titleTextStyle: TextStyle, … ) { … Surface(…) { … TopAppBarLayout( … titleTextStyle = titleTextStyle, … ) } } .

Slide 130

Slide 130 text

@Composable private fun TopAppBarLayout( … title: @Composable () -> Unit, titleTextStyle: TextStyle, … ) { Layout( { … Box( Modifier .layoutId("title") … ) { ProvideTextStyle(value = titleTextStyle) { CompositionLocalProvider( LocalContentColor provides titleContentColor, content = title ) } } … } .

Slide 131

Slide 131 text

@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) } .

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

-PDBM5FYU4UZMFQSPCMFN

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

@Composable fun TopAppBar( title: String, … ) { androidx.compose.material3.TopAppBar( title = { Text( text = title, style = MyTheme.typography.titleLarge ) }, … ) } $VTUPN

Slide 136

Slide 136 text

%FTJHO5PLFOPG#

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

(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, ) … }

Slide 139

Slide 139 text

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, … ) {

Slide 140

Slide 140 text

%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), ) {

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

5IBOLZPV