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,177 @@
package org.android.bbangzip.presentation.component.button

import androidx.annotation.DrawableRes
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
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.SideEffect
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.noRippleClickable
import org.android.bbangzip.ui.theme.BBANGZIPTheme
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

var isClicked by remember { mutableStateOf(false) }
val animatedBackgroundColor by animateColorAsState(
targetValue =
when {
isClicked -> BbangZipTheme.colors.interactionInactive_D4D3D1
isEnable -> bbangZipButtonType.enableBackgroundColor
else -> bbangZipButtonType.disableBackgroundColor
},
animationSpec = tween(durationMillis = 100),
)

if (isClicked) {
SideEffect {
Thread {
kamja0510 marked this conversation as resolved.
Show resolved Hide resolved
Thread.sleep(100)
isClicked = false
}.start()
}
}

BbangZipButtonSlot(
modifier =
modifier
.background(color = if (bbangZipButtonType is BbangZipButtonType.Outlined) animatedBackgroundColor else backgroundColor, shape = RoundedCornerShape(bbangZipButtonSize.cornerRadius))
.border(color = bbangZipButtonType.enableBorderColor, width = bbangZipButtonType.borderWidth, shape = RoundedCornerShape(bbangZipButtonSize.cornerRadius))
.noRippleClickable {
if (isEnable) {
isClicked = true
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,
)
}
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