Skip to content

Live activity#537

Draft
bjorkert wants to merge 6 commits intodevfrom
live-activity
Draft

Live activity#537
bjorkert wants to merge 6 commits intodevfrom
live-activity

Conversation

@bjorkert
Copy link
Contributor

This PR replaces #534

Work in progress.

MtlPhil and others added 6 commits March 7, 2026 17:05
…f-push)

Implements a lock screen and Dynamic Island Live Activity for LoopFollow displaying real-time glucose data updated via APNs self-push.

## What's included

- Lock screen card: glucose + trend arrow, delta, IOB, COB, projected, last update time, threshold-driven background color (green/orange/red)
- Dynamic Island: compact, expanded, and minimal presentations
- Not Looping overlay: red banner when Loop hasn't reported in 15+ min
- APNs self-push: app sends push to itself for reliable background updates without interference from background audio session
- Single source of truth: all data flows from Storage/Observable
- Source-agnostic: IOB/COB/projected are optional, safe for Dexcom-only users
- Dynamic App Group ID: derived from bundle identifier, no hardcoded team IDs
- APNs key injected via xcconfig/Info.plist — never bundled, never committed

## Files added
- LoopFollow/LiveActivity/: APNSClient, APNSJWTGenerator, AppGroupID, GlucoseLiveActivityAttributes, GlucoseSnapshot, GlucoseSnapshotBuilder, GlucoseSnapshotStore, GlucoseUnitConversion, LAAppGroupSettings, LAThresholdSync, LiveActivityManager, PreferredGlucoseUnit, StorageCurrentGlucoseStateProvider
- LoopFollowLAExtension/: LoopFollowLiveActivity, LoopFollowLABundle
- docs/LiveActivity.md (architecture + APNs setup guide)

## Files modified
- Storage: added lastBgReadingTimeSeconds, lastDeltaMgdl, lastTrendCode, lastIOB, lastCOB, projectedBgMgdl
- Observable: added isNotLooping
- BGData, DeviceStatusLoop, DeviceStatusOpenAPS: write canonical values to Storage
- DeviceStatus: write isNotLooping to Observable
- BackgroundTaskAudio: cleanup
- MainViewController: wired LiveActivityManager.refreshFromCurrentState()
- Info.plist: added APNSKeyID, APNSTeamID, APNSKeyContent build settings
- fastlane/Fastfile: added extension App ID and provisioning profile
- build_LoopFollow.yml: inject APNs key from GitHub secret
- Consolidate JWT generation into JWTManager using CryptoKit with
  multi-slot in-memory cache, removing SwiftJWT and swift-crypto SPM
  dependencies
- Separate APNs keys for LoopFollow (lf) vs remote commands, with
  automatic team-ID routing and a migration step for legacy keys
- Add dedicated APN settings page for LoopFollow's own APNs keys
- Remove hardcoded APNs credentials from CI workflow and Info.plist
  in favor of user-configured keys
- Apply swiftformat to Live Activity files
@bjorkert
Copy link
Contributor Author

Summary of changes in 524b3bb — Replace SwiftJWT with CryptoKit and separate APNs credentials

Dependency removal:

  • Removes the SwiftJWT and swift-crypto SPM packages entirely. JWT signing now uses Apple's built-in CryptoKit (P256/ES256), eliminating two third-party dependencies.

JWT consolidation:

  • Deletes APNSJWTGenerator.swift. All JWT generation logic is now in JWTManager.swift, which uses an in-memory cache (keyed by keyId:teamId, 55-min TTL) instead of persisting JWT tokens to UserDefaults.

APNs credential separation:

  • Previously there was one set of APNs credentials (apnsKey/keyId) shared between remote commands and Live Activity. Now there are two distinct sets:
    • lfApnsKey/lfKeyId — for LoopFollow's own Live Activity pushes
    • remoteApnsKey/remoteKeyId — for remote commands to Loop/Trio
  • Removes the old "Return Notification Settings" section (which appeared when team IDs differed). Instead, the remote credential fields only show when team IDs differ, and LoopFollow credentials are always entered in the new APNSettingsView.

New APNSettingsView:

  • Adds a dedicated settings screen under the Settings menu for entering LoopFollow's own APNs Key ID and Key.

Migration (migrateStep5):

  • Migrates old credential storage keys (apnsKey, keyId, returnApnsKey, returnKeyId) to the new separated keys, handling same-team vs different-team scenarios. Cleans up the legacy keys afterward.

Build/CI updates:

  • Removes the Inject APNs Key Content CI step — credentials are no longer baked into the build via xcconfig/Info.plist. They're entered by the user at runtime.
  • Removes APNSKeyContent, APNSKeyID, APNSTeamID from Info.plist.
  • Updates CI to macos-26 / Xcode_26.2.

APNSClient refactored:

  • Uses JWTManager.shared instead of APNSJWTGenerator. Reads credentials from Storage.shared. Selects sandbox vs production APNs host based on BuildDetails.isTestFlightBuild().

Code style:

  • Standardized file headers, alphabetized imports, added trailing commas, cleaned up whitespace throughout the LiveActivity and Remote modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants