diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt index 28158026..6cbe392a 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/ChatScreen.kt @@ -1,5 +1,8 @@ package com.m57.hermescontrol.ui.chat +import android.os.Build +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearEasing @@ -85,6 +88,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.m57.hermescontrol.notification.NotificationHelper @@ -136,6 +140,26 @@ fun ChatScreen( } } + // Request POST_NOTIFICATIONS runtime permission on Android 13+ (API 33). + // The manifest declaration alone is insufficient — on API 33+ the system + // requires a runtime permission prompt before the app can post any + // notification, including the foreground service notification. + val requestNotificationPermission = + rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + ) { /* granted — next lifecycle event will pick it up */ } + LaunchedEffect(Unit) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val permission = android.Manifest.permission.POST_NOTIFICATIONS + if ( + ContextCompat.checkSelfPermission(context, permission) != + android.content.pm.PackageManager.PERMISSION_GRANTED + ) { + requestNotificationPermission.launch(permission) + } + } + } + // Auto-scroll to bottom on new messages LaunchedEffect(state.messages.size, state.currentStreamingText) { if (state.messages.isNotEmpty()) {