Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Button 컴포넌트 구현 #19

Merged
merged 10 commits into from
Jan 15, 2025
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package org.android.bbangzip.presentation.component.button

import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.android.bbangzip.R
import org.android.bbangzip.presentation.type.BbangZipButtonSize
import org.android.bbangzip.presentation.type.BbangZipButtonType
import org.android.bbangzip.presentation.util.modifier.applyFilterOnClick
import org.android.bbangzip.ui.theme.BBANGZIPTheme

@Composable
fun BbangZipButton(
bbangZipButtonType: BbangZipButtonType,
bbangZipButtonSize: BbangZipButtonSize,
onClick: () -> Unit,
label: String,
modifier: Modifier = Modifier,
@DrawableRes leadingIcon: Int? = null,
@DrawableRes trailingIcon: Int? = null,
isEnable: Boolean = true,
) {
val backgroundColor = if (isEnable) bbangZipButtonType.enableBackgroundColor else bbangZipButtonType.disableBackgroundColor
val contentColor = if (isEnable) bbangZipButtonType.enableContentColor else bbangZipButtonType.disableContentColor

BbangZipButtonSlot(
modifier =
modifier
.background(color = backgroundColor, shape = RoundedCornerShape(bbangZipButtonSize.cornerRadius))
kamja0510 marked this conversation as resolved.
Show resolved Hide resolved
.border(color = bbangZipButtonType.enableBorderColor, width = bbangZipButtonType.borderWidth, shape = RoundedCornerShape(bbangZipButtonSize.cornerRadius))
.applyFilterOnClick(
baseColor = backgroundColor,
radius = bbangZipButtonSize.cornerRadius,
isDisabled = !isEnable,
onClick = {
if (isEnable) onClick()
},
)
.padding(
horizontal = bbangZipButtonSize.horizontalPadding,
vertical = bbangZipButtonSize.verticalPadding,
),
leadingIcon = {
if (leadingIcon != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5 Base를 하나 만들어두고, SolidButton Outlined Button 이런 식으로 구성하면 안 들어오면 렌더링 자체가 되지 않으니 leadingIcon이나 trailingIcon이 null인 경우를 처리해줄 필요가 업서요! 이런 식으로 분리하는 방법도 있음을 알아주셔라

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

죄송합니다 모르겠습니다 ㅠㅠㅠ

Icon(
imageVector = ImageVector.vectorResource(leadingIcon),
modifier = Modifier.size(size = bbangZipButtonSize.iconSize),
contentDescription = null,
tint = contentColor,
)
Spacer(modifier = Modifier.width(bbangZipButtonSize.spacing))
}
},
label = {
Text(
text = label,
style = bbangZipButtonSize.textStyle,
color = contentColor,
)
},
trailingIcon = {
if (trailingIcon != null) {
Icon(
imageVector = ImageVector.vectorResource(trailingIcon),
modifier = Modifier.size(size = bbangZipButtonSize.iconSize),
contentDescription = null,
tint = contentColor,
)
Spacer(modifier = Modifier.width(bbangZipButtonSize.spacing))
}
},
)
}

