Compass view#1504
Conversation
|
Looks good! Very handy for backpacking and SAR use cases. Can the node indicator match the nodenum color? |
|
@thebentern Done |
|
Just wanted to come and give a huge ❤️ for this. We have used Meshtastic for a few years a various festivals now; and "navigate to node" in a compass style is critically needed- and this is amazing. We have been using w3w's and copying locations back and forth- thank you so much! looking forward to it making it into the main release. |
There was a problem hiding this comment.
Pull request overview
This PR adds a compass view feature to the Meshtastic iOS app, enabling users to navigate to nodes using real-time heading and bearing information. The feature provides visual compass guidance with haptic feedback when aligned with a target waypoint.
Key Changes
- Introduced a new
CompassViewcomponent with bearing calculations, distance display, and alignment detection with haptic feedback - Enhanced
LocationsHandlerto support heading updates from the device's magnetometer - Integrated compass access points in both node detail screens and position popovers
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
Meshtastic/Views/Helpers/CompassView.swift |
New compass view implementation with waypoint navigation, bearing calculations, and visual/haptic feedback |
Meshtastic/Helpers/LocationsHandler.swift |
Added heading update methods and magnetometer support to track device orientation |
Meshtastic/Views/Nodes/Helpers/NodeDetail.swift |
Added "Open Compass" button and sheet presentation for compass view |
Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift |
Added compass navigation button with presentation detents and navigation destination |
Meshtastic.xcodeproj/project.pbxproj |
Added CompassView.swift to build phases |
Meshtastic.xcworkspace/xcshareddata/swiftpm/Package.resolved |
Updated package hash |
Localizable.xcstrings |
Added localization entries for compass-related strings and unrelated privacy policy updates |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let rawDiff = abs(heading - bearing).truncatingRemainder(dividingBy: 360) | ||
| let diff = min(rawDiff, 360 - rawDiff) |
There was a problem hiding this comment.
Inconsistent indentation in this function. Line 43 has extra leading spaces compared to lines 44 and 45.
| let rawDiff = abs(heading - bearing).truncatingRemainder(dividingBy: 360) | |
| let diff = min(rawDiff, 360 - rawDiff) | |
| let rawDiff = abs(heading - bearing).truncatingRemainder(dividingBy: 360) | |
| let diff = min(rawDiff, 360 - rawDiff) |
| ) | ||
| // Move waypoint marker outside compass | ||
| .onChange(of: locationsHandler.heading) { _, _ in | ||
| checkAlignment(bearing: bearing,heading:locationsHandler.heading) |
There was a problem hiding this comment.
Missing space after comma in function call. Should be checkAlignment(bearing: bearing, heading: locationsHandler.heading) with a space after the comma.
| checkAlignment(bearing: bearing,heading:locationsHandler.heading) | |
| checkAlignment(bearing: bearing, heading: locationsHandler.heading) |
| } | ||
| } | ||
| .sheet(isPresented: $showingCompassSheet) { | ||
| CompassView(waypointLocation: node.latestPosition?.nodeCoordinate ?? nil, waypointName: node.user?.longName ?? nil, color: Color(UIColor(hex: UInt32(node.num)))) |
There was a problem hiding this comment.
Using ?? nil is redundant and serves no purpose. If node.latestPosition?.nodeCoordinate is nil, it will already be nil without the nil-coalescing operator. The same applies to node.user?.longName ?? nil. Simply remove the ?? nil parts.
| CompassView(waypointLocation: node.latestPosition?.nodeCoordinate ?? nil, waypointName: node.user?.longName ?? nil, color: Color(UIColor(hex: UInt32(node.num)))) | |
| CompassView(waypointLocation: node.latestPosition?.nodeCoordinate, waypointName: node.user?.longName, color: Color(UIColor(hex: UInt32(node.num)))) |
| self.manager.headingFilter = 1 // Update heading when it changes by 1 degree | ||
| self.manager.headingOrientation = .portrait // Adjust based on device orientation | ||
| } |
There was a problem hiding this comment.
Inconsistent indentation. The body of the if statement on lines 137-138 has an extra level of indentation (two tabs instead of one). This should be aligned with the rest of the code.
| self.manager.headingFilter = 1 // Update heading when it changes by 1 degree | |
| self.manager.headingOrientation = .portrait // Adjust based on device orientation | |
| } | |
| self.manager.headingFilter = 1 // Update heading when it changes by 1 degree | |
| self.manager.headingOrientation = .portrait // Adjust based on device orientation | |
| } |
| } | ||
|
|
||
| // Trigger a vibration if aligned with waypoint | ||
| private func checkAlignment(bearing: Double,heading: Double) { |
There was a problem hiding this comment.
Missing space after comma in function parameter list. Should be checkAlignment(bearing: Double, heading: Double) with a space after the comma.
| private func checkAlignment(bearing: Double,heading: Double) { | |
| private func checkAlignment(bearing: Double, heading: Double) { |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
What changed?
Added a compass view to help you navigate to a node.
Why did it change?
This enables Meshtastic to be a more useful tool in offgrid scenarios where you need to quickly locate a friend, dog, or other Meshtastic tracker.
How is this tested?
Tested on my iPhone and verified the directions.
Screenshots/Videos (when applicable)
ScreenRecording_11-18-2025.00-24-42_1.MP4
ScreenRecording_11-18-2025.00-25-28_1.MP4
Checklist