From 87a4e840fd55112a2fc326cf97d761b2c01ae067 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Sun, 27 Jul 2025 15:31:51 +0900 Subject: [PATCH 01/16] =?UTF-8?q?[REFACTOR/#237]=20OrbitBottomSheet=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20isSheetOpen=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EA=B0=84=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yapp/ui/component/OrbitBottomSheet.kt | 44 +++---- .../bottomsheet/AlarmMissionBottomSheet.kt | 3 - .../bottomsheet/AlarmSnoozeBottomSheet.kt | 7 +- .../bottomsheet/AlarmSoundBottomSheet.kt | 35 +++--- .../yapp/onboarding/OnboardingGenderScreen.kt | 19 +-- .../component/UserInfoBottomSheet.kt | 115 +++++++++--------- 6 files changed, 102 insertions(+), 121 deletions(-) diff --git a/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt b/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt index baf7e50b..d5b3bb75 100644 --- a/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt +++ b/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt @@ -38,8 +38,7 @@ fun OrbitBottomSheet( sheetState: SheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true, ), - isSheetOpen: Boolean, - onDismissRequest: () -> Unit = {}, + onDismissRequest: () -> Unit = { }, shape: Shape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp), containerColor: Color = OrbitTheme.colors.gray_800, strokeColor: Color = OrbitTheme.colors.gray_700, @@ -47,27 +46,26 @@ fun OrbitBottomSheet( content: @Composable () -> Unit, ) { val scope = rememberCoroutineScope() - if (isSheetOpen) { - ModalBottomSheet( - modifier = modifier, - sheetState = sheetState, - shape = shape, - onDismissRequest = { - scope.launch { - sheetState.hide() - onDismissRequest() - } - }, - containerColor = containerColor, - dragHandle = null, - ) { - Box { - content() - BottomSheetTopRoundedStroke( - strokeColor = strokeColor, - strokeThickness = strokeThickness, - ) + + ModalBottomSheet( + modifier = modifier, + sheetState = sheetState, + shape = shape, + onDismissRequest = { + scope.launch { + sheetState.hide() + onDismissRequest() } + }, + containerColor = containerColor, + dragHandle = null, + ) { + Box { + content() + BottomSheetTopRoundedStroke( + strokeColor = strokeColor, + strokeThickness = strokeThickness, + ) } } } @@ -159,9 +157,7 @@ fun OrbitBottomSheetPreview() { } OrbitBottomSheet( - isSheetOpen = isSheetOpen, sheetState = sheetState, - onDismissRequest = { isSheetOpen = !isSheetOpen }, content = { Box( modifier = Modifier diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt index 9cb8669e..4db7ba80 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt @@ -65,7 +65,6 @@ internal fun AlarmMissionBottomSheet( sheetState: SheetState, missionType: MissionType, missionCount: Int, - isSheetOpen: Boolean, onDismiss: () -> Unit, onSaveMission: (MissionType, Int) -> Unit, onPreviewMission: (MissionType, Int) -> Unit, @@ -76,7 +75,6 @@ internal fun AlarmMissionBottomSheet( var selectedMissionCount by remember { mutableIntStateOf(missionCount) } OrbitBottomSheet( - isSheetOpen = isSheetOpen, sheetState = sheetState, onDismissRequest = { currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING @@ -652,7 +650,6 @@ private fun AlarmMissionSelectBottomSheetPreview() { sheetState = sheetState, missionType = MissionType.SHAKE, missionCount = 15, - isSheetOpen = true, onDismiss = {}, onSaveMission = { _, _ -> }, onPreviewMission = { _, _ -> }, diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt index 82e4caeb..17ac2425 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt @@ -44,19 +44,15 @@ internal fun AlarmSnoozeBottomSheet( onSnoozeToggle: () -> Unit, onCountSelected: (Int) -> Unit, onComplete: () -> Unit, - isSheetOpen: Boolean, onDismiss: () -> Unit, ) { val scope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) OrbitBottomSheet( - isSheetOpen = isSheetOpen, sheetState = sheetState, onDismissRequest = { - scope.launch { - sheetState.hide() - }.invokeOnCompletion { onDismiss() } + onDismiss() }, ) { BottomSheetContent( @@ -230,7 +226,6 @@ private fun AlarmSnoozeBottomSheetPreview() { onIntervalSelected = { index -> snoozeIntervalIndex = index }, onCountSelected = { index -> snoozeCountIndex = index }, onComplete = { isSheetOpen = false }, - isSheetOpen = isSheetOpen, onDismiss = { isSheetOpen = false }, ) } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt index e98fe962..488d340b 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt @@ -55,7 +55,6 @@ internal fun AlarmSoundBottomSheet( onVolumeChanged: (Int) -> Unit, onSoundSelected: (Int) -> Unit, onComplete: () -> Unit, - isSheetOpen: Boolean, onDismiss: () -> Unit, ) { val scope = rememberCoroutineScope() @@ -63,12 +62,9 @@ internal fun AlarmSoundBottomSheet( OrbitBottomSheet( modifier = Modifier.statusBarsPadding(), - isSheetOpen = isSheetOpen, sheetState = sheetState, onDismissRequest = { - scope.launch { - sheetState.hide() - }.invokeOnCompletion { onDismiss() } + onDismiss() }, ) { BottomSheetContent( @@ -308,19 +304,20 @@ private fun AlarmSoundBottomSheetPreview() { var isSheetOpen by remember { mutableStateOf(true) } OrbitTheme { - AlarmSoundBottomSheet( - vibrationEnabled = isVibrationEnabled, - soundEnabled = isSoundEnabled, - soundVolume = soundVolume, - soundIndex = soundIndex, - sounds = sounds, - onVibrationToggle = { isVibrationEnabled = !isVibrationEnabled }, - onSoundToggle = { isSoundEnabled = !isSoundEnabled }, - onVolumeChanged = { soundVolume = it }, - onSoundSelected = { soundIndex = it }, - onComplete = { isSheetOpen = false }, - isSheetOpen = isSheetOpen, - onDismiss = { isSheetOpen = false }, - ) + if (isSheetOpen) { + AlarmSoundBottomSheet( + vibrationEnabled = isVibrationEnabled, + soundEnabled = isSoundEnabled, + soundVolume = soundVolume, + soundIndex = soundIndex, + sounds = sounds, + onVibrationToggle = { isVibrationEnabled = !isVibrationEnabled }, + onSoundToggle = { isSoundEnabled = !isSoundEnabled }, + onVolumeChanged = { soundVolume = it }, + onSoundSelected = { soundIndex = it }, + onComplete = { isSheetOpen = false }, + onDismiss = { isSheetOpen = false }, + ) + } } } diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt index c9ba857d..f997a4e4 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt @@ -150,15 +150,16 @@ fun OnboardingGenderScreen( ) } - UserInfoBottomSheet( - isSheetOpen = state.isBottomSheetOpen, - onDismissRequest = onDismissRequest, - onConfirmRequest = onConfirmRequest, - name = state.userName, - gender = state.selectedGender ?: "무지개", - birthDate = state.birthDateFormatted, - birthTime = state.birthTimeFormatted, - ) + if (state.isBottomSheetOpen) { + UserInfoBottomSheet( + onDismissRequest = onDismissRequest, + onConfirmRequest = onConfirmRequest, + name = state.userName, + gender = state.selectedGender ?: "무지개", + birthDate = state.birthDateFormatted, + birthTime = state.birthTimeFormatted, + ) + } } @Composable diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt index ce6b6629..b02f785e 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt @@ -27,7 +27,6 @@ import feature.onboarding.R @Composable fun UserInfoBottomSheet( sheetState: SheetState = rememberModalBottomSheetState(), - isSheetOpen: Boolean, onDismissRequest: () -> Unit, onConfirmRequest: () -> Unit, name: String, @@ -35,70 +34,67 @@ fun UserInfoBottomSheet( birthDate: String, birthTime: String, ) { - if (isSheetOpen) { - OrbitBottomSheet( - isSheetOpen = isSheetOpen, - sheetState = sheetState, - onDismissRequest = onDismissRequest, + OrbitBottomSheet( + sheetState = sheetState, + onDismissRequest = onDismissRequest, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .paddingForScreenPercentage(allPercentage = 0.03f), ) { - Column( + Text( + text = stringResource(R.string.onboarding_step6_bs_title), + modifier = Modifier + .paddingForScreenPercentage( + topPercentage = 0.005f, + bottomPercentage = 0.027f, + ), + style = OrbitTheme.typography.heading2SemiBold, + color = OrbitTheme.colors.white, + ) + UserInfoRow(label = stringResource(R.string.onboarding_step6_bs_name), value = name) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_gender), + value = gender, + ) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_birth), + value = birthDate, + ) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_time), + value = birthTime, + ) + + Row( modifier = Modifier .fillMaxWidth() - .paddingForScreenPercentage(allPercentage = 0.03f), + .paddingForScreenPercentage(topPercentage = 0.032f), + verticalAlignment = Alignment.CenterVertically, ) { - Text( - text = stringResource(R.string.onboarding_step6_bs_title), - modifier = Modifier - .paddingForScreenPercentage( - topPercentage = 0.005f, - bottomPercentage = 0.027f, - ), - style = OrbitTheme.typography.heading2SemiBold, - color = OrbitTheme.colors.white, - ) - UserInfoRow(label = stringResource(R.string.onboarding_step6_bs_name), value = name) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_gender), - value = gender, - ) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_birth), - value = birthDate, - ) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_time), - value = birthTime, + OrbitButton( + label = stringResource(R.string.onboarding_step6_bs_btn_dismiss), + modifier = Modifier.weight(1f), + onClick = onDismissRequest, + enabled = true, + containerColor = OrbitTheme.colors.gray_600, + contentColor = OrbitTheme.colors.white, + pressedContainerColor = OrbitTheme.colors.gray_500, + pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), + shape = RoundedCornerShape(12.dp), ) + Spacer(modifier = Modifier.widthForScreenPercentage(0.032f)) + OrbitButton( + label = stringResource(R.string.onboarding_step6_bs_btn_confirm), + modifier = Modifier.weight(1f), + onClick = onConfirmRequest, + enabled = true, + pressedContainerColor = OrbitTheme.colors.main.copy(alpha = 0.8f), + pressedContentColor = OrbitTheme.colors.gray_600, + shape = RoundedCornerShape(12.dp), - Row( - modifier = Modifier - .fillMaxWidth() - .paddingForScreenPercentage(topPercentage = 0.032f), - verticalAlignment = Alignment.CenterVertically, - ) { - OrbitButton( - label = stringResource(R.string.onboarding_step6_bs_btn_dismiss), - modifier = Modifier.weight(1f), - onClick = onDismissRequest, - enabled = true, - containerColor = OrbitTheme.colors.gray_600, - contentColor = OrbitTheme.colors.white, - pressedContainerColor = OrbitTheme.colors.gray_500, - pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - shape = RoundedCornerShape(12.dp), - ) - Spacer(modifier = Modifier.widthForScreenPercentage(0.032f)) - OrbitButton( - label = stringResource(R.string.onboarding_step6_bs_btn_confirm), - modifier = Modifier.weight(1f), - onClick = onConfirmRequest, - enabled = true, - pressedContainerColor = OrbitTheme.colors.main.copy(alpha = 0.8f), - pressedContentColor = OrbitTheme.colors.gray_600, - shape = RoundedCornerShape(12.dp), - - ) - } + ) } } } @@ -134,7 +130,6 @@ fun UserInfoRow( @Preview fun UserInfoBottomSheetPreview() { UserInfoBottomSheet( - isSheetOpen = true, onDismissRequest = { }, onConfirmRequest = { }, name = "홍길동", From 72e0073a59f25b338c7159b788aa50359bc249e6 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Sun, 27 Jul 2025 15:32:52 +0900 Subject: [PATCH 02/16] =?UTF-8?q?[REFACTOR/#237]=20when=20=EB=AC=B8?= =?UTF-8?q?=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20BottomSheetT?= =?UTF-8?q?ype=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=B0=94=ED=85=80=EC=8B=9C?= =?UTF-8?q?=ED=8A=B8=20=ED=98=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/alarm/addedit/AlarmAddEditScreen.kt | 205 ++++++++++-------- 1 file changed, 116 insertions(+), 89 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 8bc32ab5..819b5475 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -227,100 +227,127 @@ fun AlarmAddEditContent( ) } - AlarmMissionBottomSheet( - sheetState = missionBottomSheetState, - missionType = missionState.missionType, - missionCount = missionState.missionCount, - isSheetOpen = state.bottomSheetState == AlarmAddEditContract.BottomSheetType.MissionSetting, - onDismiss = { - scope.launch { - missionBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher(AlarmAddEditContract.Action.ToggleBottomSheet(AlarmAddEditContract.BottomSheetType.MissionSetting)) - } - }, - onSaveMission = { missionType, missionCount -> - eventDispatcher( - AlarmAddEditContract.Action.SaveMission( - type = missionType, - count = missionCount, - ), - ) - }, - onPreviewMission = { missionType, missionCount -> - eventDispatcher( - AlarmAddEditContract.Action.NavigateToMissionPreview( - missionType = missionType, - missionCount = missionCount, - ), + when (state.bottomSheetState) { + AlarmAddEditContract.BottomSheetType.MissionSetting -> { + AlarmMissionBottomSheet( + sheetState = missionBottomSheetState, + missionType = missionState.missionType, + missionCount = missionState.missionCount, + onDismiss = { + scope.launch { + missionBottomSheetState.hide() + }.invokeOnCompletion { + eventDispatcher( + AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.BottomSheetType.MissionSetting, + ), + ) + } + }, + onSaveMission = { missionType, missionCount -> + eventDispatcher( + AlarmAddEditContract.Action.SaveMission( + type = missionType, + count = missionCount, + ), + ) + }, + onPreviewMission = { missionType, missionCount -> + eventDispatcher( + AlarmAddEditContract.Action.NavigateToMissionPreview( + missionType = missionType, + missionCount = missionCount, + ), + ) + }, ) - }, - ) + } - AlarmSnoozeBottomSheet( - snoozeEnabled = snoozeState.isSnoozeEnabled, - snoozeIntervalIndex = snoozeState.snoozeIntervalIndex, - snoozeCountIndex = snoozeState.snoozeCountIndex, - snoozeIntervals = snoozeState.snoozeIntervals, - snoozeCounts = snoozeState.snoozeCounts, - onSnoozeToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeOption) }, - onIntervalSelected = { index -> - eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeInterval( - index, - ), + AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { + AlarmSnoozeBottomSheet( + snoozeEnabled = snoozeState.isSnoozeEnabled, + snoozeIntervalIndex = snoozeState.snoozeIntervalIndex, + snoozeCountIndex = snoozeState.snoozeCountIndex, + snoozeIntervals = snoozeState.snoozeIntervals, + snoozeCounts = snoozeState.snoozeCounts, + onSnoozeToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeOption) }, + onIntervalSelected = { index -> + eventDispatcher( + AlarmAddEditContract.Action.SetSnoozeInterval( + index, + ), + ) + }, + onCountSelected = { index -> + eventDispatcher( + AlarmAddEditContract.Action.SetSnoozeRepeatCount( + index, + ), + ) + }, + onComplete = { + scope.launch { + snoozeBottomSheetState.hide() + }.invokeOnCompletion { + eventDispatcher( + AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.BottomSheetType.SnoozeSetting, + ), + ) + } + }, + onDismiss = { + scope.launch { + snoozeBottomSheetState.hide() + }.invokeOnCompletion { + eventDispatcher( + AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.BottomSheetType.SnoozeSetting, + ), + ) + } + }, ) - }, - onCountSelected = { index -> - eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeRepeatCount( - index, - ), + } + + AlarmAddEditContract.BottomSheetType.SoundSetting -> { + AlarmSoundBottomSheet( + vibrationEnabled = state.soundState.isVibrationEnabled, + soundEnabled = state.soundState.isSoundEnabled, + soundVolume = state.soundState.soundVolume, + soundIndex = state.soundState.soundIndex, + sounds = state.soundState.sounds, + onVibrationToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleVibrationOption) }, + onSoundToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSoundOption) }, + onVolumeChanged = { eventDispatcher(AlarmAddEditContract.Action.AdjustSoundVolume(it)) }, + onSoundSelected = { eventDispatcher(AlarmAddEditContract.Action.SelectAlarmSound(it)) }, + onComplete = { + scope.launch { + soundBottomSheetState.hide() + }.invokeOnCompletion { + eventDispatcher( + AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.BottomSheetType.SoundSetting, + ), + ) + } + }, + onDismiss = { + scope.launch { + soundBottomSheetState.hide() + }.invokeOnCompletion { + eventDispatcher( + AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.BottomSheetType.SoundSetting, + ), + ) + } + }, ) - }, - onComplete = { - scope.launch { - snoozeBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher(AlarmAddEditContract.Action.ToggleBottomSheet(AlarmAddEditContract.BottomSheetType.SnoozeSetting)) - } - }, - isSheetOpen = state.bottomSheetState == AlarmAddEditContract.BottomSheetType.SnoozeSetting, - onDismiss = { - scope.launch { - snoozeBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher(AlarmAddEditContract.Action.ToggleBottomSheet(AlarmAddEditContract.BottomSheetType.SnoozeSetting)) - } - }, - ) + } - AlarmSoundBottomSheet( - vibrationEnabled = state.soundState.isVibrationEnabled, - soundEnabled = state.soundState.isSoundEnabled, - soundVolume = state.soundState.soundVolume, - soundIndex = state.soundState.soundIndex, - sounds = state.soundState.sounds, - onVibrationToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleVibrationOption) }, - onSoundToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSoundOption) }, - onVolumeChanged = { eventDispatcher(AlarmAddEditContract.Action.AdjustSoundVolume(it)) }, - onSoundSelected = { eventDispatcher(AlarmAddEditContract.Action.SelectAlarmSound(it)) }, - onComplete = { - scope.launch { - soundBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher(AlarmAddEditContract.Action.ToggleBottomSheet(AlarmAddEditContract.BottomSheetType.SoundSetting)) - } - }, - isSheetOpen = state.bottomSheetState == AlarmAddEditContract.BottomSheetType.SoundSetting, - onDismiss = { - scope.launch { - soundBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher(AlarmAddEditContract.Action.ToggleBottomSheet(AlarmAddEditContract.BottomSheetType.SoundSetting)) - } - }, - ) + else -> null + } if (state.isDeleteDialogVisible) { OrbitDialog( From 184b2d2f126e8128f41c4b5e898e299765a94bdd Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Sun, 27 Jul 2025 19:32:10 +0900 Subject: [PATCH 03/16] =?UTF-8?q?[REFACTOR/#237]=20AlarmSnoozeBottomSheet?= =?UTF-8?q?=EC=9D=98=20=ED=99=9C=EC=84=B1=ED=99=94=20=EC=97=AC=EB=B6=80,?= =?UTF-8?q?=20=EA=B0=84=EA=B2=A9,=20=ED=9A=9F=EC=88=98=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=A5=BC=20=EB=82=B4=EB=B6=80=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/AlarmSnoozeBottomSheet.kt | 196 +++++++++--------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt index 17ac2425..91efbbf3 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt @@ -1,5 +1,6 @@ package com.yapp.home.alarm.component.bottomsheet +import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -36,99 +37,101 @@ import kotlinx.coroutines.launch @Composable internal fun AlarmSnoozeBottomSheet( snoozeEnabled: Boolean, - snoozeIntervalIndex: Int, - snoozeIntervals: List, + snoozeInterval: Int, + snoozeCount: Int, onIntervalSelected: (Int) -> Unit, - snoozeCountIndex: Int, - snoozeCounts: List, - onSnoozeToggle: () -> Unit, onCountSelected: (Int) -> Unit, - onComplete: () -> Unit, + onSnoozeToggle: (Boolean) -> Unit, onDismiss: () -> Unit, ) { val scope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - OrbitBottomSheet( - sheetState = sheetState, - onDismissRequest = { - onDismiss() - }, - ) { - BottomSheetContent( - isSnoozeEnabled = snoozeEnabled, - snoozeIntervalIndex = snoozeIntervalIndex, - snoozeIntervals = snoozeIntervals, - onIntervalSelected = onIntervalSelected, - snoozeCountIndex = snoozeCountIndex, - snoozeCounts = snoozeCounts, - onSnoozeToggle = onSnoozeToggle, - onCountSelected = onCountSelected, - onComplete = { - scope.launch { - sheetState.hide() - }.invokeOnCompletion { onComplete() } + val snoozeIntervalOptions = listOf(1, 3, 5, 10, 15) + val snoozeCountOptions = listOf(1, 3, 5, 10, -1) + + val snoozeIntervals = snoozeIntervalOptions.map { + stringResource(id = R.string.alarm_add_edit_interval_minute, it) + } + val snoozeCounts = listOf( + stringResource(id = R.string.alarm_add_edit_repeat_count_times, 1), + stringResource(id = R.string.alarm_add_edit_repeat_count_times, 3), + stringResource(id = R.string.alarm_add_edit_repeat_count_times, 5), + stringResource(id = R.string.alarm_add_edit_repeat_count_times, 10), + stringResource(id = R.string.alarm_add_edit_repeat_count_infinite), + ) + + var selectedSnoozeEnabled by remember { mutableStateOf(snoozeEnabled) } + var selectedSnoozeIntervalIndex by remember { mutableIntStateOf(snoozeIntervalOptions.indexOf(snoozeInterval)) } + var selectedSnoozeCountIndex by remember { + mutableIntStateOf( + if (snoozeCount == -1) { + snoozeCountOptions.lastIndex + } else { + snoozeCountOptions.indexOf(snoozeCount) }, ) } -} -@Composable -private fun BottomSheetContent( - isSnoozeEnabled: Boolean, - snoozeIntervalIndex: Int, - snoozeIntervals: List, - onIntervalSelected: (Int) -> Unit, - snoozeCountIndex: Int, - snoozeCounts: List, - onSnoozeToggle: () -> Unit, - onCountSelected: (Int) -> Unit, - onComplete: () -> Unit, -) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding( - horizontal = 24.dp, - vertical = 12.dp, - ), - horizontalAlignment = Alignment.CenterHorizontally, + OrbitBottomSheet( + sheetState = sheetState, + onDismissRequest = onDismiss, ) { - Spacer(modifier = Modifier.height(6.dp)) - VibrationSection(isSnoozeEnabled, onSnoozeToggle) - Spacer(modifier = Modifier.height(20.dp)) - SelectorSection( - title = stringResource(id = R.string.alarm_add_edit_interval), - selectedIndex = snoozeIntervalIndex, - items = snoozeIntervals, - enabled = isSnoozeEnabled, - onItemSelected = onIntervalSelected, - ) - Spacer(modifier = Modifier.height(32.dp)) - SelectorSection( - title = stringResource(id = R.string.alarm_add_edit_repeat_count), - selectedIndex = snoozeCountIndex, - items = snoozeCounts, - enabled = isSnoozeEnabled, - onItemSelected = onCountSelected, - ) - Spacer(modifier = Modifier.height(20.dp)) - if (isSnoozeEnabled) { - AlarmSnoozeMessage( - interval = snoozeIntervals[snoozeIntervalIndex], - count = snoozeCounts[snoozeCountIndex], + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer(modifier = Modifier.height(6.dp)) + VibrationSection(selectedSnoozeEnabled) { + selectedSnoozeEnabled = !selectedSnoozeEnabled + onSnoozeToggle(selectedSnoozeEnabled) + } + Spacer(modifier = Modifier.height(20.dp)) + SelectorSection( + title = stringResource(id = R.string.alarm_add_edit_interval), + selectedIndex = selectedSnoozeIntervalIndex, + items = snoozeIntervals, + enabled = selectedSnoozeEnabled, + onItemSelected = { + selectedSnoozeIntervalIndex = it + onIntervalSelected(snoozeIntervalOptions[it]) + }, + ) + Spacer(modifier = Modifier.height(32.dp)) + SelectorSection( + title = stringResource(id = R.string.alarm_add_edit_repeat_count), + selectedIndex = selectedSnoozeCountIndex, + items = snoozeCounts, + enabled = selectedSnoozeEnabled, + onItemSelected = { + selectedSnoozeCountIndex = it + onCountSelected(snoozeCountOptions[it]) + }, + ) + Spacer(modifier = Modifier.height(20.dp)) + if (selectedSnoozeEnabled) { + AlarmSnoozeMessage( + interval = snoozeIntervals[selectedSnoozeIntervalIndex], + count = snoozeCounts[selectedSnoozeCountIndex], + ) + } + Spacer(modifier = Modifier.height(40.dp)) + OrbitButton( + label = stringResource(id = R.string.alarm_add_edit_complete), + enabled = true, + containerColor = OrbitTheme.colors.gray_600, + contentColor = OrbitTheme.colors.white, + pressedContainerColor = OrbitTheme.colors.gray_500, + pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), + onClick = { + scope.launch { sheetState.hide() }.invokeOnCompletion { + onDismiss() + } + }, ) } - Spacer(modifier = Modifier.height(40.dp)) - OrbitButton( - label = stringResource(id = R.string.alarm_add_edit_complete), - enabled = true, - containerColor = OrbitTheme.colors.gray_600, - contentColor = OrbitTheme.colors.white, - pressedContainerColor = OrbitTheme.colors.gray_500, - pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - onClick = onComplete, - ) } } @@ -203,30 +206,27 @@ private fun AlarmSnoozeMessage(interval: String, count: String) { @Composable private fun AlarmSnoozeBottomSheetPreview() { var isSnoozeEnabled by remember { mutableStateOf(true) } - var snoozeIntervalIndex by remember { mutableIntStateOf(2) } - var snoozeCountIndex by remember { mutableIntStateOf(1) } - var isSheetOpen by remember { mutableStateOf(true) } + var snoozeInterval by remember { mutableIntStateOf(5) } + var snoozeCount by remember { mutableIntStateOf(5) } OrbitTheme { AlarmSnoozeBottomSheet( snoozeEnabled = isSnoozeEnabled, - snoozeIntervalIndex = snoozeIntervalIndex, - snoozeCountIndex = snoozeCountIndex, - snoozeIntervals = listOf(1, 3, 5, 10, 15).map { - stringResource(id = R.string.alarm_add_edit_interval_minute, it) + snoozeInterval = snoozeInterval, + snoozeCount = snoozeCount, + onSnoozeToggle = { + isSnoozeEnabled = !isSnoozeEnabled + Log.d("AlarmSnoozeBottomSheet", "Snooze Enabled: $isSnoozeEnabled") + }, + onIntervalSelected = { interval -> + snoozeInterval = interval + Log.d("AlarmSnoozeBottomSheet", "Snooze Interval: $snoozeInterval") + }, + onCountSelected = { count -> + snoozeCount = count + Log.d("AlarmSnoozeBottomSheet", "Snooze Count: $snoozeCount") }, - snoozeCounts = listOf( - stringResource(id = R.string.alarm_add_edit_repeat_count_times, 1), - stringResource(id = R.string.alarm_add_edit_repeat_count_times, 3), - stringResource(id = R.string.alarm_add_edit_repeat_count_times, 5), - stringResource(id = R.string.alarm_add_edit_repeat_count_times, 10), - stringResource(id = R.string.alarm_add_edit_repeat_count_infinite), - ), - onSnoozeToggle = { isSnoozeEnabled = !isSnoozeEnabled }, - onIntervalSelected = { index -> snoozeIntervalIndex = index }, - onCountSelected = { index -> snoozeCountIndex = index }, - onComplete = { isSheetOpen = false }, - onDismiss = { isSheetOpen = false }, + onDismiss = { }, ) } } From 848916dff64294413c509c3cdb20973415f40250 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Sun, 27 Jul 2025 19:34:48 +0900 Subject: [PATCH 04/16] =?UTF-8?q?[REFACTOR/#237]=20AlarmAddEditViewModel?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=8A=A4=EB=88=84=EC=A6=88=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=A5=BC=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EC=8B=A4=EC=A0=9C=20=EA=B0=92=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/addedit/AlarmAddEditContract.kt | 19 +++----- .../home/alarm/addedit/AlarmAddEditScreen.kt | 45 +++++++++---------- .../alarm/addedit/AlarmAddEditViewModel.kt | 22 ++++----- 3 files changed, 34 insertions(+), 52 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt index eb99cf01..9a0315d1 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt @@ -51,10 +51,8 @@ sealed class AlarmAddEditContract { data class AlarmSnoozeState( val isSnoozeEnabled: Boolean = true, - val snoozeIntervalIndex: Int = 2, - val snoozeCountIndex: Int = 2, - val snoozeIntervals: List = listOf("1분", "3분", "5분", "10분", "15분"), - val snoozeCounts: List = listOf("1회", "3회", "5회", "10회", "무한"), + val snoozeInterval: Int = 5, + val snoozeCount: Int = 5, ) data class AlarmSoundState( @@ -86,8 +84,8 @@ sealed class AlarmAddEditContract { data object ToggleSnoozeOption : Action() data class SaveMission(val type: MissionType, val count: Int) : Action() data class NavigateToMissionPreview(val missionType: MissionType, val missionCount: Int) : Action() - data class SetSnoozeInterval(val index: Int) : Action() - data class SetSnoozeRepeatCount(val index: Int) : Action() + data class SetSnoozeInterval(val interval: Int) : Action() + data class SetSnoozeRepeatCount(val count: Int) : Action() data object ToggleVibrationOption : Action() data object ToggleSoundOption : Action() data class AdjustSoundVolume(val volume: Int) : Action() @@ -137,13 +135,8 @@ internal fun AlarmAddEditContract.State.toAlarm(id: Long = 0): Alarm { missionType = missionState.missionType, missionCount = missionState.missionCount, isSnoozeEnabled = snoozeState.isSnoozeEnabled, - snoozeInterval = snoozeState.snoozeIntervals.getOrNull(snoozeState.snoozeIntervalIndex) - ?.filter { it.isDigit() } - ?.toIntOrNull() - ?: 5, - snoozeCount = snoozeState.snoozeCounts.getOrNull(snoozeState.snoozeCountIndex) - ?.let { if (it == "무한") -1 else it.filter { char -> char.isDigit() }.toIntOrNull() ?: 1 } - ?: 1, + snoozeInterval = snoozeState.snoozeInterval, + snoozeCount = snoozeState.snoozeCount, isVibrationEnabled = soundState.isVibrationEnabled, isSoundEnabled = soundState.isSoundEnabled, soundUri = soundState.sounds.getOrNull(soundState.soundIndex)?.uri.toString(), diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 819b5475..5406489e 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -266,36 +266,19 @@ fun AlarmAddEditContent( AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { AlarmSnoozeBottomSheet( snoozeEnabled = snoozeState.isSnoozeEnabled, - snoozeIntervalIndex = snoozeState.snoozeIntervalIndex, - snoozeCountIndex = snoozeState.snoozeCountIndex, - snoozeIntervals = snoozeState.snoozeIntervals, - snoozeCounts = snoozeState.snoozeCounts, + snoozeInterval = snoozeState.snoozeInterval, + snoozeCount = snoozeState.snoozeCount, onSnoozeToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeOption) }, - onIntervalSelected = { index -> + onIntervalSelected = { interval -> eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeInterval( - index, - ), + AlarmAddEditContract.Action.SetSnoozeInterval(interval), ) }, - onCountSelected = { index -> + onCountSelected = { count -> eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeRepeatCount( - index, - ), + AlarmAddEditContract.Action.SetSnoozeRepeatCount(count), ) }, - onComplete = { - scope.launch { - snoozeBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher( - AlarmAddEditContract.Action.ToggleBottomSheet( - AlarmAddEditContract.BottomSheetType.SnoozeSetting, - ), - ) - } - }, onDismiss = { scope.launch { snoozeBottomSheetState.hide() @@ -523,10 +506,22 @@ private fun AlarmAddEditSettingsSection( AlarmAddEditSettingItem( label = stringResource(id = R.string.alarm_add_edit_alarm_snooze), description = if (state.snoozeState.isSnoozeEnabled) { + val interval = stringResource( + id = R.string.alarm_add_edit_interval_minute, + state.snoozeState.snoozeInterval, + ) + val count = if (state.snoozeState.snoozeCount == -1) { + stringResource(id = R.string.alarm_add_edit_repeat_count_infinite) + } else { + stringResource( + id = R.string.alarm_add_edit_repeat_count_times, + state.snoozeState.snoozeCount, + ) + } stringResource( id = R.string.alarm_add_edit_alarm_selected_option, - state.snoozeState.snoozeIntervals[state.snoozeState.snoozeIntervalIndex], - state.snoozeState.snoozeCounts[state.snoozeState.snoozeCountIndex], + interval, + count, ) } else { stringResource(id = R.string.alarm_add_edit_alarm_selected_option_none) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt index fc68790e..6ebed864 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt @@ -149,17 +149,11 @@ class AlarmAddEditViewModel @Inject constructor( ): AlarmAddEditContract.AlarmSnoozeState { return currentState.snoozeState.copy( isSnoozeEnabled = alarm.isSnoozeEnabled, - snoozeIntervalIndex = findSnoozeIndex(alarm.snoozeInterval, currentState.snoozeState.snoozeIntervals), - snoozeCountIndex = findSnoozeIndex(alarm.snoozeCount, currentState.snoozeState.snoozeCounts), + snoozeInterval = alarm.snoozeInterval, + snoozeCount = alarm.snoozeCount, ) } - private fun findSnoozeIndex(value: Int, list: List): Int { - return list.indexOfFirst { - it == "무한" && value == -1 || it.filter { char -> char.isDigit() }.toIntOrNull() == value - }.takeIf { it >= 0 } ?: 0 - } - override fun onCleared() { super.onCleared() alarmUseCase.releaseSoundPlayer() @@ -183,8 +177,8 @@ class AlarmAddEditViewModel @Inject constructor( is AlarmAddEditContract.Action.SaveMission -> saveMission(action.type, action.count) is AlarmAddEditContract.Action.NavigateToMissionPreview -> navigateToMissionPreview(action.missionType, action.missionCount) is AlarmAddEditContract.Action.ToggleSnoozeOption -> toggleSnoozeOption() - is AlarmAddEditContract.Action.SetSnoozeInterval -> setSnoozeInterval(action.index) - is AlarmAddEditContract.Action.SetSnoozeRepeatCount -> setSnoozeRepeatCount(action.index) + is AlarmAddEditContract.Action.SetSnoozeInterval -> setSnoozeInterval(action.interval) + is AlarmAddEditContract.Action.SetSnoozeRepeatCount -> setSnoozeRepeatCount(action.count) is AlarmAddEditContract.Action.ToggleVibrationOption -> toggleVibrationOption() is AlarmAddEditContract.Action.ToggleSoundOption -> toggleSoundOption() is AlarmAddEditContract.Action.AdjustSoundVolume -> adjustSoundVolume(action.volume) @@ -472,15 +466,15 @@ class AlarmAddEditViewModel @Inject constructor( } } - private fun setSnoozeInterval(index: Int) = intent { - val newSnoozeState = state.snoozeState.copy(snoozeIntervalIndex = index) + private fun setSnoozeInterval(interval: Int) = intent { + val newSnoozeState = state.snoozeState.copy(snoozeInterval = interval) reduce { state.copy(snoozeState = newSnoozeState) } } - private fun setSnoozeRepeatCount(index: Int) = intent { - val newSnoozeState = state.snoozeState.copy(snoozeCountIndex = index) + private fun setSnoozeRepeatCount(count: Int) = intent { + val newSnoozeState = state.snoozeState.copy(snoozeCount = count) reduce { state.copy(snoozeState = newSnoozeState) } From 043ada5c50d9ae8d5228ca3068aa06b86a0845fe Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 09:25:52 +0900 Subject: [PATCH 05/16] =?UTF-8?q?[FEAT/#237]=20OrbitBottomSheetState=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/BottomSheetContent.kt | 6 ++++ .../bottomsheet/OrbitBottomSheetState.kt | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt create mode 100644 core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt diff --git a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt new file mode 100644 index 00000000..23e3934b --- /dev/null +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt @@ -0,0 +1,6 @@ +package com.yapp.ui.component.bottomsheet + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.runtime.Composable + +typealias BottomSheetContent = @Composable ColumnScope.() -> Unit diff --git a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt new file mode 100644 index 00000000..23ce38ab --- /dev/null +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt @@ -0,0 +1,34 @@ +package com.yapp.ui.component.bottomsheet + +import androidx.compose.material.ModalBottomSheetState +import androidx.compose.material.ModalBottomSheetValue +import androidx.compose.material.rememberModalBottomSheetState +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 + +@Composable +fun rememberOrbitBottomSheetState( + bottomSheetState: ModalBottomSheetState = rememberModalBottomSheetState( + initialValue = ModalBottomSheetValue.Hidden, + skipHalfExpanded = true, + ), +): OrbitBottomSheetState { + return remember(bottomSheetState) { OrbitBottomSheetState(state = bottomSheetState) } +} + +class OrbitBottomSheetState( + val state: ModalBottomSheetState, +) { + var content by mutableStateOf(null) + private set + + suspend fun show(sheetContent: BottomSheetContent) { + content = sheetContent + state.show() + } + + suspend fun hide() = state.hide() +} From df41065b409797c166ff446ab80684cf280d9204 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 11:49:49 +0900 Subject: [PATCH 06/16] =?UTF-8?q?[FEAT/#237]=20ModalBottomSheet=20->=20Mod?= =?UTF-8?q?alBottomSheetLayout=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + .../main/java/com/yapp/orbit/OrbitNavHost.kt | 60 +++-- .../bottomsheet/BottomSheetContent.kt | 4 +- .../OrbitBottomSheetLayout.kt} | 88 +++----- .../main/java/com/yapp/home/HomeNavGraph.kt | 3 + .../alarm/addedit/AlarmAddEditContract.kt | 9 +- .../home/alarm/addedit/AlarmAddEditScreen.kt | 211 ++++++++---------- .../alarm/addedit/AlarmAddEditViewModel.kt | 21 +- .../bottomsheet/AlarmMissionBottomSheet.kt | 127 +++++------ .../bottomsheet/AlarmSnoozeBottomSheet.kt | 110 ++++----- .../bottomsheet/AlarmSoundBottomSheet.kt | 46 +--- .../com/yapp/onboarding/OnboardingContract.kt | 8 +- .../yapp/onboarding/OnboardingGenderScreen.kt | 104 ++++++--- .../com/yapp/onboarding/OnboardingNavGraph.kt | 64 ++++-- .../yapp/onboarding/OnboardingViewModel.kt | 13 +- .../component/UserInfoBottomSheet.kt | 119 +++++----- 16 files changed, 488 insertions(+), 500 deletions(-) rename core/ui/src/main/java/com/yapp/ui/component/{OrbitBottomSheet.kt => bottomsheet/OrbitBottomSheetLayout.kt} (69%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 933fbfe3..25834d1a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -48,6 +48,7 @@ dependencies { implementation(projects.feature.setting) implementation(projects.feature.webview) implementation(platform(libs.firebase.bom)) + implementation(libs.compose.material) implementation(libs.firebase.analytics) implementation(libs.firebase.crashlytics) implementation(libs.play.services.ads) diff --git a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt index 8c802942..7030f337 100644 --- a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt +++ b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt @@ -25,6 +25,9 @@ import com.yapp.mission.missionScreen import com.yapp.onboarding.onboardingNavGraph import com.yapp.setting.settingNavGraph import com.yapp.splash.splashScreen +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetLayout +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState +import com.yapp.ui.component.bottomsheet.rememberOrbitBottomSheetState import com.yapp.ui.component.snackbar.CustomSnackBarVisuals import com.yapp.ui.component.snackbar.OrbitSnackBar import com.yapp.webview.webViewScreen @@ -34,34 +37,45 @@ import com.yapp.webview.webViewScreen internal fun OrbitNavHost( modifier: Modifier = Modifier, navigator: OrbitNavigator = rememberOrbitNavigator(), + bottomSheetState: OrbitBottomSheetState = rememberOrbitBottomSheetState(), ) { val snackBarHostState = remember { SnackbarHostState() } - Scaffold( - modifier = modifier, - snackbarHost = { - OrbitSnackBarHost(snackBarHostState = snackBarHostState) - }, - containerColor = OrbitTheme.colors.gray_900, + OrbitBottomSheetLayout( + sheetState = bottomSheetState, ) { - NavHost( - navController = navigator.navController, - startDestination = navigator.startDestination, - modifier = Modifier.navigationBarsPadding(), + Scaffold( + modifier = modifier, + snackbarHost = { + OrbitSnackBarHost(snackBarHostState = snackBarHostState) + }, + containerColor = OrbitTheme.colors.gray_900, ) { - splashScreen(navigator = navigator) - onboardingNavGraph(navigator = navigator) - homeNavGraph( - navigator = navigator, - snackBarHostState = snackBarHostState, - ) - missionScreen(navigator = navigator) - fortuneNavGraph( - navigator = navigator, - snackBarHostState = snackBarHostState, - ) - settingNavGraph(navigator = navigator) - webViewScreen(navigator = navigator) + NavHost( + navController = navigator.navController, + startDestination = navigator.startDestination, + modifier = Modifier.navigationBarsPadding(), + ) { + splashScreen( + navigator = navigator, + ) + onboardingNavGraph( + navigator = navigator, + bottomSheetState = bottomSheetState, + ) + homeNavGraph( + navigator = navigator, + bottomSheetState = bottomSheetState, + snackBarHostState = snackBarHostState, + ) + missionScreen(navigator = navigator) + fortuneNavGraph( + navigator = navigator, + snackBarHostState = snackBarHostState, + ) + settingNavGraph(navigator = navigator) + webViewScreen(navigator = navigator) + } } } } diff --git a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt index 23e3934b..23dba597 100644 --- a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/BottomSheetContent.kt @@ -1,6 +1,6 @@ package com.yapp.ui.component.bottomsheet -import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable -typealias BottomSheetContent = @Composable ColumnScope.() -> Unit +typealias BottomSheetContent = @Composable BoxScope.() -> Unit diff --git a/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetLayout.kt similarity index 69% rename from core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt rename to core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetLayout.kt index d5b3bb75..ff048441 100644 --- a/core/ui/src/main/java/com/yapp/ui/component/OrbitBottomSheet.kt +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetLayout.kt @@ -1,22 +1,19 @@ -package com.yapp.ui.component +package com.yapp.ui.component.bottomsheet import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ModalBottomSheetLayout import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.SheetState import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect @@ -33,40 +30,31 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -fun OrbitBottomSheet( +fun OrbitBottomSheetLayout( modifier: Modifier = Modifier, - sheetState: SheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true, - ), - onDismissRequest: () -> Unit = { }, + sheetState: OrbitBottomSheetState, shape: Shape = RoundedCornerShape(topStart = 30.dp, topEnd = 30.dp), containerColor: Color = OrbitTheme.colors.gray_800, strokeColor: Color = OrbitTheme.colors.gray_700, strokeThickness: Dp = 1.dp, content: @Composable () -> Unit, ) { - val scope = rememberCoroutineScope() - - ModalBottomSheet( - modifier = modifier, - sheetState = sheetState, - shape = shape, - onDismissRequest = { - scope.launch { - sheetState.hide() - onDismissRequest() + ModalBottomSheetLayout( + modifier = modifier.navigationBarsPadding(), + sheetState = sheetState.state, + sheetShape = shape, + sheetBackgroundColor = containerColor, + sheetContent = { + Box { + sheetState.content?.invoke(this) + BottomSheetTopRoundedStroke( + strokeColor = strokeColor, + strokeThickness = strokeThickness, + ) } }, - containerColor = containerColor, - dragHandle = null, ) { - Box { - content() - BottomSheetTopRoundedStroke( - strokeColor = strokeColor, - strokeThickness = strokeThickness, - ) - } + content() } } @@ -137,41 +125,31 @@ fun BottomSheetTopRoundedStroke( @Preview @Composable fun OrbitBottomSheetPreview() { - var isSheetOpen by rememberSaveable { mutableStateOf(true) } - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) + val sheetState = rememberOrbitBottomSheetState() val scope = rememberCoroutineScope() OrbitTheme { - Button( - onClick = { - scope.launch { - sheetState.show() - }.invokeOnCompletion { - if (!isSheetOpen) { - isSheetOpen = true - } - } - }, - ) { - Text("Toggle Bottom Sheet") - } - - OrbitBottomSheet( + OrbitBottomSheetLayout( sheetState = sheetState, content = { Box( modifier = Modifier - .fillMaxWidth() - .height(600.dp), + .fillMaxSize() + .background(color = OrbitTheme.colors.white), contentAlignment = Alignment.Center, ) { Button( onClick = { scope.launch { - sheetState.hide() - }.invokeOnCompletion { - if (isSheetOpen) { - isSheetOpen = false + sheetState.show { + Box( + modifier = Modifier + .fillMaxWidth() + .height(500.dp), + contentAlignment = Alignment.Center, + ) { + Text("This is a bottom sheet content") + } } } }, diff --git a/feature/home/src/main/java/com/yapp/home/HomeNavGraph.kt b/feature/home/src/main/java/com/yapp/home/HomeNavGraph.kt index 5e5fae4a..c46e3458 100644 --- a/feature/home/src/main/java/com/yapp/home/HomeNavGraph.kt +++ b/feature/home/src/main/java/com/yapp/home/HomeNavGraph.kt @@ -8,6 +8,7 @@ import com.yapp.common.navigation.OrbitNavigator import com.yapp.common.navigation.route.HomeBaseRoute import com.yapp.common.navigation.route.HomeDestination import com.yapp.home.alarm.addedit.AlarmAddEditRoute +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState const val ADD_ALARM_RESULT_KEY = "addAlarmResult" const val UPDATE_ALARM_RESULT_KEY = "updateAlarmResult" @@ -15,6 +16,7 @@ const val DELETE_ALARM_RESULT_KEY = "deleteAlarmResult" fun NavGraphBuilder.homeNavGraph( navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, snackBarHostState: SnackbarHostState, ) { navigation( @@ -30,6 +32,7 @@ fun NavGraphBuilder.homeNavGraph( composable { AlarmAddEditRoute( navigator = navigator, + bottomSheetState = bottomSheetState, snackBarHostState = snackBarHostState, ) } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt index 9a0315d1..5c53145f 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt @@ -90,7 +90,8 @@ sealed class AlarmAddEditContract { data object ToggleSoundOption : Action() data class AdjustSoundVolume(val volume: Int) : Action() data class SelectAlarmSound(val index: Int) : Action() - data class ToggleBottomSheet(val sheetType: BottomSheetType) : Action() + data class ShowBottomSheet(val sheetType: BottomSheetType) : Action() + data object HideBottomSheet : Action() } sealed class BottomSheetType { @@ -107,6 +108,12 @@ sealed class AlarmAddEditContract { val missionCount: Int, ) : SideEffect() + data class ShowBottomSheet( + val sheetType: BottomSheetType, + ) : SideEffect() + + data object HideBottomSheet : SideEffect() + data class SaveAlarm(val id: Long) : SideEffect() data class UpdateAlarm(val id: Long) : SideEffect() diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 5406489e..129d956b 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -28,7 +28,6 @@ import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -62,6 +61,7 @@ import com.yapp.home.alarm.component.bottomsheet.AlarmMissionBottomSheet import com.yapp.home.alarm.component.bottomsheet.AlarmSnoozeBottomSheet import com.yapp.home.alarm.component.bottomsheet.AlarmSoundBottomSheet import com.yapp.home.alarm.getLabelStringRes +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.dialog.OrbitDialog import com.yapp.ui.component.lottie.LottieAnimation @@ -70,7 +70,6 @@ import com.yapp.ui.component.switch.OrbitSwitch import com.yapp.ui.component.timepicker.OrbitPicker import feature.home.R import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.launch import org.orbitmvi.orbit.compose.collectSideEffect import java.time.LocalTime @@ -78,14 +77,23 @@ import java.time.LocalTime fun AlarmAddEditRoute( viewModel: AlarmAddEditViewModel = hiltViewModel(), navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, snackBarHostState: SnackbarHostState, ) { val state by viewModel.container.stateFlow.collectAsStateWithLifecycle() val coroutineScope = rememberCoroutineScope() - viewModel.collectSideEffect { - handleSideEffect(it, navigator, snackBarHostState, coroutineScope) + viewModel.collectSideEffect { sideEffect -> + handleSideEffect( + sideEffect = sideEffect, + navigator = navigator, + bottomSheetState = bottomSheetState, + snackBarHostState = snackBarHostState, + coroutineScope = coroutineScope, + state = state, + processAction = viewModel::processAction, + ) } AlarmAddEditScreen( @@ -97,37 +105,114 @@ fun AlarmAddEditRoute( private suspend fun handleSideEffect( sideEffect: AlarmAddEditContract.SideEffect, navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, snackBarHostState: SnackbarHostState, coroutineScope: CoroutineScope, + state: AlarmAddEditContract.State, + processAction: (AlarmAddEditContract.Action) -> Unit, ) { when (sideEffect) { is AlarmAddEditContract.SideEffect.NavigateBack -> { navigator.navigateBack() } + is AlarmAddEditContract.SideEffect.NavigateToMissionPreview -> { navigator.navigateToMissionPreview( missionType = sideEffect.missionType.value, missionCount = sideEffect.missionCount, ) } + + is AlarmAddEditContract.SideEffect.ShowBottomSheet -> { + bottomSheetState.show { + when (sideEffect.sheetType) { + AlarmAddEditContract.BottomSheetType.MissionSetting -> { + AlarmMissionBottomSheet( + missionType = state.missionState.missionType, + missionCount = state.missionState.missionCount, + onDismiss = { + processAction(AlarmAddEditContract.Action.HideBottomSheet) + }, + onSaveMission = { missionType, missionCount -> + processAction( + AlarmAddEditContract.Action.SaveMission( + type = missionType, + count = missionCount, + ), + ) + }, + onPreviewMission = { missionType, missionCount -> + processAction( + AlarmAddEditContract.Action.NavigateToMissionPreview( + missionType = missionType, + missionCount = missionCount, + ), + ) + }, + ) + } + + AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { + AlarmSnoozeBottomSheet( + snoozeEnabled = state.snoozeState.isSnoozeEnabled, + snoozeInterval = state.snoozeState.snoozeInterval, + snoozeCount = state.snoozeState.snoozeCount, + onSnoozeToggle = { processAction(AlarmAddEditContract.Action.ToggleSnoozeOption) }, + onIntervalSelected = { interval -> + processAction(AlarmAddEditContract.Action.SetSnoozeInterval(interval)) + }, + onCountSelected = { count -> + processAction(AlarmAddEditContract.Action.SetSnoozeRepeatCount(count)) + }, + onDismiss = { + processAction(AlarmAddEditContract.Action.HideBottomSheet) + }, + ) + } + + AlarmAddEditContract.BottomSheetType.SoundSetting -> { + AlarmSoundBottomSheet( + vibrationEnabled = state.soundState.isVibrationEnabled, + soundEnabled = state.soundState.isSoundEnabled, + soundVolume = state.soundState.soundVolume, + soundIndex = state.soundState.soundIndex, + sounds = state.soundState.sounds, + onVibrationToggle = { processAction(AlarmAddEditContract.Action.ToggleVibrationOption) }, + onSoundToggle = { processAction(AlarmAddEditContract.Action.ToggleSoundOption) }, + onVolumeChanged = { processAction(AlarmAddEditContract.Action.AdjustSoundVolume(it)) }, + onSoundSelected = { processAction(AlarmAddEditContract.Action.SelectAlarmSound(it)) }, + onComplete = { processAction(AlarmAddEditContract.Action.HideBottomSheet) }, + ) + } + } + } + } + + is AlarmAddEditContract.SideEffect.HideBottomSheet -> { + bottomSheetState.hide() + } + is AlarmAddEditContract.SideEffect.SaveAlarm -> { navigator.navController.previousBackStackEntry ?.savedStateHandle ?.set(ADD_ALARM_RESULT_KEY, sideEffect.id) navigator.navController.popBackStack() } + is AlarmAddEditContract.SideEffect.UpdateAlarm -> { navigator.navController.previousBackStackEntry ?.savedStateHandle ?.set(UPDATE_ALARM_RESULT_KEY, sideEffect.id) navigator.navigateBack() } + is AlarmAddEditContract.SideEffect.DeleteAlarm -> { navigator.navController.previousBackStackEntry ?.savedStateHandle ?.set(DELETE_ALARM_RESULT_KEY, sideEffect.id) navigator.navigateBack() } + is AlarmAddEditContract.SideEffect.ShowSnackBar -> { val result = showCustomSnackBar( scope = coroutineScope, @@ -174,13 +259,6 @@ fun AlarmAddEditContent( eventDispatcher(AlarmAddEditContract.Action.CheckUnsavedChangesBeforeExit) } - val missionState = state.missionState - val snoozeState = state.snoozeState - val missionBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val snoozeBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val soundBottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val scope = rememberCoroutineScope() - Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, @@ -227,111 +305,6 @@ fun AlarmAddEditContent( ) } - when (state.bottomSheetState) { - AlarmAddEditContract.BottomSheetType.MissionSetting -> { - AlarmMissionBottomSheet( - sheetState = missionBottomSheetState, - missionType = missionState.missionType, - missionCount = missionState.missionCount, - onDismiss = { - scope.launch { - missionBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher( - AlarmAddEditContract.Action.ToggleBottomSheet( - AlarmAddEditContract.BottomSheetType.MissionSetting, - ), - ) - } - }, - onSaveMission = { missionType, missionCount -> - eventDispatcher( - AlarmAddEditContract.Action.SaveMission( - type = missionType, - count = missionCount, - ), - ) - }, - onPreviewMission = { missionType, missionCount -> - eventDispatcher( - AlarmAddEditContract.Action.NavigateToMissionPreview( - missionType = missionType, - missionCount = missionCount, - ), - ) - }, - ) - } - - AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { - AlarmSnoozeBottomSheet( - snoozeEnabled = snoozeState.isSnoozeEnabled, - snoozeInterval = snoozeState.snoozeInterval, - snoozeCount = snoozeState.snoozeCount, - onSnoozeToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSnoozeOption) }, - onIntervalSelected = { interval -> - eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeInterval(interval), - ) - }, - onCountSelected = { count -> - eventDispatcher( - AlarmAddEditContract.Action.SetSnoozeRepeatCount(count), - ) - }, - onDismiss = { - scope.launch { - snoozeBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher( - AlarmAddEditContract.Action.ToggleBottomSheet( - AlarmAddEditContract.BottomSheetType.SnoozeSetting, - ), - ) - } - }, - ) - } - - AlarmAddEditContract.BottomSheetType.SoundSetting -> { - AlarmSoundBottomSheet( - vibrationEnabled = state.soundState.isVibrationEnabled, - soundEnabled = state.soundState.isSoundEnabled, - soundVolume = state.soundState.soundVolume, - soundIndex = state.soundState.soundIndex, - sounds = state.soundState.sounds, - onVibrationToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleVibrationOption) }, - onSoundToggle = { eventDispatcher(AlarmAddEditContract.Action.ToggleSoundOption) }, - onVolumeChanged = { eventDispatcher(AlarmAddEditContract.Action.AdjustSoundVolume(it)) }, - onSoundSelected = { eventDispatcher(AlarmAddEditContract.Action.SelectAlarmSound(it)) }, - onComplete = { - scope.launch { - soundBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher( - AlarmAddEditContract.Action.ToggleBottomSheet( - AlarmAddEditContract.BottomSheetType.SoundSetting, - ), - ) - } - }, - onDismiss = { - scope.launch { - soundBottomSheetState.hide() - }.invokeOnCompletion { - eventDispatcher( - AlarmAddEditContract.Action.ToggleBottomSheet( - AlarmAddEditContract.BottomSheetType.SoundSetting, - ), - ) - } - }, - ) - } - - else -> null - } - if (state.isDeleteDialogVisible) { OrbitDialog( title = stringResource(id = R.string.alarm_delete_dialog_title), @@ -490,7 +463,7 @@ private fun AlarmAddEditSettingsSection( }, onClick = { processAction( - AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.Action.ShowBottomSheet( AlarmAddEditContract.BottomSheetType.MissionSetting, ), ) @@ -528,7 +501,7 @@ private fun AlarmAddEditSettingsSection( }, onClick = { processAction( - AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.Action.ShowBottomSheet( AlarmAddEditContract.BottomSheetType.SnoozeSetting, ), ) @@ -564,7 +537,7 @@ private fun AlarmAddEditSettingsSection( }, onClick = { processAction( - AlarmAddEditContract.Action.ToggleBottomSheet( + AlarmAddEditContract.Action.ShowBottomSheet( AlarmAddEditContract.BottomSheetType.SoundSetting, ), ) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt index 6ebed864..c1747be2 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt @@ -183,7 +183,8 @@ class AlarmAddEditViewModel @Inject constructor( is AlarmAddEditContract.Action.ToggleSoundOption -> toggleSoundOption() is AlarmAddEditContract.Action.AdjustSoundVolume -> adjustSoundVolume(action.volume) is AlarmAddEditContract.Action.SelectAlarmSound -> selectAlarmSound(action.index) - is AlarmAddEditContract.Action.ToggleBottomSheet -> toggleBottomSheet(action.sheetType) + is AlarmAddEditContract.Action.ShowBottomSheet -> showBottomSheet(action.sheetType) + is AlarmAddEditContract.Action.HideBottomSheet -> hideBottomSheet() } } @@ -520,18 +521,12 @@ class AlarmAddEditViewModel @Inject constructor( alarmUseCase.playAlarmSound(state.soundState.soundVolume) } - private fun toggleBottomSheet(sheetType: AlarmAddEditContract.BottomSheetType) = intent { - val newBottomSheetState = if (state.bottomSheetState == sheetType) { - if (state.bottomSheetState == AlarmAddEditContract.BottomSheetType.SoundSetting) { - alarmUseCase.stopAlarmSound() - } - null - } else { - sheetType - } - reduce { - state.copy(bottomSheetState = newBottomSheetState) - } + private fun showBottomSheet(sheetType: AlarmAddEditContract.BottomSheetType) = intent { + postSideEffect(AlarmAddEditContract.SideEffect.ShowBottomSheet(sheetType)) + } + + private fun hideBottomSheet() = intent { + postSideEffect(AlarmAddEditContract.SideEffect.HideBottomSheet) } private fun getAlarmMessage(currentTime: LocalTime, selectedDays: Set): String { diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt index 4db7ba80..aabb99c6 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt @@ -19,9 +19,7 @@ import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon -import androidx.compose.material3.SheetState import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf @@ -39,7 +37,6 @@ import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme import com.yapp.domain.model.MissionType import com.yapp.home.alarm.component.SelectorItems -import com.yapp.ui.component.OrbitBottomSheet import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.lottie.LottieAnimation import com.yapp.ui.extensions.customClickable @@ -62,7 +59,6 @@ private fun MissionType.displayData(): Pair = when (this) { @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun AlarmMissionBottomSheet( - sheetState: SheetState, missionType: MissionType, missionCount: Int, onDismiss: () -> Unit, @@ -74,82 +70,74 @@ internal fun AlarmMissionBottomSheet( var selectedMissionType by remember { mutableStateOf(missionType) } var selectedMissionCount by remember { mutableIntStateOf(missionCount) } - OrbitBottomSheet( - sheetState = sheetState, - onDismissRequest = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING - onDismiss() - }, - ) { - when (currentStep) { - AlarmMissionSelectBottomSheetType.MISSION_SETTING -> { - if (selectedMissionType == MissionType.NONE) { - MissionAddContent { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT - } - } else { - MissionSettingContent( - missionType = missionType, - missionCount = missionCount, - onDetail = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_DETAIL - }, - onDelete = { - selectedMissionType = MissionType.NONE - onSaveMission(selectedMissionType, selectedMissionCount) - }, - onChange = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT - }, - onDone = { - onSaveMission(selectedMissionType, selectedMissionCount) - onDismiss() - }, - ) + when (currentStep) { + AlarmMissionSelectBottomSheetType.MISSION_SETTING -> { + if (selectedMissionType == MissionType.NONE) { + MissionAddContent { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT } - } - - AlarmMissionSelectBottomSheetType.MISSION_SELECT -> { - MissionSelectContent( - onBack = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING - }, - onClose = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING - onDismiss() - }, - onSelect = { mission -> - selectedMissionType = mission + } else { + MissionSettingContent( + missionType = missionType, + missionCount = missionCount, + onDetail = { currentStep = AlarmMissionSelectBottomSheetType.MISSION_DETAIL }, - ) - } - - AlarmMissionSelectBottomSheetType.MISSION_DETAIL -> { - MissionDetailContent( - missionType = selectedMissionType, - selectedMissionCount = selectedMissionCount, - onCountChange = { count -> - selectedMissionCount = count + onDelete = { + selectedMissionType = MissionType.NONE + onSaveMission(selectedMissionType, selectedMissionCount) }, - onBack = { + onChange = { currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT }, - onClose = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING - onDismiss() - }, - onSave = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING + onDone = { onSaveMission(selectedMissionType, selectedMissionCount) onDismiss() }, - onPreview = { - onPreviewMission(selectedMissionType, selectedMissionCount) - }, ) } } + + AlarmMissionSelectBottomSheetType.MISSION_SELECT -> { + MissionSelectContent( + onBack = { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING + }, + onClose = { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING + onDismiss() + }, + onSelect = { mission -> + selectedMissionType = mission + currentStep = AlarmMissionSelectBottomSheetType.MISSION_DETAIL + }, + ) + } + + AlarmMissionSelectBottomSheetType.MISSION_DETAIL -> { + MissionDetailContent( + missionType = selectedMissionType, + selectedMissionCount = selectedMissionCount, + onCountChange = { count -> + selectedMissionCount = count + }, + onBack = { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT + }, + onClose = { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING + onDismiss() + }, + onSave = { + currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING + onSaveMission(selectedMissionType, selectedMissionCount) + onDismiss() + }, + onPreview = { + onPreviewMission(selectedMissionType, selectedMissionCount) + }, + ) + } } } @@ -644,10 +632,7 @@ private fun MissionSelectTopAppBar( @Composable private fun AlarmMissionSelectBottomSheetPreview() { OrbitTheme { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - AlarmMissionBottomSheet( - sheetState = sheetState, missionType = MissionType.SHAKE, missionCount = 15, onDismiss = {}, diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt index 91efbbf3..1a1d467b 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt @@ -12,13 +12,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState 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.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -27,11 +25,9 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme import com.yapp.home.alarm.component.SelectorItems -import com.yapp.ui.component.OrbitBottomSheet import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.switch.OrbitSwitch import feature.home.R -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -44,9 +40,6 @@ internal fun AlarmSnoozeBottomSheet( onSnoozeToggle: (Boolean) -> Unit, onDismiss: () -> Unit, ) { - val scope = rememberCoroutineScope() - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - val snoozeIntervalOptions = listOf(1, 3, 5, 10, 15) val snoozeCountOptions = listOf(1, 3, 5, 10, -1) @@ -73,65 +66,56 @@ internal fun AlarmSnoozeBottomSheet( ) } - OrbitBottomSheet( - sheetState = sheetState, - onDismissRequest = onDismiss, + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 24.dp, vertical = 12.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Spacer(modifier = Modifier.height(6.dp)) - VibrationSection(selectedSnoozeEnabled) { - selectedSnoozeEnabled = !selectedSnoozeEnabled - onSnoozeToggle(selectedSnoozeEnabled) - } - Spacer(modifier = Modifier.height(20.dp)) - SelectorSection( - title = stringResource(id = R.string.alarm_add_edit_interval), - selectedIndex = selectedSnoozeIntervalIndex, - items = snoozeIntervals, - enabled = selectedSnoozeEnabled, - onItemSelected = { - selectedSnoozeIntervalIndex = it - onIntervalSelected(snoozeIntervalOptions[it]) - }, - ) - Spacer(modifier = Modifier.height(32.dp)) - SelectorSection( - title = stringResource(id = R.string.alarm_add_edit_repeat_count), - selectedIndex = selectedSnoozeCountIndex, - items = snoozeCounts, - enabled = selectedSnoozeEnabled, - onItemSelected = { - selectedSnoozeCountIndex = it - onCountSelected(snoozeCountOptions[it]) - }, - ) - Spacer(modifier = Modifier.height(20.dp)) - if (selectedSnoozeEnabled) { - AlarmSnoozeMessage( - interval = snoozeIntervals[selectedSnoozeIntervalIndex], - count = snoozeCounts[selectedSnoozeCountIndex], - ) - } - Spacer(modifier = Modifier.height(40.dp)) - OrbitButton( - label = stringResource(id = R.string.alarm_add_edit_complete), - enabled = true, - containerColor = OrbitTheme.colors.gray_600, - contentColor = OrbitTheme.colors.white, - pressedContainerColor = OrbitTheme.colors.gray_500, - pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - onClick = { - scope.launch { sheetState.hide() }.invokeOnCompletion { - onDismiss() - } - }, + Spacer(modifier = Modifier.height(6.dp)) + VibrationSection(selectedSnoozeEnabled) { + selectedSnoozeEnabled = !selectedSnoozeEnabled + onSnoozeToggle(selectedSnoozeEnabled) + } + Spacer(modifier = Modifier.height(20.dp)) + SelectorSection( + title = stringResource(id = R.string.alarm_add_edit_interval), + selectedIndex = selectedSnoozeIntervalIndex, + items = snoozeIntervals, + enabled = selectedSnoozeEnabled, + onItemSelected = { + selectedSnoozeIntervalIndex = it + onIntervalSelected(snoozeIntervalOptions[it]) + }, + ) + Spacer(modifier = Modifier.height(32.dp)) + SelectorSection( + title = stringResource(id = R.string.alarm_add_edit_repeat_count), + selectedIndex = selectedSnoozeCountIndex, + items = snoozeCounts, + enabled = selectedSnoozeEnabled, + onItemSelected = { + selectedSnoozeCountIndex = it + onCountSelected(snoozeCountOptions[it]) + }, + ) + Spacer(modifier = Modifier.height(20.dp)) + if (selectedSnoozeEnabled) { + AlarmSnoozeMessage( + interval = snoozeIntervals[selectedSnoozeIntervalIndex], + count = snoozeCounts[selectedSnoozeCountIndex], ) } + Spacer(modifier = Modifier.height(40.dp)) + OrbitButton( + label = stringResource(id = R.string.alarm_add_edit_complete), + enabled = true, + containerColor = OrbitTheme.colors.gray_600, + contentColor = OrbitTheme.colors.white, + pressedContainerColor = OrbitTheme.colors.gray_500, + pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), + onClick = onDismiss, + ) } } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt index 488d340b..f7e8cb70 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt @@ -10,21 +10,18 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -34,13 +31,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme import com.yapp.domain.model.AlarmSound -import com.yapp.ui.component.OrbitBottomSheet import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.radiobutton.OrbitRadioButton import com.yapp.ui.component.slider.OrbitSlider import com.yapp.ui.component.switch.OrbitSwitch import feature.home.R -import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -55,35 +50,19 @@ internal fun AlarmSoundBottomSheet( onVolumeChanged: (Int) -> Unit, onSoundSelected: (Int) -> Unit, onComplete: () -> Unit, - onDismiss: () -> Unit, ) { - val scope = rememberCoroutineScope() - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - - OrbitBottomSheet( - modifier = Modifier.statusBarsPadding(), - sheetState = sheetState, - onDismissRequest = { - onDismiss() - }, - ) { - BottomSheetContent( - vibrationEnabled = vibrationEnabled, - soundEnabled = soundEnabled, - soundVolume = soundVolume, - soundIndex = soundIndex, - sounds = sounds, - onVibrationToggle = onVibrationToggle, - onSoundToggle = onSoundToggle, - onVolumeChanged = onVolumeChanged, - onSoundSelected = onSoundSelected, - onComplete = { - scope.launch { - sheetState.hide() - }.invokeOnCompletion { onComplete() } - }, - ) - } + BottomSheetContent( + vibrationEnabled = vibrationEnabled, + soundEnabled = soundEnabled, + soundVolume = soundVolume, + soundIndex = soundIndex, + sounds = sounds, + onVibrationToggle = onVibrationToggle, + onSoundToggle = onSoundToggle, + onVolumeChanged = onVolumeChanged, + onSoundSelected = onSoundSelected, + onComplete = onComplete, + ) } @Composable @@ -316,7 +295,6 @@ private fun AlarmSoundBottomSheetPreview() { onVolumeChanged = { soundVolume = it }, onSoundSelected = { soundIndex = it }, onComplete = { isSheetOpen = false }, - onDismiss = { isSheetOpen = false }, ) } } diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingContract.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingContract.kt index 86bf3029..95dc24db 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingContract.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingContract.kt @@ -19,7 +19,6 @@ sealed class OnboardingContract { val isBirthDateValid: Boolean = false, val isBirthTimeValid: Boolean = false, val isValid: Boolean = false, - val isBottomSheetOpen: Boolean = false, val isShowWarningDialog: Boolean = false, ) : UiState { val birthDateFormatted: String @@ -54,7 +53,8 @@ sealed class OnboardingContract { data object Submit : Action() data class UpdateGender(val gender: String) : Action() data class UpdateBirthDate(val lunar: String, val year: Int, val month: Int, val day: Int) : Action() - data object ToggleBottomSheet : Action() + data object ShowBottomSheet : Action() + data object HideBottomSheet : Action() data object CompleteOnboarding : Action() data class OpenWebView(val url: String) : Action() data object ShowWarningDialog : Action() @@ -71,6 +71,10 @@ sealed class OnboardingContract { data object NavigateBack : SideEffect() + data object ShowBottomSheet : SideEffect() + + data object HideBottomSheet : SideEffect() + data object OnboardingCompleted : SideEffect() data class OpenWebView(val url: String) : SideEffect() diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt index f997a4e4..83168e66 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt @@ -1,5 +1,6 @@ package com.yapp.onboarding +import android.net.Uri import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -21,18 +22,25 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.navOptions import com.yapp.analytics.AnalyticsEvent import com.yapp.analytics.LocalAnalyticsHelper +import com.yapp.common.navigation.OrbitNavigator +import com.yapp.common.navigation.route.OnboardingBaseRoute import com.yapp.designsystem.theme.OrbitTheme import com.yapp.onboarding.component.UserInfoBottomSheet +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState import com.yapp.ui.component.dialog.OrbitDialog import com.yapp.ui.toggle.OrbitGenderToggle import com.yapp.ui.utils.heightForScreenPercentage import com.yapp.ui.utils.paddingForScreenPercentage import feature.onboarding.R +import org.orbitmvi.orbit.compose.collectSideEffect @Composable fun OnboardingGenderRoute( + navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, viewModel: OnboardingViewModel, ) { val state by viewModel.container.stateFlow.collectAsStateWithLifecycle() @@ -54,11 +62,21 @@ fun OnboardingGenderRoute( viewModel.processAction(OnboardingContract.Action.PreviousStep) } + viewModel.collectSideEffect { sideEffect -> + handleSideEffect( + sideEffect = sideEffect, + navigator = navigator, + bottomSheetState = bottomSheetState, + state = state, + processAction = viewModel::processAction, + ) + } + OnboardingGenderScreen( state = state, currentStep = 5, totalSteps = 6, - onNextClick = { viewModel.processAction(OnboardingContract.Action.ToggleBottomSheet) }, + onNextClick = { viewModel.processAction(OnboardingContract.Action.ShowBottomSheet) }, onBackClick = { viewModel.processAction(OnboardingContract.Action.PreviousStep) }, onGenderSelect = { gender -> analyticsHelper.logEvent( @@ -71,16 +89,67 @@ fun OnboardingGenderRoute( ) viewModel.processAction(OnboardingContract.Action.UpdateGender(gender)) }, - onDismissRequest = { - viewModel.processAction(OnboardingContract.Action.ToggleBottomSheet) - }, - onConfirmRequest = { - viewModel.processAction(OnboardingContract.Action.ToggleBottomSheet) - viewModel.processAction(OnboardingContract.Action.Submit) + onDialogConfirm = { + viewModel.processAction(OnboardingContract.Action.HideWarningDialog) }, ) } +private suspend fun handleSideEffect( + sideEffect: OnboardingContract.SideEffect, + navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, + state: OnboardingContract.State, + processAction: (OnboardingContract.Action) -> Unit, +) { + when (sideEffect) { + is OnboardingContract.SideEffect.NavigateToNextStep -> { + navigator.navigateToOnboardingNextStep(sideEffect.currentStep) + } + + OnboardingContract.SideEffect.NavigateBack -> { + processAction(OnboardingContract.Action.Reset) + navigator.navigateBack() + } + + is OnboardingContract.SideEffect.ShowBottomSheet -> { + bottomSheetState.show { + UserInfoBottomSheet( + name = state.userName, + gender = state.selectedGender ?: "무지개", + birthDate = state.birthDateFormatted, + birthTime = state.birthTimeFormatted, + onDismiss = { + processAction(OnboardingContract.Action.HideBottomSheet) + }, + onConfirm = { + processAction(OnboardingContract.Action.HideBottomSheet) + processAction(OnboardingContract.Action.Submit) + }, + ) + } + } + + is OnboardingContract.SideEffect.HideBottomSheet -> { + bottomSheetState.hide() + } + + OnboardingContract.SideEffect.OnboardingCompleted -> { + navigator.navigateToHome( + navOptions = navOptions { + popUpTo(OnboardingBaseRoute) { + inclusive = true + } + }, + ) + } + + is OnboardingContract.SideEffect.OpenWebView -> { + navigator.navigateToWebView(Uri.encode(sideEffect.url)) + } + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable fun OnboardingGenderScreen( @@ -90,8 +159,7 @@ fun OnboardingGenderScreen( onNextClick: () -> Unit, onBackClick: () -> Unit, onGenderSelect: (String) -> Unit, - onDismissRequest: () -> Unit, - onConfirmRequest: () -> Unit, + onDialogConfirm: () -> Unit, ) { OnboardingScreen( currentStep = currentStep, @@ -144,20 +212,7 @@ fun OnboardingGenderScreen( title = stringResource(id = R.string.onboarding_warning_dialog_title), message = stringResource(id = R.string.onboarding_warning_dialog_message), confirmText = stringResource(id = R.string.onboarding_warning_dialog_btn_confirm), - onConfirm = { - onConfirmRequest() - }, - ) - } - - if (state.isBottomSheetOpen) { - UserInfoBottomSheet( - onDismissRequest = onDismissRequest, - onConfirmRequest = onConfirmRequest, - name = state.userName, - gender = state.selectedGender ?: "무지개", - birthDate = state.birthDateFormatted, - birthTime = state.birthTimeFormatted, + onConfirm = onDialogConfirm, ) } } @@ -174,7 +229,6 @@ fun OnboardingGenderScreenPreview() { onNextClick = {}, onBackClick = {}, onGenderSelect = {}, - onDismissRequest = {}, - onConfirmRequest = {}, + onDialogConfirm = {}, ) } diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingNavGraph.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingNavGraph.kt index 7b0677fa..ff7417d7 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingNavGraph.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingNavGraph.kt @@ -9,90 +9,106 @@ import com.yapp.common.navigation.OrbitNavigator import com.yapp.common.navigation.extensions.sharedHiltViewModel import com.yapp.common.navigation.route.OnboardingBaseRoute import com.yapp.common.navigation.route.OnboardingDestination +import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState import org.orbitmvi.orbit.compose.collectSideEffect fun NavGraphBuilder.onboardingNavGraph( navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, ) { navigation(startDestination = OnboardingDestination.Explain) { composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingExplainRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingAlarmTimeSelectionRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingBirthdayRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingTimeOfBirthRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingNameRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) - } - OnboardingGenderRoute(viewModel) + + OnboardingGenderRoute(navigator, bottomSheetState, viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingAccessRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingCompleteRoute(viewModel) } composable { val viewModel = it.sharedHiltViewModel(navigator.navController) - viewModel.collectSideEffect { - handleSideEffect(it, navigator, viewModel) + + viewModel.collectSideEffect { sideEffect -> + handleOnboardingCommonSideEffect(sideEffect, navigator, viewModel::processAction) } + OnboardingCompleteRoute2(viewModel) } } } -private fun handleSideEffect( +private fun handleOnboardingCommonSideEffect( sideEffect: OnboardingContract.SideEffect, navigator: OrbitNavigator, - viewModel: OnboardingViewModel, + processAction: (OnboardingContract.Action) -> Unit, ) { when (sideEffect) { is OnboardingContract.SideEffect.NavigateToNextStep -> { @@ -100,7 +116,7 @@ private fun handleSideEffect( } OnboardingContract.SideEffect.NavigateBack -> { - viewModel.processAction(OnboardingContract.Action.Reset) + processAction(OnboardingContract.Action.Reset) navigator.navigateBack() } @@ -117,5 +133,7 @@ private fun handleSideEffect( is OnboardingContract.SideEffect.OpenWebView -> { navigator.navigateToWebView(Uri.encode(sideEffect.url)) } + + else -> { } } } diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt index 7281a9a5..24f3ba73 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingViewModel.kt @@ -57,7 +57,8 @@ class OnboardingViewModel @Inject constructor( is OnboardingContract.Action.Reset -> resetFields() is OnboardingContract.Action.Submit -> submitUserInfo() is OnboardingContract.Action.UpdateGender -> updateGender(action.gender) - is OnboardingContract.Action.ToggleBottomSheet -> toggleBottomSheet() + is OnboardingContract.Action.ShowBottomSheet -> showBottomSheet() + is OnboardingContract.Action.HideBottomSheet -> hideBottomSheet() is OnboardingContract.Action.CompleteOnboarding -> completeOnboarding() is OnboardingContract.Action.OpenWebView -> openWebView(action.url) is OnboardingContract.Action.ShowWarningDialog -> showWarningDialog() @@ -90,7 +91,6 @@ class OnboardingViewModel @Inject constructor( ), ) - reduce { state.copy(isBottomSheetOpen = false) } moveToNextStep() } else { showWarningDialog() @@ -225,9 +225,12 @@ class OnboardingViewModel @Inject constructor( reduce { state.copy(selectedGender = gender, isButtonEnabled = true) } } - private fun toggleBottomSheet() = intent { - val isCurrentlyOpen = state.isBottomSheetOpen - reduce { state.copy(isBottomSheetOpen = !isCurrentlyOpen) } + private fun showBottomSheet() = intent { + postSideEffect(OnboardingContract.SideEffect.ShowBottomSheet) + } + + private fun hideBottomSheet() = intent { + postSideEffect(OnboardingContract.SideEffect.HideBottomSheet) } private fun completeOnboarding() = intent { diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt index b02f785e..af935235 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/component/UserInfoBottomSheet.kt @@ -7,9 +7,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.SheetState import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -17,7 +15,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme -import com.yapp.ui.component.OrbitBottomSheet import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.utils.paddingForScreenPercentage import com.yapp.ui.utils.widthForScreenPercentage @@ -26,76 +23,70 @@ import feature.onboarding.R @OptIn(ExperimentalMaterial3Api::class) @Composable fun UserInfoBottomSheet( - sheetState: SheetState = rememberModalBottomSheetState(), - onDismissRequest: () -> Unit, - onConfirmRequest: () -> Unit, name: String, gender: String, birthDate: String, birthTime: String, + onDismiss: () -> Unit, + onConfirm: () -> Unit, ) { - OrbitBottomSheet( - sheetState = sheetState, - onDismissRequest = onDismissRequest, + Column( + modifier = Modifier + .fillMaxWidth() + .paddingForScreenPercentage(allPercentage = 0.03f), ) { - Column( + Text( + text = stringResource(R.string.onboarding_step6_bs_title), + modifier = Modifier + .paddingForScreenPercentage( + topPercentage = 0.005f, + bottomPercentage = 0.027f, + ), + style = OrbitTheme.typography.heading2SemiBold, + color = OrbitTheme.colors.white, + ) + UserInfoRow(label = stringResource(R.string.onboarding_step6_bs_name), value = name) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_gender), + value = gender, + ) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_birth), + value = birthDate, + ) + UserInfoRow( + label = stringResource(R.string.onboarding_step6_bs_time), + value = birthTime, + ) + + Row( modifier = Modifier .fillMaxWidth() - .paddingForScreenPercentage(allPercentage = 0.03f), + .paddingForScreenPercentage(topPercentage = 0.032f), + verticalAlignment = Alignment.CenterVertically, ) { - Text( - text = stringResource(R.string.onboarding_step6_bs_title), - modifier = Modifier - .paddingForScreenPercentage( - topPercentage = 0.005f, - bottomPercentage = 0.027f, - ), - style = OrbitTheme.typography.heading2SemiBold, - color = OrbitTheme.colors.white, - ) - UserInfoRow(label = stringResource(R.string.onboarding_step6_bs_name), value = name) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_gender), - value = gender, - ) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_birth), - value = birthDate, + OrbitButton( + label = stringResource(R.string.onboarding_step6_bs_btn_dismiss), + modifier = Modifier.weight(1f), + onClick = onDismiss, + enabled = true, + containerColor = OrbitTheme.colors.gray_600, + contentColor = OrbitTheme.colors.white, + pressedContainerColor = OrbitTheme.colors.gray_500, + pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), + shape = RoundedCornerShape(12.dp), ) - UserInfoRow( - label = stringResource(R.string.onboarding_step6_bs_time), - value = birthTime, - ) - - Row( - modifier = Modifier - .fillMaxWidth() - .paddingForScreenPercentage(topPercentage = 0.032f), - verticalAlignment = Alignment.CenterVertically, - ) { - OrbitButton( - label = stringResource(R.string.onboarding_step6_bs_btn_dismiss), - modifier = Modifier.weight(1f), - onClick = onDismissRequest, - enabled = true, - containerColor = OrbitTheme.colors.gray_600, - contentColor = OrbitTheme.colors.white, - pressedContainerColor = OrbitTheme.colors.gray_500, - pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - shape = RoundedCornerShape(12.dp), - ) - Spacer(modifier = Modifier.widthForScreenPercentage(0.032f)) - OrbitButton( - label = stringResource(R.string.onboarding_step6_bs_btn_confirm), - modifier = Modifier.weight(1f), - onClick = onConfirmRequest, - enabled = true, - pressedContainerColor = OrbitTheme.colors.main.copy(alpha = 0.8f), - pressedContentColor = OrbitTheme.colors.gray_600, - shape = RoundedCornerShape(12.dp), + Spacer(modifier = Modifier.widthForScreenPercentage(0.032f)) + OrbitButton( + label = stringResource(R.string.onboarding_step6_bs_btn_confirm), + modifier = Modifier.weight(1f), + onClick = onConfirm, + enabled = true, + pressedContainerColor = OrbitTheme.colors.main.copy(alpha = 0.8f), + pressedContentColor = OrbitTheme.colors.gray_600, + shape = RoundedCornerShape(12.dp), - ) - } + ) } } } @@ -130,11 +121,11 @@ fun UserInfoRow( @Preview fun UserInfoBottomSheetPreview() { UserInfoBottomSheet( - onDismissRequest = { }, - onConfirmRequest = { }, name = "홍길동", gender = "남성", birthDate = "1990년 1월 1일", birthTime = "12:00", + onDismiss = { }, + onConfirm = { }, ) } From 1ef65d01707d5fc544a9bf9831af5722aee49809 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:26:18 +0900 Subject: [PATCH 07/16] =?UTF-8?q?[FEAT/#237]=20AlarmMissionBottomSheet=20?= =?UTF-8?q?=EB=8B=A8=EA=B3=84=20=EC=83=81=ED=83=9C=EB=A5=BC=20=EC=8A=A4?= =?UTF-8?q?=ED=83=9D=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/AlarmMissionBottomSheet.kt | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt index aabb99c6..2579f261 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt @@ -56,7 +56,6 @@ private fun MissionType.displayData(): Pair = when (this) { else -> throw IllegalStateException("Invalid mission type") } -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun AlarmMissionBottomSheet( missionType: MissionType, @@ -65,31 +64,38 @@ internal fun AlarmMissionBottomSheet( onSaveMission: (MissionType, Int) -> Unit, onPreviewMission: (MissionType, Int) -> Unit, ) { - var currentStep by remember { mutableStateOf(AlarmMissionSelectBottomSheetType.MISSION_SETTING) } - + var stepStack by remember { mutableStateOf(listOf(AlarmMissionSelectBottomSheetType.MISSION_SETTING)) } var selectedMissionType by remember { mutableStateOf(missionType) } var selectedMissionCount by remember { mutableIntStateOf(missionCount) } + fun push(step: AlarmMissionSelectBottomSheetType) { + stepStack = stepStack + step + } + + fun pop() { + if (stepStack.size > 1) { + stepStack = stepStack.dropLast(1) + } + } + + val currentStep = stepStack.last() + when (currentStep) { AlarmMissionSelectBottomSheetType.MISSION_SETTING -> { if (selectedMissionType == MissionType.NONE) { MissionAddContent { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT + push(AlarmMissionSelectBottomSheetType.MISSION_SELECT) } } else { MissionSettingContent( - missionType = missionType, - missionCount = missionCount, - onDetail = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_DETAIL - }, + missionType = selectedMissionType, + missionCount = selectedMissionCount, + onDetail = { push(AlarmMissionSelectBottomSheetType.MISSION_DETAIL) }, onDelete = { selectedMissionType = MissionType.NONE onSaveMission(selectedMissionType, selectedMissionCount) }, - onChange = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT - }, + onChange = { push(AlarmMissionSelectBottomSheetType.MISSION_SELECT) }, onDone = { onSaveMission(selectedMissionType, selectedMissionCount) onDismiss() @@ -100,16 +106,13 @@ internal fun AlarmMissionBottomSheet( AlarmMissionSelectBottomSheetType.MISSION_SELECT -> { MissionSelectContent( - onBack = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING - }, + onBack = { pop() }, onClose = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING onDismiss() }, onSelect = { mission -> selectedMissionType = mission - currentStep = AlarmMissionSelectBottomSheetType.MISSION_DETAIL + push(AlarmMissionSelectBottomSheetType.MISSION_DETAIL) }, ) } @@ -118,18 +121,12 @@ internal fun AlarmMissionBottomSheet( MissionDetailContent( missionType = selectedMissionType, selectedMissionCount = selectedMissionCount, - onCountChange = { count -> - selectedMissionCount = count - }, - onBack = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SELECT - }, + onCountChange = { selectedMissionCount = it }, + onBack = { pop() }, onClose = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING onDismiss() }, onSave = { - currentStep = AlarmMissionSelectBottomSheetType.MISSION_SETTING onSaveMission(selectedMissionType, selectedMissionCount) onDismiss() }, From 300cfefffcc40cddc1226ca7df34ce06182827ae Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:27:40 +0900 Subject: [PATCH 08/16] =?UTF-8?q?[FIX/#237]=20OrbitBottomSheetState?= =?UTF-8?q?=EA=B0=80=20=EB=8B=AB=ED=9E=90=20=EB=95=8C=EB=A7=88=EB=8B=A4=20?= =?UTF-8?q?content=EB=A5=BC=20null=EB=A1=9C=20=EC=B4=88=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bottomsheet/OrbitBottomSheetState.kt | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt index 23ce38ab..15bdfc16 100644 --- a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt @@ -4,29 +4,44 @@ import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ModalBottomSheetValue import androidx.compose.material.rememberModalBottomSheetState import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue @Composable -fun rememberOrbitBottomSheetState( - bottomSheetState: ModalBottomSheetState = rememberModalBottomSheetState( +fun rememberOrbitBottomSheetState(): OrbitBottomSheetState { + val contentState = remember { mutableStateOf(null) } + + val bottomSheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, + confirmValueChange = { value -> + if (value == ModalBottomSheetValue.Hidden) { + contentState.value = null + } + true + }, skipHalfExpanded = true, - ), -): OrbitBottomSheetState { - return remember(bottomSheetState) { OrbitBottomSheetState(state = bottomSheetState) } + ) + + return remember(contentState, bottomSheetState) { + OrbitBottomSheetState( + state = bottomSheetState, + contentState = contentState, + setContent = { contentState.value = it }, + ) + } } class OrbitBottomSheetState( val state: ModalBottomSheetState, + val contentState: State, + val setContent: (BottomSheetContent?) -> Unit, ) { - var content by mutableStateOf(null) - private set + val content: BottomSheetContent? + get() = contentState.value suspend fun show(sheetContent: BottomSheetContent) { - content = sheetContent + setContent(sheetContent) state.show() } From 1bd36062cba9ddb204e389ecb9ae29fe102d4262 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:38:06 +0900 Subject: [PATCH 09/16] =?UTF-8?q?[REFACTOR/#237]=20=EC=95=8C=EB=9E=8C=20?= =?UTF-8?q?=EC=86=8C=EB=A6=AC=20=EB=B0=94=ED=85=80=EC=8B=9C=ED=8A=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=A7=84=EB=8F=99,=20=EC=86=8C=EB=A6=AC,?= =?UTF-8?q?=20=EC=9D=8C=EB=9F=89,=20=EC=84=A0=ED=83=9D=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=A5=BC=20=EB=82=B4=EB=B6=80=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/alarm/addedit/AlarmAddEditScreen.kt | 20 +++++- .../bottomsheet/AlarmSoundBottomSheet.kt | 67 +++++++------------ 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 129d956b..6c3a08fc 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -179,9 +179,23 @@ private suspend fun handleSideEffect( sounds = state.soundState.sounds, onVibrationToggle = { processAction(AlarmAddEditContract.Action.ToggleVibrationOption) }, onSoundToggle = { processAction(AlarmAddEditContract.Action.ToggleSoundOption) }, - onVolumeChanged = { processAction(AlarmAddEditContract.Action.AdjustSoundVolume(it)) }, - onSoundSelected = { processAction(AlarmAddEditContract.Action.SelectAlarmSound(it)) }, - onComplete = { processAction(AlarmAddEditContract.Action.HideBottomSheet) }, + onVolumeChanged = { + processAction( + AlarmAddEditContract.Action.AdjustSoundVolume( + it, + ), + ) + }, + onSoundSelected = { + processAction( + AlarmAddEditContract.Action.SelectAlarmSound( + it, + ), + ) + }, + onComplete = { + processAction(AlarmAddEditContract.Action.HideBottomSheet) + }, ) } } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt index f7e8cb70..8b1fbe62 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt @@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -37,7 +36,6 @@ import com.yapp.ui.component.slider.OrbitSlider import com.yapp.ui.component.switch.OrbitSwitch import feature.home.R -@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun AlarmSoundBottomSheet( vibrationEnabled: Boolean, @@ -51,46 +49,24 @@ internal fun AlarmSoundBottomSheet( onSoundSelected: (Int) -> Unit, onComplete: () -> Unit, ) { - BottomSheetContent( - vibrationEnabled = vibrationEnabled, - soundEnabled = soundEnabled, - soundVolume = soundVolume, - soundIndex = soundIndex, - sounds = sounds, - onVibrationToggle = onVibrationToggle, - onSoundToggle = onSoundToggle, - onVolumeChanged = onVolumeChanged, - onSoundSelected = onSoundSelected, - onComplete = onComplete, - ) -} + var selectedVibrationEnabled by remember { mutableStateOf(vibrationEnabled) } + var selectedSoundEnabled by remember { mutableStateOf(soundEnabled) } + var selectedSoundVolume by remember { mutableIntStateOf(soundVolume) } + var selectedSoundIndex by remember { mutableIntStateOf(soundIndex) } -@Composable -private fun BottomSheetContent( - vibrationEnabled: Boolean, - soundEnabled: Boolean, - soundVolume: Int, - soundIndex: Int, - sounds: List, - onVibrationToggle: () -> Unit, - onSoundToggle: () -> Unit, - onVolumeChanged: (Int) -> Unit, - onSoundSelected: (Int) -> Unit, - onComplete: () -> Unit, -) { Column( modifier = Modifier .fillMaxWidth() - .padding( - horizontal = 24.dp, - vertical = 12.dp, - ), + .padding(horizontal = 24.dp, vertical = 12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { Spacer(modifier = Modifier.height(6.dp)) VibrationSection( - isVibrationEnabled = vibrationEnabled, - onVibrationToggle = onVibrationToggle, + isVibrationEnabled = selectedVibrationEnabled, + onVibrationToggle = { + selectedVibrationEnabled = !selectedVibrationEnabled + onVibrationToggle() + }, ) Spacer( modifier = Modifier @@ -100,13 +76,22 @@ private fun BottomSheetContent( ) SoundSection( modifier = Modifier.weight(1f), - soundEnabled = soundEnabled, - onSoundToggle = onSoundToggle, - soundVolume = soundVolume, - onVolumeChanged = onVolumeChanged, - soundIndex = soundIndex, + soundEnabled = selectedSoundEnabled, + onSoundToggle = { + selectedSoundEnabled = !selectedSoundEnabled + onSoundToggle() + }, + soundVolume = selectedSoundVolume, + onVolumeChanged = { + selectedSoundVolume = it + onVolumeChanged(it) + }, + soundIndex = selectedSoundIndex, sounds = sounds, - onSoundSelected = { onSoundSelected(it) }, + onSoundSelected = { + selectedSoundIndex = it + onSoundSelected(it) + }, ) OrbitButton( @@ -294,7 +279,7 @@ private fun AlarmSoundBottomSheetPreview() { onSoundToggle = { isSoundEnabled = !isSoundEnabled }, onVolumeChanged = { soundVolume = it }, onSoundSelected = { soundIndex = it }, - onComplete = { isSheetOpen = false }, + onComplete = { }, ) } } From 98f801781bc122ba68efdc4824c78b18fdde5f3b Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:44:49 +0900 Subject: [PATCH 10/16] =?UTF-8?q?[REFACTOR/#237]=20AlarmSoundBottomSheet?= =?UTF-8?q?=EC=97=90=EC=84=9C=20soundState=EB=A5=BC=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=ED=86=B5=ED=95=A9=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/alarm/addedit/AlarmAddEditScreen.kt | 6 +--- .../bottomsheet/AlarmSoundBottomSheet.kt | 32 +++++++------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 6c3a08fc..9012f6a6 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -172,11 +172,7 @@ private suspend fun handleSideEffect( AlarmAddEditContract.BottomSheetType.SoundSetting -> { AlarmSoundBottomSheet( - vibrationEnabled = state.soundState.isVibrationEnabled, - soundEnabled = state.soundState.isSoundEnabled, - soundVolume = state.soundState.soundVolume, - soundIndex = state.soundState.soundIndex, - sounds = state.soundState.sounds, + soundState = state.soundState, onVibrationToggle = { processAction(AlarmAddEditContract.Action.ToggleVibrationOption) }, onSoundToggle = { processAction(AlarmAddEditContract.Action.ToggleSoundOption) }, onVolumeChanged = { diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt index 8b1fbe62..9e96e84a 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme import com.yapp.domain.model.AlarmSound +import com.yapp.home.alarm.addedit.AlarmAddEditContract import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.radiobutton.OrbitRadioButton import com.yapp.ui.component.slider.OrbitSlider @@ -38,21 +39,17 @@ import feature.home.R @Composable internal fun AlarmSoundBottomSheet( - vibrationEnabled: Boolean, - soundEnabled: Boolean, - soundVolume: Int, - soundIndex: Int, - sounds: List, + soundState: AlarmAddEditContract.AlarmSoundState, onVibrationToggle: () -> Unit, onSoundToggle: () -> Unit, onVolumeChanged: (Int) -> Unit, onSoundSelected: (Int) -> Unit, onComplete: () -> Unit, ) { - var selectedVibrationEnabled by remember { mutableStateOf(vibrationEnabled) } - var selectedSoundEnabled by remember { mutableStateOf(soundEnabled) } - var selectedSoundVolume by remember { mutableIntStateOf(soundVolume) } - var selectedSoundIndex by remember { mutableIntStateOf(soundIndex) } + var selectedVibrationEnabled by remember { mutableStateOf(soundState.isVibrationEnabled) } + var selectedSoundEnabled by remember { mutableStateOf(soundState.isSoundEnabled) } + var selectedSoundVolume by remember { mutableIntStateOf(soundState.soundVolume) } + var selectedSoundIndex by remember { mutableIntStateOf(soundState.soundIndex) } Column( modifier = Modifier @@ -87,7 +84,7 @@ internal fun AlarmSoundBottomSheet( onVolumeChanged(it) }, soundIndex = selectedSoundIndex, - sounds = sounds, + sounds = soundState.sounds, onSoundSelected = { selectedSoundIndex = it onSoundSelected(it) @@ -262,23 +259,18 @@ private fun SoundSelectionItem( private fun AlarmSoundBottomSheetPreview() { var isVibrationEnabled by remember { mutableStateOf(true) } var isSoundEnabled by remember { mutableStateOf(true) } - var soundVolume by remember { mutableIntStateOf(0) } - var soundIndex by remember { mutableIntStateOf(0) } - val sounds by remember { mutableStateOf((1..20).map { AlarmSound("sound $it", Uri.EMPTY) }) } var isSheetOpen by remember { mutableStateOf(true) } OrbitTheme { if (isSheetOpen) { AlarmSoundBottomSheet( - vibrationEnabled = isVibrationEnabled, - soundEnabled = isSoundEnabled, - soundVolume = soundVolume, - soundIndex = soundIndex, - sounds = sounds, + soundState = AlarmAddEditContract.AlarmSoundState( + sounds = (1..20).map { AlarmSound("sound $it", Uri.EMPTY) }, + ), onVibrationToggle = { isVibrationEnabled = !isVibrationEnabled }, onSoundToggle = { isSoundEnabled = !isSoundEnabled }, - onVolumeChanged = { soundVolume = it }, - onSoundSelected = { soundIndex = it }, + onVolumeChanged = { _ -> }, + onSoundSelected = { _ -> }, onComplete = { }, ) } From 91654462fa9107aa51f86bd9ce353560bc845934 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:46:57 +0900 Subject: [PATCH 11/16] =?UTF-8?q?[REFACTOR/#237]=20AlarmSnoozeBottomSheet?= =?UTF-8?q?=EC=97=90=EC=84=9C=20Snooze=20=EC=83=81=ED=83=9C=EB=A5=BC=20Ala?= =?UTF-8?q?rmSnoozeState=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/alarm/addedit/AlarmAddEditScreen.kt | 4 +--- .../bottomsheet/AlarmSnoozeBottomSheet.kt | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 9012f6a6..12496bf1 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -154,9 +154,7 @@ private suspend fun handleSideEffect( AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { AlarmSnoozeBottomSheet( - snoozeEnabled = state.snoozeState.isSnoozeEnabled, - snoozeInterval = state.snoozeState.snoozeInterval, - snoozeCount = state.snoozeState.snoozeCount, + snoozeState = state.snoozeState, onSnoozeToggle = { processAction(AlarmAddEditContract.Action.ToggleSnoozeOption) }, onIntervalSelected = { interval -> processAction(AlarmAddEditContract.Action.SetSnoozeInterval(interval)) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt index 1a1d467b..e60e1b06 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme +import com.yapp.home.alarm.addedit.AlarmAddEditContract import com.yapp.home.alarm.component.SelectorItems import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.switch.OrbitSwitch @@ -32,9 +33,7 @@ import feature.home.R @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun AlarmSnoozeBottomSheet( - snoozeEnabled: Boolean, - snoozeInterval: Int, - snoozeCount: Int, + snoozeState: AlarmAddEditContract.AlarmSnoozeState, onIntervalSelected: (Int) -> Unit, onCountSelected: (Int) -> Unit, onSnoozeToggle: (Boolean) -> Unit, @@ -54,14 +53,14 @@ internal fun AlarmSnoozeBottomSheet( stringResource(id = R.string.alarm_add_edit_repeat_count_infinite), ) - var selectedSnoozeEnabled by remember { mutableStateOf(snoozeEnabled) } - var selectedSnoozeIntervalIndex by remember { mutableIntStateOf(snoozeIntervalOptions.indexOf(snoozeInterval)) } + var selectedSnoozeEnabled by remember { mutableStateOf(snoozeState.isSnoozeEnabled) } + var selectedSnoozeIntervalIndex by remember { mutableIntStateOf(snoozeIntervalOptions.indexOf(snoozeState.snoozeInterval)) } var selectedSnoozeCountIndex by remember { mutableIntStateOf( - if (snoozeCount == -1) { + if (snoozeState.snoozeCount == -1) { snoozeCountOptions.lastIndex } else { - snoozeCountOptions.indexOf(snoozeCount) + snoozeCountOptions.indexOf(snoozeState.snoozeCount) }, ) } @@ -195,9 +194,11 @@ private fun AlarmSnoozeBottomSheetPreview() { OrbitTheme { AlarmSnoozeBottomSheet( - snoozeEnabled = isSnoozeEnabled, - snoozeInterval = snoozeInterval, - snoozeCount = snoozeCount, + snoozeState = AlarmAddEditContract.AlarmSnoozeState( + isSnoozeEnabled = isSnoozeEnabled, + snoozeInterval = snoozeInterval, + snoozeCount = snoozeCount, + ), onSnoozeToggle = { isSnoozeEnabled = !isSnoozeEnabled Log.d("AlarmSnoozeBottomSheet", "Snooze Enabled: $isSnoozeEnabled") From ec3d5f27a24badb0917032b690d60ff0e1b5296f Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 14:49:35 +0900 Subject: [PATCH 12/16] =?UTF-8?q?[REFACTOR/#237]=20AlarmMissionBottomSheet?= =?UTF-8?q?=EC=9D=98=20=EC=B4=88=EA=B8=B0=20=EB=AF=B8=EC=85=98=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EB=A5=BC=20AlarmMissionState=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yapp/home/alarm/addedit/AlarmAddEditScreen.kt | 3 +-- .../bottomsheet/AlarmMissionBottomSheet.kt | 13 ++++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 12496bf1..3e8139f4 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -128,8 +128,7 @@ private suspend fun handleSideEffect( when (sideEffect.sheetType) { AlarmAddEditContract.BottomSheetType.MissionSetting -> { AlarmMissionBottomSheet( - missionType = state.missionState.missionType, - missionCount = state.missionState.missionCount, + missionState = state.missionState, onDismiss = { processAction(AlarmAddEditContract.Action.HideBottomSheet) }, diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt index 2579f261..d13da171 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.yapp.designsystem.theme.OrbitTheme import com.yapp.domain.model.MissionType +import com.yapp.home.alarm.addedit.AlarmAddEditContract import com.yapp.home.alarm.component.SelectorItems import com.yapp.ui.component.button.OrbitButton import com.yapp.ui.component.lottie.LottieAnimation @@ -58,15 +59,14 @@ private fun MissionType.displayData(): Pair = when (this) { @Composable internal fun AlarmMissionBottomSheet( - missionType: MissionType, - missionCount: Int, + missionState: AlarmAddEditContract.AlarmMissionState, onDismiss: () -> Unit, onSaveMission: (MissionType, Int) -> Unit, onPreviewMission: (MissionType, Int) -> Unit, ) { var stepStack by remember { mutableStateOf(listOf(AlarmMissionSelectBottomSheetType.MISSION_SETTING)) } - var selectedMissionType by remember { mutableStateOf(missionType) } - var selectedMissionCount by remember { mutableIntStateOf(missionCount) } + var selectedMissionType by remember { mutableStateOf(missionState.missionType) } + var selectedMissionCount by remember { mutableIntStateOf(missionState.missionCount) } fun push(step: AlarmMissionSelectBottomSheetType) { stepStack = stepStack + step @@ -630,9 +630,8 @@ private fun MissionSelectTopAppBar( private fun AlarmMissionSelectBottomSheetPreview() { OrbitTheme { AlarmMissionBottomSheet( - missionType = MissionType.SHAKE, - missionCount = 15, - onDismiss = {}, + missionState = AlarmAddEditContract.AlarmMissionState(), + onDismiss = { }, onSaveMission = { _, _ -> }, onPreviewMission = { _, _ -> }, ) From f51ce5701c3aef8f73ed2d2791a668ee571fa2dc Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 15:20:11 +0900 Subject: [PATCH 13/16] =?UTF-8?q?[REFACTOR/#237]=20=EB=B0=94=ED=85=80?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=EC=97=90=EC=84=9C=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=EC=8B=9C=20=EC=83=81=ED=83=9C=EB=A5=BC=20?= =?UTF-8?q?=ED=95=9C=EB=B2=88=EC=97=90=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/addedit/AlarmAddEditContract.kt | 26 ++++-- .../home/alarm/addedit/AlarmAddEditScreen.kt | 53 ++++++----- .../alarm/addedit/AlarmAddEditViewModel.kt | 89 ++++++++++--------- .../bottomsheet/AlarmSnoozeBottomSheet.kt | 33 +++---- .../bottomsheet/AlarmSoundBottomSheet.kt | 48 +++++----- 5 files changed, 130 insertions(+), 119 deletions(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt index 5c53145f..0f128d45 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditContract.kt @@ -81,16 +81,24 @@ sealed class AlarmAddEditContract { data object ToggleWeekendsSelection : Action() data class ToggleSpecificDaySelection(val day: AlarmDay) : Action() data object ToggleHolidaySkipOption : Action() - data object ToggleSnoozeOption : Action() - data class SaveMission(val type: MissionType, val count: Int) : Action() - data class NavigateToMissionPreview(val missionType: MissionType, val missionCount: Int) : Action() - data class SetSnoozeInterval(val interval: Int) : Action() - data class SetSnoozeRepeatCount(val count: Int) : Action() - data object ToggleVibrationOption : Action() - data object ToggleSoundOption : Action() - data class AdjustSoundVolume(val volume: Int) : Action() - data class SelectAlarmSound(val index: Int) : Action() + data class SaveMissionSetting(val type: MissionType, val count: Int) : Action() + data class SaveSnoozeSetting( + val enabled: Boolean, + val interval: Int, + val count: Int, + ) : Action() + data class SaveSoundSetting( + val vibrationEnabled: Boolean, + val soundEnabled: Boolean, + val soundVolume: Int, + val soundIndex: Int, + ) : Action() + data class ToggleVibrationEnabled(val enabled: Boolean) : Action() + data class ToggleSoundEnabled(val enabled: Boolean) : Action() + data class SetSoundVolume(val volume: Int) : Action() + data class SetSoundIndex(val index: Int) : Action() data class ShowBottomSheet(val sheetType: BottomSheetType) : Action() + data class NavigateToMissionPreview(val missionType: MissionType, val missionCount: Int) : Action() data object HideBottomSheet : Action() } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt index 3e8139f4..37f7e160 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditScreen.kt @@ -134,7 +134,7 @@ private suspend fun handleSideEffect( }, onSaveMission = { missionType, missionCount -> processAction( - AlarmAddEditContract.Action.SaveMission( + AlarmAddEditContract.Action.SaveMissionSetting( type = missionType, count = missionCount, ), @@ -154,41 +154,50 @@ private suspend fun handleSideEffect( AlarmAddEditContract.BottomSheetType.SnoozeSetting -> { AlarmSnoozeBottomSheet( snoozeState = state.snoozeState, - onSnoozeToggle = { processAction(AlarmAddEditContract.Action.ToggleSnoozeOption) }, - onIntervalSelected = { interval -> - processAction(AlarmAddEditContract.Action.SetSnoozeInterval(interval)) - }, - onCountSelected = { count -> - processAction(AlarmAddEditContract.Action.SetSnoozeRepeatCount(count)) - }, onDismiss = { processAction(AlarmAddEditContract.Action.HideBottomSheet) }, + onComplete = { enabled, interval, count -> + processAction( + AlarmAddEditContract.Action.SaveSnoozeSetting( + enabled = enabled, + interval = interval, + count = count, + ), + ) + processAction(AlarmAddEditContract.Action.HideBottomSheet) + }, ) } AlarmAddEditContract.BottomSheetType.SoundSetting -> { AlarmSoundBottomSheet( soundState = state.soundState, - onVibrationToggle = { processAction(AlarmAddEditContract.Action.ToggleVibrationOption) }, - onSoundToggle = { processAction(AlarmAddEditContract.Action.ToggleSoundOption) }, - onVolumeChanged = { - processAction( - AlarmAddEditContract.Action.AdjustSoundVolume( - it, - ), - ) + onVibrationToggle = { enabled -> + processAction(AlarmAddEditContract.Action.ToggleVibrationEnabled(enabled)) + }, + onSoundToggle = { enabled -> + processAction(AlarmAddEditContract.Action.ToggleSoundEnabled(enabled)) + }, + onVolumeChanged = { volume -> + processAction(AlarmAddEditContract.Action.SetSoundVolume(volume)) }, - onSoundSelected = { + onSoundSelected = { index -> + processAction(AlarmAddEditContract.Action.SetSoundIndex(index)) + }, + onDismiss = { + processAction(AlarmAddEditContract.Action.HideBottomSheet) + }, + onComplete = { vibrationEnabled, soundEnabled, soundVolume, soundIndex -> processAction( - AlarmAddEditContract.Action.SelectAlarmSound( - it, + AlarmAddEditContract.Action.SaveSoundSetting( + vibrationEnabled = vibrationEnabled, + soundEnabled = soundEnabled, + soundVolume = soundVolume, + soundIndex = soundIndex, ), ) }, - onComplete = { - processAction(AlarmAddEditContract.Action.HideBottomSheet) - }, ) } } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt index c1747be2..b0f8dfb5 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/addedit/AlarmAddEditViewModel.kt @@ -174,15 +174,23 @@ class AlarmAddEditViewModel @Inject constructor( is AlarmAddEditContract.Action.ToggleWeekendsSelection -> toggleWeekendsSelection() is AlarmAddEditContract.Action.ToggleSpecificDaySelection -> toggleSpecificDaySelection(action.day) is AlarmAddEditContract.Action.ToggleHolidaySkipOption -> toggleHolidaySkipOption() - is AlarmAddEditContract.Action.SaveMission -> saveMission(action.type, action.count) + is AlarmAddEditContract.Action.SaveMissionSetting -> saveMissionSetting(action.type, action.count) + is AlarmAddEditContract.Action.SaveSnoozeSetting -> saveSnoozeSetting( + action.enabled, + action.interval, + action.count, + ) + is AlarmAddEditContract.Action.SaveSoundSetting -> saveSoundSetting( + action.vibrationEnabled, + action.soundEnabled, + action.soundVolume, + action.soundIndex, + ) + is AlarmAddEditContract.Action.ToggleVibrationEnabled -> toggleVibrationEnabled(action.enabled) + is AlarmAddEditContract.Action.ToggleSoundEnabled -> toggleSoundEnabled(action.enabled) + is AlarmAddEditContract.Action.SetSoundVolume -> setSoundVolume(action.volume) + is AlarmAddEditContract.Action.SetSoundIndex -> setSoundIndex(action.index) is AlarmAddEditContract.Action.NavigateToMissionPreview -> navigateToMissionPreview(action.missionType, action.missionCount) - is AlarmAddEditContract.Action.ToggleSnoozeOption -> toggleSnoozeOption() - is AlarmAddEditContract.Action.SetSnoozeInterval -> setSnoozeInterval(action.interval) - is AlarmAddEditContract.Action.SetSnoozeRepeatCount -> setSnoozeRepeatCount(action.count) - is AlarmAddEditContract.Action.ToggleVibrationOption -> toggleVibrationOption() - is AlarmAddEditContract.Action.ToggleSoundOption -> toggleSoundOption() - is AlarmAddEditContract.Action.AdjustSoundVolume -> adjustSoundVolume(action.volume) - is AlarmAddEditContract.Action.SelectAlarmSound -> selectAlarmSound(action.index) is AlarmAddEditContract.Action.ShowBottomSheet -> showBottomSheet(action.sheetType) is AlarmAddEditContract.Action.HideBottomSheet -> hideBottomSheet() } @@ -448,7 +456,7 @@ class AlarmAddEditViewModel @Inject constructor( } } - private fun saveMission(type: MissionType, count: Int) = intent { + private fun saveMissionSetting(type: MissionType, count: Int) = intent { val newMissionState = state.missionState.copy( missionType = type, missionCount = count, @@ -458,64 +466,57 @@ class AlarmAddEditViewModel @Inject constructor( } } - private fun toggleSnoozeOption() = intent { + private fun saveSnoozeSetting( + isSnoozeEnabled: Boolean, + snoozeInterval: Int, + snoozeCount: Int, + ) = intent { val newSnoozeState = state.snoozeState.copy( - isSnoozeEnabled = !state.snoozeState.isSnoozeEnabled, + isSnoozeEnabled = isSnoozeEnabled, + snoozeInterval = snoozeInterval, + snoozeCount = snoozeCount, ) - reduce { - state.copy(snoozeState = newSnoozeState) - } - } - private fun setSnoozeInterval(interval: Int) = intent { - val newSnoozeState = state.snoozeState.copy(snoozeInterval = interval) reduce { state.copy(snoozeState = newSnoozeState) } } - private fun setSnoozeRepeatCount(count: Int) = intent { - val newSnoozeState = state.snoozeState.copy(snoozeCount = count) + private fun saveSoundSetting( + vibrationEnabled: Boolean, + soundEnabled: Boolean, + soundVolume: Int, + soundIndex: Int, + ) = intent { + val newSoundState = state.soundState.copy( + isVibrationEnabled = vibrationEnabled, + isSoundEnabled = soundEnabled, + soundVolume = soundVolume, + soundIndex = soundIndex, + ) + reduce { - state.copy(snoozeState = newSnoozeState) + state.copy(soundState = newSoundState) } } - private fun toggleVibrationOption() = intent { - val newSoundState = state.soundState.copy(isVibrationEnabled = !state.soundState.isVibrationEnabled) - - if (newSoundState.isVibrationEnabled) { + private fun toggleVibrationEnabled(enabled: Boolean) = intent { + if (enabled) { hapticFeedbackManager.performHapticFeedback(HapticType.SUCCESS) } - reduce { - state.copy(soundState = newSoundState) - } } - private fun toggleSoundOption() = intent { - val newSoundState = state.soundState.copy(isSoundEnabled = !state.soundState.isSoundEnabled) - if (!newSoundState.isSoundEnabled) { + private fun toggleSoundEnabled(enabled: Boolean) = intent { + if (!enabled) { alarmUseCase.stopAlarmSound() } - reduce { - state.copy(soundState = newSoundState) - } } - private fun adjustSoundVolume(volume: Int) = intent { - val newSoundState = state.soundState.copy(soundVolume = volume) + private fun setSoundVolume(volume: Int) = intent { alarmUseCase.updateAlarmVolume(volume) - reduce { - state.copy(soundState = newSoundState) - } } - private fun selectAlarmSound(index: Int) = intent { - val newSoundState = state.soundState.copy(soundIndex = index) - reduce { - state.copy(soundState = newSoundState) - } - + private fun setSoundIndex(index: Int) = intent { val selectedSound = state.soundState.sounds[index] alarmUseCase.initializeSoundPlayer(selectedSound.uri) alarmUseCase.playAlarmSound(state.soundState.soundVolume) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt index e60e1b06..ef6643c0 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSnoozeBottomSheet.kt @@ -1,6 +1,5 @@ package com.yapp.home.alarm.component.bottomsheet -import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -34,10 +33,8 @@ import feature.home.R @Composable internal fun AlarmSnoozeBottomSheet( snoozeState: AlarmAddEditContract.AlarmSnoozeState, - onIntervalSelected: (Int) -> Unit, - onCountSelected: (Int) -> Unit, - onSnoozeToggle: (Boolean) -> Unit, - onDismiss: () -> Unit, + onDismiss: () -> Unit = {}, + onComplete: (enabled: Boolean, interval: Int, count: Int) -> Unit, ) { val snoozeIntervalOptions = listOf(1, 3, 5, 10, 15) val snoozeCountOptions = listOf(1, 3, 5, 10, -1) @@ -74,7 +71,6 @@ internal fun AlarmSnoozeBottomSheet( Spacer(modifier = Modifier.height(6.dp)) VibrationSection(selectedSnoozeEnabled) { selectedSnoozeEnabled = !selectedSnoozeEnabled - onSnoozeToggle(selectedSnoozeEnabled) } Spacer(modifier = Modifier.height(20.dp)) SelectorSection( @@ -84,7 +80,6 @@ internal fun AlarmSnoozeBottomSheet( enabled = selectedSnoozeEnabled, onItemSelected = { selectedSnoozeIntervalIndex = it - onIntervalSelected(snoozeIntervalOptions[it]) }, ) Spacer(modifier = Modifier.height(32.dp)) @@ -95,7 +90,6 @@ internal fun AlarmSnoozeBottomSheet( enabled = selectedSnoozeEnabled, onItemSelected = { selectedSnoozeCountIndex = it - onCountSelected(snoozeCountOptions[it]) }, ) Spacer(modifier = Modifier.height(20.dp)) @@ -113,7 +107,14 @@ internal fun AlarmSnoozeBottomSheet( contentColor = OrbitTheme.colors.white, pressedContainerColor = OrbitTheme.colors.gray_500, pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - onClick = onDismiss, + onClick = { + onDismiss() + onComplete( + selectedSnoozeEnabled, + snoozeIntervalOptions[selectedSnoozeIntervalIndex], + snoozeCountOptions[selectedSnoozeCountIndex], + ) + }, ) } } @@ -199,19 +200,7 @@ private fun AlarmSnoozeBottomSheetPreview() { snoozeInterval = snoozeInterval, snoozeCount = snoozeCount, ), - onSnoozeToggle = { - isSnoozeEnabled = !isSnoozeEnabled - Log.d("AlarmSnoozeBottomSheet", "Snooze Enabled: $isSnoozeEnabled") - }, - onIntervalSelected = { interval -> - snoozeInterval = interval - Log.d("AlarmSnoozeBottomSheet", "Snooze Interval: $snoozeInterval") - }, - onCountSelected = { count -> - snoozeCount = count - Log.d("AlarmSnoozeBottomSheet", "Snooze Count: $snoozeCount") - }, - onDismiss = { }, + onComplete = { _, _, _ -> }, ) } } diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt index 9e96e84a..7b706435 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmSoundBottomSheet.kt @@ -40,11 +40,12 @@ import feature.home.R @Composable internal fun AlarmSoundBottomSheet( soundState: AlarmAddEditContract.AlarmSoundState, - onVibrationToggle: () -> Unit, - onSoundToggle: () -> Unit, + onVibrationToggle: (Boolean) -> Unit, + onSoundToggle: (Boolean) -> Unit, onVolumeChanged: (Int) -> Unit, onSoundSelected: (Int) -> Unit, - onComplete: () -> Unit, + onDismiss: () -> Unit = {}, + onComplete: (vibrationEnabled: Boolean, soundEnabled: Boolean, soundVolume: Int, soundIndex: Int) -> Unit, ) { var selectedVibrationEnabled by remember { mutableStateOf(soundState.isVibrationEnabled) } var selectedSoundEnabled by remember { mutableStateOf(soundState.isSoundEnabled) } @@ -62,7 +63,7 @@ internal fun AlarmSoundBottomSheet( isVibrationEnabled = selectedVibrationEnabled, onVibrationToggle = { selectedVibrationEnabled = !selectedVibrationEnabled - onVibrationToggle() + onVibrationToggle(selectedVibrationEnabled) }, ) Spacer( @@ -76,7 +77,7 @@ internal fun AlarmSoundBottomSheet( soundEnabled = selectedSoundEnabled, onSoundToggle = { selectedSoundEnabled = !selectedSoundEnabled - onSoundToggle() + onSoundToggle(selectedSoundEnabled) }, soundVolume = selectedSoundVolume, onVolumeChanged = { @@ -98,7 +99,15 @@ internal fun AlarmSoundBottomSheet( contentColor = OrbitTheme.colors.white, pressedContainerColor = OrbitTheme.colors.gray_500, pressedContentColor = OrbitTheme.colors.white.copy(alpha = 0.7f), - onClick = onComplete, + onClick = { + onDismiss() + onComplete( + selectedVibrationEnabled, + selectedSoundEnabled, + selectedSoundVolume, + selectedSoundIndex, + ) + }, ) } } @@ -257,22 +266,17 @@ private fun SoundSelectionItem( @Preview @Composable private fun AlarmSoundBottomSheetPreview() { - var isVibrationEnabled by remember { mutableStateOf(true) } - var isSoundEnabled by remember { mutableStateOf(true) } - var isSheetOpen by remember { mutableStateOf(true) } - OrbitTheme { - if (isSheetOpen) { - AlarmSoundBottomSheet( - soundState = AlarmAddEditContract.AlarmSoundState( - sounds = (1..20).map { AlarmSound("sound $it", Uri.EMPTY) }, - ), - onVibrationToggle = { isVibrationEnabled = !isVibrationEnabled }, - onSoundToggle = { isSoundEnabled = !isSoundEnabled }, - onVolumeChanged = { _ -> }, - onSoundSelected = { _ -> }, - onComplete = { }, - ) - } + AlarmSoundBottomSheet( + soundState = AlarmAddEditContract.AlarmSoundState( + sounds = (1..20).map { AlarmSound("sound $it", Uri.EMPTY) }, + ), + onVibrationToggle = {}, + onSoundToggle = {}, + onVolumeChanged = {}, + onSoundSelected = {}, + onComplete = { _, _, _, _ -> + }, + ) } } From 13c413274eb6001456884b91042c92c0bd62e91e Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 16:37:26 +0900 Subject: [PATCH 14/16] =?UTF-8?q?[FIX/#239]=20=EB=B0=94=ED=85=80=20?= =?UTF-8?q?=EC=8B=9C=ED=8A=B8=EB=82=98=20=EB=8B=A4=EC=9D=B4=EC=96=BC?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EB=85=B8=EC=B6=9C=20=EC=8B=9C=20=EB=92=A4?= =?UTF-8?q?=EB=A1=9C=EA=B0=80=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=EB=88=84?= =?UTF-8?q?=EB=A5=B4=EB=A9=B4=20=EB=8B=AB=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 3 +- .../home/alarm/addedit/AlarmAddEditScreen.kt | 80 +++++++++-------- feature/onboarding/build.gradle.kts | 1 + .../yapp/onboarding/OnboardingGenderScreen.kt | 87 +++++++++---------- 4 files changed, 89 insertions(+), 82 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b4a973a..780b61bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,8 +22,9 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Orbit" + android:enableOnBackInvokedCallback="true" android:usesCleartextTraffic="true" - tools:targetApi="31"> + tools:targetApi="33"> AlarmAddEditContract.State, - eventDispatcher: (AlarmAddEditContract.Action) -> Unit, + state: AlarmAddEditContract.State, + bottomSheetState: OrbitBottomSheetState, + processAction: (AlarmAddEditContract.Action) -> Unit, ) { - val state = stateProvider() - if (state.initialLoading) { AlarmAddEditLoadingScreen() } else { AlarmAddEditContent( state = state, - eventDispatcher = eventDispatcher, + bottomSheetState = bottomSheetState, + processAction = processAction, ) } } @@ -269,10 +271,15 @@ fun AlarmAddEditScreen( @Composable fun AlarmAddEditContent( state: AlarmAddEditContract.State, - eventDispatcher: (AlarmAddEditContract.Action) -> Unit, + bottomSheetState: OrbitBottomSheetState, + processAction: (AlarmAddEditContract.Action) -> Unit, ) { BackHandler { - eventDispatcher(AlarmAddEditContract.Action.CheckUnsavedChangesBeforeExit) + if (bottomSheetState.state.isVisible) { + processAction(AlarmAddEditContract.Action.HideBottomSheet) + } else { + processAction(AlarmAddEditContract.Action.CheckUnsavedChangesBeforeExit) + } } Column( @@ -282,8 +289,8 @@ fun AlarmAddEditContent( AlarmAddEditTopBar( mode = state.mode, title = state.timeState.alarmMessage, - onBack = { eventDispatcher(AlarmAddEditContract.Action.CheckUnsavedChangesBeforeExit) }, - onDelete = { eventDispatcher(AlarmAddEditContract.Action.ShowDeleteDialog) }, + onBack = { processAction(AlarmAddEditContract.Action.CheckUnsavedChangesBeforeExit) }, + onDelete = { processAction(AlarmAddEditContract.Action.ShowDeleteDialog) }, ) Box( modifier = Modifier.weight(1f), @@ -292,25 +299,25 @@ fun AlarmAddEditContent( OrbitPicker( initialTime = state.timeState.initialTime, ) { newTime -> - eventDispatcher(AlarmAddEditContract.Action.SetAlarmTime(newTime)) + processAction(AlarmAddEditContract.Action.SetAlarmTime(newTime)) } } AlarmAddEditSelectDaysSection( modifier = Modifier.padding(horizontal = 20.dp), daysSelectionState = state.daySelectionState, holidayState = state.holidayState, - processAction = eventDispatcher, + processAction = processAction, ) Spacer(modifier = Modifier.height(12.dp)) AlarmAddEditSettingsSection( modifier = Modifier.padding(horizontal = 20.dp), state = state, - processAction = eventDispatcher, + processAction = processAction, ) Spacer(modifier = Modifier.height(24.dp)) OrbitButton( label = stringResource(R.string.alarm_add_edit_save), - onClick = { eventDispatcher(AlarmAddEditContract.Action.SaveAlarm) }, + onClick = { processAction(AlarmAddEditContract.Action.SaveAlarm) }, enabled = true, modifier = Modifier .padding( @@ -328,10 +335,10 @@ fun AlarmAddEditContent( confirmText = stringResource(id = R.string.alarm_delete_dialog_btn_delete), cancelText = stringResource(id = R.string.alarm_delete_dialog_btn_cancel), onConfirm = { - eventDispatcher(AlarmAddEditContract.Action.DeleteAlarm) + processAction(AlarmAddEditContract.Action.DeleteAlarm) }, onCancel = { - eventDispatcher(AlarmAddEditContract.Action.HideDeleteDialog) + processAction(AlarmAddEditContract.Action.HideDeleteDialog) }, ) } @@ -343,10 +350,10 @@ fun AlarmAddEditContent( confirmText = stringResource(id = R.string.alarm_unsaved_changes_dialog_btn_discard), cancelText = stringResource(id = R.string.alarm_unsaved_changes_dialog_btn_cancel), onConfirm = { - eventDispatcher(AlarmAddEditContract.Action.NavigateBack) + processAction(AlarmAddEditContract.Action.NavigateBack) }, onCancel = { - eventDispatcher(AlarmAddEditContract.Action.HideUnsavedChangesDialog) + processAction(AlarmAddEditContract.Action.HideUnsavedChangesDialog) }, ) } @@ -782,24 +789,23 @@ fun AlarmAddEditScreenPreview() { ), ) { AlarmAddEditScreen( - stateProvider = { - AlarmAddEditContract.State( - initialLoading = false, - timeState = AlarmAddEditContract.AlarmTimeState( - currentTime = LocalTime.of(19, 30), - ), - daySelectionState = AlarmAddEditContract.AlarmDaySelectionState( - isWeekdaysChecked = true, - isWeekendsChecked = false, - selectedDays = setOf(AlarmDay.MON, AlarmDay.TUE), - days = AlarmDay.entries.toSet(), - ), - holidayState = AlarmAddEditContract.AlarmHolidayState( - isDisableHolidayChecked = false, - ), - ) - }, - eventDispatcher = { }, + state = AlarmAddEditContract.State( + initialLoading = false, + timeState = AlarmAddEditContract.AlarmTimeState( + currentTime = LocalTime.of(19, 30), + ), + daySelectionState = AlarmAddEditContract.AlarmDaySelectionState( + isWeekdaysChecked = true, + isWeekendsChecked = false, + selectedDays = setOf(AlarmDay.MON, AlarmDay.TUE), + days = AlarmDay.entries.toSet(), + ), + holidayState = AlarmAddEditContract.AlarmHolidayState( + isDisableHolidayChecked = false, + ), + ), + bottomSheetState = rememberOrbitBottomSheetState(), + processAction = { }, ) } } diff --git a/feature/onboarding/build.gradle.kts b/feature/onboarding/build.gradle.kts index 8a44d192..e573da87 100644 --- a/feature/onboarding/build.gradle.kts +++ b/feature/onboarding/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { implementation(libs.orbit.core) implementation(libs.orbit.compose) implementation(libs.orbit.viewmodel) + implementation(libs.compose.material) implementation(libs.coil.compose) implementation(libs.coil.gif) implementation(libs.accompanist.permission) diff --git a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt index 83168e66..06a2ec94 100644 --- a/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt +++ b/feature/onboarding/src/main/java/com/yapp/onboarding/OnboardingGenderScreen.kt @@ -30,6 +30,7 @@ import com.yapp.common.navigation.route.OnboardingBaseRoute import com.yapp.designsystem.theme.OrbitTheme import com.yapp.onboarding.component.UserInfoBottomSheet import com.yapp.ui.component.bottomsheet.OrbitBottomSheetState +import com.yapp.ui.component.bottomsheet.rememberOrbitBottomSheetState import com.yapp.ui.component.dialog.OrbitDialog import com.yapp.ui.toggle.OrbitGenderToggle import com.yapp.ui.utils.heightForScreenPercentage @@ -58,10 +59,6 @@ fun OnboardingGenderRoute( ) } - BackHandler { - viewModel.processAction(OnboardingContract.Action.PreviousStep) - } - viewModel.collectSideEffect { sideEffect -> handleSideEffect( sideEffect = sideEffect, @@ -74,24 +71,10 @@ fun OnboardingGenderRoute( OnboardingGenderScreen( state = state, + bottomSheetState = bottomSheetState, currentStep = 5, totalSteps = 6, - onNextClick = { viewModel.processAction(OnboardingContract.Action.ShowBottomSheet) }, - onBackClick = { viewModel.processAction(OnboardingContract.Action.PreviousStep) }, - onGenderSelect = { gender -> - analyticsHelper.logEvent( - AnalyticsEvent( - type = "onboarding_gender_select", - properties = mapOf( - AnalyticsEvent.OnboardingPropertiesKeys.GENDER to gender, - ), - ), - ) - viewModel.processAction(OnboardingContract.Action.UpdateGender(gender)) - }, - onDialogConfirm = { - viewModel.processAction(OnboardingContract.Action.HideWarningDialog) - }, + processAction = viewModel::processAction, ) } @@ -154,19 +137,32 @@ private suspend fun handleSideEffect( @Composable fun OnboardingGenderScreen( state: OnboardingContract.State, + bottomSheetState: OrbitBottomSheetState, currentStep: Int, totalSteps: Int, - onNextClick: () -> Unit, - onBackClick: () -> Unit, - onGenderSelect: (String) -> Unit, - onDialogConfirm: () -> Unit, + processAction: (OnboardingContract.Action) -> Unit, + logEvent: (AnalyticsEvent) -> Unit = { }, ) { + BackHandler { + if (state.isShowWarningDialog) { + processAction(OnboardingContract.Action.HideWarningDialog) + } else if (bottomSheetState.state.isVisible) { + processAction(OnboardingContract.Action.HideBottomSheet) + } else { + processAction(OnboardingContract.Action.PreviousStep) + } + } + OnboardingScreen( currentStep = currentStep, totalSteps = totalSteps, isButtonEnabled = state.selectedGender != null, - onNextClick = onNextClick, - onBackClick = onBackClick, + onNextClick = { + processAction(OnboardingContract.Action.ShowBottomSheet) + }, + onBackClick = { + processAction(OnboardingContract.Action.PreviousStep) + }, buttonLabel = "다음", ) { Column( @@ -189,19 +185,24 @@ fun OnboardingGenderScreen( .paddingForScreenPercentage(topPercentage = 0.11f), horizontalArrangement = Arrangement.spacedBy(15.dp), ) { - Box(modifier = Modifier.weight(1f)) { - OrbitGenderToggle( - label = "남성", - isSelected = state.selectedGender == "남성", - onToggle = { onGenderSelect("남성") }, - ) - } - Box(modifier = Modifier.weight(1f)) { - OrbitGenderToggle( - label = "여성", - isSelected = state.selectedGender == "여성", - onToggle = { onGenderSelect("여성") }, - ) + listOf("남성", "여성").forEach { gender -> + Box(modifier = Modifier.weight(1f)) { + OrbitGenderToggle( + label = gender, + isSelected = state.selectedGender == gender, + onToggle = { + logEvent( + AnalyticsEvent( + type = "onboarding_gender_select", + properties = mapOf( + AnalyticsEvent.OnboardingPropertiesKeys.GENDER to gender, + ), + ), + ) + processAction(OnboardingContract.Action.UpdateGender(gender)) + }, + ) + } } } } @@ -212,7 +213,7 @@ fun OnboardingGenderScreen( title = stringResource(id = R.string.onboarding_warning_dialog_title), message = stringResource(id = R.string.onboarding_warning_dialog_message), confirmText = stringResource(id = R.string.onboarding_warning_dialog_btn_confirm), - onConfirm = onDialogConfirm, + onConfirm = { processAction(OnboardingContract.Action.HideWarningDialog) }, ) } } @@ -224,11 +225,9 @@ fun OnboardingGenderScreenPreview() { state = OnboardingContract.State( isButtonEnabled = true, ), + bottomSheetState = rememberOrbitBottomSheetState(), currentStep = 0, totalSteps = 0, - onNextClick = {}, - onBackClick = {}, - onGenderSelect = {}, - onDialogConfirm = {}, + processAction = {}, ) } From 99908c485e473d7401d576584d94a8635db5ea6f Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 16:45:50 +0900 Subject: [PATCH 15/16] =?UTF-8?q?[UI/#237]=20AlarmMissionBottomSheet=20?= =?UTF-8?q?=ED=9A=9F=EC=88=98=20=EC=84=A4=EC=A0=95=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=ED=95=98=EB=8B=A8=20=ED=8C=A8=EB=94=A9=20=EC=B6=95=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alarm/component/bottomsheet/AlarmMissionBottomSheet.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt index d13da171..0c84f840 100644 --- a/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt +++ b/feature/home/src/main/java/com/yapp/home/alarm/component/bottomsheet/AlarmMissionBottomSheet.kt @@ -488,9 +488,11 @@ private fun MissionDetailContent( .fillMaxWidth() .padding( horizontal = 20.dp, - vertical = 24.dp, + vertical = 12.dp, ), ) { + Spacer(modifier = Modifier.height(12.dp)) + Box( modifier = Modifier .fillMaxWidth() From e9bafd0eaee187ff191f72dbc1dab88c48219885 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Mon, 28 Jul 2025 16:48:10 +0900 Subject: [PATCH 16/16] =?UTF-8?q?[REFACTOR/#237]=20OrbitBottomSheetState.s?= =?UTF-8?q?etContent=EB=A5=BC=20private=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt index 15bdfc16..b558e1d8 100644 --- a/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt +++ b/core/ui/src/main/java/com/yapp/ui/component/bottomsheet/OrbitBottomSheetState.kt @@ -35,7 +35,7 @@ fun rememberOrbitBottomSheetState(): OrbitBottomSheetState { class OrbitBottomSheetState( val state: ModalBottomSheetState, val contentState: State, - val setContent: (BottomSheetContent?) -> Unit, + private val setContent: (BottomSheetContent?) -> Unit, ) { val content: BottomSheetContent? get() = contentState.value