@Preview(showBackground = true)
@Composable
private fun BbangZipButtonPreview() {
var addTodo by remember { mutableStateOf(true) }
var overDueCount by remember { mutableIntStateOf(1) }
BBANGZIPTheme {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
BbangZipButton(
bbangZipButtonType = BbangZipButtonType.Solid,
bbangZipButtonSize = BbangZipButtonSize.Large,
onClick = { },
label = stringResource(R.string.btn_next_label),
modifier = Modifier.fillMaxWidth(),
trailingIcon = R.drawable.ic_chevronright_thick_small_24,
)

BbangZipButton(
bbangZipButtonType = BbangZipButtonType.Solid,
bbangZipButtonSize = BbangZipButtonSize.Large,
onClick = { addTodo = !addTodo },
label = stringResource(R.string.btn_add_todo_label),
modifier = Modifier.fillMaxWidth(),
trailingIcon = R.drawable.ic_chevronright_thick_small_24,
isEnable = addTodo,
)

BbangZipButton(
bbangZipButtonType = BbangZipButtonType.Kakao,
bbangZipButtonSize = BbangZipButtonSize.Large,
onClick = { },
label = stringResource(R.string.btn_kakao_login_label),
modifier = Modifier.fillMaxWidth(),
leadingIcon = R.drawable.ic_kakao_default_24,
)

BbangZipButton(
bbangZipButtonType = BbangZipButtonType.Outlined,
bbangZipButtonSize = BbangZipButtonSize.Large,
onClick = { },
label = stringResource(R.string.btn_cancle_label),
modifier = Modifier.fillMaxWidth(),
)

BbangZipButton(
bbangZipButtonType = BbangZipButtonType.Outlined,
bbangZipButtonSize = BbangZipButtonSize.Medium,
onClick = { overDueCount += 1 },
label = String.format(stringResource(R.string.btn_todo_overdue_label), overDueCount),
trailingIcon = R.drawable.ic_chevronright_thick_small_24,
modifier = Modifier.wrapContentSize(),
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.android.bbangzip.presentation.component.button

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier

@Composable
fun BbangZipButtonSlot(
modifier: Modifier = Modifier,
leadingIcon: @Composable (RowScope.() -> Unit) = {},
label: @Composable (RowScope.() -> Unit) = {},
trailingIcon: @Composable (RowScope.() -> Unit) = {},
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
leadingIcon()

label()

trailingIcon()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.android.bbangzip.presentation.type

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import org.android.bbangzip.ui.theme.defaultBbangZipColors
import org.android.bbangzip.ui.theme.defaultBbangZipTypography

sealed class BbangZipButtonType(
val enableBackgroundColor: Color,
val enableContentColor: Color,
val enableBorderColor: Color = Color.Unspecified,
kamja0510 marked this conversation as resolved.
Show resolved Hide resolved
val disableBackgroundColor: Color = Color.Unspecified,
val disableContentColor: Color = Color.Unspecified,
val disableBorderColor: Color = Color.Unspecified,
val borderWidth: Dp = 0.dp,
) {
data object Solid : BbangZipButtonType(
enableBackgroundColor = defaultBbangZipColors.primaryNormal_282119,
enableContentColor = defaultBbangZipColors.staticWhite_FFFFFF,
disableBackgroundColor = defaultBbangZipColors.interactionDisable_F5F5F5,
disableContentColor = defaultBbangZipColors.labelDisable_282119_12,
)

data object Outlined : BbangZipButtonType(
enableBackgroundColor = defaultBbangZipColors.staticWhite_FFFFFF,
enableContentColor = defaultBbangZipColors.primaryNormal_282119,
enableBorderColor = defaultBbangZipColors.lineStrong_68645E_52,
disableBackgroundColor = Color.Unspecified,
disableContentColor = Color.Unspecified,
disableBorderColor = Color.Unspecified,
borderWidth = 1.dp,
)

data object Kakao : BbangZipButtonType(
enableBackgroundColor = defaultBbangZipColors.kakaoContainer_FEE500,
enableContentColor = defaultBbangZipColors.kakaoLabel_000000_85,
)
}

sealed class BbangZipButtonSize(
kamja0510 marked this conversation as resolved.
Show resolved Hide resolved
val cornerRadius: Dp,
val horizontalPadding: Dp,
val verticalPadding: Dp,
val iconSize: Dp,
val spacing: Dp,
val textStyle: TextStyle,
) {
data object Large : BbangZipButtonSize(
cornerRadius = 24.dp,
horizontalPadding = 28.dp,
verticalPadding = 16.dp,
iconSize = 20.dp,
spacing = 6.dp,
textStyle = defaultBbangZipTypography.body1Bold,
)

data object Medium : BbangZipButtonSize(
cornerRadius = 16.dp,
horizontalPadding = 20.dp,
verticalPadding = 9.dp,
iconSize = 18.dp,
spacing = 5.dp,
textStyle = defaultBbangZipTypography.body2Bold,
)
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package org.android.bbangzip.presentation.util.modifier

import android.graphics.BlurMaskFilter
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.semantics.Role
Expand All @@ -33,6 +39,30 @@ fun Modifier.noRippleClickable(
role = role,
)

fun Modifier.applyFilterOnClick(
baseColor: Color = Color.Transparent,
radius: Dp = 0.dp,
isDisabled: Boolean = true,
filterColor: Color = Color(0xFF282119).copy(alpha = 0.12f),
onClick: () -> Unit = {},
): Modifier =
composed {
val finalFilteredColor =
remember(baseColor, filterColor) {
filterColor.compositeOver(baseColor)
}
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()

this
.background(if (isPressed && !isDisabled) finalFilteredColor else baseColor, shape = RoundedCornerShape(size = radius))
.clickable(
interactionSource = interactionSource,
indication = null,
onClick = { onClick() },
)
}

@Composable
fun Modifier.dropShadow(
shape: Shape,
Expand Down
28 changes: 28 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,32 @@
<string name="bottomNavigation_todo_tab_title">오늘 할 일</string>
<string name="bottomNavigation_friend_tab_title">친구들</string>
<string name="bottomNavigation_my_tab_title">마이페이지</string>

<!--button-->
<string name="btn_kakao_login_label">카카오로 로그인하기</string>
<string name="btn_todo_overdue_label">"밀린 공부 %d개 하러가기"</string>
<string name="btn_select_due_label">"%s년 %s월 %s일 까지"</string>
<string name="btn_start_app_label">빵집 오픈하러 가기</string>
<string name="btn_finish_onboarding_label">빵점 탈출하러 가기</string>
<string name="btn_input_exam_date_label">시험 일자 입력하기</string>
<string name="btn_input_due_label">공부 기한 입력하기</string>
<string name="btn_input_semester_label">학년/학기 입력하기</string>
<string name="btn_next_label">다음으로</string>
<string name="btn_cancle_label">취소</string>
<string name="btn_delete_label">"%d개 삭제하기"</string>
<string name="btn_save_label">저장하기</string>
<string name="btn_slice_study_label">쪼개서 공부하기</string>
<string name="btn_slice_again_label">다시 쪼개기</string>
<string name="btn_enroll_label">등록하기</string>
<string name="btn_enroll_study_label">공부 내용 등록하기</string>
<string name="btn_modify_label">수정하기</string>
<string name="btn_modify_semester_label">학기 변경하기</string>
<string name="btn_add_label">추가하기</string>
<string name="btn_add_todo_label">오늘 할 공부 추가하기</string>
<string name="btn_add_subject_first_label">과목 먼저 추가하기</string>
<string name="btn_rollback_label">되돌리기</string>
<string name="btn_close_label">닫기</string>
<string name="btn_logout_label">로그아웃 하기</string>
<string name="btn_withdraw_label">탈퇴하기</string>

</resources>
Loading