add notification

This commit is contained in:
2026-05-28 08:55:01 +07:00
parent a2a4433a9d
commit cab12da4a5
5 changed files with 67 additions and 17 deletions

View File

@@ -72,7 +72,7 @@ val LocalNavController = staticCompositionLocalOf<NavController> {
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
@Composable @Composable
fun App() { fun App(openRoomId: Long? = null) {
val context = LocalContext.current val context = LocalContext.current
val navController = rememberNavController() val navController = rememberNavController()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -101,6 +101,12 @@ fun App() {
} }
} }
LaunchedEffect(openRoomId) {
if (openRoomId != null) {
navController.navigate(Screen.Chat(openRoomId))
}
}
MaterialExpressiveTheme( MaterialExpressiveTheme(
colorScheme = colorScheme, colorScheme = colorScheme,
typography = Typography(), typography = Typography(),

View File

@@ -23,8 +23,10 @@ class MainActivity : ComponentActivity() {
startService(intent) startService(intent)
} }
val roomId = intent.getLongExtra("room_id", -1L)
setContent { setContent {
App() App(openRoomId = if (roomId != -1L) roomId else null)
} }
} }
} }

View File

@@ -3,6 +3,7 @@ package su.reya.coop
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
@@ -45,7 +46,7 @@ class NostrForegroundService : Service() {
// Handle notifications // Handle notifications
nostr.handleLiteNotifications { event -> nostr.handleLiteNotifications { event ->
if (!isUserInApp()) { if (!isUserInApp()) {
showNewMessageNotification(event.content()) showNewMessageNotification(event.roomId(), event.content())
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
@@ -76,12 +77,26 @@ class NostrForegroundService : Service() {
.build() .build()
} }
private fun showNewMessageNotification(message: String) { private fun showNewMessageNotification(roomId: Long, message: String) {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
putExtra("room_id", roomId)
}
val pendingIntent = PendingIntent.getActivity(
this,
roomId.toInt(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification = NotificationCompat.Builder(this, "nostr_service") val notification = NotificationCompat.Builder(this, "nostr_service")
.setContentTitle("New Message") .setContentTitle("You received a new message")
.setContentText(message) .setContentText(message)
.setAutoCancel(true) .setAutoCancel(true)
.setContentIntent(pendingIntent)
.build() .build()
val manager = getSystemService(NotificationManager::class.java) val manager = getSystemService(NotificationManager::class.java)
manager?.notify(System.currentTimeMillis().toInt(), notification) manager?.notify(System.currentTimeMillis().toInt(), notification)
} }

View File

@@ -19,6 +19,8 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@@ -37,6 +39,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@@ -90,19 +93,16 @@ fun ChatScreen(
var text by remember { mutableStateOf("") } var text by remember { mutableStateOf("") }
var loading by remember { mutableStateOf(true) } var loading by remember { mutableStateOf(true) }
var newOtherMessages by remember { mutableIntStateOf(0) }
val messages = remember { mutableStateListOf<UnsignedEvent>() } val messages = remember { mutableStateListOf<UnsignedEvent>() }
val groupedMessages = remember(messages.toList()) { val groupedMessages = remember(messages.toList()) {
messages.groupBy { it.createdAt().formatAsGroupHeader() } messages.groupBy { it.createdAt().formatAsGroupHeader() }
} }
fun setLoading(value: Boolean) {
loading = value
}
LaunchedEffect(id) { LaunchedEffect(id) {
// Start loading spinner // Start loading spinner
setLoading(true) loading = true
// Get messages // Get messages
val initialMessages = viewModel.getChatRoomMessages(id) val initialMessages = viewModel.getChatRoomMessages(id)
@@ -122,7 +122,7 @@ fun ChatScreen(
} }
// Stop loading spinner // Stop loading spinner
setLoading(false) loading = false
// Handle new messages // Handle new messages
viewModel.newEvents.collect { event -> viewModel.newEvents.collect { event ->
@@ -130,6 +130,9 @@ fun ChatScreen(
if (event.id() !in messages.map { it.id() }) { if (event.id() !in messages.map { it.id() }) {
messages.add(0, event) messages.add(0, event)
} }
} else {
// If the event is not in the current room, it's a new message from another user
newOtherMessages++
} }
} }
} }
@@ -173,11 +176,21 @@ fun ChatScreen(
} }
}, },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBack) { BadgedBox(
Icon( badge = {
painter = painterResource(Res.drawable.ic_arrow_back), if (newOtherMessages > 0) {
contentDescription = "Back" Badge {
) Text(newOtherMessages.toString())
}
}
}
) {
IconButton(onClick = onBack) {
Icon(
painter = painterResource(Res.drawable.ic_arrow_back),
contentDescription = "Back"
)
}
} }
}, },
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(

View File

@@ -109,13 +109,27 @@ class NostrViewModel(
}, },
onSubscriptionClose = { onSubscriptionClose = {
getChatRooms() getChatRooms()
if (!_isPartialProcessedGiftWrap.value) { if (!_isPartialProcessedGiftWrap.value) {
_isPartialProcessedGiftWrap.value = true _isPartialProcessedGiftWrap.value = true
} }
}, },
onNewMessage = { event -> onNewMessage = { event ->
viewModelScope.launch { viewModelScope.launch {
val roomId = event.roomId()
val existingRoom = _chatRooms.value.firstOrNull { it.id == roomId }
if (existingRoom == null) {
val currentUser = nostr.signer.currentUser
if (currentUser != null) {
val newRoom = Room.new(event, currentUser)
_chatRooms.update { currentRooms ->
currentRooms + newRoom
}
}
} else {
updateRoomList(roomId, event)
}
_newEvents.emit(event) _newEvents.emit(event)
} }
}, },