mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-02 06:24:16 +02:00
chore: remove orphaned app/ discovery files from merge
These files were duplicated in androidApp/ where they belong. The app/ module no longer exists (removed in AIDL removal PR). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.app.map.discovery
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import org.meshtastic.core.ui.util.DiscoveryMapNode
|
||||
|
||||
/** Flavor-unified entry point for the discovery map. OSMDroid implementation. */
|
||||
@Composable
|
||||
fun DiscoveryMap(
|
||||
userLatitude: Double,
|
||||
userLongitude: Double,
|
||||
nodes: List<DiscoveryMapNode>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
DiscoveryOsmMap(userLatitude = userLatitude, userLongitude = userLongitude, nodes = nodes, modifier = modifier)
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package org.meshtastic.app.map.discovery
|
||||
|
||||
import android.graphics.Paint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import org.meshtastic.app.map.addCopyright
|
||||
import org.meshtastic.app.map.addScaleBarOverlay
|
||||
import org.meshtastic.app.map.model.CustomTileSource
|
||||
import org.meshtastic.app.map.rememberMapViewWithLifecycle
|
||||
import org.meshtastic.app.map.zoomIn
|
||||
import org.meshtastic.core.ui.theme.DiscoveryMapColors
|
||||
import org.meshtastic.core.ui.util.DiscoveryMapNode
|
||||
import org.meshtastic.core.ui.util.DiscoveryNeighborType
|
||||
import org.osmdroid.util.BoundingBox
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.overlay.Marker
|
||||
import org.osmdroid.views.overlay.Polyline
|
||||
|
||||
private const val SINGLE_POINT_ZOOM = 14.0
|
||||
private const val ZOOM_OUT_LEVELS = 0.5
|
||||
|
||||
/**
|
||||
* OSMDroid implementation of the discovery map. Renders discovered node markers color-coded by neighbor type (green =
|
||||
* direct, blue = mesh) with polylines from the user position to direct neighbors. Auto-zooms to fit all markers.
|
||||
*/
|
||||
@Composable
|
||||
fun DiscoveryOsmMap(
|
||||
userLatitude: Double,
|
||||
userLongitude: Double,
|
||||
nodes: List<DiscoveryMapNode>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val density = LocalDensity.current
|
||||
val hasValidUserPosition = userLatitude != 0.0 || userLongitude != 0.0
|
||||
val userGeoPoint = remember(userLatitude, userLongitude) { GeoPoint(userLatitude, userLongitude) }
|
||||
val validNodes = remember(nodes) { nodes.filter { it.latitude != 0.0 || it.longitude != 0.0 } }
|
||||
|
||||
// Build bounding box from all points
|
||||
val allGeoPoints =
|
||||
remember(validNodes, hasValidUserPosition) {
|
||||
buildList {
|
||||
if (hasValidUserPosition) add(userGeoPoint)
|
||||
validNodes.forEach { add(GeoPoint(it.latitude, it.longitude)) }
|
||||
}
|
||||
}
|
||||
val initialBounds =
|
||||
remember(allGeoPoints) {
|
||||
if (allGeoPoints.isEmpty()) BoundingBox() else BoundingBox.fromGeoPoints(allGeoPoints)
|
||||
}
|
||||
|
||||
var hasCentered by remember { mutableStateOf(false) }
|
||||
|
||||
val mapView =
|
||||
rememberMapViewWithLifecycle(
|
||||
applicationId = context.packageName,
|
||||
box = initialBounds,
|
||||
tileSource = CustomTileSource.getTileSource(0),
|
||||
)
|
||||
|
||||
// Camera auto-center once
|
||||
LaunchedEffect(allGeoPoints) {
|
||||
if (hasCentered || allGeoPoints.isEmpty()) return@LaunchedEffect
|
||||
if (allGeoPoints.size == 1) {
|
||||
mapView.controller.setCenter(allGeoPoints.first())
|
||||
mapView.controller.setZoom(SINGLE_POINT_ZOOM)
|
||||
} else {
|
||||
mapView.zoomToBoundingBox(BoundingBox.fromGeoPoints(allGeoPoints).zoomIn(-ZOOM_OUT_LEVELS), true)
|
||||
}
|
||||
hasCentered = true
|
||||
}
|
||||
|
||||
AndroidView(
|
||||
modifier = modifier,
|
||||
factory = { mapView.apply { setDestroyMode(false) } },
|
||||
update = { map ->
|
||||
map.overlays.clear()
|
||||
map.addCopyright()
|
||||
map.addScaleBarOverlay(density)
|
||||
|
||||
// User position marker
|
||||
if (hasValidUserPosition) {
|
||||
val userMarker =
|
||||
Marker(map).apply {
|
||||
position = userGeoPoint
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
title = "Your Position"
|
||||
icon = context.getDrawable(android.R.drawable.ic_menu_mylocation)
|
||||
}
|
||||
map.overlays.add(userMarker)
|
||||
}
|
||||
|
||||
// Node markers
|
||||
validNodes.forEach { node ->
|
||||
val nodeGeoPoint = GeoPoint(node.latitude, node.longitude)
|
||||
val marker =
|
||||
Marker(map).apply {
|
||||
position = nodeGeoPoint
|
||||
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
|
||||
title = node.longName ?: node.shortName ?: "Unknown"
|
||||
snippet = "SNR: ${node.snr} dB / RSSI: ${node.rssi} dBm"
|
||||
|
||||
val drawableId =
|
||||
if (node.isSensorNode) {
|
||||
org.meshtastic.app.R.drawable.ic_thermostat
|
||||
} else {
|
||||
org.meshtastic.app.R.drawable.ic_person
|
||||
}
|
||||
icon = context.getDrawable(drawableId)
|
||||
|
||||
// Default OSM marker handles color tinting via icon overlay or custom drawables if needed,
|
||||
// but setting the icon directly overrides the default teardrop pin.
|
||||
}
|
||||
map.overlays.add(marker)
|
||||
}
|
||||
|
||||
// Polylines from user to direct neighbors
|
||||
if (hasValidUserPosition) {
|
||||
validNodes
|
||||
.filter { it.neighborType == DiscoveryNeighborType.DIRECT }
|
||||
.forEach { node ->
|
||||
val polyline =
|
||||
Polyline().apply {
|
||||
setPoints(listOf(userGeoPoint, GeoPoint(node.latitude, node.longitude)))
|
||||
outlinePaint.apply {
|
||||
color = DiscoveryMapColors.DirectLine.toArgb()
|
||||
strokeWidth = with(density) { 3.dp.toPx() }
|
||||
strokeCap = Paint.Cap.ROUND
|
||||
style = Paint.Style.STROKE
|
||||
}
|
||||
}
|
||||
map.overlays.add(polyline)
|
||||
}
|
||||
}
|
||||
|
||||
map.invalidate()
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package org.meshtastic.app.map.discovery
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.google.android.gms.maps.CameraUpdateFactory
|
||||
import com.google.android.gms.maps.model.CameraPosition
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.LatLngBounds
|
||||
import com.google.maps.android.compose.ComposeMapColorScheme
|
||||
import com.google.maps.android.compose.GoogleMap
|
||||
import com.google.maps.android.compose.MapUiSettings
|
||||
import com.google.maps.android.compose.MapsComposeExperimentalApi
|
||||
import com.google.maps.android.compose.MarkerComposable
|
||||
import com.google.maps.android.compose.Polyline
|
||||
import com.google.maps.android.compose.rememberCameraPositionState
|
||||
import com.google.maps.android.compose.rememberUpdatedMarkerState
|
||||
import org.meshtastic.core.ui.icon.MeshtasticIcons
|
||||
import org.meshtastic.core.ui.icon.Person
|
||||
import org.meshtastic.core.ui.icon.Temperature
|
||||
import org.meshtastic.core.ui.util.DiscoveryMapNode
|
||||
import org.meshtastic.core.ui.util.DiscoveryNeighborType
|
||||
|
||||
private const val DEFAULT_ZOOM = 12f
|
||||
private const val BOUNDS_PADDING_PX = 100
|
||||
|
||||
private val DirectColor = Color(0xFF4CAF50)
|
||||
private val MeshColor = Color(0xFF2196F3)
|
||||
private val UserColor = Color(0xFFFF9800)
|
||||
private val DirectLineColor = Color(0xFF4CAF50).copy(alpha = 0.5f)
|
||||
|
||||
/**
|
||||
* Google Maps implementation of the discovery map. Renders discovered node markers color-coded by neighbor type (green
|
||||
* = direct, blue = mesh) with polylines from the user position to direct neighbors. Auto-zooms to fit all markers.
|
||||
*/
|
||||
@OptIn(MapsComposeExperimentalApi::class)
|
||||
@Composable
|
||||
fun DiscoveryGoogleMap(
|
||||
userLatitude: Double,
|
||||
userLongitude: Double,
|
||||
nodes: List<DiscoveryMapNode>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val dark = isSystemInDarkTheme()
|
||||
val mapColorScheme = if (dark) ComposeMapColorScheme.DARK else ComposeMapColorScheme.LIGHT
|
||||
|
||||
val userLatLng = remember(userLatitude, userLongitude) { LatLng(userLatitude, userLongitude) }
|
||||
val hasValidUserPosition = userLatitude != 0.0 || userLongitude != 0.0
|
||||
val validNodes = remember(nodes) { nodes.filter { it.latitude != 0.0 || it.longitude != 0.0 } }
|
||||
|
||||
val cameraState = rememberCameraPositionState {
|
||||
position =
|
||||
CameraPosition.fromLatLngZoom(if (hasValidUserPosition) userLatLng else LatLng(0.0, 0.0), DEFAULT_ZOOM)
|
||||
}
|
||||
|
||||
// Auto-fit bounds on first composition
|
||||
LaunchedEffect(validNodes, hasValidUserPosition) {
|
||||
val allPoints = buildList {
|
||||
if (hasValidUserPosition) add(userLatLng)
|
||||
validNodes.forEach { add(LatLng(it.latitude, it.longitude)) }
|
||||
}
|
||||
if (allPoints.size >= 2) {
|
||||
val boundsBuilder = LatLngBounds.builder()
|
||||
allPoints.forEach { boundsBuilder.include(it) }
|
||||
cameraState.animate(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), BOUNDS_PADDING_PX))
|
||||
} else if (allPoints.size == 1) {
|
||||
cameraState.animate(CameraUpdateFactory.newLatLngZoom(allPoints.first(), DEFAULT_ZOOM))
|
||||
}
|
||||
}
|
||||
|
||||
GoogleMap(
|
||||
mapColorScheme = mapColorScheme,
|
||||
modifier = modifier,
|
||||
uiSettings =
|
||||
MapUiSettings(
|
||||
zoomControlsEnabled = true,
|
||||
mapToolbarEnabled = false,
|
||||
compassEnabled = true,
|
||||
myLocationButtonEnabled = false,
|
||||
),
|
||||
cameraPositionState = cameraState,
|
||||
) {
|
||||
// User position marker
|
||||
if (hasValidUserPosition) {
|
||||
MarkerComposable(state = rememberUpdatedMarkerState(position = userLatLng), title = "Your Position") {
|
||||
DiscoveryMarkerChip(label = "You", color = UserColor)
|
||||
}
|
||||
}
|
||||
|
||||
// Node markers
|
||||
validNodes.forEach { node ->
|
||||
val nodeLatLng = LatLng(node.latitude, node.longitude)
|
||||
val markerColor =
|
||||
when (node.neighborType) {
|
||||
DiscoveryNeighborType.DIRECT -> DirectColor
|
||||
DiscoveryNeighborType.MESH -> MeshColor
|
||||
}
|
||||
val nodeIcon =
|
||||
if (node.isSensorNode) {
|
||||
MeshtasticIcons.Temperature
|
||||
} else {
|
||||
MeshtasticIcons.Person
|
||||
}
|
||||
MarkerComposable(
|
||||
state = rememberUpdatedMarkerState(position = nodeLatLng),
|
||||
title = node.longName ?: node.shortName ?: "Unknown",
|
||||
snippet = "SNR: ${node.snr} dB / RSSI: ${node.rssi} dBm",
|
||||
) {
|
||||
DiscoveryMarkerChip(label = node.shortName ?: "?", color = markerColor, icon = nodeIcon)
|
||||
}
|
||||
}
|
||||
|
||||
// Polylines from user to direct neighbors
|
||||
if (hasValidUserPosition) {
|
||||
validNodes
|
||||
.filter { it.neighborType == DiscoveryNeighborType.DIRECT }
|
||||
.forEach { node ->
|
||||
Polyline(
|
||||
points = listOf(userLatLng, LatLng(node.latitude, node.longitude)),
|
||||
color = DirectLineColor,
|
||||
width = 4f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.app.map.discovery
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import org.meshtastic.core.ui.util.DiscoveryMapNode
|
||||
|
||||
/** Flavor-unified entry point for the discovery map. Google Maps implementation. */
|
||||
@Composable
|
||||
fun DiscoveryMap(
|
||||
userLatitude: Double,
|
||||
userLongitude: Double,
|
||||
nodes: List<DiscoveryMapNode>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
DiscoveryGoogleMap(userLatitude = userLatitude, userLongitude = userLongitude, nodes = nodes, modifier = modifier)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package org.meshtastic.app.map.discovery
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/** Compact chip rendered as a Google Maps marker icon for discovery nodes. */
|
||||
@Composable
|
||||
fun DiscoveryMarkerChip(label: String, color: Color, modifier: Modifier = Modifier, icon: ImageVector? = null) {
|
||||
Box(
|
||||
modifier =
|
||||
modifier
|
||||
.background(color = color, shape = RoundedCornerShape(12.dp))
|
||||
.border(width = 1.dp, color = Color.White, shape = RoundedCornerShape(12.dp))
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
if (icon != null) {
|
||||
Icon(imageVector = icon, contentDescription = label, tint = Color.White, modifier = Modifier.size(16.dp))
|
||||
} else {
|
||||
Text(text = label, style = MaterialTheme.typography.labelSmall, color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M480,480Q414,480 367,433Q320,386 320,320Q320,254 367,207Q414,160 480,160Q546,160 593,207Q640,254 640,320Q640,386 593,433Q546,480 480,480ZM160,720L160,688Q160,654 177.5,625.5Q195,597 224,582Q286,551 350,535.5Q414,520 480,520Q546,520 610,535.5Q674,551 736,582Q765,597 782.5,625.5Q800,654 800,688L800,720Q800,753 776.5,776.5Q753,800 720,800L240,800Q207,800 183.5,776.5Q160,753 160,720Z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M560,440Q543,440 531.5,428.5Q520,417 520,400Q520,383 531.5,371.5Q543,360 560,360L680,360Q697,360 708.5,371.5Q720,383 720,400Q720,417 708.5,428.5Q697,440 680,440L560,440ZM560,280Q543,280 531.5,268.5Q520,257 520,240Q520,223 531.5,211.5Q543,200 560,200L800,200Q817,200 828.5,211.5Q840,223 840,240Q840,257 828.5,268.5Q817,280 800,280L560,280ZM320,840Q237,840 178.5,781.5Q120,723 120,640Q120,592 141,550.5Q162,509 200,480L200,240Q200,190 235,155Q270,120 320,120Q370,120 405,155Q440,190 440,240L440,480Q478,509 499,550.5Q520,592 520,640Q520,723 461.5,781.5Q403,840 320,840ZM200,640L440,640Q440,611 427.5,586Q415,561 392,544L360,520L360,240Q360,223 348.5,211.5Q337,200 320,200Q303,200 291.5,211.5Q280,223 280,240L280,520L248,544Q225,561 212.5,586Q200,611 200,640Z"/>
|
||||
</vector>
|
||||
Submodule
+1
Submodule core/proto/src/main/proto added at 79185c6fc8
Reference in New Issue
Block a user