From a6d0c2fbd60ca3f3b40aa8d285f9fc7c81c2e566 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 04:21:17 +0900 Subject: [PATCH 01/13] =?UTF-8?q?refactor:=20presentation=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=AA=85=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/teamhy2/feature/home/HomeViewModel.kt | 2 +- .../teamhy2/feature/home/component/RunningTimerComponent.kt | 2 +- .../main/java/com/teamhy2/feature/home/model/HomeUiState.kt | 2 +- .../timer/{prsentation => presentation}/Timer.kt | 3 +-- .../timer/{prsentation => presentation}/TimerViewModel.kt | 4 ++-- .../timer/{prsentation => presentation}/model/TimerUiModel.kt | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) rename timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/{prsentation => presentation}/Timer.kt (98%) rename timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/{prsentation => presentation}/TimerViewModel.kt (95%) rename timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/{prsentation => presentation}/model/TimerUiModel.kt (79%) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt index 47f3bd9c..9c546946 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt @@ -3,7 +3,7 @@ package com.teamhy2.feature.home import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.teamhy2.feature.home.model.HomeUiState -import com.teamhy2.hongikyeolgong2.timer.prsentation.model.TimerUiModel +import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import com.teamhy2.main.domain.model.WeeklyStudyDay import com.teamhy2.main.domain.model.WiseSaying import com.teamhy2.main.domain.repository.StudyDayRepository diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/component/RunningTimerComponent.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/component/RunningTimerComponent.kt index 6216a0e2..c8cf001f 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/component/RunningTimerComponent.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/component/RunningTimerComponent.kt @@ -17,7 +17,7 @@ import com.teamhy2.designsystem.ui.theme.Gray100 import com.teamhy2.designsystem.ui.theme.Gray600 import com.teamhy2.designsystem.ui.theme.HY2Theme import com.teamhy2.hongikyeolgong2.main.presentation.R -import com.teamhy2.hongikyeolgong2.timer.prsentation.HY2Timer +import com.teamhy2.hongikyeolgong2.timer.presentation.HY2Timer @Composable fun RunningTimerComponent( diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/model/HomeUiState.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/model/HomeUiState.kt index 6c81020a..b7df12dd 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/model/HomeUiState.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/model/HomeUiState.kt @@ -1,6 +1,6 @@ package com.teamhy2.feature.home.model -import com.teamhy2.hongikyeolgong2.timer.prsentation.model.TimerUiModel +import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import com.teamhy2.main.domain.model.WeeklyStudyDay import com.teamhy2.main.domain.model.WiseSaying import java.time.LocalDateTime diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/Timer.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/Timer.kt similarity index 98% rename from timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/Timer.kt rename to timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/Timer.kt index c29bca75..5fd5a4c2 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/Timer.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/Timer.kt @@ -1,4 +1,4 @@ -package com.teamhy2.hongikyeolgong2.timer.prsentation +package com.teamhy2.hongikyeolgong2.timer.presentation import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Image @@ -28,7 +28,6 @@ import com.teamhy2.designsystem.ui.theme.Gray300 import com.teamhy2.designsystem.ui.theme.Gray600 import com.teamhy2.designsystem.ui.theme.HY2Theme import com.teamhy2.designsystem.ui.theme.Yellow100 -import com.teamhy2.hongikyeolgong2.timer.presentation.R private const val LEFT_TIME_TEXT_COLOR_CHANGE_SECONDS = 30 * 60L diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/TimerViewModel.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerViewModel.kt similarity index 95% rename from timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/TimerViewModel.kt rename to timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerViewModel.kt index ff443b94..bcfcef12 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/TimerViewModel.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerViewModel.kt @@ -1,10 +1,10 @@ -package com.teamhy2.hongikyeolgong2.timer.prsentation +package com.teamhy2.hongikyeolgong2.timer.presentation import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.teamhy2.hongikyeolgong2.timer.model.Timer import com.teamhy2.hongikyeolgong2.timer.model.TimerRepository -import com.teamhy2.hongikyeolgong2.timer.prsentation.model.TimerUiModel +import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/model/TimerUiModel.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/model/TimerUiModel.kt similarity index 79% rename from timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/model/TimerUiModel.kt rename to timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/model/TimerUiModel.kt index 2fe8211b..ffb590fd 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/prsentation/model/TimerUiModel.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/model/TimerUiModel.kt @@ -1,4 +1,4 @@ -package com.teamhy2.hongikyeolgong2.timer.prsentation.model +package com.teamhy2.hongikyeolgong2.timer.presentation.model data class TimerUiModel( val startTime: String = "", From c185dcbcc6f2be34b3bc31abdbdd503175955dae Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 05:01:16 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20NotificationHandler=20ServiceNoti?= =?UTF-8?q?fication=20=EB=B9=8C=EB=8D=94=20=EB=B6=84=EB=A6=AC=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/NotificationHandler.kt | 42 +++++++++++++------ .../src/main/res/values/strings.xml | 1 + timer-presentation/build.gradle.kts | 1 + 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt b/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt index 1ce51a58..159eda98 100644 --- a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt +++ b/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt @@ -1,5 +1,6 @@ package com.teamhy2.hongikyeolgong2.notification +import android.app.Notification import android.app.NotificationManager import android.content.Context import androidx.annotation.StringRes @@ -24,11 +25,12 @@ class NotificationHandler private val notificationManager = context.getSystemService(NotificationManager::class.java) private val notificationChannel: StateFlow = - settingsRepository.notificationSwitchState.stateIn( - scope = coroutineScope, - started = SharingStarted.WhileSubscribed(5000), - initialValue = false, - ) + settingsRepository.notificationSwitchState + .stateIn( + scope = coroutineScope, + started = SharingStarted.WhileSubscribed(5000), + initialValue = false, + ) init { coroutineScope.launch { @@ -36,15 +38,28 @@ class NotificationHandler } } + fun buildServiceNotification(): Notification { + return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) + .setContentTitle("홍익열공이 열공중") + .setContentText("열람실을 이용중이에요!") + .setSmallIcon(R.drawable.ic_status_bar_logo) + .setOngoing(true) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + } + + fun buildGeneralNotification(contentText: String): Notification { + return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) + .setContentTitle("홍익열공이 알림") + .setContentText(contentText) + .setSmallIcon(R.drawable.ic_status_bar_logo) + .setAutoCancel(true) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .build() + } + fun showSimpleNotification(pushText: PushText) { - val notification = - NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) - .setContentTitle(context.getString(R.string.notification_title)) - .setContentText(context.getString(pushText.id)) - .setSmallIcon(R.drawable.ic_status_bar_logo) - .setPriority(NotificationManager.IMPORTANCE_HIGH) - .setAutoCancel(true) - .build() + val notification = buildGeneralNotification(context.getString(pushText.id)) if (notificationChannel.value) { notificationManager.notify(Random.nextInt(), notification) @@ -61,4 +76,5 @@ enum class PushText( ) { THIRTY_MINUTES(R.string.notification_content_thirty_minutes_remain), TEN_MINUTES(R.string.notification_content_ten_minutes_remain), + ZERO_MINUTES(R.string.notification_content_zero_minutes_remain), } diff --git a/app/notification/src/main/res/values/strings.xml b/app/notification/src/main/res/values/strings.xml index f3465eac..75b78db1 100644 --- a/app/notification/src/main/res/values/strings.xml +++ b/app/notification/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ 홍익열공이 열람실 연장 알림! 열람실 시간 종료 30분 전이에요.\n지금부터 열람실 연장이 가능해요! 열람실 시간 종료 10분 전이에요.\n열람실 연장이 필요하다면 서둘러주세요! + 열람실 이용이 종료되었어요! diff --git a/timer-presentation/build.gradle.kts b/timer-presentation/build.gradle.kts index 25637c1b..8c61365c 100644 --- a/timer-presentation/build.gradle.kts +++ b/timer-presentation/build.gradle.kts @@ -8,4 +8,5 @@ android { dependencies { implementation(projects.timerDomain) + implementation(projects.app.notification) } From b6072032b32fa90f4a231f4061ea8657c3676b12 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 05:02:13 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20TimerForegroundService=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/TimerForegroundService.kt | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt new file mode 100644 index 00000000..7d080c10 --- /dev/null +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt @@ -0,0 +1,135 @@ +package com.teamhy2.hongikyeolgong2.timer.presentation + +import android.app.Service +import android.content.Context +import android.content.Intent +import android.os.IBinder +import com.teamhy2.hongikyeolgong2.notification.NotificationHandler +import com.teamhy2.hongikyeolgong2.notification.PushText +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.time.Duration +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.concurrent.TimeUnit +import javax.inject.Inject + +@AndroidEntryPoint +class TimerForegroundService : Service() { + @Inject + lateinit var notificationHandler: NotificationHandler + + private val serviceScope: CoroutineScope = CoroutineScope(Dispatchers.Main) + private var timerJob: Job? = null + private var endTime: Long = 0L + + private var hasNotified30Min: Boolean = false + private var hasNotified10Min: Boolean = false + private var hasNotified0Min: Boolean = false + + override fun onBind(intent: Intent?): IBinder? = null + + override fun onStartCommand( + intent: Intent?, + flags: Int, + startId: Int, + ): Int { + val startTimeMillis: Long = + intent?.getLongExtra(EXTRA_START_TIME, System.currentTimeMillis()) + ?: System.currentTimeMillis() + val durationMillis: Long = intent?.getLongExtra(EXTRA_TIME, 0L) ?: 0L + + val startTime: LocalDateTime = + LocalDateTime.ofInstant( + java.time.Instant.ofEpochMilli(startTimeMillis), + ZoneId.systemDefault(), + ) + val duration: Duration = Duration.ofMillis(durationMillis) + + startForeground( + TIMER_NOTIFICATION_ID, + notificationHandler.buildServiceNotification(), + ) + startTimer(startTime, duration) + + return START_NOT_STICKY + } + + override fun onDestroy() { + timerJob?.cancel() + super.onDestroy() + } + + private fun startTimer( + startTime: LocalDateTime, + duration: Duration, + ) { + timerJob?.cancel() + + val startTimeInMillis: Long = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + endTime = startTimeInMillis + duration.toMillis() + + hasNotified30Min = false + hasNotified10Min = false + hasNotified0Min = false + + timerJob = + serviceScope.launch { + while (true) { + val remainingTime: Long = endTime - System.currentTimeMillis() + + if (remainingTime <= 0L) { + stopSelf() + break + } + + if (remainingTime <= TimeUnit.MINUTES.toMillis(30L) && !hasNotified30Min) { + notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) + hasNotified30Min = true + } + + if (remainingTime <= TimeUnit.MINUTES.toMillis(10L) && !hasNotified10Min) { + notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) + hasNotified10Min = true + } + + if (remainingTime <= 0L && !hasNotified0Min) { + notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) + hasNotified0Min = true + } + + delay(1000L) + } + } + } + + companion object { + const val TIMER_NOTIFICATION_ID: Int = 1 + const val EXTRA_TIME: String = "extra_time" + const val EXTRA_START_TIME: String = "extra_start_time" + + fun startService( + context: Context, + startTime: LocalDateTime, + duration: Duration, + ) { + val startTimeMillis: Long = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + + val startIntent: Intent = + Intent(context, TimerForegroundService::class.java).apply { + putExtra(EXTRA_START_TIME, startTimeMillis) + putExtra(EXTRA_TIME, duration.toMillis()) + } + context.startForegroundService(startIntent) + } + + fun stopService(context: Context) { + val stopIntent: Intent = Intent(context, TimerForegroundService::class.java) + context.stopService(stopIntent) + } + } +} From 47ed53b4d7bc228f7ea1bc3bf0a70e660351cea0 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 05:02:30 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20TimerForegroundService=20?= =?UTF-8?q?=EB=A7=A4=EB=8B=88=ED=8E=98=EC=8A=A4=ED=8A=B8=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0df93c94..62dbc9c2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,11 +2,14 @@ - - + + + + + + + From 1ca756d64c398572fe6e1d1efd2fee06ff4861a0 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 05:02:56 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20HomeScreen=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teamhy2/feature/home/HomeScreen.kt | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt index 7f51e098..a4b768ac 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt @@ -1,6 +1,7 @@ package com.teamhy2.feature.home import android.app.Activity +import android.content.Context import android.content.Intent import android.net.Uri import androidx.activity.compose.BackHandler @@ -37,10 +38,10 @@ import com.teamhy2.feature.home.component.RunningTimerComponent import com.teamhy2.feature.home.component.WeeklyStudyCalendar import com.teamhy2.feature.home.model.HomeUiState import com.teamhy2.hongikyeolgong2.main.presentation.R -import com.teamhy2.hongikyeolgong2.notification.PushText import com.teamhy2.hongikyeolgong2.timer.model.Timer -import com.teamhy2.hongikyeolgong2.timer.prsentation.TimerViewModel -import com.teamhy2.hongikyeolgong2.timer.prsentation.model.TimerUiModel +import com.teamhy2.hongikyeolgong2.timer.presentation.TimerForegroundService +import com.teamhy2.hongikyeolgong2.timer.presentation.TimerViewModel +import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import com.teamhy2.main.domain.model.WeeklyStudyDay import com.teamhy2.main.domain.model.WiseSaying import kotlinx.coroutines.flow.collectLatest @@ -50,7 +51,6 @@ import java.time.temporal.ChronoUnit @Composable fun HomeRoute( seatingChartUrl: String, - onSendNotification: (PushText) -> Unit, modifier: Modifier = Modifier, homeViewModel: HomeViewModel = hiltViewModel(), ) { @@ -92,7 +92,6 @@ fun HomeRoute( is HomeUiState.Success -> { val uiState = homeUiState as HomeUiState.Success - if (uiState.isTimePickerVisible) { HY2TimePicker( title = stringResource(R.string.main_study_room_use_start_time), @@ -102,7 +101,12 @@ fun HomeRoute( updateTimePickerVisibility(false) updateTimerRunning(true) } - startTimer(selectedTime, homeViewModel, timerViewModel, onSendNotification) + startTimer(selectedTime, homeViewModel, timerViewModel, context) + TimerForegroundService.startService( + context, + selectedTime, + timerViewModel.durationHour.value, + ) }, onCancelled = { homeViewModel.updateTimePickerVisibility(false) @@ -132,7 +136,13 @@ fun HomeRoute( LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES), homeViewModel, timerViewModel, - onSendNotification, + context, + ) + TimerForegroundService.stopService(context) + TimerForegroundService.startService( + context, + LocalDateTime.now(), + timerViewModel.durationHour.value, ) }, onDismiss = { @@ -153,6 +163,7 @@ fun HomeRoute( homeViewModel.updateStudyRoomEndDialogVisibility(false) homeViewModel.updateTimerRunning(false) homeViewModel.saveStudyDay(false) + TimerForegroundService.stopService(context) }, onDismiss = { homeViewModel.updateStudyRoomEndDialogVisibility(false) @@ -206,21 +217,20 @@ private fun startTimer( startTime: LocalDateTime, homeViewModel: HomeViewModel, timerViewModel: TimerViewModel, - onSendNotification: (PushText) -> Unit, + context: Context, ) { timerViewModel.setTimer( startTime = startTime, events = mapOf( Timer.THIRTY_MINUTES_SECONDS to { - onSendNotification(PushText.THIRTY_MINUTES) }, Timer.TEN_MINUTES_SECONDS to { - onSendNotification(PushText.TEN_MINUTES) }, Timer.TIME_OVER_SECONDS to { homeViewModel.updateTimerRunning(false) homeViewModel.saveStudyDay(false) + TimerForegroundService.stopService(context) }, ), ) From c5bd6a0d920bc349a2ca920837af0983fa4505d8 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 05:03:43 +0900 Subject: [PATCH 06/13] =?UTF-8?q?refactor:=20onSendNotification=20?= =?UTF-8?q?=EB=A0=88=EA=B1=B0=EC=8B=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teamhy2/feature/home/navigation/HomeNavigation.kt | 7 +------ .../src/main/java/com/teamhy2/feature/main/HY2NavHost.kt | 3 --- .../main/java/com/teamhy2/feature/main/InitialViewModel.kt | 2 -- .../src/main/java/com/teamhy2/feature/main/MainActivity.kt | 5 ----- 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/navigation/HomeNavigation.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/navigation/HomeNavigation.kt index 64de9b2f..34899c45 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/navigation/HomeNavigation.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/navigation/HomeNavigation.kt @@ -5,7 +5,6 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import com.teamhy2.feature.home.HomeRoute import com.teamhy2.feature.home.navigation.Home.ROUTE -import com.teamhy2.hongikyeolgong2.notification.PushText fun NavController.navigateToHome() { navigate(ROUTE) @@ -20,14 +19,10 @@ fun NavController.popUpToHome() { } } -fun NavGraphBuilder.homeScreen( - seatingChartUrl: String, - onSendNotification: (PushText) -> Unit, -) { +fun NavGraphBuilder.homeScreen(seatingChartUrl: String) { composable(route = ROUTE) { HomeRoute( seatingChartUrl = seatingChartUrl, - onSendNotification = onSendNotification, ) } } diff --git a/main-presentation/src/main/java/com/teamhy2/feature/main/HY2NavHost.kt b/main-presentation/src/main/java/com/teamhy2/feature/main/HY2NavHost.kt index 80a1ae7b..065c5683 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/main/HY2NavHost.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/main/HY2NavHost.kt @@ -11,7 +11,6 @@ import com.teamhy2.feature.home.navigation.popUpToHome import com.teamhy2.feature.main.webviews.inquiry.navigation.inquiryScreen import com.teamhy2.feature.main.webviews.inquiry.navigation.navigateToInquiry import com.teamhy2.feature.setting.presentation.navigation.settingScreen -import com.teamhy2.hongikyeolgong2.notification.PushText import com.teamhy2.onboarding.navigation.Onboarding import com.teamhy2.onboarding.navigation.onboardingScreen import com.teamhy2.onboarding.navigation.popUpToOnboarding @@ -24,7 +23,6 @@ import com.teamhy2.record.navigation.recordScreen fun HY2NavHost( navController: NavHostController, urls: Map, - onSendNotification: (PushText) -> Unit, onLogoutOrWithdrawComplete: () -> Unit, modifier: Modifier = Modifier, startDestination: String = Onboarding.ROUTE, @@ -50,7 +48,6 @@ fun HY2NavHost( homeScreen( seatingChartUrl = urls["seatingChart"] ?: "", - onSendNotification = onSendNotification, ) rankingScreen() diff --git a/main-presentation/src/main/java/com/teamhy2/feature/main/InitialViewModel.kt b/main-presentation/src/main/java/com/teamhy2/feature/main/InitialViewModel.kt index f77596f3..0f827081 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/main/InitialViewModel.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/main/InitialViewModel.kt @@ -8,7 +8,6 @@ import com.benenfeldt.remote.token.TokenRole import com.benenfeldt.remote.token.TokenValidator import com.google.firebase.firestore.FirebaseFirestore import com.teamhy2.feature.home.navigation.Home -import com.teamhy2.hongikyeolgong2.notification.NotificationHandler import com.teamhy2.onboarding.domain.repository.WebViewRepository import com.teamhy2.onboarding.navigation.Onboarding import com.teamhy2.onboarding.navigation.SignUp @@ -33,7 +32,6 @@ class InitialViewModel private val webViewRepository: WebViewRepository, private val jwtManager: JwtManager, private val tokenValidator: TokenValidator, - val notificationHandler: NotificationHandler, ) : ViewModel() { private val _initialUiState: MutableStateFlow = MutableStateFlow(InitialUiState.Loading) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/main/MainActivity.kt b/main-presentation/src/main/java/com/teamhy2/feature/main/MainActivity.kt index 61e59a56..068a0c9b 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/main/MainActivity.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/main/MainActivity.kt @@ -144,11 +144,6 @@ class MainActivity : AppCompatActivity() { navController = navController, urls = (initialUiState as InitialUiState.Success).urls, startDestination = (initialUiState as InitialUiState.Success).startDestination, - onSendNotification = { pushText -> - initialViewModel.notificationHandler.showSimpleNotification( - pushText, - ) - }, onLogoutOrWithdrawComplete = { restartMainActivity() }, From 27a2557cfd4e325c25a5013e773ce607d324f12c Mon Sep 17 00:00:00 2001 From: librarywon Date: Sat, 16 Nov 2024 15:12:22 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20=EC=A0=95=EA=B7=9C=EC=8B=9D?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=88=AB=EC=9E=90=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=EC=9D=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/teamhy2/onboarding/domain/model/NicknameValidation.kt | 2 +- onboarding-presentation/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/onboarding-domain/src/main/java/com/teamhy2/onboarding/domain/model/NicknameValidation.kt b/onboarding-domain/src/main/java/com/teamhy2/onboarding/domain/model/NicknameValidation.kt index decdef8e..061864c5 100644 --- a/onboarding-domain/src/main/java/com/teamhy2/onboarding/domain/model/NicknameValidation.kt +++ b/onboarding-domain/src/main/java/com/teamhy2/onboarding/domain/model/NicknameValidation.kt @@ -2,7 +2,7 @@ package com.teamhy2.onboarding.domain.model object NicknameValidation { fun validate(nickname: String): Boolean { - val regex = "^[가-힣a-zA-Z0-9]{2,8}$".toRegex() + val regex = "^[가-힣a-zA-Z]{2,8}$".toRegex() return regex.matches(nickname) } } diff --git a/onboarding-presentation/src/main/res/values/strings.xml b/onboarding-presentation/src/main/res/values/strings.xml index 37cde0cc..29c299a5 100644 --- a/onboarding-presentation/src/main/res/values/strings.xml +++ b/onboarding-presentation/src/main/res/values/strings.xml @@ -6,7 +6,7 @@ 회원가입 닉네임을 입력해주세요 *특수문자와 띄어쓰기를 사용할 수 없어요. - *한글, 영어, 숫자를 포함하여 2~8자를 입력해 주세요. + *한글, 영어를 포함하여 2~8자를 입력해 주세요. *닉네임을 사용할 수 있어요. *중복된 닉네임입니다. 중복확인 From 117b19e9dd6ee5e7f234db273c1bd7d44d3d6016 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sun, 17 Nov 2024 16:01:27 +0900 Subject: [PATCH 08/13] =?UTF-8?q?refactor:=20=ED=95=AD=EC=83=81=20applicat?= =?UTF-8?q?ionContext=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timer/presentation/TimerForegroundService.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt index 7d080c10..fec87e65 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt @@ -117,19 +117,21 @@ class TimerForegroundService : Service() { startTime: LocalDateTime, duration: Duration, ) { + val appContext: Context = context.applicationContext val startTimeMillis: Long = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() val startIntent: Intent = - Intent(context, TimerForegroundService::class.java).apply { + Intent(appContext, TimerForegroundService::class.java).apply { putExtra(EXTRA_START_TIME, startTimeMillis) putExtra(EXTRA_TIME, duration.toMillis()) } - context.startForegroundService(startIntent) + appContext.startForegroundService(startIntent) } fun stopService(context: Context) { - val stopIntent: Intent = Intent(context, TimerForegroundService::class.java) - context.stopService(stopIntent) + val appContext: Context = context.applicationContext + val stopIntent: Intent = Intent(appContext, TimerForegroundService::class.java) + appContext.stopService(stopIntent) } } } From 0cf84087782cee1af717caf642e42253858e2cec Mon Sep 17 00:00:00 2001 From: librarywon Date: Sun, 17 Nov 2024 16:02:30 +0900 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=EC=97=90=20=ED=98=84=EC=9E=AC=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=B4=88=EB=A5=BC=20=EB=8D=94=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/teamhy2/feature/home/HomeScreen.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt index a4b768ac..e425d55e 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt @@ -96,15 +96,18 @@ fun HomeRoute( HY2TimePicker( title = stringResource(R.string.main_study_room_use_start_time), onSelected = { selectedTime -> + val updatedSelectedTime = + selectedTime.plusSeconds(LocalDateTime.now().second.toLong()) + homeViewModel.run { - updateSelectedTime(selectedTime) + updateSelectedTime(updatedSelectedTime) updateTimePickerVisibility(false) updateTimerRunning(true) } - startTimer(selectedTime, homeViewModel, timerViewModel, context) + startTimer(updatedSelectedTime, homeViewModel, timerViewModel, context) TimerForegroundService.startService( context, - selectedTime, + updatedSelectedTime, timerViewModel.durationHour.value, ) }, From 713f382484f1e925df01a5efa25a2b4d9a679d17 Mon Sep 17 00:00:00 2001 From: librarywon Date: Sun, 17 Nov 2024 16:06:26 +0900 Subject: [PATCH 10/13] =?UTF-8?q?refactor:=20serviceScope=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/TimerForegroundService.kt | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt index fec87e65..6e222012 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt @@ -83,23 +83,21 @@ class TimerForegroundService : Service() { val remainingTime: Long = endTime - System.currentTimeMillis() if (remainingTime <= 0L) { + notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) stopSelf() break } - if (remainingTime <= TimeUnit.MINUTES.toMillis(30L) && !hasNotified30Min) { - notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) - hasNotified30Min = true - } + when { + remainingTime <= TimeUnit.MINUTES.toMillis(10L) -> { + notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) + continue + } - if (remainingTime <= TimeUnit.MINUTES.toMillis(10L) && !hasNotified10Min) { - notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) - hasNotified10Min = true - } - - if (remainingTime <= 0L && !hasNotified0Min) { - notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) - hasNotified0Min = true + remainingTime <= TimeUnit.MINUTES.toMillis(30L) -> { + notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) + continue + } } delay(1000L) From f8f5f9de05114672f5315b7dff0e0c5ca98930ee Mon Sep 17 00:00:00 2001 From: librarywon Date: Sun, 17 Nov 2024 16:55:09 +0900 Subject: [PATCH 11/13] =?UTF-8?q?refactor:=20timer=20event=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/teamhy2/hongikyeolgong2/timer/model/Timer.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/Timer.kt b/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/Timer.kt index 4dff3e1a..46288d71 100644 --- a/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/Timer.kt +++ b/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/Timer.kt @@ -72,12 +72,10 @@ class Timer( companion object { private const val START_END_TIME_FORMAT: String = "hh:mm" private const val LEFT_TIME_FORMAT: String = "%02d:%02d:%02d" - const val THIRTY_MINUTES_SECONDS: Long = 30 * 60L - const val TEN_MINUTES_SECONDS: Long = 10 * 60L - const val TIME_OVER_SECONDS: Long = 0L + const val TIME_OVER: Long = 0L private const val DELAY_MILLIS: Long = 1000L private val EVENT_TIMES: List = - listOf(THIRTY_MINUTES_SECONDS, TEN_MINUTES_SECONDS, TIME_OVER_SECONDS) + listOf(TIME_OVER) } } From 4ec0ac8f9e2769d0df5d1574509ac56743b98b3a Mon Sep 17 00:00:00 2001 From: librarywon Date: Sun, 17 Nov 2024 16:55:51 +0900 Subject: [PATCH 12/13] =?UTF-8?q?refactor:=20=EC=95=8C=EB=9E=8C=EC=9D=B4?= =?UTF-8?q?=20=ED=95=9C=20=EB=B2=88=EB=A7=8C=20=EC=98=A4=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/teamhy2/feature/home/HomeScreen.kt | 12 ++---------- .../timer/presentation/TimerForegroundService.kt | 16 ++++++++++------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt index e425d55e..55b24902 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt @@ -1,7 +1,6 @@ package com.teamhy2.feature.home import android.app.Activity -import android.content.Context import android.content.Intent import android.net.Uri import androidx.activity.compose.BackHandler @@ -104,7 +103,7 @@ fun HomeRoute( updateTimePickerVisibility(false) updateTimerRunning(true) } - startTimer(updatedSelectedTime, homeViewModel, timerViewModel, context) + startTimer(updatedSelectedTime, homeViewModel, timerViewModel) TimerForegroundService.startService( context, updatedSelectedTime, @@ -139,7 +138,6 @@ fun HomeRoute( LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES), homeViewModel, timerViewModel, - context, ) TimerForegroundService.stopService(context) TimerForegroundService.startService( @@ -220,20 +218,14 @@ private fun startTimer( startTime: LocalDateTime, homeViewModel: HomeViewModel, timerViewModel: TimerViewModel, - context: Context, ) { timerViewModel.setTimer( startTime = startTime, events = mapOf( - Timer.THIRTY_MINUTES_SECONDS to { - }, - Timer.TEN_MINUTES_SECONDS to { - }, - Timer.TIME_OVER_SECONDS to { + Timer.TIME_OVER to { homeViewModel.updateTimerRunning(false) homeViewModel.saveStudyDay(false) - TimerForegroundService.stopService(context) }, ), ) diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt index 6e222012..0e65d3be 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt @@ -70,32 +70,35 @@ class TimerForegroundService : Service() { ) { timerJob?.cancel() - val startTimeInMillis: Long = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + val startTimeInMillis: Long = + startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() endTime = startTimeInMillis + duration.toMillis() hasNotified30Min = false hasNotified10Min = false - hasNotified0Min = false timerJob = serviceScope.launch { while (true) { val remainingTime: Long = endTime - System.currentTimeMillis() - if (remainingTime <= 0L) { + if (remainingTime <= 0 && hasNotified0Min.not()) { notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) + hasNotified0Min = true stopSelf() break } when { - remainingTime <= TimeUnit.MINUTES.toMillis(10L) -> { + remainingTime <= TimeUnit.MINUTES.toMillis(10L) && hasNotified10Min.not() -> { notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) + hasNotified10Min = true continue } - remainingTime <= TimeUnit.MINUTES.toMillis(30L) -> { + remainingTime <= TimeUnit.MINUTES.toMillis(30L) && hasNotified30Min.not() -> { notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) + hasNotified30Min = true continue } } @@ -116,7 +119,8 @@ class TimerForegroundService : Service() { duration: Duration, ) { val appContext: Context = context.applicationContext - val startTimeMillis: Long = startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + val startTimeMillis: Long = + startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() val startIntent: Intent = Intent(appContext, TimerForegroundService::class.java).apply { From 6032c996cd72dfe8afcaaf34913b1c9f72a70ef7 Mon Sep 17 00:00:00 2001 From: Bandal Date: Mon, 18 Nov 2024 22:37:35 +0900 Subject: [PATCH 13/13] =?UTF-8?q?refactor:=20Notification,=20Service=20DIP?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 +- .../notification/NotificationModule.kt | 36 ---- {app => core}/notification/.gitignore | 0 {app => core}/notification/build.gradle.kts | 0 {app => core}/notification/consumer-rules.pro | 0 {app => core}/notification/proguard-rules.pro | 0 .../notification/src/main/AndroidManifest.xml | 0 .../notification/NotificationHandler.kt | 11 ++ .../notification/NotificationModule.kt | 19 ++ .../hongikyeolgong2/notification/PushText.kt | 11 ++ .../res/drawable-hdpi/ic_status_bar_logo.png | Bin .../res/drawable-mdpi/ic_status_bar_logo.png | Bin .../res/drawable-xhdpi/ic_status_bar_logo.png | Bin .../drawable-xxhdpi/ic_status_bar_logo.png | Bin .../drawable-xxxhdpi/ic_status_bar_logo.png | Bin .../src/main/res/values/strings.xml | 0 main-presentation/build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 1 + .../com/teamhy2/feature/home/HomeScreen.kt | 19 +- .../com/teamhy2/feature/home/HomeViewModel.kt | 14 ++ .../feature/home/MainNotificationHandler.kt | 38 ++-- .../home/MainNotificationHandlerModule.kt | 16 ++ onboarding-presentation/build.gradle.kts | 2 - settings.gradle.kts | 2 +- .../timer/model/TimerService.kt | 13 ++ timer-presentation/build.gradle.kts | 2 +- .../presentation/TimerForegroundService.kt | 182 +++++++++--------- .../timer/presentation/TimerServiceModule.kt | 16 ++ 28 files changed, 229 insertions(+), 158 deletions(-) delete mode 100644 app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt rename {app => core}/notification/.gitignore (100%) rename {app => core}/notification/build.gradle.kts (100%) rename {app => core}/notification/consumer-rules.pro (100%) rename {app => core}/notification/proguard-rules.pro (100%) rename {app => core}/notification/src/main/AndroidManifest.xml (100%) create mode 100644 core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt create mode 100644 core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt create mode 100644 core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/PushText.kt rename {app => core}/notification/src/main/res/drawable-hdpi/ic_status_bar_logo.png (100%) rename {app => core}/notification/src/main/res/drawable-mdpi/ic_status_bar_logo.png (100%) rename {app => core}/notification/src/main/res/drawable-xhdpi/ic_status_bar_logo.png (100%) rename {app => core}/notification/src/main/res/drawable-xxhdpi/ic_status_bar_logo.png (100%) rename {app => core}/notification/src/main/res/drawable-xxxhdpi/ic_status_bar_logo.png (100%) rename {app => core}/notification/src/main/res/values/strings.xml (100%) rename app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt => main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandler.kt (66%) create mode 100644 main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandlerModule.kt create mode 100644 timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/TimerService.kt create mode 100644 timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerServiceModule.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bd74e02a..f9e4a639 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,7 @@ android { } dependencies { - implementation(projects.app.notification) - + implementation(projects.core.notification) implementation(projects.core.designsystem) implementation(projects.core.remote) implementation(projects.core.auth) diff --git a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt b/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt deleted file mode 100644 index afc09ece..00000000 --- a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.teamhy2.hongikyeolgong2.notification - -import android.content.Context -import com.teamhy2.feature.setting.domain.repository.SettingsRepository -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object NotificationModule { - @Provides - @Singleton - fun providesCoroutineScope(): CoroutineScope { - return CoroutineScope(SupervisorJob()) - } - - @Provides - @Singleton - fun providesNotificationHandler( - @ApplicationContext context: Context, - coroutineScope: CoroutineScope, - settingsRepository: SettingsRepository, - ): NotificationHandler { - return NotificationHandler( - context = context, - coroutineScope = coroutineScope, - settingsRepository = settingsRepository, - ) - } -} diff --git a/app/notification/.gitignore b/core/notification/.gitignore similarity index 100% rename from app/notification/.gitignore rename to core/notification/.gitignore diff --git a/app/notification/build.gradle.kts b/core/notification/build.gradle.kts similarity index 100% rename from app/notification/build.gradle.kts rename to core/notification/build.gradle.kts diff --git a/app/notification/consumer-rules.pro b/core/notification/consumer-rules.pro similarity index 100% rename from app/notification/consumer-rules.pro rename to core/notification/consumer-rules.pro diff --git a/app/notification/proguard-rules.pro b/core/notification/proguard-rules.pro similarity index 100% rename from app/notification/proguard-rules.pro rename to core/notification/proguard-rules.pro diff --git a/app/notification/src/main/AndroidManifest.xml b/core/notification/src/main/AndroidManifest.xml similarity index 100% rename from app/notification/src/main/AndroidManifest.xml rename to core/notification/src/main/AndroidManifest.xml diff --git a/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt new file mode 100644 index 00000000..dbf4aa39 --- /dev/null +++ b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt @@ -0,0 +1,11 @@ +package com.teamhy2.hongikyeolgong2.notification + +import android.app.Notification + +interface NotificationHandler { + fun buildServiceNotification(): Notification + + fun buildGeneralNotification(contentText: String): Notification + + fun showSimpleNotification(pushText: PushText) +} diff --git a/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt new file mode 100644 index 00000000..9d1b66e7 --- /dev/null +++ b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationModule.kt @@ -0,0 +1,19 @@ +package com.teamhy2.hongikyeolgong2.notification + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NotificationModule { + @Provides + @Singleton + fun providesCoroutineScope(): CoroutineScope { + return CoroutineScope(SupervisorJob()) + } +} diff --git a/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/PushText.kt b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/PushText.kt new file mode 100644 index 00000000..39a2e27b --- /dev/null +++ b/core/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/PushText.kt @@ -0,0 +1,11 @@ +package com.teamhy2.hongikyeolgong2.notification + +import androidx.annotation.StringRes + +enum class PushText( + @StringRes val id: Int, +) { + THIRTY_MINUTES(R.string.notification_content_thirty_minutes_remain), + TEN_MINUTES(R.string.notification_content_ten_minutes_remain), + ZERO_MINUTES(R.string.notification_content_zero_minutes_remain), +} diff --git a/app/notification/src/main/res/drawable-hdpi/ic_status_bar_logo.png b/core/notification/src/main/res/drawable-hdpi/ic_status_bar_logo.png similarity index 100% rename from app/notification/src/main/res/drawable-hdpi/ic_status_bar_logo.png rename to core/notification/src/main/res/drawable-hdpi/ic_status_bar_logo.png diff --git a/app/notification/src/main/res/drawable-mdpi/ic_status_bar_logo.png b/core/notification/src/main/res/drawable-mdpi/ic_status_bar_logo.png similarity index 100% rename from app/notification/src/main/res/drawable-mdpi/ic_status_bar_logo.png rename to core/notification/src/main/res/drawable-mdpi/ic_status_bar_logo.png diff --git a/app/notification/src/main/res/drawable-xhdpi/ic_status_bar_logo.png b/core/notification/src/main/res/drawable-xhdpi/ic_status_bar_logo.png similarity index 100% rename from app/notification/src/main/res/drawable-xhdpi/ic_status_bar_logo.png rename to core/notification/src/main/res/drawable-xhdpi/ic_status_bar_logo.png diff --git a/app/notification/src/main/res/drawable-xxhdpi/ic_status_bar_logo.png b/core/notification/src/main/res/drawable-xxhdpi/ic_status_bar_logo.png similarity index 100% rename from app/notification/src/main/res/drawable-xxhdpi/ic_status_bar_logo.png rename to core/notification/src/main/res/drawable-xxhdpi/ic_status_bar_logo.png diff --git a/app/notification/src/main/res/drawable-xxxhdpi/ic_status_bar_logo.png b/core/notification/src/main/res/drawable-xxxhdpi/ic_status_bar_logo.png similarity index 100% rename from app/notification/src/main/res/drawable-xxxhdpi/ic_status_bar_logo.png rename to core/notification/src/main/res/drawable-xxxhdpi/ic_status_bar_logo.png diff --git a/app/notification/src/main/res/values/strings.xml b/core/notification/src/main/res/values/strings.xml similarity index 100% rename from app/notification/src/main/res/values/strings.xml rename to core/notification/src/main/res/values/strings.xml diff --git a/main-presentation/build.gradle.kts b/main-presentation/build.gradle.kts index c328efed..a122eb31 100644 --- a/main-presentation/build.gradle.kts +++ b/main-presentation/build.gradle.kts @@ -7,10 +7,10 @@ android { } dependencies { - implementation(projects.app.notification) implementation(projects.mainDomain) + implementation(projects.core.notification) implementation(projects.core.remote) implementation(projects.calendarPresentation) diff --git a/main-presentation/src/main/AndroidManifest.xml b/main-presentation/src/main/AndroidManifest.xml index c0593a9e..85e247ac 100644 --- a/main-presentation/src/main/AndroidManifest.xml +++ b/main-presentation/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt index 55b24902..23c0651e 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeScreen.kt @@ -38,7 +38,6 @@ import com.teamhy2.feature.home.component.WeeklyStudyCalendar import com.teamhy2.feature.home.model.HomeUiState import com.teamhy2.hongikyeolgong2.main.presentation.R import com.teamhy2.hongikyeolgong2.timer.model.Timer -import com.teamhy2.hongikyeolgong2.timer.presentation.TimerForegroundService import com.teamhy2.hongikyeolgong2.timer.presentation.TimerViewModel import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import com.teamhy2.main.domain.model.WeeklyStudyDay @@ -104,10 +103,9 @@ fun HomeRoute( updateTimerRunning(true) } startTimer(updatedSelectedTime, homeViewModel, timerViewModel) - TimerForegroundService.startService( - context, - updatedSelectedTime, - timerViewModel.durationHour.value, + homeViewModel.startTimerService( + startTime = updatedSelectedTime, + duration = timerViewModel.durationHour.value, ) }, onCancelled = { @@ -139,11 +137,10 @@ fun HomeRoute( homeViewModel, timerViewModel, ) - TimerForegroundService.stopService(context) - TimerForegroundService.startService( - context, - LocalDateTime.now(), - timerViewModel.durationHour.value, + homeViewModel.stopTimerService() + homeViewModel.startTimerService( + startTime = LocalDateTime.now(), + duration = timerViewModel.durationHour.value, ) }, onDismiss = { @@ -164,7 +161,7 @@ fun HomeRoute( homeViewModel.updateStudyRoomEndDialogVisibility(false) homeViewModel.updateTimerRunning(false) homeViewModel.saveStudyDay(false) - TimerForegroundService.stopService(context) + homeViewModel.stopTimerService() }, onDismiss = { homeViewModel.updateStudyRoomEndDialogVisibility(false) diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt index 9c546946..caf584d6 100644 --- a/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/HomeViewModel.kt @@ -3,6 +3,7 @@ package com.teamhy2.feature.home import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.teamhy2.feature.home.model.HomeUiState +import com.teamhy2.hongikyeolgong2.timer.model.TimerService import com.teamhy2.hongikyeolgong2.timer.presentation.model.TimerUiModel import com.teamhy2.main.domain.model.WeeklyStudyDay import com.teamhy2.main.domain.model.WiseSaying @@ -19,6 +20,7 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import java.time.Duration import java.time.LocalDateTime import java.time.LocalTime import javax.inject.Inject @@ -29,6 +31,7 @@ class HomeViewModel constructor( private val wiseSayingRepository: WiseSayingRepository, private val studyDayRepository: StudyDayRepository, + private val timerService: TimerService, ) : ViewModel() { private val _homeUiState = MutableStateFlow(HomeUiState.Loading) val homeUiState: StateFlow = _homeUiState.asStateFlow() @@ -63,6 +66,17 @@ class HomeViewModel } } + fun startTimerService( + startTime: LocalDateTime, + duration: Duration, + ) { + timerService.startService(startTime, duration) + } + + fun stopTimerService() { + timerService.stopService() + } + fun saveStudyDay(isExtend: Boolean) { val currentState = _homeUiState.value if (currentState is HomeUiState.Success) { diff --git a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandler.kt similarity index 66% rename from app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt rename to main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandler.kt index 159eda98..97f6b03e 100644 --- a/app/notification/src/main/java/com/teamhy2/hongikyeolgong2/notification/NotificationHandler.kt +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandler.kt @@ -1,11 +1,17 @@ -package com.teamhy2.hongikyeolgong2.notification +package com.teamhy2.feature.home import android.app.Notification import android.app.NotificationManager +import android.app.PendingIntent import android.content.Context -import androidx.annotation.StringRes +import android.content.Intent import androidx.core.app.NotificationCompat +import com.teamhy2.feature.main.MainActivity import com.teamhy2.feature.setting.domain.repository.SettingsRepository +import com.teamhy2.hongikyeolgong2.notification.NotificationHandler +import com.teamhy2.hongikyeolgong2.notification.PushText +import com.teamhy2.hongikyeolgong2.notification.R +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -15,13 +21,13 @@ import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.random.Random -class NotificationHandler +class MainNotificationHandler @Inject constructor( - private val context: Context, + @ApplicationContext private val context: Context, settingsRepository: SettingsRepository, coroutineScope: CoroutineScope, - ) { + ) : NotificationHandler { private val notificationManager = context.getSystemService(NotificationManager::class.java) private val notificationChannel: StateFlow = @@ -32,33 +38,41 @@ class NotificationHandler initialValue = false, ) + private val mainIntent = + Intent(context, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP + } + private val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT) + init { coroutineScope.launch { notificationChannel.collect() } } - fun buildServiceNotification(): Notification { + override fun buildServiceNotification(): Notification { return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle("홍익열공이 열공중") .setContentText("열람실을 이용중이에요!") .setSmallIcon(R.drawable.ic_status_bar_logo) .setOngoing(true) + .setContentIntent(pendingIntent) .setPriority(NotificationCompat.PRIORITY_HIGH) .build() } - fun buildGeneralNotification(contentText: String): Notification { + override fun buildGeneralNotification(contentText: String): Notification { return NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle("홍익열공이 알림") .setContentText(contentText) .setSmallIcon(R.drawable.ic_status_bar_logo) + .setContentIntent(pendingIntent) .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_HIGH) .build() } - fun showSimpleNotification(pushText: PushText) { + override fun showSimpleNotification(pushText: PushText) { val notification = buildGeneralNotification(context.getString(pushText.id)) if (notificationChannel.value) { @@ -70,11 +84,3 @@ class NotificationHandler private const val NOTIFICATION_CHANNEL_ID = "notification_channel_id" } } - -enum class PushText( - @StringRes val id: Int, -) { - THIRTY_MINUTES(R.string.notification_content_thirty_minutes_remain), - TEN_MINUTES(R.string.notification_content_ten_minutes_remain), - ZERO_MINUTES(R.string.notification_content_zero_minutes_remain), -} diff --git a/main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandlerModule.kt b/main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandlerModule.kt new file mode 100644 index 00000000..a69f7f88 --- /dev/null +++ b/main-presentation/src/main/java/com/teamhy2/feature/home/MainNotificationHandlerModule.kt @@ -0,0 +1,16 @@ +package com.teamhy2.feature.home + +import com.teamhy2.hongikyeolgong2.notification.NotificationHandler +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class MainNotificationHandlerModule { + @Binds + @Singleton + abstract fun bindMainNotificationHandler(mainNotificationHandler: MainNotificationHandler): NotificationHandler +} diff --git a/onboarding-presentation/build.gradle.kts b/onboarding-presentation/build.gradle.kts index 4e2d7875..86fae56e 100644 --- a/onboarding-presentation/build.gradle.kts +++ b/onboarding-presentation/build.gradle.kts @@ -14,6 +14,4 @@ dependencies { implementation(projects.userDomain) implementation(libs.accompanist.permissions) - - implementation(projects.app.notification) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 0125037e..efe233be 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,11 +22,11 @@ dependencyResolutionManagement { rootProject.name = "HongikYeolgong2" include(":app") -include(":app:notification") include(":core:designsystem") include(":core:remote") include(":core:auth") +include(":core:notification") include(":calendar-domain") include(":calendar-presentation") diff --git a/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/TimerService.kt b/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/TimerService.kt new file mode 100644 index 00000000..066a7f3c --- /dev/null +++ b/timer-domain/src/main/java/com/teamhy2/hongikyeolgong2/timer/model/TimerService.kt @@ -0,0 +1,13 @@ +package com.teamhy2.hongikyeolgong2.timer.model + +import java.time.Duration +import java.time.LocalDateTime + +interface TimerService { + fun startService( + startTime: LocalDateTime, + duration: Duration, + ) + + fun stopService() +} diff --git a/timer-presentation/build.gradle.kts b/timer-presentation/build.gradle.kts index 8c61365c..219e24ec 100644 --- a/timer-presentation/build.gradle.kts +++ b/timer-presentation/build.gradle.kts @@ -8,5 +8,5 @@ android { dependencies { implementation(projects.timerDomain) - implementation(projects.app.notification) + implementation(projects.core.notification) } diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt index 0e65d3be..50f9e9fc 100644 --- a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerForegroundService.kt @@ -6,7 +6,9 @@ import android.content.Intent import android.os.IBinder import com.teamhy2.hongikyeolgong2.notification.NotificationHandler import com.teamhy2.hongikyeolgong2.notification.PushText +import com.teamhy2.hongikyeolgong2.timer.model.TimerService import dagger.hilt.android.AndroidEntryPoint +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -19,102 +21,102 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject @AndroidEntryPoint -class TimerForegroundService : Service() { +class TimerForegroundService @Inject - lateinit var notificationHandler: NotificationHandler - - private val serviceScope: CoroutineScope = CoroutineScope(Dispatchers.Main) - private var timerJob: Job? = null - private var endTime: Long = 0L - - private var hasNotified30Min: Boolean = false - private var hasNotified10Min: Boolean = false - private var hasNotified0Min: Boolean = false - - override fun onBind(intent: Intent?): IBinder? = null - - override fun onStartCommand( - intent: Intent?, - flags: Int, - startId: Int, - ): Int { - val startTimeMillis: Long = - intent?.getLongExtra(EXTRA_START_TIME, System.currentTimeMillis()) - ?: System.currentTimeMillis() - val durationMillis: Long = intent?.getLongExtra(EXTRA_TIME, 0L) ?: 0L - - val startTime: LocalDateTime = - LocalDateTime.ofInstant( - java.time.Instant.ofEpochMilli(startTimeMillis), - ZoneId.systemDefault(), + constructor() : Service(), TimerService { + @Inject + lateinit var notificationHandler: NotificationHandler + + @Inject + @ApplicationContext + lateinit var context: Context + + private val serviceScope: CoroutineScope = CoroutineScope(Dispatchers.Main) + private var timerJob: Job? = null + private var endTime: Long = 0L + + private var hasNotified30Min: Boolean = false + private var hasNotified10Min: Boolean = false + private var hasNotified0Min: Boolean = false + + override fun onBind(intent: Intent?): IBinder? = null + + override fun onStartCommand( + intent: Intent?, + flags: Int, + startId: Int, + ): Int { + val startTimeMillis: Long = + intent?.getLongExtra(EXTRA_START_TIME, System.currentTimeMillis()) + ?: System.currentTimeMillis() + val durationMillis: Long = intent?.getLongExtra(EXTRA_TIME, 0L) ?: 0L + + val startTime: LocalDateTime = + LocalDateTime.ofInstant( + java.time.Instant.ofEpochMilli(startTimeMillis), + ZoneId.systemDefault(), + ) + val duration: Duration = Duration.ofMillis(durationMillis) + + startForeground( + TIMER_NOTIFICATION_ID, + notificationHandler.buildServiceNotification(), ) - val duration: Duration = Duration.ofMillis(durationMillis) + startTimer(startTime, duration) - startForeground( - TIMER_NOTIFICATION_ID, - notificationHandler.buildServiceNotification(), - ) - startTimer(startTime, duration) + return START_NOT_STICKY + } - return START_NOT_STICKY - } + override fun onDestroy() { + timerJob?.cancel() + super.onDestroy() + } - override fun onDestroy() { - timerJob?.cancel() - super.onDestroy() - } + private fun startTimer( + startTime: LocalDateTime, + duration: Duration, + ) { + timerJob?.cancel() - private fun startTimer( - startTime: LocalDateTime, - duration: Duration, - ) { - timerJob?.cancel() - - val startTimeInMillis: Long = - startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - endTime = startTimeInMillis + duration.toMillis() - - hasNotified30Min = false - hasNotified10Min = false - - timerJob = - serviceScope.launch { - while (true) { - val remainingTime: Long = endTime - System.currentTimeMillis() - - if (remainingTime <= 0 && hasNotified0Min.not()) { - notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) - hasNotified0Min = true - stopSelf() - break - } + val startTimeInMillis: Long = + startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + endTime = startTimeInMillis + duration.toMillis() + + hasNotified30Min = false + hasNotified10Min = false - when { - remainingTime <= TimeUnit.MINUTES.toMillis(10L) && hasNotified10Min.not() -> { - notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) - hasNotified10Min = true - continue + timerJob = + serviceScope.launch { + while (true) { + val remainingTime: Long = endTime - System.currentTimeMillis() + + if (remainingTime <= 0 && hasNotified0Min.not()) { + notificationHandler.showSimpleNotification(PushText.ZERO_MINUTES) + hasNotified0Min = true + stopSelf() + break } - remainingTime <= TimeUnit.MINUTES.toMillis(30L) && hasNotified30Min.not() -> { - notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) - hasNotified30Min = true - continue + when { + remainingTime <= TimeUnit.MINUTES.toMillis(10L) && hasNotified10Min.not() -> { + notificationHandler.showSimpleNotification(PushText.TEN_MINUTES) + hasNotified10Min = true + continue + } + + remainingTime <= TimeUnit.MINUTES.toMillis(30L) && hasNotified30Min.not() -> { + notificationHandler.showSimpleNotification(PushText.THIRTY_MINUTES) + hasNotified30Min = true + continue + } } - } - delay(1000L) + delay(1000L) + } } - } - } - - companion object { - const val TIMER_NOTIFICATION_ID: Int = 1 - const val EXTRA_TIME: String = "extra_time" - const val EXTRA_START_TIME: String = "extra_start_time" + } - fun startService( - context: Context, + override fun startService( startTime: LocalDateTime, duration: Duration, ) { @@ -130,10 +132,14 @@ class TimerForegroundService : Service() { appContext.startForegroundService(startIntent) } - fun stopService(context: Context) { - val appContext: Context = context.applicationContext - val stopIntent: Intent = Intent(appContext, TimerForegroundService::class.java) - appContext.stopService(stopIntent) + override fun stopService() { + val stopIntent = Intent(context, TimerForegroundService::class.java) + context.stopService(stopIntent) + } + + companion object { + const val TIMER_NOTIFICATION_ID: Int = 1 + const val EXTRA_TIME: String = "extra_time" + const val EXTRA_START_TIME: String = "extra_start_time" } } -} diff --git a/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerServiceModule.kt b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerServiceModule.kt new file mode 100644 index 00000000..80a5a8a6 --- /dev/null +++ b/timer-presentation/src/main/java/com/teamhy2/hongikyeolgong2/timer/presentation/TimerServiceModule.kt @@ -0,0 +1,16 @@ +package com.teamhy2.hongikyeolgong2.timer.presentation + +import com.teamhy2.hongikyeolgong2.timer.model.TimerService +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class TimerServiceModule { + @Binds + @Singleton + abstract fun bindTimerService(timerForegroundService: TimerForegroundService): TimerService +}