diff --git a/adapt/src/androidMain/kotlin/design/adapt/previews/cupertino/Button.kt b/adapt/src/androidMain/kotlin/design/adapt/previews/cupertino/Button.kt new file mode 100644 index 0000000..e3a8b8c --- /dev/null +++ b/adapt/src/androidMain/kotlin/design/adapt/previews/cupertino/Button.kt @@ -0,0 +1,451 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.previews.cupertino + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.movableContentOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.rememberVectorPainter +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import design.adapt.cupertino.CupertinoButton +import design.adapt.cupertino.CupertinoButtonDefaults +import design.adapt.cupertino.CupertinoButtonSize +import design.adapt.cupertino.CupertinoButtonStyle +import design.adapt.cupertino.CupertinoIcon +import design.adapt.cupertino.CupertinoText +import design.adapt.cupertino.LocalCupertinoColors +import design.adapt.cupertino.cupertinoColorsDark + +@Preview(device = "spec:id=reference_desktop,shape=Normal,width=1920,height=1700,unit=dp,dpi=160") +@Composable +fun LightMode() { + Buttons() +} + +@Preview( + device = "spec:id=reference_desktop,shape=Normal,width=1920,height=1700,unit=dp,dpi=160", + uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL +) +@Composable +fun DarkMode() { + CompositionLocalProvider(LocalCupertinoColors provides cupertinoColorsDark) { + Buttons() + } +} + +@Composable +private fun Buttons() { + val text = remember { + movableContentOf { + CupertinoText(text = "Play") + } + } + val icon = remember { + movableContentOf { + CupertinoIcon( + modifier = Modifier.size(CupertinoButtonDefaults.IconSize), + painter = rememberVectorPainter(image = Icons.Default.PlayArrow), + contentDescription = null, + ) + } + } + val padding1 = remember { movableContentOf { Spacer(modifier = Modifier.width(14.dp)) } } + val padding2 = remember { movableContentOf { Spacer(modifier = Modifier.width(44.dp)) } } + val padding3 = remember { movableContentOf { Spacer(modifier = Modifier.width(15.dp)) } } + val padding4 = remember { movableContentOf { Spacer(modifier = Modifier.width(45.dp)) } } + val padding5 = remember { movableContentOf { Spacer(modifier = Modifier.width(18.dp)) } } + val padding6 = remember { movableContentOf { Spacer(modifier = Modifier.width(4.dp)) } } + val padding7 = remember { movableContentOf { Spacer(modifier = Modifier.width(56.dp)) } } + val padding8 = remember { movableContentOf { Spacer(modifier = Modifier.width(88.dp)) } } + val padding9 = remember { movableContentOf { Spacer(modifier = Modifier.width(60.dp)) } } + val padding10 = remember { movableContentOf { Spacer(modifier = Modifier.width(92.dp)) } } + val padding11 = remember { movableContentOf { Spacer(modifier = Modifier.width(64.dp)) } } + val padding12 = remember { movableContentOf { Spacer(modifier = Modifier.width(40.dp)) } } + val padding13 = remember { movableContentOf { Spacer(modifier = Modifier.width(68.dp)) } } + val gapBetweenButtonTypes = remember { movableContentOf { Spacer(modifier = Modifier.height(40.dp)) } } + + Box( + modifier = Modifier + .background( + color = Color(color = 0xFFCCCCCC), + shape = RoundedCornerShape(2.dp) + ) + .border( + width = 1.dp, + color = Color.Black.copy(alpha = 0.25f), + shape = RoundedCornerShape(2.dp) + ) + ) { + Column( + modifier = Modifier.padding(32.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + // Borderless + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Borderless, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Borderless, onMaterial = true) + } + + gapBetweenButtonTypes() + + // Bezeled Gray + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.BezeledGray, onMaterial = true) + } + + gapBetweenButtonTypes() + + // Bezeled + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Bezeled, onMaterial = true) + } + + gapBetweenButtonTypes() + + // Filled + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding1() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding2() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding3() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding4() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding5() + CupertinoButton(onClick = {}, text = text, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + Row { + padding6() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding7() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding8() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding9() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding10() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding11() + CupertinoButton(onClick = {}, icon = icon, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = true, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + Row { + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Small, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding12() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Medium, style = CupertinoButtonStyle.Filled, onMaterial = true) + padding13() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = false) + padding2() + CupertinoButton(onClick = {}, text = text, enabled = false, size = CupertinoButtonSize.Large, style = CupertinoButtonStyle.Filled, onMaterial = true) + } + } + } +} diff --git a/adapt/src/commonMain/kotlin/design/adapt/cupertino/Button.kt b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Button.kt new file mode 100644 index 0000000..3d04446 --- /dev/null +++ b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Button.kt @@ -0,0 +1,279 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.cupertino + +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Composable +fun CupertinoButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + size: CupertinoButtonSize = CupertinoButtonSize.Small, + style: CupertinoButtonStyle = CupertinoButtonStyle.Borderless, + colors: CupertinoButtonColors = CupertinoButtonDefaults.buttonColors(), + shape: Shape? = null, + enabled: Boolean = true, + onMaterial: Boolean = false, + textStyle: TextStyle = CupertinoButtonDefaults.textStyle(size), + icon: (@Composable () -> Unit)? = null, + text: (@Composable () -> Unit)? = null, +) { + val isInLightMode = !isSystemInDarkTheme() + + val isIconOnly = remember(icon, text) { icon != null && text == null } + + val defaultShape = remember(shape, isIconOnly, size) { + shape ?: CupertinoButtonDefaults.shape(isIconOnly = isIconOnly, size = size) + } + + val horizontalArrangement: Dp = remember(size) { + when (size) { + CupertinoButtonSize.Small -> 3.dp + CupertinoButtonSize.Medium -> 4.dp + CupertinoButtonSize.Large -> 4.dp + } + } + + val horizontalPadding: Dp = remember(size) { + when (size) { + CupertinoButtonSize.Small -> 10.dp + CupertinoButtonSize.Medium -> 14.dp + CupertinoButtonSize.Large -> 20.dp + } + } + + val verticalPadding: Dp = remember(size) { + when (size) { + CupertinoButtonSize.Small -> 4.dp + CupertinoButtonSize.Medium -> 7.dp + CupertinoButtonSize.Large -> 14.dp + } + } + + val containerColor: Color = remember(style, enabled, isInLightMode, onMaterial, colors) { + when (style) { + CupertinoButtonStyle.Borderless -> { + if (enabled) colors.borderlessContainerColor + else colors.disabledBorderlessContainerColor + } + + CupertinoButtonStyle.BezeledGray -> { + if (enabled) colors.bezeledGrayContainerColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialBezeledGrayContainerColor + else colors.disabledBezeledGrayContainerColor + } + + CupertinoButtonStyle.Bezeled -> { + if (enabled) colors.bezeledContainerColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialBezeledContainerColor + else colors.disabledBezeledContainerColor + } + + CupertinoButtonStyle.Filled -> { + if (enabled) colors.filledContainerColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialFilledContainerColor + else colors.disabledFilledContainerColor + } + } + } + + val contentColor: Color = remember(style, enabled, isInLightMode, onMaterial, colors) { + when (style) { + CupertinoButtonStyle.Borderless -> { + if (enabled) colors.borderlessContentColor + else colors.disabledBorderlessContentColor + } + + CupertinoButtonStyle.BezeledGray -> { + if (enabled) colors.bezeledGrayContentColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialBezeledGrayContentColor + else colors.disabledBezeledGrayContentColor + } + + CupertinoButtonStyle.Bezeled -> { + if (enabled) colors.bezeledContentColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialBezeledContentColor + else colors.disabledBezeledContentColor + } + + CupertinoButtonStyle.Filled -> { + if (enabled) colors.filledContentColor + // The material color should only be used with light mode + else if (isInLightMode && onMaterial) colors.disabledOnMaterialFilledContentColor + else colors.disabledFilledContentColor + } + } + } + + Row( + modifier = modifier + .pointerInput(Unit) { detectTapGestures { onClick() } } + .background(color = containerColor, shape = defaultShape) + .padding( + horizontal = if (isIconOnly) verticalPadding else horizontalPadding, + vertical = verticalPadding, + ), + horizontalArrangement = Arrangement.spacedBy(horizontalArrangement), + verticalAlignment = Alignment.CenterVertically, + ) { + icon?.let { safeIcon -> + CompositionLocalProvider(LocalContentColor provides contentColor) { + Box( + modifier = Modifier.defaultMinSize( + minWidth = CupertinoButtonDefaults.IconSize, + minHeight = CupertinoButtonDefaults.IconSize, + ), + contentAlignment = Alignment.Center, + ) { + safeIcon() + } + } + } + + text?.let { safeText -> + CompositionLocalProvider( + LocalCupertinoTextStyle provides textStyle, + LocalContentColor provides contentColor, + content = safeText, + ) + } + } +} + +@Immutable +data class CupertinoButtonColors( + val borderlessContainerColor: Color, + val borderlessContentColor: Color, + val bezeledGrayContainerColor: Color, + val bezeledGrayContentColor: Color, + val bezeledContainerColor: Color, + val bezeledContentColor: Color, + val filledContainerColor: Color, + val filledContentColor: Color, + val disabledBorderlessContainerColor: Color, + val disabledBorderlessContentColor: Color, + val disabledBezeledGrayContainerColor: Color, + val disabledBezeledGrayContentColor: Color, + val disabledBezeledContainerColor: Color, + val disabledBezeledContentColor: Color, + val disabledFilledContainerColor: Color, + val disabledFilledContentColor: Color, + val disabledOnMaterialBezeledGrayContainerColor: Color, + val disabledOnMaterialBezeledGrayContentColor: Color, + val disabledOnMaterialBezeledContainerColor: Color, + val disabledOnMaterialBezeledContentColor: Color, + val disabledOnMaterialFilledContainerColor: Color, + val disabledOnMaterialFilledContentColor: Color, +) + +object CupertinoButtonDefaults { + @Composable + fun buttonColors( + borderlessContainerColor: Color = Color.Transparent, + borderlessContentColor: Color = CupertinoTheme.colors.systemBlue, + bezeledGrayContainerColor: Color = CupertinoTheme.colors.fillTertiary, + bezeledGrayContentColor: Color = CupertinoTheme.colors.systemBlue, + bezeledContainerColor: Color = CupertinoTheme.colors.systemBlue.copy(alpha = 0.15f), + bezeledContentColor: Color = CupertinoTheme.colors.systemBlue, + filledContainerColor: Color = CupertinoTheme.colors.systemBlue, + filledContentColor: Color = CupertinoTheme.colors.systemWhite, + disabledBorderlessContainerColor: Color = Color.Transparent, + disabledBorderlessContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledBezeledGrayContainerColor: Color = CupertinoTheme.colors.fillTertiary, + disabledBezeledGrayContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledBezeledContainerColor: Color = CupertinoTheme.colors.fillTertiary, + disabledBezeledContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledFilledContainerColor: Color = CupertinoTheme.colors.fillTertiary, + disabledFilledContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledOnMaterialBezeledGrayContainerColor: Color = CupertinoTheme.colors.systemWhite.copy(alpha = 0.12f), + disabledOnMaterialBezeledGrayContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledOnMaterialBezeledContainerColor: Color = CupertinoTheme.colors.systemWhite.copy(alpha = 0.12f), + disabledOnMaterialBezeledContentColor: Color = CupertinoTheme.colors.labelTertiary, + disabledOnMaterialFilledContainerColor: Color = CupertinoTheme.colors.systemWhite.copy(alpha = 0.12f), + disabledOnMaterialFilledContentColor: Color = CupertinoTheme.colors.labelTertiary, + ): CupertinoButtonColors = CupertinoButtonColors( + borderlessContainerColor = borderlessContainerColor, + borderlessContentColor = borderlessContentColor, + bezeledGrayContainerColor = bezeledGrayContainerColor, + bezeledGrayContentColor = bezeledGrayContentColor, + bezeledContainerColor = bezeledContainerColor, + bezeledContentColor = bezeledContentColor, + filledContainerColor = filledContainerColor, + filledContentColor = filledContentColor, + disabledBorderlessContainerColor = disabledBorderlessContainerColor, + disabledBorderlessContentColor = disabledBorderlessContentColor, + disabledBezeledGrayContainerColor = disabledBezeledGrayContainerColor, + disabledBezeledGrayContentColor = disabledBezeledGrayContentColor, + disabledBezeledContainerColor = disabledBezeledContainerColor, + disabledBezeledContentColor = disabledBezeledContentColor, + disabledFilledContainerColor = disabledFilledContainerColor, + disabledFilledContentColor = disabledFilledContentColor, + disabledOnMaterialBezeledGrayContainerColor = disabledOnMaterialBezeledGrayContainerColor, + disabledOnMaterialBezeledGrayContentColor = disabledOnMaterialBezeledGrayContentColor, + disabledOnMaterialBezeledContainerColor = disabledOnMaterialBezeledContainerColor, + disabledOnMaterialBezeledContentColor = disabledOnMaterialBezeledContentColor, + disabledOnMaterialFilledContainerColor = disabledOnMaterialFilledContainerColor, + disabledOnMaterialFilledContentColor = disabledOnMaterialFilledContentColor, + ) + + fun shape(isIconOnly: Boolean, size: CupertinoButtonSize): Shape = RoundedCornerShape( + when { + isIconOnly -> 400.dp + size == CupertinoButtonSize.Large -> 12.dp + else -> 40.dp + } + ) + + @Composable + fun textStyle(size: CupertinoButtonSize): TextStyle = with(LocalCupertinoTypography.current) { + when (size) { + CupertinoButtonSize.Small -> subheadlineRegular + CupertinoButtonSize.Medium -> subheadlineRegular + CupertinoButtonSize.Large -> bodyRegular + } + } + + val IconSize = 20.dp +} + +enum class CupertinoButtonSize { Small, Medium, Large } +enum class CupertinoButtonStyle { Borderless, BezeledGray, Bezeled, Filled } diff --git a/adapt/src/commonMain/kotlin/design/adapt/cupertino/Colors.kt b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Colors.kt new file mode 100644 index 0000000..5fec794 --- /dev/null +++ b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Colors.kt @@ -0,0 +1,184 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.cupertino + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Color + +object CupertinoTheme { + val colors: CupertinoColors + @Composable + @ReadOnlyComposable + get() = LocalCupertinoColors.current +} + +val LocalCupertinoColors = compositionLocalOf { cupertinoColorsLight } + +val LocalContentColor = compositionLocalOf { cupertinoColorsLight.systemBlue } + +@Immutable +data class CupertinoColors( + val systemRed: Color, + val systemOrange: Color, + val systemYellow: Color, + val systemGreen: Color, + val systemMint: Color, + val systemTeal: Color, + val systemCyan: Color, + val systemBlue: Color, + val systemIndigo: Color, + val systemPurple: Color, + val systemPink: Color, + val systemBrown: Color, + val systemBlack: Color, + val systemGray: Color, + val systemGray2: Color, + val systemGray3: Color, + val systemGray4: Color, + val systemGray5: Color, + val systemGray6: Color, + val systemWhite: Color, + val systemBackgroundPrimary: (CupertinoBackgroundColorVariant) -> Color, + val systemBackgroundSecondary: (CupertinoBackgroundColorVariant) -> Color, + val systemBackgroundTertiary: (CupertinoBackgroundColorVariant) -> Color, + val labelPrimary: Color, + val labelSecondary: Color, + val labelTertiary: Color, + val labelQuaternary: Color, + val systemGroupedBackgroundPrimary: (CupertinoBackgroundColorVariant) -> Color, + val systemGroupedBackgroundSecondary: (CupertinoBackgroundColorVariant) -> Color, + val systemGroupedBackgroundTertiary: (CupertinoBackgroundColorVariant) -> Color, + val fillPrimary: Color, + val fillSecondary: Color, + val fillTertiary: Color, + val fillQuaternary: Color, + val separatorOpaque: Color, + val separatorNonOpaque: Color, +) + +enum class CupertinoBackgroundColorVariant { Elevated, Base } + +internal val cupertinoColorsLight = CupertinoColors( + systemRed = Color(0XFFFF3B30), + systemOrange = Color(0XFFFF9500), + systemYellow = Color(0XFFFFCC00), + systemGreen = Color(0XFF34C759), + systemMint = Color(0XFF00C7BE), + systemTeal = Color(0XFF30B0C7), + systemCyan = Color(0XFF32ADE6), + systemBlue = Color(0XFF007AFF), + systemIndigo = Color(0XFF5856D6), + systemPurple = Color(0XFFAF52DE), + systemPink = Color(0XFFFF2D55), + systemBrown = Color(0XFFA2845E), + systemBlack = Color(0XFF000000), + systemGray = Color(0XFF8E8E93), + systemGray2 = Color(0XFFAEAEB2), + systemGray3 = Color(0XFFC7C7CC), + systemGray4 = Color(0XFFD1D1D6), + systemGray5 = Color(0XFFE5E5EA), + systemGray6 = Color(0XFFF2F2F7), + systemWhite = Color(0XFFFFFFFF), + systemBackgroundPrimary = { Color(0XFFFFFFFF) }, + systemBackgroundSecondary = { Color(0XFFF2F2F7) }, + systemBackgroundTertiary = { Color(0XFFFFFFFF) }, + labelPrimary = Color(0XFF000000), + labelSecondary = Color(0X993C3C43), + labelTertiary = Color(0X4D3C3C43), + labelQuaternary = Color(0X2E3C3C43), + systemGroupedBackgroundPrimary = { Color(0XFFF2F2F7) }, + systemGroupedBackgroundSecondary = { Color(0XFFFFFFFF) }, + systemGroupedBackgroundTertiary = { Color(0XFFF2F2F7) }, + fillPrimary = Color(0X33787880), + fillSecondary = Color(0X29787880), + fillTertiary = Color(0X1F767680), + fillQuaternary = Color(0X14747480), + separatorOpaque = Color(0XFFC6C6C8), + separatorNonOpaque = Color(0X5C3C3C43), +) + +internal val cupertinoColorsDark = CupertinoColors( + systemRed = Color(0XFFFF453A), + systemOrange = Color(0XFFFF9F0A), + systemYellow = Color(0XFFFFD60A), + systemGreen = Color(0XFF30D158), + systemMint = Color(0XFF63E6E2), + systemTeal = Color(0XFF40CBE0), + systemCyan = Color(0XFF64D2FF), + systemBlue = Color(0XFF0A84FF), + systemIndigo = Color(0XFF5E5CE6), + systemPurple = Color(0XFFBF5AF2), + systemPink = Color(0XFFFF375F), + systemBrown = Color(0XFFAC8E68), + systemBlack = Color(0XFF000000), + systemGray = Color(0XFF8E8E93), + systemGray2 = Color(0XFF8E8E93), + systemGray3 = Color(0XFF48484A), + systemGray4 = Color(0XFF3A3A3C), + systemGray5 = Color(0XFF2C2C2E), + systemGray6 = Color(0XFF1C1C1E), + systemWhite = Color(0XFFFFFFFF), + systemBackgroundPrimary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF1C1C1E) + CupertinoBackgroundColorVariant.Base -> Color(0XFF000000) + } + }, + systemBackgroundSecondary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF2C2C2E) + CupertinoBackgroundColorVariant.Base -> Color(0XFF1C1C1E) + } + }, + systemBackgroundTertiary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF3A3A3C) + CupertinoBackgroundColorVariant.Base -> Color(0XFF2C2C2E) + } + }, + labelPrimary = Color(0XFFFFFFFF), + labelSecondary = Color(0X99EBEBF5), + labelTertiary = Color(0X4DEBEBF5), + labelQuaternary = Color(0X29EBEBF5), + systemGroupedBackgroundPrimary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF1C1C1E) + CupertinoBackgroundColorVariant.Base -> Color(0XFF000000) + } + }, + systemGroupedBackgroundSecondary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF2C2C2E) + CupertinoBackgroundColorVariant.Base -> Color(0XFF1C1C1E) + } + }, + systemGroupedBackgroundTertiary = { variant -> + when (variant) { + CupertinoBackgroundColorVariant.Elevated -> Color(0XFF3A3A3C) + CupertinoBackgroundColorVariant.Base -> Color(0XFF2C2C2E) + } + }, + fillPrimary = Color(0X5C787880), + fillSecondary = Color(0X52787880), + fillTertiary = Color(0X3D767680), + fillQuaternary = Color(0X2E747480), + separatorOpaque = Color(0XFF38383A), + separatorNonOpaque = Color(0XA6545458), +) diff --git a/adapt/src/commonMain/kotlin/design/adapt/cupertino/Icon.kt b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Icon.kt new file mode 100644 index 0000000..087db30 --- /dev/null +++ b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Icon.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.cupertino + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.toolingGraphicsLayer +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp + +@Composable +fun CupertinoIcon( + painter: Painter, + contentDescription: String?, + modifier: Modifier = Modifier, + tint: Color = LocalContentColor.current +) { + val colorFilter = remember(tint) { + if (tint == Color.Unspecified) null else ColorFilter.tint(tint) + } + val semantics = + if (contentDescription != null) { + Modifier.semantics { + this.contentDescription = contentDescription + this.role = Role.Image + } + } else { + Modifier + } + Box( + modifier + .toolingGraphicsLayer() + .defaultSizeFor(painter) + .paint(painter, colorFilter = colorFilter, contentScale = ContentScale.Fit) + .then(semantics) + ) +} + +private fun Modifier.defaultSizeFor(painter: Painter) = + this.then( + if (painter.intrinsicSize == Size.Unspecified || painter.intrinsicSize.isInfinite()) { + DefaultIconSizeModifier + } else { + Modifier + } + ) + +private fun Size.isInfinite() = width.isInfinite() && height.isInfinite() + +// Default icon size, for icons with no intrinsic size information +private val DefaultIconSizeModifier = Modifier.size(16.dp, 20.dp) diff --git a/adapt/src/commonMain/kotlin/design/adapt/cupertino/Text.kt b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Text.kt new file mode 100644 index 0000000..3b05829 --- /dev/null +++ b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Text.kt @@ -0,0 +1,111 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.cupertino + +import androidx.compose.foundation.text.BasicText +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorProducer +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextOverflow + +@Composable +fun CupertinoText( + text: String, + modifier: Modifier = Modifier, + style: TextStyle? = null, + onTextLayout: ((TextLayoutResult) -> Unit)? = null, + overflow: TextOverflow = TextOverflow.Clip, + softWrap: Boolean = true, + maxLines: Int = Int.MAX_VALUE, + minLines: Int = 1, + color: ColorProducer? = null +) { + val contentColor = LocalContentColor.current + style?.let { safeStyle -> + CompositionLocalProvider(LocalCupertinoTextStyle provides safeStyle) { + BasicText( + text = text, + modifier = modifier, + style = LocalCupertinoTextStyle.current, + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines, + color = color, + ) + } + } ?: run { + BasicText( + text = text, + modifier = modifier, + style = LocalCupertinoTextStyle.current, + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines, + color = color ?: ColorProducer { contentColor }, + ) + } +} + +@Composable +fun CupertinoText( + text: AnnotatedString, + modifier: Modifier = Modifier, + style: TextStyle? = null, + onTextLayout: ((TextLayoutResult) -> Unit)? = null, + overflow: TextOverflow = TextOverflow.Clip, + softWrap: Boolean = true, + maxLines: Int = Int.MAX_VALUE, + minLines: Int = 1, + color: ColorProducer? = null +) { + val contentColor = LocalContentColor.current + style?.let { safeStyle -> + CompositionLocalProvider(LocalCupertinoTextStyle provides safeStyle) { + BasicText( + text = text, + modifier = modifier, + style = LocalCupertinoTextStyle.current, + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines, + color = color, + ) + } + } ?: run { + BasicText( + text = text, + modifier = modifier, + style = LocalCupertinoTextStyle.current, + onTextLayout = onTextLayout, + overflow = overflow, + softWrap = softWrap, + maxLines = maxLines, + minLines = minLines, + color = color ?: ColorProducer { contentColor }, + ) + } +} diff --git a/adapt/src/commonMain/kotlin/design/adapt/cupertino/Typography.kt b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Typography.kt new file mode 100644 index 0000000..b0854f6 --- /dev/null +++ b/adapt/src/commonMain/kotlin/design/adapt/cupertino/Typography.kt @@ -0,0 +1,308 @@ +/* + * Copyright 2023 Shubham Singh + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package design.adapt.cupertino + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +@Immutable +data class CupertinoTypography( + val fontFamily: FontFamily? = null, + val largeTitleRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 34.sp, + lineHeight = 41.sp, + letterSpacing = (-0.4).sp, + ), + val largeTitleEmphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Bold, + fontStyle = FontStyle.Normal, + fontSize = 34.sp, + lineHeight = 41.sp, + letterSpacing = (-0.4).sp, + ), + val title1Regular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 28.sp, + lineHeight = 34.sp, + letterSpacing = (-0.4).sp, + ), + val title1Emphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Bold, + fontStyle = FontStyle.Normal, + fontSize = 28.sp, + lineHeight = 34.sp, + letterSpacing = (-0.4).sp, + ), + val title2Regular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = (-0.4).sp, + ), + val title2Emphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Bold, + fontStyle = FontStyle.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = (-0.4).sp, + ), + val title3Regular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 20.sp, + lineHeight = 25.sp, + letterSpacing = (-0.4).sp, + ), + val title3Emphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 20.sp, + lineHeight = 25.sp, + letterSpacing = (-0.4).sp, + ), + val headlineRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val headlineItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val bodyRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val bodyEmphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val bodyItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val bodyEmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 17.sp, + lineHeight = 22.sp, + letterSpacing = (-0.4).sp, + ), + val calloutRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 16.sp, + lineHeight = 21.sp, + letterSpacing = (-0.4).sp, + ), + val calloutEmphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 16.sp, + lineHeight = 21.sp, + letterSpacing = (-0.4).sp, + ), + val calloutItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 16.sp, + lineHeight = 21.sp, + letterSpacing = (-0.4).sp, + ), + val calloutEmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 16.sp, + lineHeight = 21.sp, + letterSpacing = (-0.4).sp, + ), + val subheadlineRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = (-0.4).sp, + ), + val subheadlineEmphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = (-0.4).sp, + ), + val subheadlineItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = (-0.4).sp, + ), + val subheadlineEmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 15.sp, + lineHeight = 20.sp, + letterSpacing = (-0.4).sp, + ), + val footnoteRegular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = (-0.4).sp, + ), + val footnoteEmphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = (-0.4).sp, + ), + val footnoteItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = (-0.4).sp, + ), + val footnoteEmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 13.sp, + lineHeight = 18.sp, + letterSpacing = (-0.4).sp, + ), + val caption1Regular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = (-0.4).sp, + ), + val caption1Emphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Medium, + fontStyle = FontStyle.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = (-0.4).sp, + ), + val caption1Italic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = (-0.4).sp, + ), + val caption1EmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Medium, + fontStyle = FontStyle.Italic, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = (-0.4).sp, + ), + val caption2Regular: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + fontSize = 11.sp, + lineHeight = 13.sp, + letterSpacing = (-0.4).sp, + ), + val caption2Emphasised: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Normal, + fontSize = 11.sp, + lineHeight = 13.sp, + letterSpacing = (-0.4).sp, + ), + val caption2Italic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Italic, + fontSize = 11.sp, + lineHeight = 13.sp, + letterSpacing = (-0.4).sp, + ), + val caption2EmphasisedItalic: TextStyle = TextStyle( + fontFamily = fontFamily, + fontWeight = FontWeight.SemiBold, + fontStyle = FontStyle.Italic, + fontSize = 11.sp, + lineHeight = 13.sp, + letterSpacing = (-0.4).sp, + ), +) + +val LocalCupertinoTextStyle = compositionLocalOf { CupertinoTypography().subheadlineRegular } + +val LocalCupertinoTypography = compositionLocalOf { CupertinoTypography() } + +// TODO: Create a composable font provider that uses the SF-Pro font family here