feat: implement basic notification #6
@@ -72,7 +72,7 @@ val LocalNavController = staticCompositionLocalOf<NavController> {
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun App() {
|
||||
fun App(openRoomId: Long? = null) {
|
||||
val context = LocalContext.current
|
||||
val navController = rememberNavController()
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -101,6 +101,12 @@ fun App() {
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(openRoomId) {
|
||||
if (openRoomId != null) {
|
||||
navController.navigate(Screen.Chat(openRoomId))
|
||||
}
|
||||
}
|
||||
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography(),
|
||||
|
||||
@@ -23,8 +23,10 @@ class MainActivity : ComponentActivity() {
|
||||
startService(intent)
|
||||
}
|
||||
|
||||
val roomId = intent.getLongExtra("room_id", -1L)
|
||||
|
||||
setContent {
|
||||
App()
|
||||
App(openRoomId = if (roomId != -1L) roomId else null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package su.reya.coop
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
@@ -45,7 +46,7 @@ class NostrForegroundService : Service() {
|
||||
// Handle notifications
|
||||
nostr.handleLiteNotifications { event ->
|
||||
if (!isUserInApp()) {
|
||||
showNewMessageNotification(event.content())
|
||||
showNewMessageNotification(event.roomId(), event.content())
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
@@ -76,12 +77,26 @@ class NostrForegroundService : Service() {
|
||||
.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")
|
||||
.setContentTitle("New Message")
|
||||
.setContentTitle("You received a new message")
|
||||
.setContentText(message)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent)
|
||||
.build()
|
||||
|
||||
val manager = getSystemService(NotificationManager::class.java)
|
||||
manager?.notify(System.currentTimeMillis().toInt(), notification)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
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.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
@@ -37,6 +39,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -90,19 +93,16 @@ fun ChatScreen(
|
||||
|
||||
var text by remember { mutableStateOf("") }
|
||||
var loading by remember { mutableStateOf(true) }
|
||||
var newOtherMessages by remember { mutableIntStateOf(0) }
|
||||
|
||||
val messages = remember { mutableStateListOf<UnsignedEvent>() }
|
||||
val groupedMessages = remember(messages.toList()) {
|
||||
messages.groupBy { it.createdAt().formatAsGroupHeader() }
|
||||
}
|
||||
|
||||
fun setLoading(value: Boolean) {
|
||||
loading = value
|
||||
}
|
||||
|
||||
LaunchedEffect(id) {
|
||||
// Start loading spinner
|
||||
setLoading(true)
|
||||
loading = true
|
||||
|
||||
// Get messages
|
||||
val initialMessages = viewModel.getChatRoomMessages(id)
|
||||
@@ -122,7 +122,7 @@ fun ChatScreen(
|
||||
}
|
||||
|
||||
// Stop loading spinner
|
||||
setLoading(false)
|
||||
loading = false
|
||||
|
||||
// Handle new messages
|
||||
viewModel.newEvents.collect { event ->
|
||||
@@ -130,6 +130,9 @@ fun ChatScreen(
|
||||
if (event.id() !in messages.map { it.id() }) {
|
||||
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 = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_arrow_back),
|
||||
contentDescription = "Back"
|
||||
)
|
||||
BadgedBox(
|
||||
badge = {
|
||||
if (newOtherMessages > 0) {
|
||||
Badge {
|
||||
Text(newOtherMessages.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_arrow_back),
|
||||
contentDescription = "Back"
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
|
||||
@@ -109,13 +109,27 @@ class NostrViewModel(
|
||||
},
|
||||
onSubscriptionClose = {
|
||||
getChatRooms()
|
||||
|
||||
if (!_isPartialProcessedGiftWrap.value) {
|
||||
_isPartialProcessedGiftWrap.value = true
|
||||
}
|
||||
},
|
||||
onNewMessage = { event ->
|
||||
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)
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user