From 1486a1a0c4b2556df2441fb62ed87e3c6b596ea4 Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 10:34:25 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[FEAT/#243]=20=ED=99=88=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20sheetHalfExpandHeight=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EC=8B=9C=20statusBar=20=EB=B0=8F=20navBar=20=EB=86=92=EC=9D=B4?= =?UTF-8?q?=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 +- app/src/main/java/com/yapp/orbit/MainActivity.kt | 12 +----------- app/src/main/java/com/yapp/orbit/OrbitNavHost.kt | 2 -- .../home/src/main/java/com/yapp/home/HomeScreen.kt | 12 +++++++++--- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 25834d1a..b955d234 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -12,7 +12,7 @@ android { defaultConfig { versionCode = 5 versionName = "1.0.3" - targetSdk = 34 + targetSdk = 35 } buildTypes { diff --git a/app/src/main/java/com/yapp/orbit/MainActivity.kt b/app/src/main/java/com/yapp/orbit/MainActivity.kt index fc4e3461..35358445 100644 --- a/app/src/main/java/com/yapp/orbit/MainActivity.kt +++ b/app/src/main/java/com/yapp/orbit/MainActivity.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.content.pm.ActivityInfo import android.os.Bundle import androidx.activity.ComponentActivity -import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.CompositionLocalProvider @@ -25,16 +24,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - enableEdgeToEdge( - statusBarStyle = SystemBarStyle.light( - android.graphics.Color.TRANSPARENT, - android.graphics.Color.TRANSPARENT, - ), - navigationBarStyle = SystemBarStyle.light( - android.graphics.Color.BLACK, - android.graphics.Color.BLACK, - ), - ) + enableEdgeToEdge() setContent { val navigator = rememberOrbitNavigator() diff --git a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt index 7030f337..962bcf0b 100644 --- a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt +++ b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt @@ -6,7 +6,6 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost @@ -54,7 +53,6 @@ internal fun OrbitNavHost( NavHost( navController = navigator.navController, startDestination = navigator.startDestination, - modifier = Modifier.navigationBarsPadding(), ) { splashScreen( navigator = navigator, diff --git a/feature/home/src/main/java/com/yapp/home/HomeScreen.kt b/feature/home/src/main/java/com/yapp/home/HomeScreen.kt index 19d45307..8c44e05a 100644 --- a/feature/home/src/main/java/com/yapp/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/yapp/home/HomeScreen.kt @@ -15,12 +15,16 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn @@ -278,6 +282,8 @@ private fun HomeContent( eventDispatcher: (HomeContract.Action) -> Unit, ) { val screenHeight = LocalConfiguration.current.screenHeightDp.dp + val statusBarHeight = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + val navBarHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() var sheetHalfExpandHeight by remember { mutableStateOf(0.dp) } val listState = rememberLazyListState() @@ -391,7 +397,7 @@ private fun HomeContent( .fillMaxWidth() .layout { measurable, constraints -> val placeable = measurable.measure(constraints) - sheetHalfExpandHeight = screenHeight - placeable.height.toDp() + sheetHalfExpandHeight = screenHeight - placeable.height.toDp() - statusBarHeight - navBarHeight layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) } @@ -536,7 +542,7 @@ private fun HomeTopBar( } @Composable -fun HillWithGradient() { +private fun HillWithGradient() { val hillTopY = (LocalConfiguration.current.screenHeightDp.dp * 0.28f).toPx() Canvas( @@ -572,7 +578,7 @@ fun HillWithGradient() { } @Composable -fun SkyImage() { +private fun SkyImage() { Image( painter = painterResource(id = core.designsystem.R.drawable.ic_main_sky), contentDescription = "IMG_MAIN_SKY", From fb3ba1d1e0d50f7f37dea4ee02db38e8314341cd Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 11:02:24 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[FEAT/#243]=20NavigationBar=20=EC=98=81?= =?UTF-8?q?=EC=97=AD=EC=97=90=20=EA=B2=80=EC=9D=80=EC=83=89=20=EB=B0=B0?= =?UTF-8?q?=EA=B2=BD=EC=9D=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/yapp/orbit/OrbitNavHost.kt | 87 ++++++++++++------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt index 962bcf0b..69bc23ac 100644 --- a/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt +++ b/app/src/main/java/com/yapp/orbit/OrbitNavHost.kt @@ -6,14 +6,24 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import androidx.navigation.compose.NavHost import com.yapp.common.navigation.OrbitNavigator import com.yapp.common.navigation.rememberOrbitNavigator @@ -40,44 +50,57 @@ internal fun OrbitNavHost( ) { val snackBarHostState = remember { SnackbarHostState() } - OrbitBottomSheetLayout( - sheetState = bottomSheetState, - ) { - Scaffold( - modifier = modifier, - snackbarHost = { - OrbitSnackBarHost(snackBarHostState = snackBarHostState) - }, - containerColor = OrbitTheme.colors.gray_900, - ) { - NavHost( - navController = navigator.navController, - startDestination = navigator.startDestination, + Box { + OrbitBottomSheetLayout(sheetState = bottomSheetState) { + Scaffold( + modifier = modifier, + snackbarHost = { OrbitSnackBarHost(snackBarHostState) }, + containerColor = OrbitTheme.colors.gray_900, ) { - splashScreen( - navigator = navigator, - ) - onboardingNavGraph( - navigator = navigator, - bottomSheetState = bottomSheetState, - ) - homeNavGraph( + OrbitNavigationGraph( navigator = navigator, bottomSheetState = bottomSheetState, snackBarHostState = snackBarHostState, ) - missionScreen(navigator = navigator) - fortuneNavGraph( - navigator = navigator, - snackBarHostState = snackBarHostState, - ) - settingNavGraph(navigator = navigator) - webViewScreen(navigator = navigator) } } + + NavigationBarScrim() } } +@Composable +private fun OrbitNavigationGraph( + navigator: OrbitNavigator, + bottomSheetState: OrbitBottomSheetState, + snackBarHostState: SnackbarHostState, +) { + NavHost( + navController = navigator.navController, + startDestination = navigator.startDestination, + ) { + splashScreen(navigator) + onboardingNavGraph(navigator, bottomSheetState) + homeNavGraph(navigator, bottomSheetState, snackBarHostState) + missionScreen(navigator) + fortuneNavGraph(navigator, snackBarHostState) + settingNavGraph(navigator) + webViewScreen(navigator) + } +} + +@Composable +private fun BoxScope.NavigationBarScrim() { + Box( + modifier = Modifier + .align(Alignment.BottomCenter) + .fillMaxWidth() + .windowInsetsBottomHeight(WindowInsets.navigationBars) + .background(Color.Black) + .zIndex(1f), + ) +} + @Composable private fun OrbitSnackBarHost( snackBarHostState: SnackbarHostState, @@ -85,9 +108,7 @@ private fun OrbitSnackBarHost( AnimatedVisibility( visible = snackBarHostState.currentSnackbarData != null, enter = slideInVertically(initialOffsetY = { it }) + fadeIn(), - exit = slideOutVertically( - targetOffsetY = { it }, - ) + fadeOut(), + exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(), ) { SnackbarHost( hostState = snackBarHostState, @@ -100,9 +121,9 @@ private fun OrbitSnackBarHost( end = 20.dp, bottom = visuals?.bottomPadding ?: 12.dp, ), - label = visuals?.actionLabel ?: "", + label = visuals?.actionLabel.orEmpty(), iconRes = visuals?.iconRes, - message = visuals?.message ?: "", + message = visuals?.message.orEmpty(), onAction = { snackBarHostState.currentSnackbarData?.performAction() }, ) }, From d3a61d0c37733c51358b5d29ec5804250b7d534d Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 13:24:03 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[FIX/#243]=20AlarmActionScreen=EC=9D=84=20?= =?UTF-8?q?=ED=86=B5=ED=95=B4=20=EB=AF=B8=EC=85=98=20=EC=A7=84=EC=9E=85?= =?UTF-8?q?=EC=9D=B4=20=EC=95=88=EB=90=98=EB=8A=94=20=EC=9D=B4=EC=8A=88=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yapp/alarm/AlarmConstants.kt | 2 + .../interaction/AlarmDismissPendingIntent.kt | 8 +- .../AlarmInteractionActivityReceiver.kt | 14 ++- .../com/yapp/alarm/receivers/AlarmReceiver.kt | 108 ++++++++++-------- .../com/yapp/alarm/services/AlarmService.kt | 14 +-- .../interaction/AlarmInteractionActivity.kt | 41 ++----- .../action/AlarmActionViewModel.kt | 6 +- .../snooze/AlarmSnoozeTimerViewModel.kt | 6 +- .../java/com/yapp/mission/MissionViewModel.kt | 56 ++++----- 9 files changed, 132 insertions(+), 123 deletions(-) diff --git a/core/alarm/src/main/java/com/yapp/alarm/AlarmConstants.kt b/core/alarm/src/main/java/com/yapp/alarm/AlarmConstants.kt index e007649e..3c2541bc 100644 --- a/core/alarm/src/main/java/com/yapp/alarm/AlarmConstants.kt +++ b/core/alarm/src/main/java/com/yapp/alarm/AlarmConstants.kt @@ -7,6 +7,8 @@ object AlarmConstants { const val ACTION_ALARM_INTERACTION_ACTIVITY_CLOSE = "com.yapp.orbit.ACTION_ALERT_INTERACTION_CLOSE" const val EXTRA_NOTIFICATION_ID = "com.yapp.orbit.EXTRA_NOTIFICATION_ID" + const val EXTRA_MISSION_TYPE = "com.yapp.orbit.EXTRA_MISSION_TYPE" + const val EXTRA_MISSION_COUNT = "com.yapp.orbit.EXTRA_MISSION_COUNT" const val EXTRA_ALARM = "com.yapp.orbit.EXTRA_ALARM" const val EXTRA_ALARM_DAY = "com.yapp.orbit.EXTRA_ALARM_DAY" diff --git a/core/alarm/src/main/java/com/yapp/alarm/pendingIntent/interaction/AlarmDismissPendingIntent.kt b/core/alarm/src/main/java/com/yapp/alarm/pendingIntent/interaction/AlarmDismissPendingIntent.kt index 075651be..3d702fb1 100644 --- a/core/alarm/src/main/java/com/yapp/alarm/pendingIntent/interaction/AlarmDismissPendingIntent.kt +++ b/core/alarm/src/main/java/com/yapp/alarm/pendingIntent/interaction/AlarmDismissPendingIntent.kt @@ -12,8 +12,10 @@ import com.yapp.alarm.receivers.AlarmReceiver fun createAlarmDismissPendingIntent( applicationContext: Context, pendingIntentId: Long, + missionType: Int, + missionCount: Int, ): PendingIntent { - val alarmDismissIntent = createAlarmDismissIntent(applicationContext, pendingIntentId) + val alarmDismissIntent = createAlarmDismissIntent(applicationContext, pendingIntentId, missionType, missionCount) return PendingIntent.getBroadcast( applicationContext, pendingIntentId.toInt(), @@ -25,10 +27,14 @@ fun createAlarmDismissPendingIntent( fun createAlarmDismissIntent( context: Context, notificationId: Long, + missionType: Int, + missionCount: Int, ): Intent { return Intent(AlarmConstants.ACTION_ALARM_DISMISSED).apply { setClass(context, AlarmReceiver::class.java) putExtra(AlarmConstants.EXTRA_NOTIFICATION_ID, notificationId) + putExtra(AlarmConstants.EXTRA_MISSION_TYPE, missionType) + putExtra(AlarmConstants.EXTRA_MISSION_COUNT, missionCount) } } diff --git a/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt b/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt index 4f7a4ceb..d7f38c3e 100644 --- a/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt +++ b/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmInteractionActivityReceiver.kt @@ -3,6 +3,7 @@ package com.yapp.alarm.receivers import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.util.Log import androidx.activity.ComponentActivity import androidx.core.net.toUri import com.yapp.alarm.AlarmConstants @@ -29,14 +30,25 @@ class AlarmInteractionActivityReceiver(private val activity: ComponentActivity) activity.finish() if (!isSnoozed) { + val notificationId = intent.getLongExtra(AlarmConstants.EXTRA_NOTIFICATION_ID, -1L) + val missionType = intent.getIntExtra(AlarmConstants.EXTRA_MISSION_TYPE, -1) + val missionCount = intent.getIntExtra(AlarmConstants.EXTRA_MISSION_COUNT, -1) + + if (notificationId == -1L || missionType == -1 || missionCount == -1) { + Log.e("AlarmInteraction", "필수 값 누락") + return + } + CoroutineScope(Dispatchers.IO).launch { val fortuneDate = fortuneRepository.fortuneDateFlow.firstOrNull() val todayDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE) if (fortuneDate != todayDate) { context?.let { + val uriString = + "orbitapp://mission?notificationId=$notificationId&missionType=$missionType&missionCount=$missionCount" val missionIntent = - Intent(Intent.ACTION_VIEW, "orbitapp://mission".toUri()).apply { + Intent(Intent.ACTION_VIEW, uriString.toUri()).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) setPackage(context.packageName) } diff --git a/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt b/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt index 878cf68e..edd18466 100644 --- a/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt +++ b/core/alarm/src/main/java/com/yapp/alarm/receivers/AlarmReceiver.kt @@ -46,10 +46,11 @@ class AlarmReceiver : BroadcastReceiver() { val alarmServiceIntent = createAlarmServiceIntent(context, intent) when (intent.action) { AlarmConstants.ACTION_ALARM_TRIGGERED -> { - Log.d("AlarmReceiver", "Alarm Triggered") - val alarm: Alarm? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - alarmServiceIntent.getParcelableExtra(AlarmConstants.EXTRA_ALARM, Alarm::class.java) + alarmServiceIntent.getParcelableExtra( + AlarmConstants.EXTRA_ALARM, + Alarm::class.java, + ) } else { @Suppress("DEPRECATION") alarmServiceIntent.getParcelableExtra(AlarmConstants.EXTRA_ALARM) @@ -68,8 +69,6 @@ class AlarmReceiver : BroadcastReceiver() { } AlarmConstants.ACTION_ALARM_SNOOZED -> { - Log.d("AlarmReceiver", "Alarm Snoozed") - val alarm: Alarm? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { intent.getParcelableExtra(AlarmConstants.EXTRA_ALARM, Alarm::class.java) } else { @@ -86,44 +85,54 @@ class AlarmReceiver : BroadcastReceiver() { ) alarm?.let { handleSnooze(context, it) } - Toast.makeText(context, "알람이 ${alarm?.snoozeInterval}분 후 다시 울려요", Toast.LENGTH_SHORT).show() + Toast.makeText( + context, + "알람이 ${alarm?.snoozeInterval}분 후 다시 울려요", + Toast.LENGTH_SHORT, + ).show() } AlarmConstants.ACTION_ALARM_DISMISSED -> { - Log.d("AlarmReceiver", "Alarm Dismissed") - - val alarmId = intent.getLongExtra(AlarmConstants.EXTRA_NOTIFICATION_ID, -1L) - if (alarmId != -1L) { - CoroutineScope(Dispatchers.IO).launch { - val alarms = alarmUseCase.getAllAlarms().first().sortedBy { it.isAlarmActive } - val isFirstAlarm = alarms.firstOrNull()?.id == alarmId - - analyticsHelper.logEvent( - AnalyticsEvent( - type = "alarm_dismiss", - properties = mapOf( - AnalyticsEvent.AlarmPropertiesKeys.ALARM_ID to "$alarmId", - AnalyticsEvent.AlarmPropertiesKeys.DISMISS_IS_FIRST_ALARM to isFirstAlarm, - ), - ), - ) - val existingId = fortuneRepository.firstDismissedAlarmIdFlow.firstOrNull() - if (existingId == null) { - // 첫 번째 알람 해제 기록 - fortuneRepository.saveFirstDismissedAlarmId(alarmId) - } else if (existingId != alarmId) { - // 두 번째 알람 해제 감지 - 기존 기록 삭제 - fortuneRepository.clearDismissedAlarmId() - } - } + val notificationId = intent.getLongExtra(AlarmConstants.EXTRA_NOTIFICATION_ID, -1L) + val missionType = intent.getIntExtra(AlarmConstants.EXTRA_MISSION_TYPE, -1) + val missionCount = intent.getIntExtra(AlarmConstants.EXTRA_MISSION_COUNT, -1) - androidAlarmScheduler.cancelSnoozedAlarm(alarmId) - } else { - Log.e("AlarmReceiver", "알람 ID 수신 실패") + if (notificationId == -1L) { + Log.e("AlarmReceiver", "notificationId 수신 실패") + return } - androidAlarmScheduler.cancelSnoozedAlarm(alarmId) + + androidAlarmScheduler.cancelSnoozedAlarm(notificationId) context.stopService(alarmServiceIntent) - sendBroadCastToCloseAlarmInteractionActivity(context) + + sendBroadCastToCloseAlarmInteractionActivity( + context = context, + notificationId = notificationId, + missionType = missionType, + missionCount = missionCount, + ) + + CoroutineScope(Dispatchers.IO).launch { + val alarms = alarmUseCase.getAllAlarms().first().sortedBy { it.isAlarmActive } + val isFirstAlarm = alarms.firstOrNull()?.id == notificationId + + analyticsHelper.logEvent( + AnalyticsEvent( + type = "alarm_dismiss", + properties = mapOf( + AnalyticsEvent.AlarmPropertiesKeys.ALARM_ID to "$notificationId", + AnalyticsEvent.AlarmPropertiesKeys.DISMISS_IS_FIRST_ALARM to isFirstAlarm, + ), + ), + ) + + val existingId = fortuneRepository.firstDismissedAlarmIdFlow.firstOrNull() + if (existingId == null) { + fortuneRepository.saveFirstDismissedAlarmId(notificationId) + } else if (existingId != notificationId) { + fortuneRepository.clearDismissedAlarmId() + } + } Toast.makeText(context, "알람이 해제되었어요", Toast.LENGTH_SHORT).show() } @@ -160,21 +169,22 @@ class AlarmReceiver : BroadcastReceiver() { id = alarm.id + AlarmConstants.SNOOZE_ID_OFFSET, ) - Log.d( - "AlarmReceiver", - "Scheduling snooze alarm: alarmId=${updatedAlarm.id}, newTime=${updatedAlarm.hour}:${updatedAlarm.minute}, remaining snoozeCount=$newSnoozeCount", - ) - context.stopService(Intent(context, AlarmService::class.java)) androidAlarmScheduler.scheduleAlarm(updatedAlarm) } - private fun sendBroadCastToCloseAlarmInteractionActivity(context: Context) { - Log.d("AlarmReceiver", "Send Broadcast to close Alarm Interaction Activity") - val alarmAlertActivityCloseIntent = - Intent(AlarmConstants.ACTION_ALARM_INTERACTION_ACTIVITY_CLOSE).apply { - putExtra(AlarmConstants.EXTRA_IS_SNOOZED, false) - } - context.sendBroadcast(alarmAlertActivityCloseIntent) + private fun sendBroadCastToCloseAlarmInteractionActivity( + context: Context, + notificationId: Long, + missionType: Int, + missionCount: Int, + ) { + val intent = Intent(AlarmConstants.ACTION_ALARM_INTERACTION_ACTIVITY_CLOSE).apply { + putExtra(AlarmConstants.EXTRA_IS_SNOOZED, false) + putExtra(AlarmConstants.EXTRA_NOTIFICATION_ID, notificationId) + putExtra(AlarmConstants.EXTRA_MISSION_TYPE, missionType) + putExtra(AlarmConstants.EXTRA_MISSION_COUNT, missionCount) + } + context.sendBroadcast(intent) } } diff --git a/core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt b/core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt index 70cc193d..cbea504e 100644 --- a/core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt +++ b/core/alarm/src/main/java/com/yapp/alarm/services/AlarmService.kt @@ -20,6 +20,7 @@ import androidx.core.net.toUri import com.yapp.alarm.AlarmConstants import com.yapp.alarm.AndroidAlarmScheduler import com.yapp.alarm.pendingIntent.interaction.createAlarmAlertPendingIntent +import com.yapp.alarm.pendingIntent.interaction.createAlarmDismissPendingIntent import com.yapp.alarm.pendingIntent.interaction.createAlarmSnoozePendingIntent import com.yapp.alarm.pendingIntent.interaction.createNavigateToMissionPendingIntent import com.yapp.domain.model.Alarm @@ -134,7 +135,7 @@ class AlarmService : Service() { val alarmAlertPendingIntent = createAlarmAlertPendingIntent(applicationContext, alarm) - /*val alarmDismissPendingIntent = if (shouldNavigateToMission) { + val alarmDismissPendingIntent = if (shouldNavigateToMission) { createNavigateToMissionPendingIntent( applicationContext = applicationContext, notificationId = alarm.id, @@ -145,15 +146,10 @@ class AlarmService : Service() { createAlarmDismissPendingIntent( applicationContext = applicationContext, pendingIntentId = alarm.id, + missionType = alarm.missionType.value, + missionCount = alarm.missionCount, ) - }*/ - - val alarmDismissPendingIntent = createNavigateToMissionPendingIntent( - applicationContext = applicationContext, - notificationId = alarm.id, - missionType = alarm.missionType.value, - missionCount = alarm.missionCount, - ) + } val snoozePendingIntent = if (alarm.isSnoozeEnabled && alarm.snoozeCount != 0) { createAlarmSnoozePendingIntent(applicationContext, alarm) diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt index 5860eb6d..92d52cee 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionActivity.kt @@ -7,23 +7,16 @@ import android.content.IntentFilter import android.content.pm.ActivityInfo import android.os.Build import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity -import androidx.activity.SystemBarStyle import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.material3.Surface import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.Modifier import androidx.core.util.Consumer import androidx.navigation.compose.NavHost import com.yapp.alarm.AlarmConstants import com.yapp.alarm.receivers.AlarmInteractionActivityReceiver import com.yapp.common.navigation.rememberOrbitNavigator import com.yapp.common.navigation.route.AlarmInteractionBaseRoute -import com.yapp.designsystem.theme.OrbitTheme import com.yapp.domain.model.Alarm import dagger.hilt.android.AndroidEntryPoint @@ -48,35 +41,18 @@ class AlarmInteractionActivity : ComponentActivity() { registerAlarmInteractionActivityCloseReceiver() - enableEdgeToEdge( - statusBarStyle = SystemBarStyle.light( - android.graphics.Color.TRANSPARENT, - android.graphics.Color.TRANSPARENT, - ), - navigationBarStyle = SystemBarStyle.light( - android.graphics.Color.BLACK, - android.graphics.Color.BLACK, - ), - ) + enableEdgeToEdge() setContent { val navigator = rememberOrbitNavigator() - Surface( - color = OrbitTheme.colors.gray_900, - modifier = Modifier - .fillMaxSize() - .navigationBarsPadding(), + NavHost( + navController = navigator.navController, + startDestination = AlarmInteractionBaseRoute, ) { - NavHost( - navController = navigator.navController, - startDestination = AlarmInteractionBaseRoute, - modifier = Modifier.navigationBarsPadding(), - ) { - alarmInteractionNavGraph( - navigator = navigator, - alarm = alarm, - ) - } + alarmInteractionNavGraph( + navigator = navigator, + alarm = alarm, + ) } DisposableEffect(this, navigator.navController) { @@ -87,7 +63,6 @@ class AlarmInteractionActivity : ComponentActivity() { @Suppress("DEPRECATION") newIntent.getParcelableExtra(AlarmConstants.EXTRA_ALARM) } - Log.d("AlarmInteractionActivity", "New Intent: $newIntent") newAlarm?.let { alarm -> navigator.navigateToAlarmAction(alarm = alarm) } diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt index 30d95dfe..a15a85c5 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionViewModel.kt @@ -119,10 +119,12 @@ class AlarmActionViewModel @Inject constructor( } private fun sendAlarmDismissEventToAlarmReceiver() { - alarm?.id?.let { id -> + alarm?.let { alarm -> val alarmDismissIntent = createAlarmDismissIntent( context = app, - notificationId = id, + notificationId = alarm.id, + missionType = alarm.missionType.value, + missionCount = alarm.missionCount, ) app.sendBroadcast(alarmDismissIntent) } diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt index 2d362032..1f0e6d1b 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerViewModel.kt @@ -91,10 +91,12 @@ class AlarmSnoozeTimerViewModel @Inject constructor( } private fun sendAlarmDismissEventToAlarmReceiver() { - alarm?.id?.let { id -> + alarm?.let { alarm -> val alarmDismissIntent = createAlarmDismissIntent( context = app, - notificationId = id, + notificationId = alarm.id, + missionType = alarm.missionType.value, + missionCount = alarm.missionCount, ) app.sendBroadcast(alarmDismissIntent) } diff --git a/feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt b/feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt index 33650e31..9d8808e4 100644 --- a/feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt +++ b/feature/mission/src/main/java/com/yapp/mission/MissionViewModel.kt @@ -32,15 +32,13 @@ class MissionViewModel @Inject constructor( private val fortuneRepository: FortuneRepository, private val userInfoRepository: UserInfoRepository, private val app: Application, - savedStateHandle: SavedStateHandle, + private val savedStateHandle: SavedStateHandle, ) : ViewModel(), ContainerHost { override val container: Container = container( initialState = MissionContract.State(), ) { - savedStateHandle.get("notificationId")?.toLong()?.let { - sendAlarmDismissIntent(it) - } + sendAlarmDismissIntent() loadMissionInfo( missionTypeRaw = savedStateHandle.get("missionType"), missionCountRaw = savedStateHandle.get("missionCount"), @@ -59,6 +57,20 @@ class MissionViewModel @Inject constructor( } } + private fun sendAlarmDismissIntent() { + val notificationId = savedStateHandle.get("notificationId")?.toLongOrNull() ?: return + val missionType = savedStateHandle.get("missionType")?.toIntOrNull() ?: -1 + val missionCount = savedStateHandle.get("missionCount")?.toIntOrNull() ?: -1 + + val alarmDismissIntent = createAlarmDismissIntent( + context = app, + notificationId = notificationId, + missionType = missionType, + missionCount = missionCount, + ) + app.sendBroadcast(alarmDismissIntent) + } + private fun loadMissionInfo( missionTypeRaw: String?, missionCountRaw: String?, @@ -122,6 +134,16 @@ class MissionViewModel @Inject constructor( } } + private fun completeMission(type: String) = intent { + performHapticSuccess() + logMissionSuccess(type) + if (state.missionMode == MissionMode.REAL) { + postFortune() + } else { + postSideEffect(MissionContract.SideEffect.NavigateBack) + } + } + private fun postFortune(isRetry: Boolean = false) = intent { val userId = userInfoRepository.userIdFlow.firstOrNull() ?: return@intent @@ -147,20 +169,6 @@ class MissionViewModel @Inject constructor( postFortune(isRetry = true) } - private fun completeMission(type: String) = intent { - performHapticSuccess() - logMissionSuccess(type) - if (state.missionMode == MissionMode.REAL) { - postFortune() - } else { - postSideEffect(MissionContract.SideEffect.NavigateBack) - } - } - - private fun performHapticSuccess() { - hapticFeedbackManager.performHapticFeedback(HapticType.SUCCESS) - } - private fun logMissionSuccess(type: String) { analyticsHelper.logEvent( AnalyticsEvent( @@ -172,15 +180,11 @@ class MissionViewModel @Inject constructor( ) } - private fun navigateToHome() = intent { - postSideEffect(MissionContract.SideEffect.NavigateToHome) + private fun performHapticSuccess() { + hapticFeedbackManager.performHapticFeedback(HapticType.SUCCESS) } - private fun sendAlarmDismissIntent(id: Long) { - val alarmDismissIntent = createAlarmDismissIntent( - context = app, - notificationId = id, - ) - app.sendBroadcast(alarmDismissIntent) + private fun navigateToHome() = intent { + postSideEffect(MissionContract.SideEffect.NavigateToHome) } } From 8412970bd8c8ce6842c8cf487a31b0e51eaa860f Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 13:28:05 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[FIX/#243]=20HomeBaseRoute=EA=B0=80=20Alarm?= =?UTF-8?q?InteractionActivity=EC=97=90=20=EC=97=86=EA=B8=B0=20=EB=95=8C?= =?UTF-8?q?=EB=AC=B8=EC=97=90=20=EC=95=8C=EB=9E=8C=20ID=EA=B0=80=20null?= =?UTF-8?q?=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=ED=99=88=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=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 --- .../yapp/alarm/interaction/AlarmInteractionNavGraph.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionNavGraph.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionNavGraph.kt index d5ee04d9..eb025a86 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionNavGraph.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/AlarmInteractionNavGraph.kt @@ -48,14 +48,6 @@ fun NavGraphBuilder.alarmInteractionNavGraph( } }, ) - } ?: run { - navigator.navigateToHome( - navOptions { - popUpTo(AlarmInteractionBaseRoute) { - inclusive = true - } - }, - ) } } } From 55ec36bf93411d2b01dfdddafb6bf0c51c077a4c Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 13:38:12 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[UI/#243]=20=EB=B0=B0=EA=B2=BD=EC=97=90=20s?= =?UTF-8?q?tatusBarsPadding=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interaction/action/AlarmActionScreen.kt | 151 +++++++++--------- 1 file changed, 73 insertions(+), 78 deletions(-) diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt index c8fb991a..d58bdda1 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/action/AlarmActionScreen.kt @@ -50,8 +50,8 @@ internal fun AlarmActionRoute( } AlarmActionScreen( - stateProvider = { state }, - eventDispatcher = viewModel::processAction, + state = state, + processAction = viewModel::processAction, ) } @@ -68,10 +68,9 @@ private fun handleSideEffect( @Composable internal fun AlarmActionScreen( - stateProvider: () -> AlarmActionContract.State, - eventDispatcher: (AlarmActionContract.Action) -> Unit, + state: AlarmActionContract.State, + processAction: (AlarmActionContract.Action) -> Unit, ) { - val state = stateProvider() val context = LocalContext.current if (state.initialLoading) { @@ -86,9 +85,9 @@ internal fun AlarmActionScreen( snoozeInterval = state.snoozeInterval, snoozeCount = state.snoozeCount, isFirstMission = state.isFirstMission, - onSnoozeClick = { eventDispatcher(AlarmActionContract.Action.Snooze) }, + onSnoozeClick = { processAction(AlarmActionContract.Action.Snooze) }, onDismissClick = { - eventDispatcher(AlarmActionContract.Action.Dismiss) + processAction(AlarmActionContract.Action.Dismiss) (context as? androidx.activity.ComponentActivity)?.finish() }, ) @@ -125,74 +124,72 @@ private fun AlarmActionContent( onSnoozeClick: () -> Unit, onDismissClick: () -> Unit, ) { - Box(modifier = Modifier.statusBarsPadding()) { - Column( - modifier = Modifier - .fillMaxSize() - .background( - color = Color(0xFF496381), - ), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Spacer( - modifier = Modifier.heightForScreenPercentage( - 0.17f, - ), - ) + Column( + modifier = Modifier + .fillMaxSize() + .background( + color = Color(0xFF496381), + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Spacer( + modifier = Modifier.heightForScreenPercentage( + 0.17f, + ), + ) - AlarmTime( - isAm = isAm, - hour = hour, - minute = minute, - todayDate = todayDate, - ) + AlarmTime( + isAm = isAm, + hour = hour, + minute = minute, + todayDate = todayDate, + ) - Spacer(modifier = Modifier.height(102.dp)) + Spacer(modifier = Modifier.height(102.dp)) - Icon( - painter = painterResource(id = core.designsystem.R.drawable.ic_alarm_action_character), - tint = Color(0xFF07203E), - contentDescription = "Alarm Action Character", - ) + Icon( + painter = painterResource(id = core.designsystem.R.drawable.ic_alarm_action_character), + tint = Color(0xFF07203E), + contentDescription = "Alarm Action Character", + ) - Spacer(modifier = Modifier.height(56.dp)) + Spacer(modifier = Modifier.height(56.dp)) - if (snoozeEnabled && snoozeCount != 0) { - AlarmSnoozeButton( - snoozeInterval = snoozeInterval, - snoozeCount = snoozeCount, - onSnoozeClick = onSnoozeClick, - ) - } else { - Spacer(modifier = Modifier.height(54.dp)) - } + if (snoozeEnabled && snoozeCount != 0) { + AlarmSnoozeButton( + snoozeInterval = snoozeInterval, + snoozeCount = snoozeCount, + onSnoozeClick = onSnoozeClick, + ) + } else { + Spacer(modifier = Modifier.height(54.dp)) + } - Spacer(modifier = Modifier.weight(1f)) + Spacer(modifier = Modifier.weight(1f)) - if (isFirstMission != null) { - OrbitButton( - label = if (isFirstMission) { - stringResource(id = R.string.alarm_off_mission_start_btn) - } else { - stringResource(id = R.string.alarm_off_btn) - }, - enabled = true, - modifier = Modifier - .padding( - start = 40.dp, - end = 40.dp, - bottom = 48.dp, - ) - .height(62.dp), - onClick = onDismissClick, - ) - } else { - Spacer(modifier = Modifier.height(62.dp)) - } + if (isFirstMission != null) { + OrbitButton( + label = if (isFirstMission) { + stringResource(id = R.string.alarm_off_mission_start_btn) + } else { + stringResource(id = R.string.alarm_off_btn) + }, + enabled = true, + modifier = Modifier + .padding( + start = 40.dp, + end = 40.dp, + bottom = 48.dp, + ) + .height(62.dp), + onClick = onDismissClick, + ) + } else { + Spacer(modifier = Modifier.height(62.dp)) } - - AdsBanner() } + + AdsBanner(modifier = Modifier.statusBarsPadding()) } @Composable @@ -302,18 +299,16 @@ private fun AlarmSnoozeButton( internal fun AlarmActionScreenPreview() { OrbitTheme { AlarmActionScreen( - stateProvider = { - AlarmActionContract.State( - initialLoading = false, - isAm = true, - hour = 10, - minute = 30, - todayDate = "10월 10일 월요일", - snoozeInterval = 5, - snoozeCount = -1, - ) - }, - eventDispatcher = {}, + state = AlarmActionContract.State( + initialLoading = false, + isAm = true, + hour = 10, + minute = 30, + todayDate = "10월 10일 월요일", + snoozeInterval = 5, + snoozeCount = -1, + ), + processAction = {}, ) } } From 374369fab2af02c423eb7847c5555cc36eb2330b Mon Sep 17 00:00:00 2001 From: dongchyeon Date: Tue, 29 Jul 2025 13:39:06 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[REFACTOR/#243]=20AlarmSnoozeTimerScreen?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=83=81=ED=83=9C=EB=A5=BC=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=A0=84=EB=8B=AC=EB=B0=9B=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interaction/snooze/AlarmSnoozeTimerScreen.kt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerScreen.kt b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerScreen.kt index 0cb9b177..da09090f 100644 --- a/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerScreen.kt +++ b/feature/alarm-interaction/src/main/java/com/yapp/alarm/interaction/snooze/AlarmSnoozeTimerScreen.kt @@ -53,17 +53,16 @@ internal fun AlarmSnoozeTimerRoute( val state by viewModel.container.stateFlow.collectAsStateWithLifecycle() AlarmSnoozeTimerScreen( - stateProvider = { state }, - eventDispatcher = viewModel::processAction, + state = state, + processAction = viewModel::processAction, ) } @Composable internal fun AlarmSnoozeTimerScreen( - stateProvider: () -> AlarmSnoozeTimerContract.State, - eventDispatcher: (AlarmSnoozeTimerContract.Action) -> Unit, + state: AlarmSnoozeTimerContract.State, + processAction: (AlarmSnoozeTimerContract.Action) -> Unit, ) { - val state = stateProvider() val context = LocalContext.current if (state.initialLoading) { @@ -74,7 +73,7 @@ internal fun AlarmSnoozeTimerScreen( totalSeconds = state.totalSeconds, isFirstMission = state.isFirstMission, onDismissClick = { - eventDispatcher(AlarmSnoozeTimerContract.Action.Dismiss) + processAction(AlarmSnoozeTimerContract.Action.Dismiss) (context as? ComponentActivity)?.finish() }, ) @@ -296,8 +295,8 @@ private fun AlarmOffButton( internal fun PreviewAlarmSnoozeTimerScreen() { OrbitTheme { AlarmSnoozeTimerScreen( - stateProvider = { AlarmSnoozeTimerContract.State() }, - eventDispatcher = {}, + state = AlarmSnoozeTimerContract.State(), + processAction = {}, ) } }