공통으로 사용할 팝업은 크게 가로 버튼 1개, 가로 버튼 2개, 세로 버튼 2개 UI로 구성 되어있다 따라서 DialogType을 정의 해준뒤 필요한 요소를 넣을수있게 만들었다!
@ExperimentalComposeUiApi
@Composable
fun CommonDialog(
dialogType: Int,
modifier: Modifier = Modifier,
onDismissRequest: () -> Unit = {},
imageDrawable: Int? = null, //ex) imageDrawable = "R.id.img_welcomechall_stamp1"
imageRaw: String? = null,
title: String = "",
msg: String = "",
btn_positive: String = "",
btn_negative: String = "",
hasCloseButton: Boolean = false,
isCancelable: Boolean = false,
onClickCallback: (Int) -> Unit = {},
) {
/**
* 우리 프로젝트 환경에선 Dialog 쓰면 화면 위에 살짝 공백이 생겨서 Dialog 대신 Popup으로 변경
*/
Popup(
onDismissRequest = onDismissRequest,
properties = PopupProperties(
focusable = true,
dismissOnBackPress = isCancelable,
dismissOnClickOutside = isCancelable,
),
) {
// Dialog(
// onDismissRequest = onDismissRequest,
// properties = DialogProperties(
// dismissOnBackPress = isCancelable,
// dismissOnClickOutside = isCancelable,
// ),
// ) {
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.fillMaxSize()
.background(Transparent70)
) {
Card(
modifier = modifier
.padding(end = 32.dp, start = 32.dp)
.wrapContentSize(),
shape = RoundedCornerShape(16.dp),
backgroundColor = Gray600,
contentColor = Gray600,
) {
Column(
modifier = modifier
.padding(top = 32.dp, end = ScreenSideMargin, start = ScreenSideMargin, bottom = 24.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
if (hasCloseButton) {
Box(modifier = modifier
.wrapContentSize()
.align(Alignment.End)
.padding(5.dp)
.clickable { onDismissRequest.invoke() }
) {
Image(
painter = painterResource(id = R.drawable.ic_popup_close),
contentDescription = "",
modifier = modifier,
)
}
}
if (imageDrawable != null) {
Spacer(modifier = modifier.height(5.dp))
Image(
painter = painterResource(id = imageDrawable),
contentDescription = "",
modifier = modifier.wrapContentSize()
)
}
if (!imageRaw.isNullOrEmpty()) {
Spacer(modifier = modifier.height(5.dp))
AsyncImage(
model = imageRaw,
contentDescription = "",
modifier = modifier
.wrapContentSize()
)
}
if (title.isNotEmpty()) {
Spacer(modifier = modifier.height(5.dp))
Text(
text = title,
fontSize = 18.nonScaledSp,
fontFamily = nanumsquare,
fontWeight = FontWeight.Bold,
style = TextStyle(
color = White,
lineHeight = 24.nonScaledSp
),
textAlign = TextAlign.Center,
)
}
if (msg.isNotEmpty()) {
Spacer(modifier = modifier.height(16.dp))
Text(
text = msg,
fontSize = 14.nonScaledSp,
lineHeight = 20.nonScaledSp,
fontFamily = nanumsquare,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center,
style = YafitTextStyle(
color = White,
)
)
}
Spacer(modifier = modifier.height(32.dp))
when (dialogType) {
DialogType.DIALOGTYPE_BUTTON_YES -> {
YafitTextButton(
text = btn_positive,
onClick = {
onClickCallback.invoke(DialogType.DIALOG_CALLBACK_TYPE_POSITIVE)
},
modifier = modifier
.fillMaxWidth()
.height(40.dp)
)
}
DialogType.DIALOGTYPE_BUTTON_YES_NO -> {
Row(
modifier = modifier
.height(40.dp)
.fillMaxWidth()
) {
YafitTextButton(
text = btn_negative,
textColor = Gray200,
contentColor = Gray500,
onClick = {
onClickCallback.invoke(DialogType.DIALOG_CALLBACK_TYPE_NEGATIVE)
},
modifier = modifier
.fillMaxWidth()
.weight(1f)
)
Spacer(modifier = modifier.width(8.dp))
YafitTextButton(
text = btn_positive,
onClick = {
onClickCallback.invoke(DialogType.DIALOG_CALLBACK_TYPE_POSITIVE)
},
modifier = modifier
.fillMaxWidth()
.weight(1f)
)
}
}
else -> {
YafitTextButton(
text = btn_positive,
onClick = {
onClickCallback.invoke(DialogType.DIALOG_CALLBACK_TYPE_POSITIVE)
},
modifier = modifier
.fillMaxWidth()
.height(40.dp)
)
Spacer(modifier = modifier.height(4.dp))
YafitTextButton(
text = btn_negative,
textColor = Gray200,
contentColor = Gray600,
onClick = {
onClickCallback.invoke(DialogType.DIALOG_CALLBACK_TYPE_NEGATIVE)
},
modifier = modifier
.fillMaxWidth()
.height(40.dp)
)
}
}
}
}
}
}
}
object DialogType {
const val DIALOGTYPE_BUTTON_YES = 1
const val DIALOGTYPE_BUTTON_YES_NO = 2
const val DIALOGTYPE_BUTTON_YES_NO_HIGHLIGHT = 3
const val DIALOG_CALLBACK_TYPE_POSITIVE = 0
const val DIALOG_CALLBACK_TYPE_NEGATIVE = 1
}
우리 프로젝트 환경에선 navigation bar와 BottomSheetDialog가 겹치는 현상이 일어나서 아래처럼 공백을 주었다.
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun BlueModalBottomSheet(
modifier: Modifier,
onDismissRequest: () -> Unit = {},
sheetState: SheetState = rememberModalBottomSheetState(),
contentColor: Color = Gray700,
content: @Composable ColumnScope.() -> Unit,
) {
/**
* ModalBottomSheet에 이거 넣으면 하단 padding 안먹는데 Spacer로 넣으면 떨어짐
* windowInsets = WindowInsets.navigationBarsIgnoringVisibility
*/
ModalBottomSheet(
modifier = modifier.wrapContentHeight(),
onDismissRequest = { onDismissRequest.invoke() },
sheetState = sheetState,
dragHandle = { BottomSheetDefaults.DragHandle() },
containerColor = contentColor,
) {
Column {
content()
Spacer(
modifier = modifier.windowInsetsBottomHeight(
WindowInsets.navigationBarsIgnoringVisibility
)
)
}
}
}
참고 코드 : https://github.com/ChargeMap/Compose-NumberPicker
아래 코드에서 체크 포인트는 윤년 계산과 날짜 선택 완료시 UI에 날짜 포맷을 만드는 부분이다.