mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
* Update messaging list separator insets
* Dont show unread messages or notifications for emoji reactions matching iMessage.
* Restore ble state method (#1416)
* Restore BLE State
* Log privacy
* AccessoryManager to handle restored connection
* Comment task out
* Update restore state function based on conversation with jake
* Update Meshtastic/Accessory/Transports/Bluetooth Low Energy/BLETransport.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Meshtastic/Accessory/Transports/Bluetooth Low Energy/BLETransport.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Two Column Node List (#1425)
* Restore BLE State
* Log privacy
* AccessoryManager to handle restored connection
* Comment task out
* Switch the node list to a two column layout
* Keep asian translations of channel details string
* Update restore state function based on conversation with jake
* Update Meshtastic/Accessory/Transports/Bluetooth Low Energy/BLETransport.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Meshtastic/Accessory/Transports/Bluetooth Low Energy/BLETransport.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* always show node list search bar
* Update auto correct modifier
* Dont show online animations for ios 17, remove online animation from node map, remove online circle from position popover
* Work in progress.
* Update detents
* Gate the discovery process while restoring
* Use geometry reader to size weather tiles on node details
* Update BLE Transport
* Update location weather condistion styles
* Log privacy in didReceive
* Remove extra dividers from admin key config, fix onboarding typo
* Bump minimum catalyst target
* Bump mac target version
* Use @FetchRequest for UserList to try and use less memory on ios 17
* Revert change to @fetchrequest
* Stab in the dark for Devices crash
* Updated UserList (back?) to @FetchRequest
* Set mac minimum to 15
* Nil out continuation after use
* Use @FetchRequest for the node list to stop crashes on iOS 17
* Handle failed connections during restoration
---------
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update protos
* Update protos
* Remove stale keys
* Serbian translations update (#1422)
* Log privacy
* Add Serbian translations
---------
Co-authored-by: Garth Vander Houwen <garthvh@yahoo.com>
* Clarify public key sub-text in security settings (#1412)
* Clarify public key sub-text in settings
* Trigger lint
* freq slot num pad (#1410)
* kill keyboard toolbar on lora config
* delete extranious scrollDismissesKeyboard
* Properly set catalyst target
* Update Meshtastic/Views/Onboarding/DeviceOnboarding.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Meshtastic/Views/Settings/Config/SecurityConfig.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update Meshtastic/Enums/DeviceEnums.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Make current location nilable, remove log spam
* clean up toUser logic
* Fix telemetry entity not added in nodeInfoPacket
* fix typo: powerMetrics.hasChXCurrent mismatch
* Duplicate decoding of telemetry.current removed
* Clean up mesh map fetch request and distance filter logic
* Revert attempt to fix message logic
* Bump datadog version
* Missing message fix, attempt #2 (#1431)
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
* Retry fewer times for longer
* Revert "Missing message fix, attempt #2 (#1431)" (#1432)
This reverts commit a96d318adb.
* Make retry 2 seconds
* Add back link to node details from position popover without navigation stack and link, clear notifications when deleting database
* Add clear notifications function
* Link from channel messages to node info
* Link to node details
* Discovery on retry fix
* Discovery on retry fix fix
* Add contact to device node db if you get an encrypted send faild routing error
* Seperate channel message view into two views for better performance.
* Refactor User Message List
* Update device hardware
Add liquid glass to config save button
* Save button cleanup
* Update button structure on users view
* Move encrypted send logic out of the router. Update protos
* Restore node long- and short- names (#1442)
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
* Update Meshtastic/Accessory/Transports/Bluetooth Low Energy/BLEConnection.swift
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Revert routing error
* Toggle for enabling device telemetry broadcast enable
* Update
* Enhancements for interval dropdowns (#1445)
* Cleanup
* Fix core data version
* Add never to update interval
* Device telemetry Enabled Boolean (#1446)
* Update core data and interval picker
* Move formatter
* Rework to nest options under enabled
* Clearer names
* Safer devicehardware api call, remove node history filter from mesh map
* Fix build
* Simplify mesh map filter
* Remove stale translation keys
---------
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Nikola Dašić <dasic.nikola@yandex.com>
Co-authored-by: Spencer Smith <dontaskspencer@gmail.com>
Co-authored-by: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
172 lines
6.1 KiB
Swift
172 lines
6.1 KiB
Swift
//
|
|
// RouteLines.swift
|
|
// Meshtastic
|
|
//
|
|
// Created by Garth Vander Houwen on 3/14/24.
|
|
//
|
|
import SwiftUI
|
|
import MapKit
|
|
import CoreData
|
|
|
|
struct NodeMapContent: MapContent {
|
|
|
|
@ObservedObject var node: NodeInfoEntity
|
|
@State var showUserLocation: Bool = false
|
|
@State var positions: [PositionEntity] = []
|
|
/// Map State User Defaults
|
|
@AppStorage("meshMapShowNodeHistory") private var showNodeHistory = false
|
|
@AppStorage("meshMapShowRouteLines") private var showRouteLines = false
|
|
@AppStorage("enableMapWaypoints") private var showWaypoints = true
|
|
@AppStorage("enableMapConvexHull") private var showConvexHull = false
|
|
@AppStorage("enableMapTraffic") private var showTraffic: Bool = false
|
|
@AppStorage("enableMapPointsOfInterest") private var showPointsOfInterest: Bool = false
|
|
@AppStorage("mapLayer") private var selectedMapLayer: MapLayer = .hybrid
|
|
|
|
// Map Configuration
|
|
@Namespace var mapScope
|
|
@State var mapStyle: MapStyle = MapStyle.hybrid(elevation: .realistic, pointsOfInterest: .all, showsTraffic: true)
|
|
@State var position = MapCameraPosition.automatic
|
|
@State var scene: MKLookAroundScene?
|
|
@State var isLookingAround = false
|
|
@State var isShowingAltitude = false
|
|
@State var isEditingSettings = false
|
|
@State var selectedPosition: PositionEntity?
|
|
@State var isMeshMap = false
|
|
|
|
@MapContentBuilder
|
|
var nodeMap: some MapContent {
|
|
let positionArray = node.positions?.array as? [PositionEntity] ?? []
|
|
let lineCoords = positionArray.compactMap({(position) -> CLLocationCoordinate2D in
|
|
return position.nodeCoordinate ?? LocationsHandler.DefaultLocation
|
|
})
|
|
|
|
/// Node Color from node.num
|
|
let nodeColor = UIColor(hex: UInt32(node.num))
|
|
|
|
/// Node Annotations
|
|
ForEach(node.positions?.array as? [PositionEntity] ?? [], id: \.id) { position in
|
|
|
|
let pf = PositionFlags(rawValue: Int(position.nodePosition?.metadata?.positionFlags ?? 771))
|
|
let headingDegrees = Angle.degrees(Double(position.heading))
|
|
/// Reduced Precision Map Circle
|
|
if position.latest && 12...15 ~= position.precisionBits {
|
|
let pp = PositionPrecision(rawValue: Int(position.precisionBits))
|
|
let radius: CLLocationDistance = pp?.precisionMeters ?? 0
|
|
if radius > 0.0 {
|
|
MapCircle(center: position.coordinate, radius: radius)
|
|
.foregroundStyle(Color(nodeColor).opacity(0.25))
|
|
.stroke(.white, lineWidth: 2)
|
|
}
|
|
}
|
|
let loraNodes = positions.filter { $0.nodePosition?.viaMqtt ?? true == false }
|
|
let loraCoords = Array(loraNodes).compactMap({(position) -> CLLocationCoordinate2D in
|
|
return position.nodeCoordinate ?? LocationsHandler.DefaultLocation
|
|
})
|
|
/// Convex Hull
|
|
if showConvexHull {
|
|
if loraCoords.count > 0 {
|
|
let hull = loraCoords.getConvexHull()
|
|
MapPolygon(coordinates: hull)
|
|
.stroke(.blue, lineWidth: 3)
|
|
.foregroundStyle(.indigo.opacity(0.4))
|
|
}
|
|
}
|
|
/// Route Lines
|
|
if showRouteLines {
|
|
let gradient = LinearGradient(
|
|
colors: [Color(nodeColor.lighter().lighter().lighter()), Color(nodeColor.lighter()), Color(nodeColor)],
|
|
startPoint: .leading, endPoint: .trailing
|
|
)
|
|
let dashed = StrokeStyle(
|
|
lineWidth: 3,
|
|
lineCap: .round, lineJoin: .round, dash: [10, 10]
|
|
)
|
|
MapPolyline(coordinates: lineCoords)
|
|
.stroke(gradient, style: dashed)
|
|
}
|
|
/// Lastest Position Pin
|
|
if position.latest {
|
|
/// Node Annotations
|
|
Annotation(position.latest ? node.user?.shortName ?? "?": "", coordinate: position.coordinate) {
|
|
LazyVStack {
|
|
ZStack {
|
|
if pf.contains(.Heading) {
|
|
Image(systemName: pf.contains(.Speed) && position.speed > 1 ? "location.north" : "octagon")
|
|
.padding(5)
|
|
.foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
|
|
.background(Color(nodeColor.darker()))
|
|
.clipShape(Circle())
|
|
.rotationEffect(headingDegrees)
|
|
.onTapGesture {
|
|
selectedPosition = (selectedPosition == position ? nil : position)
|
|
}
|
|
.popover(item: $selectedPosition) { selection in
|
|
PositionPopover(position: selection)
|
|
.padding()
|
|
.opacity(0.8)
|
|
.presentationCompactAdaptation(.popover)
|
|
}
|
|
|
|
} else {
|
|
Image(systemName: "flipphone")
|
|
.symbolEffect(.pulse.byLayer)
|
|
.padding(5)
|
|
.foregroundStyle(Color(nodeColor).isLight() ? .black : .white)
|
|
.background(Color(UIColor(hex: UInt32(node.num)).darker()))
|
|
.clipShape(Circle())
|
|
.onTapGesture {
|
|
selectedPosition = (selectedPosition == position ? nil : position)
|
|
}
|
|
.popover(item: $selectedPosition) { selection in
|
|
PositionPopover(position: selection)
|
|
.padding()
|
|
.opacity(0.8)
|
|
.presentationCompactAdaptation(.popover)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.tag(position.time)
|
|
.annotationTitles(.automatic)
|
|
.annotationSubtitles(.automatic)
|
|
}
|
|
/// Node History
|
|
if showNodeHistory {
|
|
if position.latest == false && position.nodePosition?.favorite ?? false {
|
|
let pf = PositionFlags(rawValue: Int(position.nodePosition?.metadata?.positionFlags ?? 771))
|
|
let headingDegrees = Angle.degrees(Double(position.heading))
|
|
Annotation("", coordinate: position.coordinate) {
|
|
LazyVStack {
|
|
if pf.contains(.Heading) {
|
|
Image(systemName: "location.north.circle")
|
|
.resizable()
|
|
.scaledToFit()
|
|
.foregroundStyle(Color(UIColor(hex: UInt32(position.nodePosition?.num ?? 0))).isLight() ? .black : .white)
|
|
.background(Color(UIColor(hex: UInt32(position.nodePosition?.num ?? 0))))
|
|
.clipShape(Circle())
|
|
.rotationEffect(headingDegrees)
|
|
.frame(width: 16, height: 16)
|
|
|
|
} else {
|
|
Circle()
|
|
.fill(Color(UIColor(hex: UInt32(position.nodePosition?.num ?? 0))))
|
|
.strokeBorder(Color(UIColor(hex: UInt32(position.nodePosition?.num ?? 0))).isLight() ? .black : .white, lineWidth: 2)
|
|
.frame(width: 12, height: 12)
|
|
}
|
|
}
|
|
}
|
|
.annotationTitles(.hidden)
|
|
.annotationSubtitles(.hidden)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@MapContentBuilder
|
|
var body: some MapContent {
|
|
if node.positions?.count ?? 0 > 0 {
|
|
nodeMap
|
|
}
|
|
}
|
|
}
|