Skip to content

Commit 7197d14

Browse files
committed
Merge remote-tracking branch 'origin/dev' into fix/alarm-audio-session-activation
2 parents 32c103a + d691b34 commit 7197d14

82 files changed

Lines changed: 5753 additions & 783 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Lint
2+
run-name: Lint (${{ github.head_ref || github.ref_name }})
3+
4+
on:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
concurrency:
9+
group: lint-${{ github.ref }}
10+
cancel-in-progress: true
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
swiftformat:
17+
name: SwiftFormat
18+
runs-on: ubuntu-latest
19+
container: swift:6.0
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v5
23+
24+
- name: Cache SwiftFormat build
25+
uses: actions/cache@v4
26+
with:
27+
path: BuildTools/.build
28+
key: ${{ runner.os }}-swiftformat-${{ hashFiles('BuildTools/Package.resolved', 'BuildTools/Package.swift') }}
29+
restore-keys: |
30+
${{ runner.os }}-swiftformat-
31+
32+
- name: SwiftFormat --lint
33+
run: |
34+
swift run -c release --package-path BuildTools swiftformat . \
35+
--lint \
36+
--header "LoopFollow\n{file}" \
37+
--exclude Pods,Generated,R.generated.swift,fastlane/swift,Dependencies,dexcom-share-client-swift

.github/workflows/warn_main_pr.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Warn PR targets main
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, edited]
6+
branches:
7+
- main
8+
9+
jobs:
10+
warn:
11+
if: github.repository_owner == 'loopandlearn'
12+
runs-on: ubuntu-latest
13+
14+
permissions:
15+
pull-requests: write
16+
17+
steps:
18+
- name: Comment on PR
19+
uses: actions/github-script@v7
20+
with:
21+
script: |
22+
await github.rest.issues.createComment({
23+
owner: context.repo.owner,
24+
repo: context.repo.repo,
25+
issue_number: context.payload.pull_request.number,
26+
body: '⚠️ This PR targets the `main` branch. We do not accept PRs directly to `main` — please retarget your PR to the `dev` branch instead.'
27+
});

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,11 @@ fastlane/test_output
8080
fastlane/FastlaneRunner
8181

8282
LoopFollowConfigOverride.xcconfig
83-
.history
83+
.history*.xcuserstate
84+
docs/PR_configurable_slots.md
85+
docs/LiveActivityTestPlan.md
86+
87+
# Claude
88+
CLAUDE.md
89+
90+
node_modules/

Config.xcconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
unique_id = ${DEVELOPMENT_TEAM}
77

88
//Version (DEFAULT)
9-
LOOP_FOLLOW_MARKETING_VERSION = 5.0.9
9+
LOOP_FOLLOW_MARKETING_VERSION = 6.0.8

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ GEM
33
specs:
44
CFPropertyList (3.0.8)
55
abbrev (0.1.2)
6-
addressable (2.8.8)
6+
addressable (2.9.0)
77
public_suffix (>= 2.0.2, < 8.0)
88
artifactory (3.0.17)
99
atomos (0.1.3)

LoopFollow.xcodeproj/project.pbxproj

Lines changed: 300 additions & 51 deletions
Large diffs are not rendered by default.

LoopFollow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 96 deletions
This file was deleted.

LoopFollow/Alarm/Alarm.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct Alarm: Identifiable, Codable, Equatable {
107107
case missedBolusPrebolusWindow, missedBolusIgnoreSmallBolusUnits
108108
case missedBolusIgnoreUnderGrams, missedBolusIgnoreUnderBG
109109
case bolusCountThreshold, bolusWindowMinutes
110+
case sensorLifetimeDays
110111
}
111112

