mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: Integrate notification management and preferences across platforms (#4819)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
0b2e89c46f
commit
8c964a15ca
45 changed files with 1304 additions and 61 deletions
|
|
@ -19,10 +19,14 @@ package org.meshtastic.core.data.manager
|
|||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.repository.FromRadioPacketHandler
|
||||
import org.meshtastic.core.repository.MeshRouter
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.MqttManager
|
||||
import org.meshtastic.core.repository.Notification
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.client_notification
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.proto.FromRadio
|
||||
|
||||
/** Implementation of [FromRadioPacketHandler] that dispatches [FromRadio] variants to specialized handlers. */
|
||||
|
|
@ -32,7 +36,7 @@ class FromRadioPacketHandlerImpl(
|
|||
private val router: Lazy<MeshRouter>,
|
||||
private val mqttManager: MqttManager,
|
||||
private val packetHandler: PacketHandler,
|
||||
private val serviceNotifications: MeshServiceNotifications,
|
||||
private val notificationManager: NotificationManager,
|
||||
) : FromRadioPacketHandler {
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
override fun handleFromRadio(proto: FromRadio) {
|
||||
|
|
@ -62,7 +66,13 @@ class FromRadioPacketHandlerImpl(
|
|||
channel != null -> router.value.configHandler.handleChannel(channel)
|
||||
clientNotification != null -> {
|
||||
serviceRepository.setClientNotification(clientNotification)
|
||||
serviceNotifications.showClientNotification(clientNotification)
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getString(Res.string.client_notification),
|
||||
message = clientNotification.message,
|
||||
category = Notification.Category.Alert,
|
||||
),
|
||||
)
|
||||
packetHandler.removeResponse(0, complete = false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ import org.meshtastic.core.repository.MeshActionHandler
|
|||
import org.meshtastic.core.repository.MeshDataHandler
|
||||
import org.meshtastic.core.repository.MeshMessageProcessor
|
||||
import org.meshtastic.core.repository.MeshPrefs
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
|
|
@ -61,7 +61,7 @@ class MeshActionHandlerImpl(
|
|||
private val analytics: PlatformAnalytics,
|
||||
private val meshPrefs: MeshPrefs,
|
||||
private val databaseManager: DatabaseManager,
|
||||
private val serviceNotifications: MeshServiceNotifications,
|
||||
private val notificationManager: NotificationManager,
|
||||
private val messageProcessor: Lazy<MeshMessageProcessor>,
|
||||
) : MeshActionHandler {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
|
@ -346,7 +346,7 @@ class MeshActionHandlerImpl(
|
|||
nodeManager.clear()
|
||||
messageProcessor.value.clearEarlyPackets()
|
||||
databaseManager.switchActiveDatabase(deviceAddr)
|
||||
serviceNotifications.clearNotifications()
|
||||
notificationManager.cancelAll()
|
||||
nodeManager.loadCachedNodeDB()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ import org.meshtastic.core.repository.MeshServiceNotifications
|
|||
import org.meshtastic.core.repository.MessageFilter
|
||||
import org.meshtastic.core.repository.NeighborInfoHandler
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.Notification
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
|
|
@ -62,6 +64,8 @@ import org.meshtastic.core.resources.Res
|
|||
import org.meshtastic.core.resources.critical_alert
|
||||
import org.meshtastic.core.resources.error_duty_cycle
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.low_battery_message
|
||||
import org.meshtastic.core.resources.low_battery_title
|
||||
import org.meshtastic.core.resources.unknown_username
|
||||
import org.meshtastic.core.resources.waypoint_received
|
||||
import org.meshtastic.proto.AdminMessage
|
||||
|
|
@ -96,6 +100,7 @@ class MeshDataHandlerImpl(
|
|||
private val serviceRepository: ServiceRepository,
|
||||
private val packetRepository: Lazy<PacketRepository>,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
private val notificationManager: NotificationManager,
|
||||
private val serviceNotifications: MeshServiceNotifications,
|
||||
private val analytics: PlatformAnalytics,
|
||||
private val dataMapper: MeshDataMapper,
|
||||
|
|
@ -396,6 +401,7 @@ class MeshDataHandlerImpl(
|
|||
rememberDataPacket(dataPacket, myNodeNum)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun handleTelemetry(packet: MeshPacket, dataPacket: DataPacket, myNodeNum: Int) {
|
||||
val payload = packet.decoded?.payload ?: return
|
||||
val t =
|
||||
|
|
@ -425,7 +431,18 @@ class MeshDataHandlerImpl(
|
|||
) {
|
||||
scope.launch {
|
||||
if (shouldBatteryNotificationShow(fromNum, t, myNodeNum)) {
|
||||
serviceNotifications.showOrUpdateLowBatteryNotification(nextNode, isRemote)
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getString(Res.string.low_battery_title, nextNode.user.short_name),
|
||||
message =
|
||||
getString(
|
||||
Res.string.low_battery_message,
|
||||
nextNode.user.long_name,
|
||||
nextNode.deviceMetrics.battery_level ?: 0,
|
||||
),
|
||||
category = Notification.Category.Battery,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -435,7 +452,7 @@ class MeshDataHandlerImpl(
|
|||
batteryPercentCooldowns.remove(fromNum)
|
||||
}
|
||||
}
|
||||
serviceNotifications.cancelLowBatteryNotification(nextNode)
|
||||
notificationManager.cancel(nextNode.num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -642,10 +659,13 @@ class MeshDataHandlerImpl(
|
|||
val nodeMuted = nodeManager.nodeDBbyID[dataPacket.from]?.isMuted == true
|
||||
val isSilent = conversationMuted || nodeMuted
|
||||
if (dataPacket.dataType == PortNum.ALERT_APP.value && !isSilent) {
|
||||
serviceNotifications.showAlertNotification(
|
||||
contactKey,
|
||||
getSenderName(dataPacket),
|
||||
dataPacket.alert ?: getString(Res.string.critical_alert),
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getSenderName(dataPacket),
|
||||
message = dataPacket.alert ?: getString(Res.string.critical_alert),
|
||||
category = Notification.Category.Alert,
|
||||
contactKey = contactKey,
|
||||
),
|
||||
)
|
||||
} else if (updateNotification && !isSilent) {
|
||||
scope.handledLaunch { updateNotification(contactKey, dataPacket, isSilent) }
|
||||
|
|
@ -682,12 +702,14 @@ class MeshDataHandlerImpl(
|
|||
|
||||
PortNum.WAYPOINT_APP.value -> {
|
||||
val message = getString(Res.string.waypoint_received, dataPacket.waypoint!!.name)
|
||||
serviceNotifications.updateWaypointNotification(
|
||||
contactKey,
|
||||
getSenderName(dataPacket),
|
||||
message,
|
||||
dataPacket.waypoint!!.id,
|
||||
isSilent,
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getSenderName(dataPacket),
|
||||
message = message,
|
||||
category = Notification.Category.Message,
|
||||
contactKey = contactKey,
|
||||
isSilent = isSilent,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,14 @@ import org.meshtastic.core.model.Node
|
|||
import org.meshtastic.core.model.NodeInfo
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.model.util.NodeIdLookup
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.Notification
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.core.resources.new_node_seen
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.Paxcount
|
||||
|
|
@ -56,7 +60,7 @@ import org.meshtastic.proto.Position as ProtoPosition
|
|||
class NodeManagerImpl(
|
||||
private val nodeRepository: NodeRepository,
|
||||
private val serviceBroadcasts: ServiceBroadcasts,
|
||||
private val serviceNotifications: MeshServiceNotifications,
|
||||
private val notificationManager: NotificationManager,
|
||||
) : NodeManager {
|
||||
private var scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
|
|
@ -192,7 +196,13 @@ class NodeManagerImpl(
|
|||
node.copy(user = newUser, channel = channel, manuallyVerified = manuallyVerified)
|
||||
}
|
||||
if (newNode && !shouldPreserve) {
|
||||
serviceNotifications.showNewNodeSeenNotification(next)
|
||||
notificationManager.dispatch(
|
||||
Notification(
|
||||
title = getString(Res.string.new_node_seen, next.user.short_name),
|
||||
message = next.user.long_name,
|
||||
category = Notification.Category.NodeEvent,
|
||||
),
|
||||
)
|
||||
}
|
||||
next
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,16 @@ package org.meshtastic.core.data.manager
|
|||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.meshtastic.core.repository.MeshRouter
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.MqttManager
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.proto.ClientNotification
|
||||
import org.meshtastic.proto.Config
|
||||
import org.meshtastic.proto.DeviceMetadata
|
||||
|
|
@ -39,19 +41,23 @@ class FromRadioPacketHandlerImplTest {
|
|||
private val router: MeshRouter = mockk(relaxed = true)
|
||||
private val mqttManager: MqttManager = mockk(relaxed = true)
|
||||
private val packetHandler: PacketHandler = mockk(relaxed = true)
|
||||
private val serviceNotifications: MeshServiceNotifications = mockk(relaxed = true)
|
||||
private val notificationManager: NotificationManager = mockk(relaxed = true)
|
||||
|
||||
private lateinit var handler: FromRadioPacketHandlerImpl
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkStatic("org.meshtastic.core.resources.GetStringKt")
|
||||
every { getString(any()) } returns "test string"
|
||||
every { getString(any(), *anyVararg()) } returns "test string"
|
||||
|
||||
handler =
|
||||
FromRadioPacketHandlerImpl(
|
||||
serviceRepository,
|
||||
lazy { router },
|
||||
mqttManager,
|
||||
packetHandler,
|
||||
serviceNotifications,
|
||||
notificationManager,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +132,7 @@ class FromRadioPacketHandlerImplTest {
|
|||
handler.handleFromRadio(proto)
|
||||
|
||||
verify { serviceRepository.setClientNotification(notification) }
|
||||
verify { serviceNotifications.showClientNotification(notification) }
|
||||
verify { notificationManager.dispatch(any()) }
|
||||
verify { packetHandler.removeResponse(0, complete = false) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.meshtastic.core.repository.MeshServiceNotifications
|
|||
import org.meshtastic.core.repository.MessageFilter
|
||||
import org.meshtastic.core.repository.NeighborInfoHandler
|
||||
import org.meshtastic.core.repository.NodeManager
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.PacketHandler
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.PlatformAnalytics
|
||||
|
|
@ -58,6 +59,7 @@ class MeshDataHandlerTest {
|
|||
private val packetRepository: PacketRepository = mockk(relaxed = true)
|
||||
private val packetRepositoryLazy: Lazy<PacketRepository> = lazy { packetRepository }
|
||||
private val serviceBroadcasts: ServiceBroadcasts = mockk(relaxed = true)
|
||||
private val notificationManager: NotificationManager = mockk(relaxed = true)
|
||||
private val serviceNotifications: MeshServiceNotifications = mockk(relaxed = true)
|
||||
private val analytics: PlatformAnalytics = mockk(relaxed = true)
|
||||
private val dataMapper: MeshDataMapper = mockk(relaxed = true)
|
||||
|
|
@ -86,6 +88,7 @@ class MeshDataHandlerTest {
|
|||
serviceRepository,
|
||||
packetRepositoryLazy,
|
||||
serviceBroadcasts,
|
||||
notificationManager,
|
||||
serviceNotifications,
|
||||
analytics,
|
||||
dataMapper,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
*/
|
||||
package org.meshtastic.core.data.manager
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
|
|
@ -24,9 +26,10 @@ import org.junit.Assert.assertTrue
|
|||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.NotificationManager
|
||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||
import org.meshtastic.core.resources.getString
|
||||
import org.meshtastic.proto.HardwareModel
|
||||
import org.meshtastic.proto.Position
|
||||
import org.meshtastic.proto.User
|
||||
|
|
@ -35,13 +38,17 @@ class NodeManagerImplTest {
|
|||
|
||||
private val nodeRepository: NodeRepository = mockk(relaxed = true)
|
||||
private val serviceBroadcasts: ServiceBroadcasts = mockk(relaxed = true)
|
||||
private val serviceNotifications: MeshServiceNotifications = mockk(relaxed = true)
|
||||
private val notificationManager: NotificationManager = mockk(relaxed = true)
|
||||
|
||||
private lateinit var nodeManager: NodeManagerImpl
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
nodeManager = NodeManagerImpl(nodeRepository, serviceBroadcasts, serviceNotifications)
|
||||
mockkStatic("org.meshtastic.core.resources.GetStringKt")
|
||||
every { getString(any()) } returns "test string"
|
||||
every { getString(any(), *anyVararg()) } returns "test string"
|
||||
|
||||
nodeManager = NodeManagerImpl(nodeRepository, serviceBroadcasts, notificationManager)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue