kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
feat: show unique messaging notifications per contact (#1381)
* Show unique notifications per contact Instead of a single notification for all messages, each contact now has its own, unique notification. This uses the `NotificationCompat.MessagingStyle` and the contact's name to create distinct notifications, enhancing message organization. * feat: Add notification tap action to open contacts tab This is done by: - Adding an intent extra to the notification with the contact key for future use to navigate to the message thread. - Adding a new action to the MainActivity to handle the intent. - Updating the message notification to include the intent. * Open message notification to the correct conversation Adds an extra to the message notification intent to open the correct conversation. This ensures that when a user taps on a message notification, they are taken to the conversation with the sender of that message.pull/1384/head
rodzic
eea62e6533
commit
80e915a36c
|
@ -270,6 +270,14 @@ class MainActivity : AppCompatActivity(), Logging {
|
||||||
// We now wait for the device to connect, once connected, we ask the user if they want to switch to the new channel
|
// We now wait for the device to connect, once connected, we ask the user if they want to switch to the new channel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MeshServiceNotifications.OPEN_MESSAGE_ACTION -> {
|
||||||
|
val contactKey =
|
||||||
|
intent.getStringExtra(MeshServiceNotifications.OPEN_MESSAGE_EXTRA_CONTACT_KEY)
|
||||||
|
val contactName =
|
||||||
|
intent.getStringExtra(MeshServiceNotifications.OPEN_MESSAGE_EXTRA_CONTACT_NAME)
|
||||||
|
showMessages(contactKey, contactName)
|
||||||
|
}
|
||||||
|
|
||||||
UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
|
UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
|
||||||
showSettingsPage()
|
showSettingsPage()
|
||||||
}
|
}
|
||||||
|
@ -599,6 +607,13 @@ class MainActivity : AppCompatActivity(), Logging {
|
||||||
binding.pager.currentItem = 5
|
binding.pager.currentItem = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showMessages(contactKey: String?, contactName: String?) {
|
||||||
|
model.setCurrentTab(0)
|
||||||
|
if (contactKey != null && contactName != null) {
|
||||||
|
supportFragmentManager.navigateToMessages(contactKey, contactName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
menuInflater.inflate(R.menu.menu_main, menu)
|
menuInflater.inflate(R.menu.menu_main, menu)
|
||||||
|
|
|
@ -247,7 +247,7 @@ class MeshService : Service(), Logging {
|
||||||
startPacketQueue()
|
startPacketQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMessageNotification(dataPacket: DataPacket) {
|
private fun updateMessageNotification(contactKey: String, dataPacket: DataPacket) {
|
||||||
val message: String = when (dataPacket.dataType) {
|
val message: String = when (dataPacket.dataType) {
|
||||||
Portnums.PortNum.TEXT_MESSAGE_APP_VALUE -> dataPacket.text!!
|
Portnums.PortNum.TEXT_MESSAGE_APP_VALUE -> dataPacket.text!!
|
||||||
Portnums.PortNum.WAYPOINT_APP_VALUE -> {
|
Portnums.PortNum.WAYPOINT_APP_VALUE -> {
|
||||||
|
@ -256,7 +256,7 @@ class MeshService : Service(), Logging {
|
||||||
|
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
serviceNotifications.updateMessageNotification(getSenderName(dataPacket), message)
|
serviceNotifications.updateMessageNotification(contactKey, getSenderName(dataPacket), message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
|
@ -627,7 +627,7 @@ class MeshService : Service(), Logging {
|
||||||
packetRepository.get().apply {
|
packetRepository.get().apply {
|
||||||
insert(packetToSave)
|
insert(packetToSave)
|
||||||
val isMuted = getContactSettings(contactKey).isMuted
|
val isMuted = getContactSettings(contactKey).isMuted
|
||||||
if (updateNotification && !isMuted) updateMessageNotification(dataPacket)
|
if (updateNotification && !isMuted) updateMessageNotification(contactKey, dataPacket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import android.media.RingtoneManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.Person
|
||||||
import com.geeksville.mesh.MainActivity
|
import com.geeksville.mesh.MainActivity
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.TelemetryProtos.LocalStats
|
import com.geeksville.mesh.TelemetryProtos.LocalStats
|
||||||
|
@ -29,13 +30,16 @@ class MeshServiceNotifications(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FIFTEEN_MINUTES_IN_MILLIS = 15L * 60 * 1000
|
private const val FIFTEEN_MINUTES_IN_MILLIS = 15L * 60 * 1000
|
||||||
|
const val OPEN_MESSAGE_ACTION = "com.geeksville.mesh.OPEN_MESSAGE_ACTION"
|
||||||
|
const val OPEN_MESSAGE_EXTRA_CONTACT_KEY = "com.geeksville.mesh.OPEN_MESSAGE_EXTRA_CONTACT_KEY"
|
||||||
|
const val OPEN_MESSAGE_EXTRA_CONTACT_NAME =
|
||||||
|
"com.geeksville.mesh.OPEN_MESSAGE_EXTRA_CONTACT_NAME"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val notificationManager: NotificationManager get() = context.notificationManager
|
private val notificationManager: NotificationManager get() = context.notificationManager
|
||||||
|
|
||||||
// We have two notification channels: one for general service status and another one for messages
|
// We have two notification channels: one for general service status and another one for messages
|
||||||
val notifyId = 101
|
val notifyId = 101
|
||||||
private val messageNotifyId = 102
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
private fun createNotificationChannel(): String {
|
private fun createNotificationChannel(): String {
|
||||||
|
@ -165,10 +169,10 @@ class MeshServiceNotifications(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMessageNotification(name: String, message: String) =
|
fun updateMessageNotification(contactKey: String, name: String, message: String) =
|
||||||
notificationManager.notify(
|
notificationManager.notify(
|
||||||
messageNotifyId,
|
contactKey.hashCode(), // show unique notifications,
|
||||||
createMessageNotification(name, message)
|
createMessageNotification(contactKey, name, message)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun showNewNodeSeenNotification(node: NodeEntity) {
|
fun showNewNodeSeenNotification(node: NodeEntity) {
|
||||||
|
@ -187,6 +191,21 @@ class MeshServiceNotifications(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun openMessageIntent(contactKey: String, contactName: String): PendingIntent {
|
||||||
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
|
intent.action = OPEN_MESSAGE_ACTION
|
||||||
|
intent.putExtra(OPEN_MESSAGE_EXTRA_CONTACT_KEY, contactKey)
|
||||||
|
intent.putExtra(OPEN_MESSAGE_EXTRA_CONTACT_NAME, contactName)
|
||||||
|
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntentCompat.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
return pendingIntent
|
||||||
|
}
|
||||||
|
|
||||||
private fun commonBuilder(channel: String): NotificationCompat.Builder {
|
private fun commonBuilder(channel: String): NotificationCompat.Builder {
|
||||||
val builder = NotificationCompat.Builder(context, channel)
|
val builder = NotificationCompat.Builder(context, channel)
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
@ -246,22 +265,19 @@ class MeshServiceNotifications(
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var messageNotificationBuilder: NotificationCompat.Builder
|
lateinit var messageNotificationBuilder: NotificationCompat.Builder
|
||||||
private fun createMessageNotification(name: String, message: String): Notification {
|
private fun createMessageNotification(contactKey: String, name: String, message: String): Notification {
|
||||||
if (!::messageNotificationBuilder.isInitialized) {
|
if (!::messageNotificationBuilder.isInitialized) {
|
||||||
messageNotificationBuilder = commonBuilder(messageChannelId)
|
messageNotificationBuilder = commonBuilder(messageChannelId)
|
||||||
}
|
}
|
||||||
|
val person = Person.Builder().setName(name).build()
|
||||||
with(messageNotificationBuilder) {
|
with(messageNotificationBuilder) {
|
||||||
|
setContentIntent(openMessageIntent(contactKey, name))
|
||||||
priority = NotificationCompat.PRIORITY_DEFAULT
|
priority = NotificationCompat.PRIORITY_DEFAULT
|
||||||
setCategory(Notification.CATEGORY_MESSAGE)
|
setCategory(Notification.CATEGORY_MESSAGE)
|
||||||
setAutoCancel(true)
|
setAutoCancel(true)
|
||||||
setContentTitle(name)
|
|
||||||
setContentText(message)
|
|
||||||
setStyle(
|
setStyle(
|
||||||
NotificationCompat.BigTextStyle()
|
NotificationCompat.MessagingStyle(person).addMessage(message, System.currentTimeMillis(), person)
|
||||||
.bigText(message),
|
|
||||||
)
|
)
|
||||||
setWhen(System.currentTimeMillis())
|
|
||||||
setShowWhen(true)
|
|
||||||
}
|
}
|
||||||
return messageNotificationBuilder.build()
|
return messageNotificationBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue