feat: show lock icon for nodes with public keys 🔒

pull/1219/head
andrekir 2024-09-16 18:44:18 -03:00
rodzic 092ed32c23
commit 24886994a6
6 zmienionych plików z 43 dodań i 28 usunięć

Wyświetl plik

@ -21,6 +21,7 @@ import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.QuickChatActionRepository
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.database.entity.toNodeInfo
@ -229,9 +230,9 @@ class UIViewModel @Inject constructor(
)
@OptIn(ExperimentalCoroutinesApi::class)
val nodeList: StateFlow<List<NodeInfo>> = nodesUiState.flatMapLatest { state ->
val nodeList: StateFlow<List<NodeEntity>> = nodesUiState.flatMapLatest { state ->
nodeDB.getNodes(state.sort, state.filter, state.includeUnknown)
}.mapLatest { list -> list.map { it.toNodeInfo() } }.stateIn(
}.stateIn(
scope = viewModelScope,
started = Eagerly,
initialValue = emptyList(),

Wyświetl plik

@ -26,6 +26,7 @@ import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.database.entity.toNodeInfo
import com.geeksville.mesh.databinding.MessagesFragmentBinding
import com.geeksville.mesh.model.Message
import com.geeksville.mesh.model.UIViewModel
@ -294,9 +295,9 @@ class MessagesFragment : Fragment(), Logging {
}
private fun openNodeInfo(msg: Message) = lifecycleScope.launch {
model.nodeList.firstOrNull()?.find { it.user?.id == msg.user.id }?.let { node ->
model.nodeList.firstOrNull()?.find { it.user.id == msg.user.id }?.let { node ->
parentFragmentManager.popBackStack()
model.focusUserNode(node)
model.focusUserNode(node.toNodeInfo())
}
}
}

Wyświetl plik

@ -75,11 +75,13 @@ fun NodeInfo(
blinking: Boolean = false,
expanded: Boolean = false,
currentTimeMillis: Long,
hasPublicKey: Boolean = false,
) {
val isUnknownUser = thatNodeInfo.user?.hwModel == MeshProtos.HardwareModel.UNSET
val unknownShortName = stringResource(id = R.string.unknown_node_short_name)
val unknownLongName = stringResource(id = R.string.unknown_username)
val longName = thatNodeInfo.user?.longName ?: stringResource(id = R.string.unknown_username)
val nodeName = thatNodeInfo.user?.longName ?: unknownLongName
val nodeName = if (hasPublicKey) "🔒 $longName" else longName
val isThisNode = thisNodeInfo?.num == thatNodeInfo.num
val distance = thisNodeInfo?.distanceStr(thatNodeInfo, distanceUnits)
val (textColor, nodeColor) = thatNodeInfo.colors
@ -101,7 +103,7 @@ fun NodeInfo(
label = "blinking node"
)
val style = if (thatNodeInfo.user?.hwModel == MeshProtos.HardwareModel.UNSET) {
val style = if (isUnknownUser) {
LocalTextStyle.current.copy(fontStyle = FontStyle.Italic)
} else {
LocalTextStyle.current

Wyświetl plik

@ -4,12 +4,12 @@ import android.view.Gravity
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.PopupMenu
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.NodeEntity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
internal fun View.nodeMenu(
node: NodeInfo,
node: NodeEntity,
ignoreIncomingList: List<Int>,
isOurNode: Boolean = false,
isManaged: Boolean = false,
@ -43,7 +43,7 @@ internal fun View.nodeMenu(
val message = if (isIgnored) R.string.ignore_remove else R.string.ignore_add
MaterialAlertDialogBuilder(context)
.setTitle(R.string.ignore)
.setMessage(context.getString(message, node.user?.longName))
.setMessage(context.getString(message, node.user.longName))
.setNeutralButton(R.string.cancel) { _, _ -> }
.setPositiveButton(R.string.send) { _, _ ->
item.onMenuItemAction()

Wyświetl plik

@ -22,9 +22,11 @@ import androidx.compose.ui.unit.dp
import androidx.fragment.app.activityViewModels
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.toNodeInfo
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.components.NodeFilterTextField
import com.geeksville.mesh.ui.components.rememberTimeTickWithLifecycle
@ -36,7 +38,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
private val model: UIViewModel by activityViewModels()
private fun popup(node: NodeInfo) {
private fun popup(node: NodeEntity) {
if (!model.isConnected()) return
val isOurNode = node.num == model.myNodeNum
val ignoreIncomingList = model.ignoreIncomingList
@ -77,30 +79,31 @@ class UsersFragment : ScreenFragment("Users"), Logging {
}
R.id.remote_admin -> {
navigateToRadioConfig(node)
navigateToRadioConfig(node.num)
}
R.id.metrics -> {
navigateToMetrics(node)
navigateToMetrics(node.num)
}
}
}
}
private fun navigateToMessages(node: NodeInfo) = node.user?.let { user ->
val contactKey = "${node.channel}${user.id}"
private fun navigateToMessages(node: NodeEntity) = node.user.let { user ->
val channel = if (user.publicKey.isEmpty) node.channel else DataPacket.PKC_CHANNEL_INDEX
val contactKey = "$channel${user.id}"
info("calling MessagesFragment filter: $contactKey")
parentFragmentManager.navigateToMessages(contactKey, user.longName)
}
private fun navigateToRadioConfig(node: NodeInfo) {
info("calling RadioConfig --> destNum: ${node.num}")
parentFragmentManager.navigateToRadioConfig(node.num)
private fun navigateToRadioConfig(nodeNum: Int) {
info("calling RadioConfig --> destNum: $nodeNum")
parentFragmentManager.navigateToRadioConfig(nodeNum)
}
private fun navigateToMetrics(node: NodeInfo) {
info("calling Metrics --> destNum: ${node.num}")
parentFragmentManager.navigateToMetrics(node.num)
private fun navigateToMetrics(nodeNum: Int) {
info("calling Metrics --> destNum: $nodeNum")
parentFragmentManager.navigateToMetrics(nodeNum)
}
@ -124,7 +127,7 @@ class UsersFragment : ScreenFragment("Users"), Logging {
@Composable
fun NodesScreen(
model: UIViewModel = hiltViewModel(),
chipClicked: (NodeInfo) -> Unit,
chipClicked: (NodeEntity) -> Unit,
) {
val focusManager = LocalFocusManager.current
val state by model.nodesUiState.collectAsStateWithLifecycle()
@ -136,7 +139,7 @@ fun NodesScreen(
val focusedNode by model.focusedNode.collectAsStateWithLifecycle()
LaunchedEffect(focusedNode) {
focusedNode?.let { node ->
val index = nodes.indexOfFirst { it == node }
val index = nodes.indexOfFirst { it.num == node.num }
if (index != -1) {
listState.animateScrollToItem(index)
}
@ -167,9 +170,10 @@ fun NodesScreen(
}
items(nodes, key = { it.num }) { node ->
val nodeInfo = node.toNodeInfo()
NodeInfo(
thisNodeInfo = ourNodeInfo,
thatNodeInfo = node,
thatNodeInfo = nodeInfo,
gpsFormat = state.gpsFormat,
distanceUnits = state.distanceUnits,
tempInFahrenheit = state.tempInFahrenheit,
@ -178,9 +182,10 @@ fun NodesScreen(
focusManager.clearFocus()
chipClicked(node)
},
blinking = node == focusedNode,
blinking = nodeInfo == focusedNode,
expanded = state.showDetails,
currentTimeMillis = currentTimeMillis
currentTimeMillis = currentTimeMillis,
hasPublicKey = !node.user.publicKey.isEmpty
)
}
}

Wyświetl plik

@ -47,6 +47,7 @@ import com.geeksville.mesh.android.hasGps
import com.geeksville.mesh.android.hasLocationPermission
import com.geeksville.mesh.copy
import com.geeksville.mesh.database.entity.Packet
import com.geeksville.mesh.database.entity.toNodeInfo
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.map.CustomTileSource
import com.geeksville.mesh.model.map.MarkerWithLabel
@ -59,6 +60,8 @@ import com.geeksville.mesh.util.zoomIn
import com.geeksville.mesh.waypoint
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.mapLatest
import org.osmdroid.bonuspack.utils.BonusPackHelper.getBitmapFromVectorDrawable
import org.osmdroid.config.Configuration
import org.osmdroid.events.MapEventsReceiver
@ -299,7 +302,10 @@ fun MapView(
if (permissions.entries.all { it.value }) map.toggleMyLocation()
}
val nodes by model.nodeList.collectAsStateWithLifecycle()
@OptIn(ExperimentalCoroutinesApi::class)
val nodes by model.nodeList
.mapLatest { list -> list.map { it.toNodeInfo() } }
.collectAsStateWithLifecycle(emptyList())
val waypoints by model.waypoints.collectAsStateWithLifecycle(emptyMap())
var showDownloadButton: Boolean by remember { mutableStateOf(false) }