112113
init(from decoder: Decoder) throws {
@@ -137,6 +138,7 @@ struct Alarm: Identifiable, Codable, Equatable {
137138
missedBolusIgnoreUnderBG = try container.decodeIfPresent(Double.self, forKey: .missedBolusIgnoreUnderBG)
138139
bolusCountThreshold = try container.decodeIfPresent(Int.self, forKey: .bolusCountThreshold)
139140
bolusWindowMinutes = try container.decodeIfPresent(Int.self, forKey: .bolusWindowMinutes)
141+
sensorLifetimeDays = try container.decodeIfPresent(Int.self, forKey: .sensorLifetimeDays)
140142
}
141143

142144
func encode(to encoder: Encoder) throws {
@@ -165,6 +167,7 @@ struct Alarm: Identifiable, Codable, Equatable {
165167
try container.encodeIfPresent(missedBolusIgnoreUnderBG, forKey: .missedBolusIgnoreUnderBG)
166168
try container.encodeIfPresent(bolusCountThreshold, forKey: .bolusCountThreshold)
167169
try container.encodeIfPresent(bolusWindowMinutes, forKey: .bolusWindowMinutes)
170+
try container.encodeIfPresent(sensorLifetimeDays, forKey: .sensorLifetimeDays)
168171
}
169172

170173
// ─────────────────────────────────────────────────────────────
@@ -191,6 +194,12 @@ struct Alarm: Identifiable, Codable, Equatable {
191194
/// ...within this many minutes
192195
var bolusWindowMinutes: Int?
193196

197+
// ─────────────────────────────────────────────────────────────
198+
// Sensor‑Change fields ─
199+
// ─────────────────────────────────────────────────────────────
200+
/// CGM sensor lifetime in days (e.g. 10 for Dexcom G6, 15 for G7 15-day)
201+
var sensorLifetimeDays: Int?
202+
194203
/// Function for when the alarm is triggered.
195204
/// If this alarm, all alarms is disabled or snoozed, then should not be called. This or all alarmd could be muted, then this function will just generate a notification.
196205
func trigger(config: AlarmConfiguration, now: Date) {
@@ -318,6 +327,7 @@ struct Alarm: Identifiable, Codable, Equatable {
318327
case .sensorChange:
319328
soundFile = .wakeUpWillYou
320329
threshold = 12
330+
sensorLifetimeDays = 10
321331
case .pumpChange:
322332
soundFile = .wakeUpWillYou
323333
threshold = 12

LoopFollow/Alarm/AlarmCondition/PumpChangeCondition.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct PumpChangeCondition: AlarmCondition {
2222
func evaluate(alarm: Alarm, data: AlarmData, now _: Date) -> Bool {
2323
// 0. sanity guards
2424
guard let warnAheadHrs = alarm.threshold, warnAheadHrs > 0 else { return false }
25-
guard let insertTS = data.pumpInsertTime else { return false }
25+
guard let insertTS = data.pumpInsertTime, insertTS > 0 else { return false }
2626

2727
// convert UNIX timestamp → Date
2828
let insertedAt = Date(timeIntervalSince1970: insertTS)

LoopFollow/Alarm/AlarmCondition/SensorAgeCondition.swift

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,23 @@
33

44
import Foundation
55

6-
/// Fires once when we are **≤ threshold hours** away from the
7-
/// Dexcom 10-day hard-stop. No repeats once triggered.
6+
/// Fires when we are **≤ threshold hours** away from the
7+
/// sensor's configured lifetime.
88
struct SensorAgeCondition: AlarmCondition {
99
static let type: AlarmType = .sensorChange
1010
init() {}
1111

12-
/// Dexcom hard-stop = 10 days = 240 h
13-
private let lifetime: TimeInterval = 10 * 24 * 60 * 60
14-
1512
func evaluate(alarm: Alarm, data: AlarmData, now _: Date) -> Bool {
1613
// 0. basic guards
1714
guard let warnAheadHrs = alarm.threshold, warnAheadHrs > 0 else { return false }
18-
guard let insertTS = data.sageInsertTime else { return false }
15+
guard let insertTS = data.sageInsertTime, insertTS > 0 else { return false }
1916

2017
// convert UNIX timestamp to Date
2118
let insertedAt = Date(timeIntervalSince1970: insertTS)
2219

23-
// 1. compute trigger moment
20+
// 1. compute trigger moment using configurable lifetime (default 10 days)
21+
let lifetimeDays = alarm.sensorLifetimeDays ?? 10
22+
let lifetime: TimeInterval = Double(lifetimeDays) * 24 * 60 * 60
2423
let expiry = insertedAt.addingTimeInterval(lifetime)
2524
let trigger = expiry.addingTimeInterval(-warnAheadHrs * 3600)
2625

0 commit comments

Comments
 (0)