Skip to content

Commit

Permalink
feat: fcm token 전송 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
HyomK committed Feb 19, 2024
1 parent 68df59d commit 0cea0e9
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 18 deletions.
13 changes: 11 additions & 2 deletions app/src/main/java/nexters/hyomk/dontforget/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import java.util.Locale
@AndroidEntryPoint
class MainActivity : ComponentActivity() {

private val viwModel by viewModels<SplashViewModel>()
private val viewModel by viewModels<SplashViewModel>()

private val lan: String = Locale.getDefault().language
private val guide = getSupportGuide(lan.enumValueOrNull<SupportLanguage>())
Expand All @@ -46,11 +46,20 @@ class MainActivity : ComponentActivity() {
val token = task.result

// Log and toast
Timber.d("[fcm] : $token")
Timber.d("[device] : ${viewModel.deviceId.value} /[fcm] : $token")
if (viewModel.deviceId.value.isNotBlank() && token.isNotBlank()) {
viewModel.updateFcmInfo(token)
}
},
)
}

fun updateToken(token: String) {
if (viewModel.deviceId.value.isNotBlank() && token.isNotBlank()) {
viewModel.updateFcmInfo(token)
}
}

override fun onResume() {
super.onResume()
getFcmToken()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,48 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import nexters.hyomk.domain.model.AlarmStatus
import nexters.hyomk.domain.model.FcmInfo
import nexters.hyomk.domain.usecase.GetDeviceInfoUseCase
import nexters.hyomk.domain.usecase.UpdateAnniversaryAlarmStateUseCase
import nexters.hyomk.dontforget.MainActivity
import nexters.hyomk.dontforget.R
import timber.log.Timber
import javax.inject.Inject

@AndroidEntryPoint
class MyFirebaseMessageService : FirebaseMessagingService() {
// 새로운 토큰이 생성될 때 마다 해당 콜백이 호출된다.

@Inject
lateinit var updateTokenUseCase: UpdateAnniversaryAlarmStateUseCase

@Inject
lateinit var deviceInfoUseCase: GetDeviceInfoUseCase

override fun onNewToken(token: String) {
super.onNewToken(token)
Timber.d("onNewToken: $token")
// TODO 새로운 토큰 수신 시 서버로 전송
// MainActivity.uploadToken(token)
CoroutineScope(Dispatchers.IO).launch {
deviceInfoUseCase.invoke().catch {
Timber.e("fcm token refresh fail : $it")
}.collectLatest {
if (!it.isNullOrBlank()) {
updateTokenUseCase.invoke(FcmInfo(token = token, deviceId = it, AlarmStatus.ON)).catch {
Timber.e("fcm token refresh fail : $it")
}.collectLatest {
Timber.d(it.toString())
}
}
}
}
}

// Foreground에서 Push Service를 받기 위해 Notification 설정
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,25 @@ fun SplashScreen(
)
}

OnLifecycleEvent { owner, event ->
when (event) {
Lifecycle.Event.ON_RESUME -> {
if (permissionRequestState.requestPermission) {
if (deviceId.isNotBlank()) {
navHostController.navigate(
NavigationItem.Home.route,
) {
launchSingleTop = true
popUpTo(NavigationItem.Splash.route) { inclusive = true }
}
}
}
}

else -> {}
}
}

RequestPermission(
context = context,
requestState = permissionRequestState,
Expand Down Expand Up @@ -189,15 +208,6 @@ fun SplashScreen(
}
}

@Composable
fun Loader() {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.splash_lottie))
LottieAnimation(
composition,
modifier = Modifier.fillMaxSize(),
)
}

