diff --git a/app/src/internal/java/com/kickstarter/ui/activities/DesignSystemActivity.kt b/app/src/internal/java/com/kickstarter/ui/activities/DesignSystemActivity.kt index 7a90720b07..01e8ecfd56 100644 --- a/app/src/internal/java/com/kickstarter/ui/activities/DesignSystemActivity.kt +++ b/app/src/internal/java/com/kickstarter/ui/activities/DesignSystemActivity.kt @@ -1,5 +1,6 @@ package com.kickstarter.ui.activities +import android.annotation.SuppressLint import android.content.res.Configuration import android.os.Bundle import android.view.View @@ -38,8 +39,11 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import com.kickstarter.R +import com.kickstarter.ui.compose.designsystem.FBLoginButton import com.kickstarter.ui.compose.designsystem.KSAlertDialog import com.kickstarter.ui.compose.designsystem.KSAlertDialogNoHeadline +import com.kickstarter.ui.compose.designsystem.KSButton +import com.kickstarter.ui.compose.designsystem.KSButtonType import com.kickstarter.ui.compose.designsystem.KSCheckbox import com.kickstarter.ui.compose.designsystem.KSCircularProgressIndicator import com.kickstarter.ui.compose.designsystem.KSClickableText @@ -110,6 +114,7 @@ fun DesignSystemViewPreview() { } } +@SuppressLint("UnrememberedMutableInteractionSource") @OptIn(ExperimentalComposeUiApi::class) @Composable fun DesignSystemView(darkMode: MutableState, onBackClicked: () -> Unit) { @@ -159,6 +164,10 @@ fun DesignSystemView(darkMode: MutableState, onBackClicked: () -> Unit) Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + NewDesignSystemButtonsVisuals() + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + BadgesVisuals() Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) @@ -344,6 +353,261 @@ fun ButtonsVisuals() { } } +@Composable +fun NewDesignSystemButtonsVisuals() { + Column { + Text( + text = "New Design System Buttons", + style = typographyV2.title1Bold, + color = colors.kds_support_700 + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Filled", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Green", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Inverted", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Borderless", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Outlined", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Outlined Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Borderless Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + + Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) + + FBLoginButton(onClickAction = {}, text = "Continue with Facebook") + FBLoginButton(onClickAction = {}, text = "Continue with Facebook", isPressed = true) + } +} + @Composable fun BadgesVisuals() { Column { @@ -563,7 +827,11 @@ fun FootersVisuals() { @Composable fun ClickableText() { Column { - Text(text = "Clickable Text", style = typographyV2.title1Bold, color = colors.kds_support_700) + Text( + text = "Clickable Text", + style = typographyV2.title1Bold, + color = colors.kds_support_700 + ) Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) @@ -592,7 +860,11 @@ fun Dividers() { fun TypographyVisuals() { Column { // NEW DESIGN SYSTEM - Text(text = "Heading2XL", style = typographyV2.heading2XL, color = colors.kds_support_700) + Text( + text = "Heading2XL", + style = typographyV2.heading2XL, + color = colors.kds_support_700 + ) Text(text = "HeadingXL", style = typographyV2.headingXL, color = colors.kds_support_700) Text(text = "HeadingLG", style = typographyV2.headingLG, color = colors.kds_support_700) Text(text = "HeadingMD", style = typographyV2.headingMD, color = colors.kds_support_700) @@ -602,21 +874,49 @@ fun TypographyVisuals() { Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) Text(text = "BodyXL", style = typographyV2.bodyXL, color = colors.kds_support_700) - Text(text = "BodyBoldXL", style = typographyV2.bodyBoldXL, color = colors.kds_support_700) + Text( + text = "BodyBoldXL", + style = typographyV2.bodyBoldXL, + color = colors.kds_support_700 + ) Text(text = "BodyLG", style = typographyV2.bodyLG, color = colors.kds_support_700) - Text(text = "BodyBoldLG", style = typographyV2.bodyBoldLG, color = colors.kds_support_700) + Text( + text = "BodyBoldLG", + style = typographyV2.bodyBoldLG, + color = colors.kds_support_700 + ) Text(text = "BodyMD", style = typographyV2.bodyMD, color = colors.kds_support_700) - Text(text = "BodyBoldMD", style = typographyV2.bodyBoldMD, color = colors.kds_support_700) + Text( + text = "BodyBoldMD", + style = typographyV2.bodyBoldMD, + color = colors.kds_support_700 + ) Text(text = "BodySM", style = typographyV2.bodySM, color = colors.kds_support_700) - Text(text = "BodyBoldSM", style = typographyV2.bodyBoldSM, color = colors.kds_support_700) + Text( + text = "BodyBoldSM", + style = typographyV2.bodyBoldSM, + color = colors.kds_support_700 + ) Text(text = "BodyXS", style = typographyV2.bodyXS, color = colors.kds_support_700) - Text(text = "BodyBoldXS", style = typographyV2.bodyBoldXS, color = colors.kds_support_700) + Text( + text = "BodyBoldXS", + style = typographyV2.bodyBoldXS, + color = colors.kds_support_700 + ) Text(text = "BodyXXS", style = typographyV2.bodyXXS, color = colors.kds_support_700) - Text(text = "BodyBoldXXS", style = typographyV2.bodyBoldXXS, color = colors.kds_support_700) + Text( + text = "BodyBoldXXS", + style = typographyV2.bodyBoldXXS, + color = colors.kds_support_700 + ) Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) - Text(text = "ButtonLabel", style = typographyV2.buttonLabel, color = colors.kds_support_700) + Text( + text = "ButtonLabel", + style = typographyV2.buttonLabel, + color = colors.kds_support_700 + ) Spacer(modifier = Modifier.height(dimensions.listItemSpacingMediumSmall)) @@ -629,15 +929,39 @@ fun TypographyVisuals() { // OLD DESIGN SYSTEM Text(text = "Title1", style = typographyV2.title1, color = colors.kds_support_700) - Text(text = "Title1Bold", style = typographyV2.title1Bold, color = colors.kds_support_700) + Text( + text = "Title1Bold", + style = typographyV2.title1Bold, + color = colors.kds_support_700 + ) Text(text = "Title2", style = typographyV2.title2, color = colors.kds_support_700) - Text(text = "Title2Bold", style = typographyV2.title2Bold, color = colors.kds_support_700) - Text(text = "TitleRewardBold", style = typographyV2.titleRewardBold, color = colors.kds_support_700) + Text( + text = "Title2Bold", + style = typographyV2.title2Bold, + color = colors.kds_support_700 + ) + Text( + text = "TitleRewardBold", + style = typographyV2.titleRewardBold, + color = colors.kds_support_700 + ) Text(text = "Headline", style = typographyV2.headLine, color = colors.kds_support_700) Text(text = "Body", style = typographyV2.body, color = colors.kds_support_700) Text(text = "Footnote", style = typographyV2.footNote, color = colors.kds_support_700) - Text(text = "FootnoteMedium", style = typographyV2.footNoteMedium, color = colors.kds_support_700) - Text(text = "SubHeadline", style = typographyV2.subHeadline, color = colors.kds_support_700) - Text(text = "SubHeadlineMedium", style = typographyV2.subHeadlineMedium, color = colors.kds_support_700) + Text( + text = "FootnoteMedium", + style = typographyV2.footNoteMedium, + color = colors.kds_support_700 + ) + Text( + text = "SubHeadline", + style = typographyV2.subHeadline, + color = colors.kds_support_700 + ) + Text( + text = "SubHeadlineMedium", + style = typographyV2.subHeadlineMedium, + color = colors.kds_support_700 + ) } } diff --git a/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsColors.kt b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsColors.kt new file mode 100644 index 0000000000..bf6f8622f3 --- /dev/null +++ b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsColors.kt @@ -0,0 +1,138 @@ +package com.kickstarter.ui.compose.designsystem + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color + +@Immutable +data class KSButtonColors( + // Filled Button Colors + val filledBackgroundAction: Color = Color.Unspecified, + val filledBackgroundActionPressed: Color = Color.Unspecified, + val filledBackgroundActionDisabled: Color = Color.Unspecified, + val filledTextInverseDisabled: Color = Color.Unspecified, + val filledLoadingSpinner: Color = Color.Unspecified, + + // Green Button Colors + val greenBackgroundAccentBold: Color = Color.Unspecified, + val greenBackgroundAccentBoldPressed: Color = Color.Unspecified, + val greenBackgroundAccentDisabled: Color = Color.Unspecified, + val greenTextDisabled: Color = Color.Unspecified, + val greenLoadingSpinner: Color = Color.Unspecified, + + // Filled Inverted Button Colors + val filledInvertedBackgroundSurfacePrimary: Color = Color.Unspecified, + val filledInvertedBackgroundInversePressed: Color = Color.Unspecified, + val filledInvertedBackgroundInverseDisabled: Color = Color.Unspecified, + val filledInvertedTextPrimary: Color = Color.Unspecified, + val filledInvertedTextDisabled: Color = Color.Unspecified, + val filledInvertedLoadingSpinner: Color = Color.Unspecified, + + // Filled Destructive Button Colors + val destructiveBackgroundBold: Color = Color.Unspecified, + val destructiveBackgroundDisabled: Color = Color.Unspecified, + val destructiveTextInversePrimary: Color = Color.Unspecified, + val destructiveTextAccentRedInverseDisabled: Color = Color.Unspecified, + val destructiveLoadingSpinner: Color = Color.Unspecified, + + // Borderless Button Colors + val borderlessTextPrimary: Color = Color.Unspecified, + val borderlessBackgroundInversePressed: Color = Color.Unspecified, + val borderlessTextDisabled: Color = Color.Unspecified, + val borderlessLoadingSpinner: Color = Color.Unspecified, + + // Outlined Button Colors + val outlinedBorderBold: Color = Color.Unspecified, + val outlinedBackgroundInversePressed: Color = Color.Unspecified, + val outlinedBorderSubtle: Color = Color.Unspecified, + val outlinedTextPrimary: Color = Color.Unspecified, + val outlinedTextDisabled: Color = Color.Unspecified, + val outlinedLoadingSpinner: Color = Color.Unspecified, + + // Outlined Destructive Button Colors + val outlinedDestructiveBackgroundBold: Color = Color.Unspecified, + val outlinedDestructiveTextAccentRed: Color = Color.Unspecified, + val outlinedDestructiveBackgroundAccentRedSubtle: Color = Color.Unspecified, + val outlinedDestructiveBorderDangerBold: Color = Color.Unspecified, + val outlinedDestructiveTextAccentRedDisabled: Color = Color.Unspecified, + val outlinedDestructiveLoadingSpinner: Color = Color.Unspecified, + + // Borderless Destructive Button Colors + val borderlessDestructiveTextAccentRed: Color = Color.Unspecified, + val borderlessDestructiveTextAccentRedBolder: Color = Color.Unspecified, + val borderlessDestructiveTextAccentRedDisabled: Color = Color.Unspecified, + val borderlessDestructiveBackgroundAccentRedSubtle: Color = Color.Unspecified, + val borderlessDestructiveLoadingSpinner: Color = Color.Unspecified, + + // Facebook Login Button Colors + val fbLoginButtonBackgroundColor: Color = Color.Unspecified, + val fbLoginButtonTextColor: Color = Color.Unspecified, + val fbLoginButtonPressedColor: Color = Color.Unspecified, +) + +val LocalKSButtonColors = staticCompositionLocalOf { KSButtonColors() } + +val KSDefaultButtonColors = KSButtonColors( + // Filled Button Colors – reuse common neutral colors + filledBackgroundAction = Color(0xFF171717), + filledBackgroundActionPressed = Color(0xFF3C3C3C), + filledBackgroundActionDisabled = Color(0xFFB3B3B3), + filledTextInverseDisabled = Color(0xFFF2F2F2), + filledLoadingSpinner = Color(0xFF3C3C3C), + + // Green Button Colors + greenBackgroundAccentBold = Color(0xFF037242), + greenBackgroundAccentBoldPressed = Color(0xFF024629), + greenBackgroundAccentDisabled = Color(0xFFEBFEF6), + greenTextDisabled = Color(0xFFB3B3B3), + greenLoadingSpinner = Color(0xFF025A34), + + // Filled Inverted Button Colors + filledInvertedBackgroundSurfacePrimary = Color(0xFFFFFFFF), + filledInvertedBackgroundInversePressed = Color(0xFFE0E0E0), + filledInvertedBackgroundInverseDisabled = Color(0xFFF2F2F2), + filledInvertedTextPrimary = Color(0xFF171717), + filledInvertedTextDisabled = Color(0xFFB3B3B3), + filledInvertedLoadingSpinner = Color(0xFF3C3C3C), + + // Filled Destructive Button Colors + destructiveBackgroundBold = Color(0xFFB81F14), + destructiveBackgroundDisabled = Color(0xFFF7BBB7), + destructiveTextInversePrimary = Color(0xFFFFFFFF), + destructiveTextAccentRedInverseDisabled = Color(0xFFFEF2F1), + destructiveLoadingSpinner = Color(0xFF931910), + + // Borderless Button Colors + borderlessTextPrimary = Color(0xFF171717), + borderlessBackgroundInversePressed = Color(0xFFE0E0E0), + borderlessTextDisabled = Color(0xFFB3B3B3), + borderlessLoadingSpinner = Color(0xFF3C3C3C), + + // Outlined Button Colors + outlinedBorderBold = Color(0xFFC9C9C9), + outlinedBackgroundInversePressed = Color(0xFFE0E0E0), + outlinedBorderSubtle = Color(0xFFE0E0E0), + outlinedTextPrimary = Color(0xFF171717), + outlinedTextDisabled = Color(0xFFB3B3B3), + outlinedLoadingSpinner = Color(0xFF3C3C3C), + + // Outlined Destructive Button Colors + outlinedDestructiveBackgroundBold = Color(0xFFB81F14), + outlinedDestructiveTextAccentRed = Color(0xFF73140D), + outlinedDestructiveBackgroundAccentRedSubtle = Color(0xFFFEF2F1), + outlinedDestructiveBorderDangerBold = Color(0xFF73140D), + outlinedDestructiveTextAccentRedDisabled = Color(0xFFF7BBB7), + outlinedDestructiveLoadingSpinner = Color(0xFF931910), + + // Borderless Destructive Button Colors + borderlessDestructiveTextAccentRed = Color(0xFFB81F14), + borderlessDestructiveTextAccentRedBolder = Color(0xFF73140D), + borderlessDestructiveTextAccentRedDisabled = Color(0xFFF7BBB7), + borderlessDestructiveBackgroundAccentRedSubtle = Color(0xFFFEF2F1), + borderlessDestructiveLoadingSpinner = Color(0xFF931910), + + // Facebook Login Button Colors + fbLoginButtonBackgroundColor = Color(0xFF1877F2), + fbLoginButtonTextColor = Color.White, + fbLoginButtonPressedColor = Color(0xFF135ABE) +) diff --git a/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsV2.kt b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsV2.kt new file mode 100644 index 0000000000..9f44b126b1 --- /dev/null +++ b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSButtonsV2.kt @@ -0,0 +1,697 @@ +package com.kickstarter.ui.compose.designsystem + +import androidx.compose.foundation.Image +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.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.kickstarter.R +import com.kickstarter.ui.compose.designsystem.KSTheme.colors +import com.kickstarter.ui.compose.designsystem.KSTheme.dimensions +import com.kickstarter.ui.compose.designsystem.KSTheme.typographyV2 + +data class ButtonColorVariables( + val backgroundColor: Color, + val pressedColor: Color, + val disabledColor: Color, + val textColor: Color, + val disabledTextColor: Color, + val loadingSpinnerColor: Color, + val borderColor: Color, + val borderColorPressed: Color, + val borderColorDisabled: Color, +) + +val FilledButtonColors = ButtonColorVariables( + backgroundColor = KSDefaultButtonColors.filledBackgroundAction, + pressedColor = KSDefaultButtonColors.filledBackgroundActionPressed, + disabledColor = KSDefaultButtonColors.filledBackgroundActionDisabled, + textColor = Color.White, + disabledTextColor = KSDefaultButtonColors.filledTextInverseDisabled, + loadingSpinnerColor = KSDefaultButtonColors.filledLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Green buttons, enabled text is also white. +val GreenButtonColors = ButtonColorVariables( + backgroundColor = KSDefaultButtonColors.greenBackgroundAccentBold, + pressedColor = KSDefaultButtonColors.greenBackgroundAccentBoldPressed, + disabledColor = KSDefaultButtonColors.greenBackgroundAccentDisabled, + textColor = Color.White, + disabledTextColor = KSDefaultButtonColors.greenTextDisabled, + loadingSpinnerColor = KSDefaultButtonColors.greenLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Filled Inverted buttons, we use the inverted color palette. +val FilledInvertedButtonColors = ButtonColorVariables( + backgroundColor = KSDefaultButtonColors.filledInvertedBackgroundSurfacePrimary, + pressedColor = KSDefaultButtonColors.filledInvertedBackgroundInversePressed, + disabledColor = KSDefaultButtonColors.filledInvertedBackgroundInverseDisabled, + textColor = KSDefaultButtonColors.filledInvertedTextPrimary, + disabledTextColor = KSDefaultButtonColors.filledInvertedTextDisabled, + loadingSpinnerColor = KSDefaultButtonColors.filledInvertedLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Filled Destructive buttons. +val FilledDestructiveButtonColors = ButtonColorVariables( + backgroundColor = KSDefaultButtonColors.destructiveBackgroundBold, + pressedColor = KSDefaultButtonColors.destructiveBackgroundBold, // Using the same as background for pressed. + disabledColor = KSDefaultButtonColors.destructiveBackgroundDisabled, + textColor = KSDefaultButtonColors.destructiveTextInversePrimary, + disabledTextColor = KSDefaultButtonColors.destructiveTextAccentRedInverseDisabled, + loadingSpinnerColor = KSDefaultButtonColors.destructiveLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Borderless buttons, we use a transparent background. +val BorderlessButtonColors = ButtonColorVariables( + backgroundColor = Color.Transparent, + pressedColor = KSDefaultButtonColors.borderlessBackgroundInversePressed, + disabledColor = Color.Transparent, + textColor = KSDefaultButtonColors.borderlessTextPrimary, + disabledTextColor = KSDefaultButtonColors.borderlessTextDisabled, + loadingSpinnerColor = KSDefaultButtonColors.borderlessLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Outlined buttons. +val OutlinedButtonColors = ButtonColorVariables( + backgroundColor = Color.Transparent, + pressedColor = KSDefaultButtonColors.outlinedBackgroundInversePressed, + disabledColor = Color.Transparent, + textColor = KSDefaultButtonColors.outlinedTextPrimary, + disabledTextColor = KSDefaultButtonColors.outlinedTextDisabled, + loadingSpinnerColor = KSDefaultButtonColors.outlinedLoadingSpinner, + borderColor = KSDefaultButtonColors.outlinedBorderBold, + borderColorPressed = KSDefaultButtonColors.outlinedBackgroundInversePressed, + borderColorDisabled = KSDefaultButtonColors.outlinedBorderSubtle +) + +// For Outlined Destructive buttons. +val OutlinedDestructiveButtonColors = ButtonColorVariables( + backgroundColor = Color.Transparent, + pressedColor = KSDefaultButtonColors.outlinedDestructiveBackgroundAccentRedSubtle, + disabledColor = Color.Transparent, + textColor = KSDefaultButtonColors.outlinedDestructiveTextAccentRed, + disabledTextColor = KSDefaultButtonColors.outlinedDestructiveTextAccentRedDisabled, + loadingSpinnerColor = KSDefaultButtonColors.outlinedDestructiveLoadingSpinner, + borderColor = KSDefaultButtonColors.outlinedDestructiveBackgroundBold, + borderColorPressed = KSDefaultButtonColors.outlinedDestructiveTextAccentRed, + borderColorDisabled = KSDefaultButtonColors.outlinedDestructiveTextAccentRedDisabled +) + +// For Borderless Destructive buttons. +val BorderlessDestructiveButtonColors = ButtonColorVariables( + backgroundColor = Color.Transparent, + pressedColor = KSDefaultButtonColors.borderlessDestructiveBackgroundAccentRedSubtle, + disabledColor = Color.Transparent, + textColor = KSDefaultButtonColors.borderlessDestructiveTextAccentRed, + disabledTextColor = KSDefaultButtonColors.borderlessDestructiveTextAccentRedDisabled, + loadingSpinnerColor = KSDefaultButtonColors.borderlessDestructiveLoadingSpinner, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// For Facebook Login buttons. +val FBLoginButtonColors = ButtonColorVariables( + backgroundColor = KSDefaultButtonColors.fbLoginButtonBackgroundColor, + pressedColor = KSDefaultButtonColors.fbLoginButtonPressedColor, + disabledColor = KSDefaultButtonColors.fbLoginButtonBackgroundColor, + textColor = KSDefaultButtonColors.fbLoginButtonTextColor, + disabledTextColor = KSDefaultButtonColors.fbLoginButtonTextColor, + loadingSpinnerColor = Color.Transparent, + borderColor = Color.Transparent, + borderColorPressed = Color.Transparent, + borderColorDisabled = Color.Transparent +) + +// Define a sealed class for different button types +sealed class KSButtonType(val colors: ButtonColorVariables) { + object Filled : KSButtonType(FilledButtonColors) + object Green : KSButtonType(GreenButtonColors) + object FilledInverted : KSButtonType(FilledInvertedButtonColors) + object FilledDestructive : KSButtonType(FilledDestructiveButtonColors) + object Borderless : KSButtonType(BorderlessButtonColors) + object Outlined : KSButtonType(OutlinedButtonColors) + object OutlinedDestructive : KSButtonType(OutlinedDestructiveButtonColors) + object BorderlessDestructive : KSButtonType(BorderlessDestructiveButtonColors) + object Facebook : KSButtonType(FBLoginButtonColors) +} + +@Composable +fun KSButton( + modifier: Modifier = Modifier, + type: KSButtonType, + onClickAction: () -> Unit, + text: String, + isEnabled: Boolean = true, + isLoading: Boolean = false, + isPressed: Boolean = false, + imageId: Int? = null, + imageContentDescription: String? = null, +) { + CreateButton( + modifier = if (type is KSButtonType.Outlined || type is KSButtonType.OutlinedDestructive) { + modifier.border( + width = dimensions.dividerThickness, + color = when { + isPressed -> type.colors.borderColorPressed + !isEnabled -> type.colors.borderColorDisabled + else -> type.colors.borderColor + }, + shape = RoundedCornerShape(size = dimensions.radiusExtraSmall) + ) + } else modifier, + onClickAction = onClickAction, + text = text, + colors = type.colors, + imageId = imageId, + imageContentDescription = imageContentDescription, + isEnabled = isEnabled, + isLoading = isLoading, + isPressed = isPressed, + isBorderless = type is KSButtonType.Borderless || type is KSButtonType.BorderlessDestructive + ) +} + +@Composable +fun CreateButton( + modifier: Modifier = Modifier, + onClickAction: () -> Unit, + text: String, + colors: ButtonColorVariables, + imageId: Int? = null, + imageContentDescription: String? = null, + isEnabled: Boolean = true, + isLoading: Boolean = false, + isPressed: Boolean = false, + isBorderless: Boolean = false, +) { + BaseButton( + modifier = modifier, + onClickAction = onClickAction, + text = text, + backgroundColor = colors.backgroundColor, + pressedColor = colors.pressedColor, + disabledColor = colors.disabledColor, + textColor = colors.textColor, + disabledTextColor = colors.disabledTextColor, + loadingSpinnerColor = colors.loadingSpinnerColor, + imageId = imageId, + imageContentDescription = imageContentDescription, + isEnabled = isEnabled, + isLoading = isLoading, + isPressed = isPressed, + isBorderless = isBorderless + ) +} + +@Composable +fun BaseButton( + modifier: Modifier = Modifier, + onClickAction: () -> Unit, + text: String, + backgroundColor: Color, + pressedColor: Color, + disabledColor: Color, + textColor: Color, + disabledTextColor: Color, + loadingSpinnerColor: Color, + imageId: Int? = null, + imageContentDescription: String? = null, + isEnabled: Boolean = true, + isLoading: Boolean = false, + isPressed: Boolean = false, + isBorderless: Boolean = false, +) { + val currentBackgroundColor = when { + !isEnabled -> disabledColor + isPressed -> pressedColor + else -> backgroundColor + } + + val currentTextColor = if (isEnabled) textColor else disabledTextColor + + Button( + modifier = modifier + .fillMaxWidth() + .defaultMinSize(minHeight = dimensions.minButtonHeight), + colors = ButtonDefaults.buttonColors( + backgroundColor = currentBackgroundColor, + disabledBackgroundColor = disabledColor + ), + onClick = { onClickAction.invoke() }, + enabled = isEnabled && !isLoading, + shape = RoundedCornerShape(size = dimensions.radiusExtraSmall), + elevation = ButtonDefaults.elevation(0.dp) + ) { + Box(contentAlignment = Alignment.Center) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + if (imageId != null) { + Image( + modifier = Modifier.size(dimensions.paddingMedium), + painter = painterResource(id = imageId), + contentDescription = imageContentDescription + ) + } + Text( + text = text, + color = currentTextColor, + style = typographyV2.buttonLabel, + modifier = Modifier.padding(start = if (imageId != null) dimensions.paddingSmall else dimensions.none) + ) + } + if (isLoading) { + CircularProgressIndicator( + modifier = Modifier.size(dimensions.loadingSpinnerSize), + color = loadingSpinnerColor, + strokeWidth = dimensions.strokeWith + ) + } + } + } +} + +@Composable +fun FBLoginButton( + modifier: Modifier = Modifier, + onClickAction: () -> Unit, + text: String, + isPressed: Boolean = false, +) { + val currentBackgroundColor = + if (isPressed) FBLoginButtonColors.pressedColor else FBLoginButtonColors.backgroundColor + + Button( + onClick = { onClickAction.invoke() }, + modifier = modifier + .fillMaxWidth() + .defaultMinSize(minHeight = dimensions.minButtonHeight), + colors = ButtonDefaults.buttonColors(backgroundColor = currentBackgroundColor), + shape = RoundedCornerShape(size = dimensions.radiusExtraSmall) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(id = R.drawable.com_facebook_button_icon), + contentDescription = "Facebook Logo", + modifier = Modifier + .size(dimensions.imageSizeMedium) + ) + Text( + text = text, + color = FBLoginButtonColors.textColor, + style = typographyV2.buttonLabel, + modifier = Modifier.padding(start = dimensions.paddingSmall) + ) + } + } +} + +@Preview +@Composable +fun KSFilledButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth() + .background(colors.kds_white), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Filled", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Filled, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSGreenButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth() + .background(colors.kds_white), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Green", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Green, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSFilledInvertedButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth() + .background(colors.kds_white), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Inverted", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledInverted, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSFilledDestructiveButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth() + .background(colors.kds_white), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.FilledDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSBorderlessButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Borderless", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Borderless, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSOutlinedButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Outlined", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.Outlined, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSOutlinedDestructiveButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Outlined Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.OutlinedDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun KSBorderlessDestructiveButtonPreview() { + KSTheme { + Column( + Modifier + .padding(all = dimensions.paddingSmall) + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically) + ) { + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Borderless Destructive", + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Pressed", + isPressed = true, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Disabled", + isEnabled = false, + imageId = R.drawable.icon_eye_gray + ) + KSButton( + onClickAction = {}, + type = KSButtonType.BorderlessDestructive, + text = "Loading", + isLoading = true, + imageId = R.drawable.icon_eye_gray + ) + } + } +} + +@Preview +@Composable +fun FBLoginButtonPreview() { + KSTheme { + Column( + Modifier + .fillMaxWidth() + .background(colors.kds_white) + .padding(all = dimensions.paddingSmall), + verticalArrangement = Arrangement.spacedBy(60.dp, Alignment.CenterVertically), + horizontalAlignment = Alignment.CenterHorizontally + ) { + FBLoginButton(onClickAction = {}, text = "Continue with Facebook") + FBLoginButton(onClickAction = {}, text = "Continue with Facebook", isPressed = true) + } + } +} diff --git a/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSDimensions.kt b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSDimensions.kt index 8ea4493999..ea26ea9cdb 100644 --- a/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSDimensions.kt +++ b/app/src/main/java/com/kickstarter/ui/compose/designsystem/KSDimensions.kt @@ -29,6 +29,7 @@ data class KSDimensions( val listItemSpacingMediumSmall: Dp = Dp.Unspecified, val listItemSpacingMedium: Dp = Dp.Unspecified, val listItemSpacingLarge: Dp = Dp.Unspecified, + val radiusExtraSmall: Dp = Dp.Unspecified, val radiusSmall: Dp = Dp.Unspecified, val radiusMediumSmall: Dp = Dp.Unspecified, val radiusMedium: Dp = Dp.Unspecified, @@ -63,7 +64,8 @@ data class KSDimensions( val cardWidth: Dp = Dp.Unspecified, val cardImageHeight: Dp = Dp.Unspecified, val cardImageAspectRatio: Float = Float.NaN, - + val loadingSpinnerSize: Dp = Dp.Unspecified, + val strokeWith: Dp = Dp.Unspecified, ) val LocalKSCustomDimensions = staticCompositionLocalOf { @@ -71,6 +73,7 @@ val LocalKSCustomDimensions = staticCompositionLocalOf { } val KSStandardDimensions = KSDimensions( + strokeWith = 2.dp, dividerThickness = 1.dp, paddingXSmall = 4.dp, paddingSmall = 8.dp, @@ -92,6 +95,7 @@ val KSStandardDimensions = KSDimensions( listItemSpacingMediumSmall = 12.dp, listItemSpacingMedium = 16.dp, listItemSpacingLarge = 24.dp, + radiusExtraSmall = 4.dp, radiusSmall = 6.dp, radiusMediumSmall = 9.dp, radiusMedium = 12.dp, @@ -125,5 +129,6 @@ val KSStandardDimensions = KSDimensions( plotChargeItemWidth = 100.dp, cardWidth = 294.dp, cardImageHeight = 196.dp, - cardImageAspectRatio = 3f / 2f + cardImageAspectRatio = 3f / 2f, + loadingSpinnerSize = 24.dp ) diff --git a/app/src/main/res/drawable/icon_eye_gray.xml b/app/src/main/res/drawable/icon_eye_gray.xml new file mode 100644 index 0000000000..fb7d777b58 --- /dev/null +++ b/app/src/main/res/drawable/icon_eye_gray.xml @@ -0,0 +1,10 @@ + + +