mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: replace user with node in Message model
This commit is contained in:
parent
746f155a99
commit
4a1319a645
7 changed files with 52 additions and 29 deletions
|
|
@ -190,7 +190,7 @@ data class DataPacket(
|
|||
const val PKC_CHANNEL_INDEX = 8
|
||||
|
||||
fun nodeNumToDefaultId(n: Int): String = "!%08x".format(n)
|
||||
fun idToDefaultNodeNum(id: String?): Int? = id?.toLong(16)?.toInt()
|
||||
fun idToDefaultNodeNum(id: String?): Int? = runCatching { id?.toLong(16)?.toInt() }.getOrNull()
|
||||
|
||||
override fun createFromParcel(parcel: Parcel): DataPacket {
|
||||
return DataPacket(parcel)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,12 @@ class NodeRepository @Inject constructor(
|
|||
.conflate()
|
||||
.stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, emptyMap())
|
||||
|
||||
fun getNode(userId: String): NodeEntity = nodeDBbyNum.value.values.find { it.user.id == userId }
|
||||
?: NodeEntity(
|
||||
num = DataPacket.idToDefaultNodeNum(userId) ?: 0,
|
||||
user = getUser(userId),
|
||||
)
|
||||
|
||||
fun getUser(nodeNum: Int): MeshProtos.User = getUser(DataPacket.nodeNumToDefaultId(nodeNum))
|
||||
|
||||
fun getUser(userId: String): MeshProtos.User =
|
||||
|
|
|
|||
|
|
@ -33,18 +33,18 @@ data class PacketEntity(
|
|||
@Relation(entity = ReactionEntity::class, parentColumn = "packet_id", entityColumn = "reply_id")
|
||||
val reactions: List<ReactionEntity> = emptyList(),
|
||||
) {
|
||||
suspend fun toMessage(getUser: suspend (userId: String?) -> User) = with(packet) {
|
||||
suspend fun toMessage(getNode: suspend (userId: String?) -> NodeEntity) = with(packet) {
|
||||
Message(
|
||||
uuid = uuid,
|
||||
receivedTime = received_time,
|
||||
user = getUser(data.from),
|
||||
node = getNode(data.from),
|
||||
text = data.text.orEmpty(),
|
||||
time = getShortDateTime(data.time),
|
||||
read = read,
|
||||
status = data.status,
|
||||
routingError = routingError,
|
||||
packetId = packetId,
|
||||
emojis = reactions.toReaction(getUser),
|
||||
emojis = reactions.toReaction(getNode),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -101,14 +101,14 @@ data class ReactionEntity(
|
|||
)
|
||||
|
||||
private suspend fun ReactionEntity.toReaction(
|
||||
getUser: suspend (userId: String?) -> User
|
||||
getNode: suspend (userId: String?) -> NodeEntity
|
||||
) = Reaction(
|
||||
replyId = replyId,
|
||||
user = getUser(userId),
|
||||
user = getNode(userId).user,
|
||||
emoji = emoji,
|
||||
timestamp = timestamp,
|
||||
)
|
||||
|
||||
private suspend fun List<ReactionEntity>.toReaction(
|
||||
getUser: suspend (userId: String?) -> User
|
||||
) = this.map { it.toReaction(getUser) }
|
||||
getNode: suspend (userId: String?) -> NodeEntity
|
||||
) = this.map { it.toReaction(getNode) }
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@
|
|||
package com.geeksville.mesh.model
|
||||
|
||||
import com.geeksville.mesh.MeshProtos.Routing
|
||||
import com.geeksville.mesh.MeshProtos.User
|
||||
import com.geeksville.mesh.MessageStatus
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.database.entity.NodeEntity
|
||||
import com.geeksville.mesh.database.entity.Reaction
|
||||
|
||||
val Routing.Error.stringRes: Int
|
||||
|
|
@ -47,7 +47,7 @@ val Routing.Error.stringRes: Int
|
|||
data class Message(
|
||||
val uuid: Long,
|
||||
val receivedTime: Long,
|
||||
val user: User,
|
||||
val node: NodeEntity,
|
||||
val text: String,
|
||||
val time: String,
|
||||
val read: Boolean,
|
||||
|
|
|
|||
|
|
@ -255,6 +255,7 @@ class UIViewModel @Inject constructor(
|
|||
get() = preferences.getInt(MAP_STYLE_ID, 0)
|
||||
set(value) = preferences.edit { putInt(MAP_STYLE_ID, value) }
|
||||
|
||||
fun getNode(userId: String?) = nodeDB.getNode(userId ?: DataPacket.ID_BROADCAST)
|
||||
fun getUser(userId: String?) = nodeDB.getUser(userId ?: DataPacket.ID_BROADCAST)
|
||||
|
||||
private val _snackbarText = MutableLiveData<Any?>(null)
|
||||
|
|
@ -330,7 +331,7 @@ class UIViewModel @Inject constructor(
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun getMessagesFrom(contactKey: String) = packetRepository.getMessagesFrom(contactKey)
|
||||
.mapLatest { list -> list.map { it.toMessage(::getUser) } }
|
||||
.mapLatest { list -> list.map { it.toMessage(::getNode) } }
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val waypoints = packetRepository.getWaypoints().mapLatest { list ->
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Chip
|
||||
import androidx.compose.material.ChipDefaults
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LocalContentColor
|
||||
|
|
@ -55,16 +56,19 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.geeksville.mesh.DataPacket
|
||||
import com.geeksville.mesh.MessageStatus
|
||||
import com.geeksville.mesh.R
|
||||
import com.geeksville.mesh.database.entity.NodeEntity
|
||||
import com.geeksville.mesh.ui.components.AutoLinkText
|
||||
import com.geeksville.mesh.ui.preview.NodeEntityPreviewParameterProvider
|
||||
import com.geeksville.mesh.ui.theme.AppTheme
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun MessageItem(
|
||||
shortName: String?,
|
||||
node: NodeEntity,
|
||||
messageText: String?,
|
||||
messageTime: String,
|
||||
messageStatus: MessageStatus?,
|
||||
|
|
@ -81,7 +85,7 @@ internal fun MessageItem(
|
|||
.background(color = if (selected) Color.Gray else MaterialTheme.colors.background),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val fromLocal = shortName == null
|
||||
val fromLocal = node.user.id == DataPacket.ID_LOCAL
|
||||
val messageColor = if (fromLocal) R.color.colorMyMsg else R.color.colorMsg
|
||||
val (topStart, topEnd) = if (fromLocal) 12.dp to 4.dp else 4.dp to 12.dp
|
||||
val messageModifier = if (fromLocal) {
|
||||
|
|
@ -110,15 +114,19 @@ internal fun MessageItem(
|
|||
.padding(horizontal = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
if (shortName != null) {
|
||||
if (!fromLocal) {
|
||||
Chip(
|
||||
onClick = onChipClick,
|
||||
modifier = Modifier
|
||||
.padding(end = 8.dp)
|
||||
.width(72.dp),
|
||||
colors = ChipDefaults.chipColors(
|
||||
backgroundColor = Color(node.colors.second),
|
||||
contentColor = Color(node.colors.first),
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = shortName,
|
||||
text = node.user.shortName,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
fontSize = MaterialTheme.typography.button.fontSize,
|
||||
fontWeight = FontWeight.Normal,
|
||||
|
|
@ -129,11 +137,14 @@ internal fun MessageItem(
|
|||
Column(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
) {
|
||||
// Text(
|
||||
// text = longName ?: stringResource(id = R.string.unknown_username),
|
||||
// color = MaterialTheme.colors.onSurface,
|
||||
// fontSize = MaterialTheme.typography.button.fontSize,
|
||||
// )
|
||||
// if (!fromLocal) {
|
||||
// Text(
|
||||
// text = with(node.user) { "$longName ($id)" },
|
||||
// modifier = Modifier.padding(bottom = 4.dp),
|
||||
// color = MaterialTheme.colors.onSurface,
|
||||
// fontSize = MaterialTheme.typography.caption.fontSize,
|
||||
// )
|
||||
// }
|
||||
AutoLinkText(
|
||||
text = messageText.orEmpty(),
|
||||
style = LocalTextStyle.current.copy(
|
||||
|
|
@ -181,8 +192,7 @@ internal fun MessageItem(
|
|||
private fun MessageItemPreview() {
|
||||
AppTheme {
|
||||
MessageItem(
|
||||
shortName = stringResource(R.string.some_username),
|
||||
// longName = stringResource(R.string.unknown_username),
|
||||
node = NodeEntityPreviewParameterProvider().values.first(),
|
||||
messageText = stringResource(R.string.sample_message),
|
||||
messageTime = "10:00",
|
||||
messageStatus = MessageStatus.DELIVERED,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import com.geeksville.mesh.DataPacket
|
||||
import com.geeksville.mesh.database.entity.Reaction
|
||||
import com.geeksville.mesh.model.Message
|
||||
|
|
@ -50,6 +52,7 @@ internal fun MessageList(
|
|||
onSendReaction: (String, Int) -> Unit,
|
||||
onClick: (Message) -> Unit = {}
|
||||
) {
|
||||
val haptics = LocalHapticFeedback.current
|
||||
val inSelectionMode by remember { derivedStateOf { selectedIds.value.isNotEmpty() } }
|
||||
val listState = rememberLazyListState(
|
||||
initialFirstVisibleItemIndex = messages.indexOfLast { !it.read }.coerceAtLeast(0)
|
||||
|
|
@ -70,10 +73,10 @@ internal fun MessageList(
|
|||
ReactionDialog(reactions) { showReactionDialog = null }
|
||||
}
|
||||
|
||||
fun toggle(uuid: Long) = if (selectedIds.value.contains(uuid)) {
|
||||
selectedIds.value -= uuid
|
||||
fun MutableState<Set<Long>>.toggle(uuid: Long) = if (value.contains(uuid)) {
|
||||
value -= uuid
|
||||
} else {
|
||||
selectedIds.value += uuid
|
||||
value += uuid
|
||||
}
|
||||
|
||||
LazyColumn(
|
||||
|
|
@ -83,18 +86,21 @@ internal fun MessageList(
|
|||
contentPadding = contentPadding
|
||||
) {
|
||||
items(messages, key = { it.uuid }) { msg ->
|
||||
val fromLocal = msg.user.id == DataPacket.ID_LOCAL
|
||||
val fromLocal = msg.node.user.id == DataPacket.ID_LOCAL
|
||||
val selected by remember { derivedStateOf { selectedIds.value.contains(msg.uuid) } }
|
||||
|
||||
ReactionRow(fromLocal, msg.emojis) { showReactionDialog = msg.emojis }
|
||||
MessageItem(
|
||||
shortName = msg.user.shortName.takeIf { !fromLocal },
|
||||
node = msg.node,
|
||||
messageText = msg.text,
|
||||
messageTime = msg.time,
|
||||
messageStatus = msg.status,
|
||||
selected = selected,
|
||||
onClick = { if (inSelectionMode) toggle(msg.uuid) },
|
||||
onLongClick = { toggle(msg.uuid) },
|
||||
onClick = { if (inSelectionMode) selectedIds.toggle(msg.uuid) },
|
||||
onLongClick = {
|
||||
selectedIds.toggle(msg.uuid)
|
||||
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
},
|
||||
onChipClick = { onClick(msg) },
|
||||
onStatusClick = { showStatusDialog = msg },
|
||||
onSendReaction = { onSendReaction(it, msg.packetId) },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue