Skip to content

Instantly share code, notes, and snippets.

@mirzemehdi
Last active January 18, 2024 02:14
Show Gist options
  • Select an option

  • Save mirzemehdi/1760e9381dfa385e5f27290cbe0caa5e to your computer and use it in GitHub Desktop.

Select an option

Save mirzemehdi/1760e9381dfa385e5f27290cbe0caa5e to your computer and use it in GitHub Desktop.
AppleSignInButton - Can be used in Compose Multliplatform
#AppleSignInButton - Can be used in Compose Kotlin Multliplatform that follows
Apple's design guidelines and can be easily customized to fit into your project.
package com.mmk.kmpauth.uihelper.apple
public sealed interface AppleButtonMode {
public data object Black : AppleButtonMode
public data object White : AppleButtonMode
public data object WhiteWithOutline : AppleButtonMode
}
package com.mmk.kmpauth.uihelper.apple
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
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.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.graphics.graphicsLayer
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.mmk.kmpauth.uihelper.theme.Fonts
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
import kotlin.math.roundToInt
@Composable
public fun AppleSignInButtonIconOnly(
modifier: Modifier = Modifier.size(44.dp),
mode: AppleButtonMode = AppleButtonMode.Black,
shape: Shape = ButtonDefaults.shape,
onClick: () -> Unit,
) {
val buttonColor = getButtonColor(mode)
val borderStroke = getBorderStroke(mode)
var buttonHeight by remember { mutableStateOf(44) }
val localDensity = LocalDensity.current
Button(
modifier = modifier
.onGloballyPositioned { coordinates ->
buttonHeight =
with(localDensity) { coordinates.size.height.toDp().value.roundToInt() }
},
contentPadding = PaddingValues(0.dp),
onClick = onClick,
shape = shape,
colors = buttonColor,
border = borderStroke,
) {
AppleIcon(modifier = Modifier.size(buttonHeight.dp), mode = mode)
}
}
/**
* As per guideline
* call-to-action should be "Sign in with Apple", "Sign up with Apple", or "Continue with Apple".
*/
@Composable
public fun AppleSignInButton(
modifier: Modifier = Modifier.height(44.dp),
mode: AppleButtonMode = AppleButtonMode.Black,
text: String = "Sign in with Apple",
fontFamily: FontFamily? = null,
shape: Shape = ButtonDefaults.shape,
onClick: () -> Unit,
) {
val buttonColor = getButtonColor(mode)
val borderStroke = getBorderStroke(mode)
val horizontalPadding = 0.dp
val iconTextPadding = 0.dp
var fontSize by remember { mutableStateOf(19) }
var buttonHeight by remember { mutableStateOf(44) }
var marginEnd by remember { mutableStateOf(0) }
val localDensity = LocalDensity.current
Button(
modifier = modifier
.onGloballyPositioned { coordinates ->
val height =
with(localDensity) { coordinates.size.height.toDp().value.roundToInt() }
val width = with(localDensity) { coordinates.size.width.toDp().value.roundToInt() }
marginEnd = (width * 0.08).roundToInt()
buttonHeight = height
fontSize = ((height * 0.43).roundToInt())
}.defaultMinSize(minWidth = 140.dp, minHeight = 30.dp),
contentPadding = PaddingValues(horizontal = horizontalPadding),
onClick = onClick,
shape = shape,
colors = buttonColor,
border = borderStroke,
) {
Row(verticalAlignment = Alignment.CenterVertically) {
AppleIcon(modifier = Modifier.size(buttonHeight.dp), mode = mode)
Spacer(modifier = Modifier.width(iconTextPadding))
Text(
modifier = Modifier.graphicsLayer {
translationY = (-1).dp.toPx()
}
.padding(end = marginEnd.dp),
text = text,
fontSize = fontSize.sp,
maxLines = 1,
fontFamily = fontFamily,
)
}
}
}
@OptIn(ExperimentalResourceApi::class)
@Composable
private fun AppleIcon(modifier: Modifier = Modifier, mode: AppleButtonMode) {
val source = when (mode) {
AppleButtonMode.Black -> "drawable/ic_apple_logo_white.xml"
AppleButtonMode.White -> "drawable/ic_apple_logo_black.xml"
AppleButtonMode.WhiteWithOutline -> "drawable/ic_apple_logo_black.xml"
}
Image(
modifier = modifier,
painter = painterResource(source),
contentDescription = "appleIcon"
)
}
private fun getBorderStroke(mode: AppleButtonMode): BorderStroke? {
val borderStroke = when (mode) {
AppleButtonMode.WhiteWithOutline -> BorderStroke(
width = 1.dp,
color = Color.Black,
)
else -> null
}
return borderStroke
}
@Composable
private fun getButtonColor(mode: AppleButtonMode): ButtonColors {
val containerColor = when (mode) {
AppleButtonMode.Black -> Color.Black
else -> Color.White
}
val contentColor = when (mode) {
AppleButtonMode.Black -> Color.White
else -> Color.Black
}
return ButtonDefaults.buttonColors(containerColor = containerColor, contentColor = contentColor)
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:viewportWidth="56"
android:viewportHeight="56">
<path
android:pathData="M6,6h44v44h-44z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M28.223,20.385C29.055,20.385 30.098,19.805 30.719,19.032C31.281,18.331 31.691,17.353 31.691,16.374C31.691,16.242 31.68,16.109 31.656,16C30.73,16.036 29.617,16.64 28.949,17.449C28.422,18.065 27.941,19.032 27.941,20.022C27.941,20.167 27.965,20.312 27.977,20.36C28.035,20.373 28.129,20.385 28.223,20.385ZM25.293,35C26.43,35 26.934,34.215 28.352,34.215C29.793,34.215 30.109,34.976 31.375,34.976C32.617,34.976 33.449,33.792 34.234,32.633C35.113,31.304 35.477,29.999 35.5,29.939C35.418,29.915 33.039,28.912 33.039,26.098C33.039,23.658 34.914,22.559 35.02,22.474C33.777,20.638 31.891,20.59 31.375,20.59C29.98,20.59 28.844,21.46 28.129,21.46C27.355,21.46 26.336,20.638 25.129,20.638C22.832,20.638 20.5,22.595 20.5,26.291C20.5,28.586 21.367,31.014 22.434,32.584C23.348,33.913 24.145,35 25.293,35Z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="56dp"
android:height="56dp"
android:viewportWidth="56"
android:viewportHeight="56">
<path
android:pathData="M6,6h44v44h-44z"
android:strokeWidth="1"
android:fillColor="#000000"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M28.223,20.385C29.055,20.385 30.098,19.805 30.719,19.032C31.281,18.331 31.691,17.353 31.691,16.374C31.691,16.242 31.68,16.109 31.656,16C30.73,16.036 29.617,16.64 28.949,17.449C28.422,18.065 27.941,19.032 27.941,20.022C27.941,20.167 27.965,20.312 27.977,20.36C28.035,20.373 28.129,20.385 28.223,20.385ZM25.293,35C26.43,35 26.934,34.215 28.352,34.215C29.793,34.215 30.109,34.976 31.375,34.976C32.617,34.976 33.449,33.792 34.234,32.633C35.113,31.304 35.477,29.999 35.5,29.939C35.418,29.915 33.039,28.912 33.039,26.098C33.039,23.658 34.914,22.559 35.02,22.474C33.777,20.638 31.891,20.59 31.375,20.59C29.98,20.59 28.844,21.46 28.129,21.46C27.355,21.46 26.336,20.638 25.129,20.638C22.832,20.638 20.5,22.595 20.5,26.291C20.5,28.586 21.367,31.014 22.434,32.584C23.348,33.913 24.145,35 25.293,35Z"
android:strokeWidth="1"
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
</vector>
@mirzemehdi
Copy link
Author

@mirzemehdi
Copy link
Author

mirzemehdi commented Jan 17, 2024

Button different mode and shapes in android and ios

 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment