mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor messages to Room database
This commit is contained in:
parent
ab7bf4922b
commit
65e982ddd5
12 changed files with 191 additions and 279 deletions
|
|
@ -1,152 +0,0 @@
|
|||
package com.geeksville.mesh.model
|
||||
|
||||
import android.os.RemoteException
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.DataPacket
|
||||
import com.geeksville.mesh.MessageStatus
|
||||
|
||||
|
||||
class MessagesState(private val ui: UIViewModel) : Logging {
|
||||
/* We now provide fake messages a via MockInterface
|
||||
private val testTexts = listOf(
|
||||
DataPacket(
|
||||
"+16508765310",
|
||||
"I found the cache"
|
||||
),
|
||||
DataPacket(
|
||||
"+16508765311",
|
||||
"Help! I've fallen and I can't get up."
|
||||
)
|
||||
) */
|
||||
|
||||
/// This is the inner storage for messages
|
||||
private val messagesList = emptyList<DataPacket>().toMutableList()
|
||||
|
||||
// If the following (unused otherwise) line is commented out, the IDE preview window works.
|
||||
// if left in the preview always renders as empty.
|
||||
val messages =
|
||||
object : MutableLiveData<List<DataPacket>>(messagesList) {
|
||||
|
||||
}
|
||||
|
||||
private var contactsList = emptyMap<String?, DataPacket>().toMutableMap()
|
||||
val contacts = object : MutableLiveData<MutableMap<String?, DataPacket>>() {
|
||||
|
||||
}
|
||||
|
||||
private fun emptyDataPacket(to: String? = DataPacket.ID_BROADCAST): DataPacket {
|
||||
return DataPacket(to, null, 1, DataPacket.ID_LOCAL, 0L)
|
||||
}
|
||||
|
||||
// Map each contactId to last DataPacket message sent or received
|
||||
// Broadcast: it.to == DataPacket.ID_BROADCAST; Direct Messages: it.to != DataPacket.ID_BROADCAST
|
||||
private fun buildContacts() {
|
||||
contactsList = messagesList.associateBy {
|
||||
if (it.from == DataPacket.ID_LOCAL || it.to == DataPacket.ID_BROADCAST)
|
||||
it.to else it.from
|
||||
}.toMutableMap()
|
||||
|
||||
val all = DataPacket.ID_BROADCAST // always show contacts, even when empty
|
||||
if (contactsList[all] == null)
|
||||
contactsList[all] = emptyDataPacket()
|
||||
|
||||
contacts.value = contactsList
|
||||
}
|
||||
|
||||
fun setMessages(m: List<DataPacket>) {
|
||||
messagesList.clear()
|
||||
messagesList.addAll(m)
|
||||
messages.value = messagesList
|
||||
buildContacts()
|
||||
}
|
||||
|
||||
/// add a message our GUI list of past msgs
|
||||
fun addMessage(m: DataPacket) {
|
||||
debug("Adding message to view id=${m.id}")
|
||||
// FIXME - don't just slam in a new list each time, it probably causes extra drawing.
|
||||
|
||||
messagesList.add(m)
|
||||
|
||||
messages.value = messagesList
|
||||
buildContacts()
|
||||
}
|
||||
|
||||
private fun removeMessages(deleteList: List<DataPacket>) {
|
||||
debug("Removing ${deleteList.size} messages from view")
|
||||
|
||||
messagesList.removeAll(deleteList)
|
||||
messages.value = messagesList
|
||||
buildContacts()
|
||||
}
|
||||
|
||||
private fun removeAllMessages() {
|
||||
debug("Removing all messages")
|
||||
|
||||
messagesList.clear()
|
||||
messages.value = messagesList
|
||||
buildContacts()
|
||||
}
|
||||
|
||||
fun updateStatus(id: Int, status: MessageStatus) {
|
||||
// Super inefficent but this is rare
|
||||
debug("Handling message status change $id: $status")
|
||||
|
||||
messagesList.find { it.id == id }?.let { p ->
|
||||
// Note: it seems that the service is keeping only a reference to our original packet (so it has already updated p.status)
|
||||
// This seems to be an AIDL optimization when both the service and the client are in the same process. But we still want to trigger
|
||||
// a GUI update
|
||||
// if (p.status != status) {
|
||||
p.status = status
|
||||
// Trigger an expensive complete redraw FIXME
|
||||
messages.value = messagesList
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a message and added it to our GUI log
|
||||
fun sendMessage(str: String, dest: String = DataPacket.ID_BROADCAST) {
|
||||
|
||||
val service = ui.meshService
|
||||
val p = DataPacket(dest, str)
|
||||
|
||||
if (service != null)
|
||||
try {
|
||||
service.send(p)
|
||||
} catch (ex: RemoteException) {
|
||||
p.errorMessage = "Error: ${ex.message}"
|
||||
}
|
||||
else
|
||||
p.errorMessage = "Error: No Mesh service"
|
||||
|
||||
// FIXME - why is the first time we are called p is already in the list at this point?
|
||||
addMessage(p)
|
||||
}
|
||||
|
||||
fun deleteMessages(deleteList: List<DataPacket>) {
|
||||
val service = ui.meshService
|
||||
|
||||
if (service != null) {
|
||||
try {
|
||||
service.deleteMessages(deleteList)
|
||||
} catch (ex: RemoteException) {
|
||||
debug("Error: ${ex.message}")
|
||||
}
|
||||
} else {
|
||||
debug("Error: No Mesh service")
|
||||
}
|
||||
removeMessages(deleteList)
|
||||
}
|
||||
|
||||
fun deleteAllMessages() {
|
||||
val service = ui.meshService
|
||||
if (service != null) {
|
||||
try {
|
||||
service.deleteAllMessages()
|
||||
} catch (ex: RemoteException) {
|
||||
errormsg("Error: ${ex.message}")
|
||||
}
|
||||
removeAllMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import androidx.core.content.edit
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.*
|
||||
|
|
@ -28,9 +29,12 @@ import com.geeksville.mesh.util.GPSFormat
|
|||
import com.geeksville.mesh.util.positionToMeter
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedWriter
|
||||
|
|
@ -98,8 +102,8 @@ class UIViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
packetRepository.getAll().collect { meshPackets ->
|
||||
_packets.value = meshPackets
|
||||
packetRepository.getAllPackets().collect { packets ->
|
||||
_packets.value = packets
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
|
|
@ -120,10 +124,53 @@ class UIViewModel @Inject constructor(
|
|||
debug("ViewModel created")
|
||||
}
|
||||
|
||||
private val contactKey: MutableStateFlow<String> = MutableStateFlow(DataPacket.ID_BROADCAST)
|
||||
fun setContactKey(contact: String) {
|
||||
contactKey.value = contact
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val messages: LiveData<List<Packet>> = contactKey.flatMapLatest { contactKey ->
|
||||
packetRepository.getMessagesFrom(contactKey)
|
||||
}.asLiveData()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val contacts: LiveData<Map<String, Packet>> = _packets.mapLatest { list ->
|
||||
list.associateBy { packet -> packet.contact_key }
|
||||
.filter { it.value.port_num == Portnums.PortNum.TEXT_MESSAGE_APP_VALUE }
|
||||
}.asLiveData()
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val waypoints: LiveData<Map<Int?, Packet>> = _packets.mapLatest { list ->
|
||||
list.associateBy { packet -> packet.data.waypoint?.id }
|
||||
.filter { it.value.port_num == Portnums.PortNum.WAYPOINT_APP_VALUE }
|
||||
}.asLiveData()
|
||||
|
||||
fun sendMessage(str: String, channel: Int = 0, dest: String = DataPacket.ID_BROADCAST) {
|
||||
val p = DataPacket(dest, channel, str)
|
||||
sendDataPacket(p)
|
||||
}
|
||||
|
||||
fun sendDataPacket(p: DataPacket) {
|
||||
try {
|
||||
meshService?.send(p)
|
||||
} catch (ex: RemoteException) {
|
||||
errormsg("Send DataPacket error: ${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteAllLogs() = viewModelScope.launch(Dispatchers.IO) {
|
||||
meshLogRepository.deleteAll()
|
||||
}
|
||||
|
||||
fun deleteAllMessages() = viewModelScope.launch(Dispatchers.IO) {
|
||||
packetRepository.deleteAllMessages()
|
||||
}
|
||||
|
||||
fun deleteMessages(uuidList: List<Long>) = viewModelScope.launch(Dispatchers.IO) {
|
||||
packetRepository.deleteMessages(uuidList)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getPreferences(context: Context): SharedPreferences =
|
||||
context.getSharedPreferences("ui-prefs", Context.MODE_PRIVATE)
|
||||
|
|
@ -134,7 +181,6 @@ class UIViewModel @Inject constructor(
|
|||
var meshService: IMeshService? = null
|
||||
|
||||
val nodeDB = NodeDB(this)
|
||||
val messagesState = MessagesState(this)
|
||||
|
||||
/// Connection state to our radio device
|
||||
private val _connectionState = MutableLiveData(MeshService.ConnectionState.DISCONNECTED)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue