Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
1059911
feat(ios): add Live Activity support for mapping sessions
Bjorkan Jul 14, 2026
2708c82
Fix unnecessary string interpolation braces in Live Activity title
agessaman Aug 12, 2026
2547c52
Add MeshMapperWatch watchOS app target
agessaman Aug 12, 2026
a9fff83
Add watch transport: snapshots down, commands up
agessaman Aug 13, 2026
b2bedbe
Add watch map page with pings, repeaters, and follow mode
agessaman Aug 13, 2026
51332e2
Add heard-node list in both placements, plus stale badge
agessaman Aug 13, 2026
73c6c03
Mirror the app's Top Heard overlay on the watch map
agessaman Aug 13, 2026
cef0e6b
Fit Top Heard on the smallest watch and drop the countdown into the c…
agessaman Aug 13, 2026
ce6af9a
Move the map overlay to a full-width bottom panel with a countdown bar
agessaman Aug 13, 2026
6866035
Overlay the countdown label on the bar and offset the camera for the …
agessaman Aug 13, 2026
5ed21ab
Size the countdown bar to the watch, and place the fix via the map proxy
agessaman Aug 13, 2026
25af775
Put both bar labels back on the track and fit the panel to the displa…
agessaman Aug 13, 2026
2fa0aef
Raise the panel 4 pt without spending the curvature clearance on width
agessaman Aug 13, 2026
f0961c1
Scale the panel gaps with the corner radius, and stop asserting lapse…
agessaman Aug 13, 2026
bbd01ca
Add wrist controls, and make every unavailable control say why
agessaman Aug 13, 2026
0385297
Open the map at 500 m, and remember the wearer's zoom
agessaman Aug 13, 2026
76d8a3b
Cut to the fix on launch, mirror the app's ping markers and ping gate…
agessaman Aug 13, 2026
ea78b4f
Single-source the manual-ping gate, and stop labels and errors misrep…
agessaman Aug 13, 2026
b82b409
Acknowledge admission, not completion, and give async failures a channel
agessaman Aug 13, 2026
b460b98
Send wrist commands over a queued transport, and expire them
agessaman Aug 13, 2026
e998227
Start the mode the region allows, and name it on the button
agessaman Aug 13, 2026
2768c79
Rebuild the Live Activity on the map overlay's vocabulary
agessaman Aug 13, 2026
224772d
Stop telegraphing a routine result: de-tint the bar and keyline
agessaman Aug 13, 2026
a6d7e2d
Give the watch map its discovery and trace pings
agessaman Aug 13, 2026
6a8ba00
Stop drawing a map at a wrist nobody is looking at
agessaman Aug 13, 2026
ad826e7
Key the drain to its deadline, not its caption; widen the panel to be…
agessaman Aug 13, 2026
ac862b7
Keep the fix still and move the world under it
agessaman Aug 13, 2026
e8027d6
Anchor the Live Activity countdown to the end of its bar
agessaman Aug 13, 2026
bce27b1
Stop rebuilding the watch payload twice a second, and fix repeater id…
agessaman Aug 13, 2026
6e1112b
Tell the truth about starting, idling, and going stale
agessaman Aug 13, 2026
10f2e12
Retry Live Activities within a session after they become available
agessaman Aug 13, 2026
aef4030
Offer the readout as a main page, not only when the wrist drops
agessaman Aug 13, 2026
001812a
Say the smallest true thing the dimmed countdown can
agessaman Aug 13, 2026
20bc491
Put the map/readout switch in the system's corner, not ours
agessaman Aug 13, 2026
5ad2c89
Hold the readout still when the wrist drops
agessaman Aug 13, 2026
00759dc
Take back the height Always-On returns, not just the position
agessaman Aug 13, 2026
48aa208
Start the map at 250 m, and stop MapKit overwriting it
agessaman Aug 13, 2026
590e5b7
Put session control in the watch's second corner
agessaman Aug 13, 2026
e1adacb
Make the controls page look like the rest of MeshMapper
agessaman Aug 14, 2026
3b9b895
Let the map page be a page: swipe navigates, crown zooms
agessaman Aug 14, 2026
4a461da
Stop the wrist from starting a session the phone would refuse
agessaman Aug 14, 2026
df145cf
Stop shipping map geography to a watch that isn't showing a map
agessaman Aug 14, 2026
c2b9735
Let MapKit know what covers the map instead of shifting the camera
agessaman Aug 14, 2026
13346e9
Flag the vestigial MapReader for a decision before the PR
agessaman Aug 14, 2026
336d047
Stop renaming every map marker when one new ping arrives
agessaman Aug 14, 2026
df0dcbd
Add a wrist switch for measuring the countdown drain
agessaman Aug 14, 2026
a1dbb2f
Stop a swipe off the map stranding a sheet over the next page
agessaman Aug 14, 2026
8dd93e2
Measure the panel's height, not where it is
agessaman Aug 14, 2026
8430f96
Stop the map camera resting at a continental span
agessaman Aug 14, 2026
591b9ed
Show why the phone is or is not talking to the watch
agessaman Aug 14, 2026
ebc09fb
Stop the puck lagging the pings beside it
agessaman Aug 14, 2026
71dd8dd
Keep the map on screen when the display dims
agessaman Aug 14, 2026
1d7bbe0
Stop the movement-gate tests racing the throttle
agessaman Aug 14, 2026
0b38315
Let the watch app install on watchOS 11
agessaman Aug 15, 2026
0e3916d
Stop a fast watch clock widening the transmit window
agessaman Aug 15, 2026
24370e4
Stop retained state reading as fresh on watch launch
agessaman Aug 15, 2026
41949ac
Clear out two pieces of development residue
agessaman Aug 15, 2026
87f6f1e
Run the tests in CI
agessaman Aug 15, 2026
5a2be4d
Answer a requested refresh even when nothing changed
agessaman Aug 15, 2026
2bfe0e2
Stop map-geo lease renewals forcing a snapshot
agessaman Aug 15, 2026
d9cf509
Reconcile on resume, not only on first appearance
agessaman Aug 15, 2026
6bce3ae
Stop both countdown bars animating against the system
agessaman Aug 16, 2026
50a157f
Stop the status panel dragging the camera when it resizes
agessaman Aug 16, 2026
675fa11
Let a Smart Stack tap reach the watch app
agessaman Aug 16, 2026
afe34cf
Let the wearer's text size reach the reason a control is dead
agessaman Aug 16, 2026
ac7f64f
Dim the held map, and hold it for twelve seconds instead of twenty
agessaman Aug 16, 2026
f4ca85f
Keep the delivery thread off rendered state, and let a failure be felt
agessaman Aug 16, 2026
6925b34
Walk the sample fix so a follow animation can be reviewed
agessaman Aug 16, 2026
d8f3bbe
Slide the map to a new fix instead of cutting to it
agessaman Aug 16, 2026
161a96c
Darken the held map to what a powerlog says it costs
agessaman Aug 16, 2026
8e8f421
Stop a millisecond of deadline drift bypassing the update throttle
agessaman Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@ jobs:
- run: dart run build_runner build --delete-conflicting-outputs
- run: dart format --output=none --set-exit-if-changed .
- run: flutter analyze
#- run: flutter test
# no tests yet, fails without ./test directory
- run: flutter test
29 changes: 29 additions & 0 deletions docs/LIVE_ACTIVITIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# iOS Live Activities

