Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
5a752fc
Add endo report PDF generator
greyghost99 Jun 5, 2026
952e141
Fix Nightscout profile auto-fill decoder for Trio/missing fields
greyghost99 Jun 5, 2026
3fda82b
Add time range labels to Glucose by Time of Day strip
greyghost99 Jun 8, 2026
9ff1cd5
Show all TIR zones in bar and fix time-of-day value centering
greyghost99 Jun 17, 2026
693a929
Fix Endo report config redeclaration and improve report layout spacing
greyghost99 Jun 17, 2026
7c48af8
Refine Endo report charts and fix Nightscout autofill profile parsing
greyghost99 Jun 20, 2026
310de67
Move release flow to PR-based and add CODEOWNERS for branch protectio…
bjorkert May 30, 2026
828fcde
CI: Bump dev version to 6.1.1 [skip ci]
github-actions[bot] May 30, 2026
f36b8a9
Diagnose and skip rogue Nightscout profile records (#635)
bjorkert May 30, 2026
f62e712
CI: Bump dev version to 6.1.2 [skip ci]
github-actions[bot] May 30, 2026
ee48e3e
Prevent stale foreground-restart latch from tearing down freshly rene…
bjorkert May 31, 2026
17582b0
CI: Bump dev version to 6.1.3 [skip ci]
github-actions[bot] May 31, 2026
39d3d39
Recover Live Activity after APNs 410 token expiry (#657)
bjorkert May 31, 2026
3eee687
CI: Bump dev version to 6.1.4 [skip ci]
github-actions[bot] May 31, 2026
f792d74
Auto-restart Live Activity when iOS sends .ended (#659)
bjorkert May 31, 2026
478328b
CI: Bump dev version to 6.1.5 [skip ci]
github-actions[bot] May 31, 2026
19905bb
Deduplicate Dexcom Share readings to fix delta always showing zero (#…
bjorkert May 31, 2026
f7f731e
CI: Bump dev version to 6.1.6 [skip ci]
github-actions[bot] May 31, 2026
a1e8e95
Remove storyboard, migrate to SwiftUI layout (#608)
bjorkert Jun 12, 2026
b0ce2d1
Suppress silent passive notifications in willPresent handler (#655)
bjorkert Jun 14, 2026
b363c13
Bump fastlane to 2.235.0 and jwt to 3.2.0 (CVE-2026-45363) (#663)
bjorkert Jun 14, 2026
99cd60e
Fix BG history truncation caused by duplicate readings from multiple …
bjorkert Jun 14, 2026
51fe214
Match Trio's override/temp-target colors for non-Loop backends (#668)
bjorkert Jun 14, 2026
de98f2e
Quick-Pick Boluses and Meals for remote commands (#603)
bjorkert Jun 14, 2026
ed6ec77
Add Nightscout WebSocket support for real-time data updates (#606)
bjorkert Jun 14, 2026
cf69cfa
Default debug logging on and prompt for description when sharing logs…
bjorkert Jun 14, 2026
2d8e8f9
Add optional yesterday BG comparison line to main graph (#665)
bjorkert Jun 14, 2026
919b772
Scale info data table text with Dynamic Type (#667)
bjorkert Jun 15, 2026
8dda66f
CI: Bump dev version to 6.1.7 [skip ci]
github-actions[bot] Jun 15, 2026
33e67cb
ITMS-91061 - privacy manifest for Charts framework (#666)
luborjurena Jun 16, 2026
7ce2bcf
CI: Bump dev version to 6.1.8 [skip ci]
github-actions[bot] Jun 16, 2026
1717823
Remove the Nightscout-based remote command path (#618)
bjorkert Jun 16, 2026
f02eece
CI: Bump dev version to 6.1.9 [skip ci]
github-actions[bot] Jun 16, 2026
fa31b21
Cap prediction cone to shortest predBG array length (#653)
quarktwain Jun 16, 2026
7e71f59
CI: Bump dev version to 6.1.10 [skip ci]
github-actions[bot] Jun 16, 2026
f27be2a
CI: Re-run lint when a PR's base branch changes (#676)
bjorkert Jun 17, 2026
ab43544
CI: Bump dev version to 6.1.11 [skip ci]
github-actions[bot] Jun 17, 2026
0ef8881
Remove empty Nightscout group from project file (#675)
bjorkert Jun 17, 2026
6479c0c
CI: Bump dev version to 6.1.12 [skip ci]
github-actions[bot] Jun 17, 2026
9d2cea6
update version to 6.2.0 [skip ci]
marionbarker Jun 21, 2026
ad760fb
Merge pull request #1 from type1ghost/feature/endo-report
greyghost99 Jun 22, 2026
7a57393
Merge branch 'loopandlearn:dev' into dev
greyghost99 Jun 22, 2026
f110079
Merge pull request #2 from type1ghost/dev
greyghost99 Jun 22, 2026
083afcf
Merge branch 'loopandlearn:main' into feature/endo-report
greyghost99 Jun 22, 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
14 changes: 8 additions & 6 deletions LoopFollow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@
65E153C32E4BB69100693A4F /* URLTokenValidationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E153C22E4BB69100693A4F /* URLTokenValidationView.swift */; };
65E8A2862E44B0300065037B /* VolumeButtonHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65E8A2852E44B0300065037B /* VolumeButtonHandler.swift */; };
66E3D12E66AA4534A144A54B /* BackgroundRefreshManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CA8BE0B3D247408FE088B4 /* BackgroundRefreshManager.swift */; };
9C7FB98C98BE4FF98F4815EE /* Telemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFBE69CEF18416D84959974 /* Telemetry.swift */; };
A1A1A10001000000A0CFEED1 /* APNsCredentialValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A10001000000A0CFEED2 /* APNsCredentialValidator.swift */; };
A1A1A10002000000A0CFEED1 /* LogRedactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A10002000000A0CFEED2 /* LogRedactor.swift */; };
AB1CD0012C7B30D40048F05C /* RemoteDiagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB1CD0022C7B30D40048F05C /* RemoteDiagnostics.swift */; };
ACE7F6DE0D065BEB52CDC0DB /* FutureCarbsAlarmEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D2A4EFD18B7B7748B6669E /* FutureCarbsAlarmEditor.swift */; };
DD0247592DB2E89600FCADF6 /* AlarmCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0247582DB2E89600FCADF6 /* AlarmCondition.swift */; };
DD0247712DB4337700FCADF6 /* BuildExpireCondition.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD02475B2DB2E8FB00FCADF6 /* BuildExpireCondition.swift */; };
Expand Down Expand Up @@ -259,7 +263,6 @@
DDD10F0B2C54192A00D76A8E /* TemporaryTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD10F0A2C54192A00D76A8E /* TemporaryTarget.swift */; };
DDDB86F12DF7223C00AADDAC /* DeleteAlarmSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB86F02DF7223C00AADDAC /* DeleteAlarmSection.swift */; };
DDDC01DD2E244B3100D9975C /* JWTManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDC01DC2E244B3100D9975C /* JWTManager.swift */; };
A1A1A10002000000A0CFEED1 /* LogRedactor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A10002000000A0CFEED2 /* LogRedactor.swift */; };
DDDC31CC2E13A7DF009EA0F3 /* AddAlarmSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDC31CB2E13A7DF009EA0F3 /* AddAlarmSheet.swift */; };
DDDC31CE2E13A811009EA0F3 /* AlarmTile.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDC31CD2E13A811009EA0F3 /* AlarmTile.swift */; };
DDE69ED22C7256260013EAEC /* RemoteType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE69ED12C7256260013EAEC /* RemoteType.swift */; };
Expand Down Expand Up @@ -301,7 +304,6 @@
FC1BDD3224A2585C001B652C /* DataStructs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1BDD2E24A232A3001B652C /* DataStructs.swift */; };
FC3AE7B5249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FC3AE7B3249E8E0E00AAE1E0 /* LoopFollow.xcdatamodeld */; };
FC3CAB022493B6220068A152 /* BackgroundTaskAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC688592489554800A0279D /* BackgroundTaskAudio.swift */; };
A1A1A10001000000A0CFEED1 /* APNsCredentialValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A10001000000A0CFEED2 /* APNsCredentialValidator.swift */; };
FC5A5C3D2497B229009C550E /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FC5A5C3C2497B229009C550E /* Config.xcconfig */; };
FC7CE518248ABE37001F83B8 /* Siri_Alert_Calibration_Needed.caf in Resources */ = {isa = PBXBuildFile; fileRef = FC7CE4A9248ABE2B001F83B8 /* Siri_Alert_Calibration_Needed.caf */; };
FC7CE519248ABE37001F83B8 /* Rise_And_Shine.caf in Resources */ = {isa = PBXBuildFile; fileRef = FC7CE4AA248ABE2B001F83B8 /* Rise_And_Shine.caf */; };
Expand Down Expand Up @@ -432,7 +434,6 @@
FCC6886B24898FD800A0279D /* ObservationToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC6886A24898FD800A0279D /* ObservationToken.swift */; };
FCC6886D2489909D00A0279D /* AnyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC6886C2489909D00A0279D /* AnyConvertible.swift */; };
FCC6886F2489A53800A0279D /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC6886E2489A53800A0279D /* AppConstants.swift */; };
9C7FB98C98BE4FF98F4815EE /* Telemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFBE69CEF18416D84959974 /* Telemetry.swift */; };
FCD2A27D24C9D044009F7B7B /* Globals.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCD2A27C24C9D044009F7B7B /* Globals.swift */; };
FCE537BC249A4D7D00F80BF8 /* carbBolusArrays.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCE537BB249A4D7D00F80BF8 /* carbBolusArrays.swift */; };
FCEF87AC24A141A700AE6FA0 /* Localizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEF87AA24A1417900AE6FA0 /* Localizer.swift */; };
Expand Down Expand Up @@ -532,9 +533,13 @@
65A100022F5AA00000AA1002 /* UnitsConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsConfigurationView.swift; sourceTree = "<group>"; };
65E153C22E4BB69100693A4F /* URLTokenValidationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLTokenValidationView.swift; sourceTree = "<group>"; };
65E8A2852E44B0300065037B /* VolumeButtonHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VolumeButtonHandler.swift; sourceTree = "<group>"; };
A1A1A10001000000A0CFEED2 /* APNsCredentialValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNsCredentialValidator.swift; sourceTree = "<group>"; };
A1A1A10002000000A0CFEED2 /* LogRedactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRedactor.swift; sourceTree = "<group>"; };
A7D55B42A22051DAD69E89D0 /* Pods_LoopFollow.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_LoopFollow.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A8CA8BE0B3D247408FE088B4 /* BackgroundRefreshManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundRefreshManager.swift; sourceTree = "<group>"; };
AB1CD0022C7B30D40048F05C /* RemoteDiagnostics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteDiagnostics.swift; sourceTree = "<group>"; };
B7D2A4EFD18B7B7748B6669E /* FutureCarbsAlarmEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FutureCarbsAlarmEditor.swift; sourceTree = "<group>"; };
BDFBE69CEF18416D84959974 /* Telemetry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Telemetry.swift; sourceTree = "<group>"; };
DD0247582DB2E89600FCADF6 /* AlarmCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmCondition.swift; sourceTree = "<group>"; };
DD02475B2DB2E8FB00FCADF6 /* BuildExpireCondition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildExpireCondition.swift; sourceTree = "<group>"; };
DD026E582EA2C8A200A39CB5 /* InsulinPrecisionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinPrecisionManager.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -728,7 +733,6 @@
DDD10F0A2C54192A00D76A8E /* TemporaryTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemporaryTarget.swift; sourceTree = "<group>"; };
DDDB86F02DF7223C00AADDAC /* DeleteAlarmSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteAlarmSection.swift; sourceTree = "<group>"; };
DDDC01DC2E244B3100D9975C /* JWTManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTManager.swift; sourceTree = "<group>"; };
A1A1A10002000000A0CFEED2 /* LogRedactor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogRedactor.swift; sourceTree = "<group>"; };
DDDC31CB2E13A7DF009EA0F3 /* AddAlarmSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAlarmSheet.swift; sourceTree = "<group>"; };
DDDC31CD2E13A811009EA0F3 /* AlarmTile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlarmTile.swift; sourceTree = "<group>"; };
DDE69ED12C7256260013EAEC /* RemoteType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteType.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -896,15 +900,13 @@
FCA2DDE52501095000254A8C /* Timers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Timers.swift; sourceTree = "<group>"; };
FCC0FAC124922A22003E610E /* DictionaryKeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryKeyPath.swift; sourceTree = "<group>"; };
FCC688592489554800A0279D /* BackgroundTaskAudio.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundTaskAudio.swift; sourceTree = "<group>"; };
A1A1A10001000000A0CFEED2 /* APNsCredentialValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNsCredentialValidator.swift; sourceTree = "<group>"; };
FCC6885B2489559400A0279D /* blank.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = blank.wav; sourceTree = "<group>"; };
FCC6885D24896A6C00A0279D /* silence.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = silence.mp3; sourceTree = "<group>"; };
FCC6886624898F8000A0279D /* UserDefaultsValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsValue.swift; sourceTree = "<group>"; };
FCC6886824898FB100A0279D /* UserDefaultsValueGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsValueGroups.swift; sourceTree = "<group>"; };
FCC6886A24898FD800A0279D /* ObservationToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservationToken.swift; sourceTree = "<group>"; };
FCC6886C2489909D00A0279D /* AnyConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyConvertible.swift; sourceTree = "<group>"; };
FCC6886E2489A53800A0279D /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = "<group>"; };
BDFBE69CEF18416D84959974 /* Telemetry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Telemetry.swift; sourceTree = "<group>"; };
FCC688702489A57C00A0279D /* Loop Follow.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Loop Follow.entitlements"; sourceTree = "<group>"; };
FCD2A27C24C9D044009F7B7B /* Globals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Globals.swift; sourceTree = "<group>"; };
FCE537BB249A4D7D00F80BF8 /* carbBolusArrays.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = carbBolusArrays.swift; sourceTree = "<group>"; };
Expand Down
21 changes: 16 additions & 5 deletions LoopFollow/Stats/AggregatedStatsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct AggregatedStatsView: View {
@State private var loadingError = false
@State private var loadingTimer: Timer?
@State private var timeoutTimer: Timer?
@State private var showEndoReport = false

init(viewModel: AggregatedStatsViewModel, onDismiss: (() -> Void)? = nil) {
self.viewModel = viewModel
Expand Down Expand Up @@ -108,15 +109,25 @@ struct AggregatedStatsView: View {
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("Refresh") {
loadingError = false
isLoadingData = true
viewModel.updateDateRange(start: startDate, end: endDate) {
isLoadingData = false
HStack {
Button {
showEndoReport = true
} label: {
Label("Endo Report", systemImage: "doc.richtext")
}
Button("Refresh") {
loadingError = false
isLoadingData = true
viewModel.updateDateRange(start: startDate, end: endDate) {
isLoadingData = false
}
}
}
}
}
.sheet(isPresented: $showEndoReport) {
EndoReportView(dataService: viewModel.dataService)
}
.onAppear {
loadingError = false
isLoadingData = true
Expand Down
42 changes: 42 additions & 0 deletions LoopFollow/Stats/EndoReportConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// LoopFollow
// EndoReportConfig.swift

import UIKit

struct EndoReportConfig {
let patientName: String
let dateOfBirth: String
let diagnosisDate: String
let providerName: String
let insulinType: String
let aidSystem: String
let pumpDevice: String
let cgmDevice: String
let carbRatio: String
let isf: String
let basalRate: String
let targetGlucose: String
let units: String
let accentColorHex: String
let notes: String
let includeGlucoseSummary: Bool
let includeInsulin: Bool
let includeNutrition: Bool
let includeTherapySettings: Bool
let includeDevices: Bool
let includeAGP: Bool
let includeDailyBreakdown: Bool
let includeFatProtein: Bool
let startDate: Date
let endDate: Date

var accentColor: UIColor {
UIColor(hex: accentColorHex) ?? UIColor(red: 0.137, green: 0.624, blue: 0.675, alpha: 1)
}

var isMMOL: Bool { units == "mmol/L" }
func convert(_ mgdl: Double) -> Double { isMMOL ? mgdl * 0.0555 : mgdl }
func fmtBG(_ mgdl: Double) -> String {
isMMOL ? String(format: "%.1f", mgdl * 0.0555) : String(format: "%.0f", mgdl)
}
}
Loading