I made 2 Sheets and 1 Popup in different files to make the code of the MainActivity tidy and to call on them in a wrapped file called HSApp.kt. This, when the User taps the notification, each respective sheet or popup will show.
The notifications show now, but only when the app is opened.
Can anyone kindly help me, please?
MYFIREBASEMESSAGINGSERVICE.kt:
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
// Check if the message contains notification payload
remoteMessage.notification?.let {
showNotification(it.title, it.body, remoteMessage.data["type"])
}
// Check if the message contains data payload
if (remoteMessage.data.isNotEmpty()) {
val title = remoteMessage.data["title"]
val message = remoteMessage.data["message"]
val type = remoteMessage.data["type"] // "devotional", "quiz", "word_for_the_day"
// Show a notification only if there's no UI popover to be displayed
if (type.isNullOrEmpty()) {
showNotification(title, message, null)
} else {
handleFirebaseEvent(type)
}
}
}
private fun handleFirebaseEvent(type: String) {
// Send a broadcast with the action defined in our constant.
val intent = Intent(NOTIFICATION_TRIGGER_ACTION).apply {
putExtra("type", type)
}
sendBroadcast(intent)
}
private fun showNotification(title: String?, message: String?, type: String?) {
val channelId = "default_channel_id"
val channelName = "Default Channel"
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create notification channel (API 26+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Default channel for app notifications"
}
notificationManager.createNotificationChannel(channel)
}
// Intent to open MainActivity when tapped
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
putExtra("notification_type", type)
}
val pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
// Build the notification
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.logo_image)
.setColor(Color.parseColor("#660d77"))
.setAutoCancel(true)
.setContentIntent(pendingIntent)
// Show the notification
notificationManager.notify(0, notificationBuilder.build())
}
override fun onNewToken(token: String) {
Log.d("MyAppFCM", "New token: $token")
sendTokenToServer(token)
}
private fun sendTokenToServer(token: String) {
Log.d("FCM", "Firebase token: $token")
// TODO: Implement API call to send the token to your backend
}
}
MAINACTIVITY:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize Firebase
FirebaseApp.initializeApp(this)
if (!checkPermissions()) {
requestPermissions()
}
val notificationType: String? = intent.getStringExtra("notification_type")
setContent {
// Pass the notification extra to HSMApp.
HSMApp(notificationType = notificationType)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
}
HSMAPP.kt:
@Composable
fun HSMApp(notificationType: String?) {
var isDevotionalSheetVisible by remember { mutableStateOf(false) }
var isQuizSheetVisible by remember { mutableStateOf(false) }
var isWordPopupVisible by remember { mutableStateOf(false) }
val context = LocalContext.current
// Use LaunchedEffect keyed on the passed notificationType to update state.
LaunchedEffect(notificationType) {
notificationType?.let { type ->
when (type) {
"devotional" -> isDevotionalSheetVisible = true
"quiz" -> isQuizSheetVisible = true
"wordPopup", "word_for_the_day" -> isWordPopupVisible = true
}
}
}
// Also register a BroadcastReceiver for in-app triggers.
DisposableEffect(Unit) {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val type = intent?.getStringExtra("type")
when (type) {
"devotional" -> isDevotionalSheetVisible = true
"quiz" -> isQuizSheetVisible = true
"wordPopup", "word_for_the_day" -> isWordPopupVisible = true
}
}
}
val filter = IntentFilter(NOTIFICATION_TRIGGER_ACTION)
context.registerReceiver(receiver, filter, Context.RECEIVER_NOT_EXPORTED)
onDispose { context.unregisterReceiver(receiver) }
}
HSMAppTheme {
// Pass dummy lambdas to MainScreen (if youโre not using buttons in production).
MainScreen(
onDismiss = {
isDevotionalSheetVisible = false
isQuizSheetVisible = false
isWordPopupVisible = false
},
showDevotionalSheet = { isDevotionalSheetVisible = true },
showQuizSheet = { isQuizSheetVisible = true },
showWordPopup = { isWordPopupVisible = true }
)
if (isDevotionalSheetVisible) {
DevotionalSheet(onDismiss = { isDevotionalSheetVisible = false })
}
if (isQuizSheetVisible) {
QuizSheet(onDismiss = { isQuizSheetVisible = false })
}
if (isWordPopupVisible) {
WordForTheDayPopup(onDismiss = { isWordPopupVisible = false })
}
}
}
DEVOTIONAL Example of Sheet:
@Composable
fun DevotionalSheet(onDismiss: () -> Unit) {
ModalBottomSheet(
onDismissRequest = { onDismiss() },
sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
containerColor = Color.White,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
) {
WebViewPage(url = "https://www.google.comโ)
}
}