fun Context.navigateToAppSettings() {
this.startActivity(
Intent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import nexters.hyomk.domain.model.AlarmStatus
import nexters.hyomk.domain.model.FcmInfo
import nexters.hyomk.domain.usecase.GetDeviceInfoUseCase
import nexters.hyomk.domain.usecase.UpdateAnniversaryAlarmStateUseCase
import nexters.hyomk.domain.usecase.UpdateDeviceInfoUseCase
import nexters.hyomk.dontforget.utils.DeviceIdProvider
import timber.log.Timber
import javax.inject.Inject

@HiltViewModel
class SplashViewModel @Inject constructor(
private val application: Application,
private val updateDeviceInfoUseCase: UpdateDeviceInfoUseCase,
private val updateFcmInfoUseCase: UpdateAnniversaryAlarmStateUseCase,
private val getDeviceInfoUseCase: GetDeviceInfoUseCase,
) : AndroidViewModel(application) {
private val _deviceId = MutableStateFlow("")
Expand All @@ -35,4 +41,16 @@ class SplashViewModel @Inject constructor(
}
}
}

fun updateFcmInfo(fcmToken: String) {
viewModelScope.launch {
updateFcmInfoUseCase.invoke(
FcmInfo(token = fcmToken, deviceId = deviceId.value, status = AlarmStatus.ON),
).catch {
Timber.e(it)
}.collectLatest {
Timber.d(it.toString())
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nexters.hyomk.data.model.request

import com.google.gson.annotations.SerializedName
import nexters.hyomk.domain.model.FcmInfo

data class UpdateFcmInfoDTO(
@SerializedName("token") val token: String,
@SerializedName("deviceUuid") val deviceUuid: String,
@SerializedName("status") val status: String,
)

fun FcmInfo.toRequestDTO(): UpdateFcmInfoDTO {
return UpdateFcmInfoDTO(
token = this.token,
deviceUuid = this.deviceId,
status = this.status.name,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package nexters.hyomk.data.remote

import nexters.hyomk.data.model.request.CreateAnniversaryDTO
import nexters.hyomk.data.model.request.ModifyAnniversaryDTO
import nexters.hyomk.data.model.request.UpdateFcmInfoDTO
import nexters.hyomk.data.model.response.AnniversaryItemDTO
import nexters.hyomk.data.model.response.DetailAnniversaryDTO
import retrofit2.Response
Expand Down Expand Up @@ -29,6 +30,6 @@ interface DontForgetService {
@DELETE("/api/anniversary/{eventId}")
suspend fun deleteAnniversary(@Path("eventId") eventId: Long): Response<*>

@PUT("/api/device")
suspend fun modifyAlarmState(): Response<Unit>
@POST("/api/v1/notice/device")
suspend fun postFcmInfo(@Body request: UpdateFcmInfoDTO): Response<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package nexters.hyomk.data.repositoryImpl

import kotlinx.coroutines.flow.Flow
import nexters.hyomk.data.model.request.toRequestDTO
import nexters.hyomk.data.remote.DontForgetService
import nexters.hyomk.data.util.DeviceInfoManager
import nexters.hyomk.data.util.SafeApiCall
import nexters.hyomk.domain.model.FcmInfo
import nexters.hyomk.domain.repository.DeviceInfoRepository
import javax.inject.Inject

Expand All @@ -13,5 +15,5 @@ class DeviceInfoRepositoryImpl @Inject constructor(private val service: DontForg

override suspend fun initDeviceId(deviceId: String) = deviceInfoManager.initDeviceId(deviceId)

override suspend fun changeAlarmState(): Flow<Unit> = SafeApiCall.call(service.modifyAlarmState())
override suspend fun changeAlarmState(request: FcmInfo): Flow<Unit> = SafeApiCall.call(service.postFcmInfo(request.toRequestDTO()))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package nexters.hyomk.domain.model

enum class AlarmStatus {
ON, OFF
}
7 changes: 7 additions & 0 deletions domain/src/main/java/nexters/hyomk/domain/model/FcmInfo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package nexters.hyomk.domain.model

data class FcmInfo(
val token: String,
val deviceId: String,
val status: AlarmStatus
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package nexters.hyomk.domain.repository

import kotlinx.coroutines.flow.Flow
import nexters.hyomk.domain.model.FcmInfo

interface DeviceInfoRepository {
suspend fun getDeviceId(): Flow<String?>
suspend fun initDeviceId(deviceId: String)
suspend fun changeAlarmState(): Flow<Unit>
suspend fun changeAlarmState(request: FcmInfo): Flow<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package nexters.hyomk.domain.usecase

import kotlinx.coroutines.flow.Flow
import nexters.hyomk.domain.model.FcmInfo

interface UpdateAnniversaryAlarmStateUseCase {
suspend fun invoke(): Flow<Unit>
suspend fun invoke(request: FcmInfo): Flow<Unit>
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package nexters.hyomk.domain.usecaseImpl

import kotlinx.coroutines.flow.Flow
import nexters.hyomk.domain.model.FcmInfo
import nexters.hyomk.domain.repository.DeviceInfoRepository
import nexters.hyomk.domain.usecase.UpdateAnniversaryAlarmStateUseCase
import javax.inject.Inject

class UpdateAnniversaryAlarmStateUseCaseImpl @Inject constructor(
private val deviceInfoRepository: DeviceInfoRepository,
) : UpdateAnniversaryAlarmStateUseCase {
override suspend fun invoke(): Flow<Unit> = deviceInfoRepository.changeAlarmState()
override suspend fun invoke(request: FcmInfo): Flow<Unit> = deviceInfoRepository.changeAlarmState(request)
}

0 comments on commit 0cea0e9

Please sign in to comment.