MeshMapper starts one read-only Live Activity while an automatic wardriving session or manual ping cycle is active. It mirrors the same state used by the in-app controls.

## Displayed information

- Current mode and phase (`Sending`, `Listening`, `Next ping`, `Cooldown`, GPS/zone/reconnect states)
- System-rendered countdowns based on absolute timer deadlines
- The strongest repeaters from the current or latest completed cycle, sorted by SNR
- TX/RX counters, upload queue, zone, connection state, and stale-update warnings
- Lock Screen, Dynamic Island, and an iOS 18 small-family layout suitable for CarPlay on supported systems

## Architecture

- Dart builds a compact `LiveActivitySnapshot` from `AppStateProvider`.
- `LiveActivityService` deduplicates and throttles noncritical updates before sending them over `meshmapper/live_activity`.
- `LiveActivityManager` creates, updates, deduplicates, and ends the native ActivityKit activity.
- `MeshMapperLiveActivityExtension` renders the snapshot using SwiftUI and WidgetKit.

No push server or App Group is required. The Live Activity does not replace the existing BLE/location background execution; it only presents its state.

## Platform requirements

- Live Activity: iOS 16.2 or later
- Small supplemental activity family: iOS 18 or later
- CarPlay presentation of Live Activities: iOS 26 or later
- A physical iPhone is recommended for final background, Dynamic Island, and CarPlay validation

The main Runner target keeps its existing deployment target. Unsupported devices skip ActivityKit creation.
1 change: 1 addition & 0 deletions ios/Flutter/LiveActivity.xcconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "Generated.xcconfig"
29 changes: 29 additions & 0 deletions ios/MeshMapperLiveActivity/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>MeshMapper</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>NSSupportsLiveActivities</key>
<true/>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>
Loading