kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
feat: Initial implementation of adding nodes to favorites (#1520)
* Implement initial support for adding and removing nodes from favorites * Make favorite nodes' names show up bold in the node list * Forgot to add this here when I was fixing the previous merge conflicts. Whoops! * Make detekt happy --------- Co-authored-by: James Rich <2199651+jamesarich@users.noreply.github.com>pull/1575/head^2
rodzic
584fe8d6f8
commit
e15ad23c46
|
@ -485,6 +485,14 @@ class UIViewModel @Inject constructor(
|
||||||
updateLoraConfig { it.copy { region = value } }
|
updateLoraConfig { it.copy { region = value } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun favoriteNode(node: Node) = viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
radioConfigRepository.onServiceAction(ServiceAction.Favorite(node))
|
||||||
|
} catch (ex: RemoteException) {
|
||||||
|
errormsg("Favorite node error:", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ignoreNode(node: Node) = viewModelScope.launch {
|
fun ignoreNode(node: Node) = viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
radioConfigRepository.onServiceAction(ServiceAction.Ignore(node))
|
radioConfigRepository.onServiceAction(ServiceAction.Ignore(node))
|
||||||
|
|
|
@ -106,6 +106,7 @@ import kotlin.math.absoluteValue
|
||||||
|
|
||||||
sealed class ServiceAction {
|
sealed class ServiceAction {
|
||||||
data class GetDeviceMetadata(val destNum: Int) : ServiceAction()
|
data class GetDeviceMetadata(val destNum: Int) : ServiceAction()
|
||||||
|
data class Favorite(val node: Node) : ServiceAction()
|
||||||
data class Ignore(val node: Node) : ServiceAction()
|
data class Ignore(val node: Node) : ServiceAction()
|
||||||
data class Reaction(val emoji: String, val replyId: Int, val contactKey: String) : ServiceAction()
|
data class Reaction(val emoji: String, val replyId: Int, val contactKey: String) : ServiceAction()
|
||||||
}
|
}
|
||||||
|
@ -1791,6 +1792,7 @@ class MeshService : Service(), Logging {
|
||||||
private fun onServiceAction(action: ServiceAction) {
|
private fun onServiceAction(action: ServiceAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is ServiceAction.GetDeviceMetadata -> getDeviceMetadata(action.destNum)
|
is ServiceAction.GetDeviceMetadata -> getDeviceMetadata(action.destNum)
|
||||||
|
is ServiceAction.Favorite -> favoriteNode(action.node)
|
||||||
is ServiceAction.Ignore -> ignoreNode(action.node)
|
is ServiceAction.Ignore -> ignoreNode(action.node)
|
||||||
is ServiceAction.Reaction -> sendReaction(action)
|
is ServiceAction.Reaction -> sendReaction(action)
|
||||||
}
|
}
|
||||||
|
@ -1802,6 +1804,21 @@ class MeshService : Service(), Logging {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun favoriteNode(node: Node) = toRemoteExceptions {
|
||||||
|
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket {
|
||||||
|
if (node.isFavorite) {
|
||||||
|
debug("removing node ${node.num} from favorite list")
|
||||||
|
removeFavoriteNode = node.num
|
||||||
|
} else {
|
||||||
|
debug("adding node ${node.num} to favorite list")
|
||||||
|
setFavoriteNode = node.num
|
||||||
|
}
|
||||||
|
})
|
||||||
|
updateNodeInfo(node.num) {
|
||||||
|
it.isFavorite = !node.isFavorite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun ignoreNode(node: Node) = toRemoteExceptions {
|
private fun ignoreNode(node: Node) = toRemoteExceptions {
|
||||||
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket {
|
sendToRadio(newMeshPacketTo(myNodeNum).buildAdminPacket {
|
||||||
if (node.isIgnored) {
|
if (node.isIgnored) {
|
||||||
|
|
|
@ -84,6 +84,7 @@ fun NodeItem(
|
||||||
currentTimeMillis: Long,
|
currentTimeMillis: Long,
|
||||||
isConnected: Boolean = false,
|
isConnected: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
val isFavorite = thatNode.isFavorite
|
||||||
val isIgnored = thatNode.isIgnored
|
val isIgnored = thatNode.isIgnored
|
||||||
val longName = thatNode.user.longName.ifEmpty { stringResource(id = R.string.unknown_username) }
|
val longName = thatNode.user.longName.ifEmpty { stringResource(id = R.string.unknown_username) }
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ fun NodeItem(
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = thatNode.user.shortName.ifEmpty { "???" },
|
text = thatNode.user.shortName.ifEmpty { "???" },
|
||||||
fontWeight = FontWeight.Normal,
|
fontWeight = if (isFavorite) FontWeight.Bold else FontWeight.Normal,
|
||||||
fontSize = MaterialTheme.typography.button.fontSize,
|
fontSize = MaterialTheme.typography.button.fontSize,
|
||||||
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
|
@ -173,6 +174,7 @@ fun NodeItem(
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
text = longName,
|
text = longName,
|
||||||
|
fontWeight = if (isFavorite) FontWeight.Bold else FontWeight.Normal,
|
||||||
style = style,
|
style = style,
|
||||||
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
||||||
softWrap = true,
|
softWrap = true,
|
||||||
|
|
|
@ -136,6 +136,7 @@ fun NodesScreen(
|
||||||
when (menuItem) {
|
when (menuItem) {
|
||||||
is NodeMenuAction.Remove -> model.removeNode(node.num)
|
is NodeMenuAction.Remove -> model.removeNode(node.num)
|
||||||
is NodeMenuAction.Ignore -> model.ignoreNode(node)
|
is NodeMenuAction.Ignore -> model.ignoreNode(node)
|
||||||
|
is NodeMenuAction.Favorite -> model.favoriteNode(node)
|
||||||
is NodeMenuAction.DirectMessage -> navigateToMessages(node)
|
is NodeMenuAction.DirectMessage -> navigateToMessages(node)
|
||||||
is NodeMenuAction.RequestUserInfo -> model.requestUserInfo(node.num)
|
is NodeMenuAction.RequestUserInfo -> model.requestUserInfo(node.num)
|
||||||
is NodeMenuAction.RequestPosition -> model.requestPosition(node.num)
|
is NodeMenuAction.RequestPosition -> model.requestPosition(node.num)
|
||||||
|
|
|
@ -47,8 +47,25 @@ fun NodeMenu(
|
||||||
expanded: Boolean = false,
|
expanded: Boolean = false,
|
||||||
onAction: (NodeMenuAction) -> Unit
|
onAction: (NodeMenuAction) -> Unit
|
||||||
) {
|
) {
|
||||||
|
var displayFavoriteDialog by remember { mutableStateOf(false) }
|
||||||
var displayIgnoreDialog by remember { mutableStateOf(false) }
|
var displayIgnoreDialog by remember { mutableStateOf(false) }
|
||||||
var displayRemoveDialog by remember { mutableStateOf(false) }
|
var displayRemoveDialog by remember { mutableStateOf(false) }
|
||||||
|
if (displayFavoriteDialog) {
|
||||||
|
SimpleAlertDialog(
|
||||||
|
title = R.string.favorite,
|
||||||
|
text = stringResource(
|
||||||
|
id = if (node.isFavorite) R.string.favorite_remove else R.string.favorite_add,
|
||||||
|
node.user.longName
|
||||||
|
),
|
||||||
|
onConfirm = {
|
||||||
|
displayFavoriteDialog = false
|
||||||
|
onAction(NodeMenuAction.Favorite(node))
|
||||||
|
},
|
||||||
|
onDismiss = {
|
||||||
|
displayFavoriteDialog = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
if (displayIgnoreDialog) {
|
if (displayIgnoreDialog) {
|
||||||
SimpleAlertDialog(
|
SimpleAlertDialog(
|
||||||
title = R.string.ignore,
|
title = R.string.ignore,
|
||||||
|
@ -113,6 +130,25 @@ fun NodeMenu(
|
||||||
},
|
},
|
||||||
content = { Text(stringResource(R.string.traceroute)) }
|
content = { Text(stringResource(R.string.traceroute)) }
|
||||||
)
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
onDismissRequest()
|
||||||
|
displayFavoriteDialog = true
|
||||||
|
},
|
||||||
|
enabled = !node.isIgnored,
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.favorite))
|
||||||
|
Spacer(Modifier.weight(1f))
|
||||||
|
Checkbox(
|
||||||
|
checked = node.isFavorite,
|
||||||
|
onCheckedChange = {
|
||||||
|
onDismissRequest()
|
||||||
|
displayFavoriteDialog = true
|
||||||
|
},
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
enabled = !node.isIgnored,
|
||||||
|
)
|
||||||
|
}
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
|
@ -152,6 +188,7 @@ fun NodeMenu(
|
||||||
sealed class NodeMenuAction {
|
sealed class NodeMenuAction {
|
||||||
data class Remove(val node: Node) : NodeMenuAction()
|
data class Remove(val node: Node) : NodeMenuAction()
|
||||||
data class Ignore(val node: Node) : NodeMenuAction()
|
data class Ignore(val node: Node) : NodeMenuAction()
|
||||||
|
data class Favorite(val node: Node) : NodeMenuAction()
|
||||||
data class DirectMessage(val node: Node) : NodeMenuAction()
|
data class DirectMessage(val node: Node) : NodeMenuAction()
|
||||||
data class RequestUserInfo(val node: Node) : NodeMenuAction()
|
data class RequestUserInfo(val node: Node) : NodeMenuAction()
|
||||||
data class RequestPosition(val node: Node) : NodeMenuAction()
|
data class RequestPosition(val node: Node) : NodeMenuAction()
|
||||||
|
|
|
@ -283,6 +283,7 @@ internal fun MessageScreen(
|
||||||
when (action) {
|
when (action) {
|
||||||
is NodeMenuAction.Remove -> viewModel.removeNode(action.node.num)
|
is NodeMenuAction.Remove -> viewModel.removeNode(action.node.num)
|
||||||
is NodeMenuAction.Ignore -> viewModel.ignoreNode(action.node)
|
is NodeMenuAction.Ignore -> viewModel.ignoreNode(action.node)
|
||||||
|
is NodeMenuAction.Favorite -> viewModel.favoriteNode(action.node)
|
||||||
is NodeMenuAction.DirectMessage -> navigateToMessages(action.node)
|
is NodeMenuAction.DirectMessage -> navigateToMessages(action.node)
|
||||||
is NodeMenuAction.RequestUserInfo -> viewModel.requestUserInfo(action.node.num)
|
is NodeMenuAction.RequestUserInfo -> viewModel.requestUserInfo(action.node.num)
|
||||||
is NodeMenuAction.RequestPosition -> viewModel.requestPosition(action.node.num)
|
is NodeMenuAction.RequestPosition -> viewModel.requestPosition(action.node.num)
|
||||||
|
|
|
@ -313,6 +313,9 @@
|
||||||
<string name="unknown_age">Unknown Age</string>
|
<string name="unknown_age">Unknown Age</string>
|
||||||
<string name="copy">Copy</string>
|
<string name="copy">Copy</string>
|
||||||
<string name="alert_bell_text">Alert Bell Character!</string>
|
<string name="alert_bell_text">Alert Bell Character!</string>
|
||||||
|
<string name="favorite">Favorite</string>
|
||||||
|
<string name="favorite_add">Add \'%s\' as a favorite node?</string>
|
||||||
|
<string name="favorite_remove">Remove \'%s\' as a favorite node?</string>
|
||||||
<string name="power_metrics_log">Power Metrics Log</string>
|
<string name="power_metrics_log">Power Metrics Log</string>
|
||||||
<string name="channel_1">Channel 1</string>
|
<string name="channel_1">Channel 1</string>
|
||||||
<string name="channel_2">Channel 2</string>
|
<string name="channel_2">Channel 2</string>
|
||||||
|
|
Ładowanie…
Reference in New Issue