Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.terning.core.designsystem.type

enum class NotificationRedirect(val path: String) {
CALENDAR("calendar"),
HOME("home"),
SEARCH("search");

companion object {
fun from(type: String?): NotificationRedirect? =
entries.firstOrNull { it.path.equals(type, ignoreCase = true) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.terning.core.designsystem.util

object DeeplinkDefaults {
const val REDIRECT: String = "redirect"

fun build(base: String) = "terning://${base}"
}
4 changes: 4 additions & 0 deletions core/firebase/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ android {
dependencies {
//core
implementation(projects.core.navigator)
implementation(projects.core.designsystem)

// domain
implementation(projects.domain.user)
Expand All @@ -23,4 +24,7 @@ dependencies {
implementation(libs.firebase.analytics)
implementation(libs.firebase.messaging)
implementation(libs.firebase.config)

// coil
implementation(libs.coil.compose)
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package com.terning.core.firebase.messageservice

import android.app.ActivityManager
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import coil3.BitmapImage
import coil3.ImageLoader
import coil3.request.ImageRequest
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.terning.core.designsystem.type.NotificationRedirect
import com.terning.core.designsystem.util.DeeplinkDefaults
import com.terning.core.designsystem.util.DeeplinkDefaults.REDIRECT
import com.terning.core.firebase.R
import com.terning.domain.user.repository.UserRepository
import com.terning.navigator.NavigatorProvider
Expand All @@ -36,44 +43,53 @@ class TerningMessagingService : FirebaseMessagingService() {
override fun handleIntent(intent: Intent?) {
super.handleIntent(intent)

if (intent?.getStringExtra(TITLE)?.isEmpty() == true
|| !userRepository.getAlarmAvailable()
) return

val title = intent?.getStringExtra(TITLE).orEmpty()
val body = intent?.getStringExtra(BODY).orEmpty()
val type = intent?.getStringExtra(TYPE).orEmpty()

sendNotification(
title = title,
body = body,
type = type
extractInformation(
title = intent?.getStringExtra(TITLE),
body = intent?.getStringExtra(BODY),
type = intent?.getStringExtra(TYPE),
imageUrl = intent?.getStringExtra(IMAGE_URL)
)
}

override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)

if (message.data.isEmpty()
|| !userRepository.getAlarmAvailable()
) return
extractInformation(
title = message.data[TITLE],
body = message.data[BODY],
type = message.data[TYPE],
imageUrl = message.data[IMAGE_URL]
)
}

val title = message.data[TITLE].orEmpty()
val body = message.data[BODY].orEmpty()
val type = message.data[TYPE].orEmpty()
private fun extractInformation(
title: String?,
body: String?,
type: String?,
imageUrl: String?
) {
if (title.isNullOrEmpty() || !userRepository.getAlarmAvailable()) return

sendNotification(
title = title,
body = body,
type = type
body = body.orEmpty(),
type = type.orEmpty(),
imageUrl = imageUrl.orEmpty()
)
}

private fun sendNotification(title: String, body: String, type: String) {
private fun sendNotification(
title: String,
body: String,
type: String,
imageUrl: String
) {
val notifyId = Random().nextInt()
val intent = navigatorProvider.getMainActivityIntent(deeplink = type).apply {
val isForeground = isAppInForeground()
val deeplink = buildDeeplink(type, isForeground)
val intent = navigatorProvider.getMainActivityIntent(deeplink = deeplink).apply {
action = Intent.ACTION_VIEW
data = type.toUri()
data = deeplink.toUri()
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
val pendingIntent = PendingIntent.getActivity(
Expand All @@ -82,32 +98,66 @@ class TerningMessagingService : FirebaseMessagingService() {
intent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_MUTABLE
)
val channelId: String = CHANNEL_ID
val notificationBuilder =
NotificationCompat.Builder(this, channelId).apply {
NotificationCompat.Builder(this, CHANNEL_ID).apply {
setSmallIcon(R.mipmap.ic_terning_launcher)
setContentTitle(title)
setContentText(body)
setPriority(NotificationManagerCompat.IMPORTANCE_HIGH)
setAutoCancel(true)
setPriority(NotificationCompat.PRIORITY_HIGH)
setContentIntent(pendingIntent)
}

getSystemService<NotificationManager>()?.run {
createNotificationChannel(
NotificationChannel(
channelId,
channelId,
NotificationManager.IMPORTANCE_HIGH,
),
val notificationManager = getSystemService<NotificationManager>()
notificationManager?.createNotificationChannel(
NotificationChannel(
CHANNEL_ID,
CHANNEL_ID,
NotificationManager.IMPORTANCE_HIGH
)
notify(notifyId, notificationBuilder.build())
}
)
val imageLoader = ImageLoader(this)
val request = ImageRequest.Builder(this)
.data(imageUrl)
.target(
onSuccess = { image ->
val bitmap = (image as BitmapImage).bitmap
notificationBuilder.setLargeIcon(bitmap)
notificationManager?.notify(notifyId, notificationBuilder.build())
},
onError = {
notificationManager?.notify(notifyId, notificationBuilder.build())
}
)
.build()

imageLoader.enqueue(request)
}

private fun isAppInForeground(): Boolean {
val appProcesses =
(getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).runningAppProcesses

return appProcesses?.any {
val isForeground =
it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
val isCurrentApp = it.processName == packageName

isForeground && isCurrentApp
} == true
Comment on lines +140 to +146
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조건들을 변수로 선언해두면 코드 가독성이 지금보다 좋아질 것 같아요!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다! 가독성이 좋아진 것 같네요:)

}

private fun buildDeeplink(type: String, isForeground: Boolean): String {
val base = NotificationRedirect.from(type) ?: return ""

return if (isForeground) DeeplinkDefaults.build(base.path)
else DeeplinkDefaults.build("splash?$REDIRECT=${base.path}")
}

companion object {
private const val CHANNEL_ID: String = "terning"
private const val TITLE: String = "title"
private const val BODY: String = "body"
private const val TYPE: String = "type"
private const val IMAGE_URL: String = "imageUrl"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.terning.core.analytics.EventType
import com.terning.core.analytics.LocalTracker
import com.terning.core.designsystem.component.topappbar.CalendarTopAppBar
import com.terning.core.designsystem.extension.getWeekIndexContainingSelectedDate
import com.terning.core.designsystem.theme.Grey200
import com.terning.core.designsystem.theme.White
import com.terning.feature.calendar.calendar.component.ScreenTransition
import com.terning.feature.calendar.calendar.component.WeekDaysHeader
import com.terning.feature.calendar.calendar.model.CalendarUiState
Expand All @@ -48,6 +50,12 @@ fun CalendarRoute(
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val amplitudeTracker = LocalTracker.current

val systemUiController = rememberSystemUiController()

LaunchedEffect(Unit) {
systemUiController.setStatusBarColor(color = White)
systemUiController.setNavigationBarColor(color = White)
}

CalendarScreen(
uiState = uiState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import com.terning.core.designsystem.util.DeeplinkDefaults
import com.terning.core.navigation.MainTabRoute
import com.terning.feature.calendar.calendar.CalendarRoute
import kotlinx.serialization.Serializable


fun NavController.navigateCalendar(navOptions: NavOptions? = null) {
navigate(
route = Calendar,
Expand All @@ -23,7 +24,13 @@ fun NavGraphBuilder.calendarNavGraph(
navigateIntern: (Long) -> Unit,
paddingValues: PaddingValues
) {
composable<Calendar> {
composable<Calendar>(
deepLinks = listOf(
navDeepLink<Calendar>(
basePath = DeeplinkDefaults.build("calendar")
)
)
) {
CalendarRoute(
modifier = Modifier.padding(paddingValues),
navigateToAnnouncement = navigateIntern
Expand Down
22 changes: 9 additions & 13 deletions feature/home/src/main/java/com/terning/feature/home/HomeRoute.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -106,19 +105,11 @@ fun HomeRoute(
}

val systemUiController = rememberSystemUiController()
SideEffect {
systemUiController.setStatusBarColor(
color = White
)
systemUiController.setNavigationBarColor(
color = White
)
}

val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current

val amplitudeTracker = LocalTracker.current
LaunchedEffect(Unit) {
systemUiController.setStatusBarColor(color = White)
systemUiController.setNavigationBarColor(color = White)
}

LaunchedEffect(key1 = true) {
viewModel.getProfile()
Expand All @@ -127,6 +118,9 @@ fun HomeRoute(
viewModel.getRecommendInternFlow()
}

val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current

LaunchedEffect(viewModel.homeSideEffect, lifecycleOwner) {
viewModel.homeSideEffect.flowWithLifecycle(lifecycle = lifecycleOwner.lifecycle)
.collect { sideEffect ->
Expand All @@ -138,6 +132,8 @@ fun HomeRoute(
}
}

val amplitudeTracker = LocalTracker.current

HomeScreen(
paddingValues = paddingValues,
navigateToIntern = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.terning.feature.home.navigation

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.PaddingValues
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import com.terning.core.designsystem.util.DeeplinkDefaults
import com.terning.core.navigation.MainTabRoute
import com.terning.feature.home.HomeRoute
import kotlinx.serialization.Serializable
Expand All @@ -16,12 +20,19 @@ fun NavController.navigateHome(navOptions: NavOptions? = null) {
)
}

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun NavGraphBuilder.homeNavGraph(
paddingValues: PaddingValues,
navigateToCalendar: () -> Unit,
navigateToIntern: (Long) -> Unit
) {
composable<Home> {
composable<Home>(
deepLinks = listOf(
navDeepLink<Home>(
basePath = DeeplinkDefaults.build("home")
)
)
) {
HomeRoute(
paddingValues = paddingValues,
navigateToCalendar = navigateToCalendar,
Expand Down
2 changes: 2 additions & 0 deletions feature/main/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ android {
dependencies {
// core
implementation(projects.core.navigator)
implementation(projects.core.firebase)
implementation(projects.core.designsystem)

// feature
implementation(projects.feature.calendar)
Expand Down
Loading