Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,8 @@ fastlane/screenshots
fastlane/test_output
fastlane/FastlaneRunner

ConfigOverride.xcconfig
ConfigOverride.xcconfig

# Node.js
node_modules/
scripts/dist/
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public extension OverrideStored {
@NSManaged var advancedSettings: Bool
@NSManaged var cr: Bool
@NSManaged var date: Date?
@NSManaged var disableDynamicISF: Bool
@NSManaged var duration: NSDecimalNumber?
@NSManaged var enabled: Bool
@NSManaged var end: NSDecimalNumber?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
<attribute name="advancedSettings" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="cr" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="disableDynamicISF" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="duration" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="end" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
Expand Down
39 changes: 39 additions & 0 deletions Trio.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,12 @@
FE41E4D629463EE20047FD55 /* NightscoutPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */; };
FE66D16B291F74F8005D6F77 /* Bundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */; };
FEFFA7A22929FE49007B8193 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */; };
4A46020CE79D50DE354388D2 /* ProfilePreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 454A047D1EAFCC939EE5F78F /* ProfilePreset.swift */; };
14D41039DA2596F4C61FF78D /* ProfilePresetStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1483D2092478350967C2F187 /* ProfilePresetStorage.swift */; };
431717ABC2142AA702DBE4BA /* ProfilePresetsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCE7ED830845881A9B7BFB13 /* ProfilePresetsDataFlow.swift */; };
A631E9E032EA6B20DC562273 /* ProfilePresetsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088BDB99FF13DF5C230E6505 /* ProfilePresetsProvider.swift */; };
562F7BCF655FE3E27FFDEAD7 /* ProfilePresetsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4206D510BF1723B0AE70D025 /* ProfilePresetsStateModel.swift */; };
1251C1C60CFB17F89B01BB17 /* ProfilePresetsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EB73A32687A94A200129336 /* ProfilePresetsRootView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1556,6 +1562,12 @@
FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutPreferences.swift; sourceTree = "<group>"; };
FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extensions.swift"; sourceTree = "<group>"; };
FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = "<group>"; };
454A047D1EAFCC939EE5F78F /* ProfilePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePreset.swift; sourceTree = "<group>"; };
1483D2092478350967C2F187 /* ProfilePresetStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePresetStorage.swift; sourceTree = "<group>"; };
FCE7ED830845881A9B7BFB13 /* ProfilePresetsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePresetsDataFlow.swift; sourceTree = "<group>"; };
088BDB99FF13DF5C230E6505 /* ProfilePresetsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePresetsProvider.swift; sourceTree = "<group>"; };
4206D510BF1723B0AE70D025 /* ProfilePresetsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePresetsStateModel.swift; sourceTree = "<group>"; };
6EB73A32687A94A200129336 /* ProfilePresetsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePresetsRootView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
Expand Down Expand Up @@ -1910,6 +1922,7 @@
19D466A129AA2B0A004D5F33 /* MealSettings */,
D533BF261CDC1C3F871E7BFD /* NightscoutConfig */,
BD47FD142D88AACC0043966B /* Onboarding */,
618FF40ED4142BF1E47414B8 /* ProfilePresets */,
99C01B871ACAB3F32CE755C7 /* PumpConfig */,
DD9ECB6B2CA99FA400AA7C45 /* RemoteControlConfig */,
3811DE3825C9D4A100A708ED /* Settings */,
Expand Down Expand Up @@ -2409,6 +2422,7 @@
BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
583684072BD195A700070A60 /* Determination.swift */,
BDC2EA462C3045AD00E5BBD0 /* Override.swift */,
454A047D1EAFCC939EE5F78F /* ProfilePreset.swift */,
DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */,
DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */,
DD9ECB692CA99F6C00AA7C45 /* CommandPayload.swift */,
Expand Down Expand Up @@ -3751,6 +3765,25 @@
path = View;
sourceTree = "<group>";
};
618FF40ED4142BF1E47414B8 /* ProfilePresets */ = {
isa = PBXGroup;
children = (
F801374D2248527BC2D92195 /* View */,
FCE7ED830845881A9B7BFB13 /* ProfilePresetsDataFlow.swift */,
088BDB99FF13DF5C230E6505 /* ProfilePresetsProvider.swift */,
4206D510BF1723B0AE70D025 /* ProfilePresetsStateModel.swift */,
);
path = ProfilePresets;
sourceTree = "<group>";
};
F801374D2248527BC2D92195 /* View */ = {
isa = PBXGroup;
children = (
6EB73A32687A94A200129336 /* ProfilePresetsRootView.swift */,
);
path = View;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -4117,6 +4150,12 @@
buildActionMask = 2147483647;
files = (
DD5DC9F12CF3D97C00AB8703 /* AdjustmentsStateModel+Overrides.swift in Sources */,
4A46020CE79D50DE354388D2 /* ProfilePreset.swift in Sources */,
14D41039DA2596F4C61FF78D /* ProfilePresetStorage.swift in Sources */,
431717ABC2142AA702DBE4BA /* ProfilePresetsDataFlow.swift in Sources */,
A631E9E032EA6B20DC562273 /* ProfilePresetsProvider.swift in Sources */,
562F7BCF655FE3E27FFDEAD7 /* ProfilePresetsStateModel.swift in Sources */,
1251C1C60CFB17F89B01BB17 /* ProfilePresetsRootView.swift in Sources */,
3811DE2325C9D48300A708ED /* MainDataFlow.swift in Sources */,
C2A0A42F2CE03131003B98E8 /* ConstantValues.swift in Sources */,
BD3CC0722B0B89D50013189E /* MainChartView.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Trio/Resources/javascript/bundle/determine-basal.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Trio/Sources/APS/OpenAPS/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,6 @@ extension OpenAPS {
static let settings = "freeaps/freeaps_settings.json"
static let tempTargetsPresets = "freeaps/temptargets_presets.json"
static let calibrations = "freeaps/calibrations.json"
static let profilePresets = "freeaps/profile_presets.json"
}
}
4 changes: 3 additions & 1 deletion Trio/Sources/APS/OpenAPS/OpenAPS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ final class OpenAPS {
let isOverrideIndefinite = activeOverrides.first?.indefinite ?? true
let disableSMBs = activeOverrides.first?.smbIsOff ?? false
let overrideTargetBG = activeOverrides.first?.target?.decimalValue ?? 0
let disableDynamicISF = activeOverrides.first?.disableDynamicISF ?? false

// Calculate averages for Total Daily Dose (TDD)
let totalTDD = historicalTDDData.compactMap { ($0["total"] as? NSDecimalNumber)?.decimalValue }.reduce(0, +)
Expand Down Expand Up @@ -452,7 +453,8 @@ final class OpenAPS {
start: (activeOverrides.first?.start ?? 0) as Decimal,
end: (activeOverrides.first?.end ?? 0) as Decimal,
smbMinutes: activeOverrides.first?.smbMinutes?.decimalValue ?? maxSMBBasalMinutes,
uamMinutes: activeOverrides.first?.uamMinutes?.decimalValue ?? maxUAMBasalMinutes
uamMinutes: activeOverrides.first?.uamMinutes?.decimalValue ?? maxUAMBasalMinutes,
disableDynamicISF: disableDynamicISF
)

// Save and return contents of Trio's custom oref variables
Expand Down
2 changes: 2 additions & 0 deletions Trio/Sources/APS/Storage/OverrideStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
newOverride.cr = override.cr
newOverride.enabled = override.enabled
newOverride.smbIsOff = override.smbIsOff
newOverride.disableDynamicISF = override.disableDynamicISF
if override.overrideTarget {
newOverride.target = override.target as NSDecimalNumber
} else {
Expand Down Expand Up @@ -195,6 +196,7 @@ final class BaseOverrideStorage: @preconcurrency OverrideStorage, Injectable {
newOverride.end = override.end
newOverride.smbMinutes = override.smbMinutes
newOverride.uamMinutes = override.uamMinutes
newOverride.disableDynamicISF = override.disableDynamicISF
newOverride.isUploadedToNS = true // set to true to avoid getting duplicate entries on NS

await viewContext.perform {
Expand Down
98 changes: 98 additions & 0 deletions Trio/Sources/APS/Storage/ProfilePresetStorage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import Foundation
import Swinject

protocol ProfilePresetStorage {
func presets() -> [ProfilePreset]
func savePresets(_ presets: [ProfilePreset])
func saveCurrentProfileAsPreset(name: String) -> ProfilePreset?
func activatePreset(_ preset: ProfilePreset) -> Bool
func deletePreset(id: String)
}

final class BaseProfilePresetStorage: ProfilePresetStorage, Injectable {
@Injected() private var storage: FileStorage!
@Injected() private var broadcaster: Broadcaster!

init(resolver: Resolver) {
injectServices(resolver)
}

func presets() -> [ProfilePreset] {
storage.retrieve(OpenAPS.Trio.profilePresets, as: [ProfilePreset].self) ?? []
}

func savePresets(_ presets: [ProfilePreset]) {
storage.save(presets, as: OpenAPS.Trio.profilePresets)
}

func saveCurrentProfileAsPreset(name: String) -> ProfilePreset? {
let basalProfile = storage.retrieve(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self)
?? [BasalProfileEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.basalProfile))
?? []

let insulinSensitivities = storage.retrieve(OpenAPS.Settings.insulinSensitivities, as: InsulinSensitivities.self)
?? InsulinSensitivities(from: OpenAPS.defaults(for: OpenAPS.Settings.insulinSensitivities))
?? InsulinSensitivities(units: .mgdL, userPreferredUnits: .mgdL, sensitivities: [])

let carbRatios = storage.retrieve(OpenAPS.Settings.carbRatios, as: CarbRatios.self)
?? CarbRatios(from: OpenAPS.defaults(for: OpenAPS.Settings.carbRatios))
?? CarbRatios(units: .grams, schedule: [])

let bgTargets = storage.retrieve(OpenAPS.Settings.bgTargets, as: BGTargets.self)
?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])

guard !basalProfile.isEmpty,
!insulinSensitivities.sensitivities.isEmpty,
!carbRatios.schedule.isEmpty,
!bgTargets.targets.isEmpty
else {
return nil
}

let preset = ProfilePreset(
name: name,
basalProfile: basalProfile,
insulinSensitivities: insulinSensitivities,
carbRatios: carbRatios,
bgTargets: bgTargets
)

var existingPresets = presets()
existingPresets.append(preset)
savePresets(existingPresets)

return preset
}

func activatePreset(_ preset: ProfilePreset) -> Bool {
guard !preset.basalProfile.isEmpty,
!preset.insulinSensitivities.sensitivities.isEmpty,
!preset.carbRatios.schedule.isEmpty,
!preset.bgTargets.targets.isEmpty
else {
return false
}

storage.save(preset.basalProfile, as: OpenAPS.Settings.basalProfile)
storage.save(preset.insulinSensitivities, as: OpenAPS.Settings.insulinSensitivities)
storage.save(preset.carbRatios, as: OpenAPS.Settings.carbRatios)
storage.save(preset.bgTargets, as: OpenAPS.Settings.bgTargets)

broadcaster.notify(BasalProfileObserver.self, on: .main) {
$0.basalProfileDidChange(preset.basalProfile)
}

broadcaster.notify(BGTargetsObserver.self, on: .main) {
$0.bgTargetsDidChange(preset.bgTargets)
}

return true
}

func deletePreset(id: String) {
var existingPresets = presets()
existingPresets.removeAll { $0.id == id }
savePresets(existingPresets)
}
}
1 change: 1 addition & 0 deletions Trio/Sources/Assemblies/StorageAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ final class StorageAssembly: Assembly {
container.register(SettingsManager.self) { r in BaseSettingsManager(resolver: r) }
container.register(Keychain.self) { _ in BaseKeychain() }
container.register(AlertHistoryStorage.self) { r in BaseAlertHistoryStorage(resolver: r) }
container.register(ProfilePresetStorage.self) { r in BaseProfilePresetStorage(resolver: r) }
}
}
1 change: 1 addition & 0 deletions Trio/Sources/Models/Override.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ struct Override {
let end: Decimal
let smbMinutes: Decimal
let uamMinutes: Decimal
let disableDynamicISF: Bool
}
55 changes: 55 additions & 0 deletions Trio/Sources/Models/ProfilePreset.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Foundation

struct ProfilePreset: JSON, Identifiable, Equatable {
let id: String
var name: String
var basalProfile: [BasalProfileEntry]
var insulinSensitivities: InsulinSensitivities
var carbRatios: CarbRatios
var bgTargets: BGTargets

init(
id: String = UUID().uuidString,
name: String,
basalProfile: [BasalProfileEntry],
insulinSensitivities: InsulinSensitivities,
carbRatios: CarbRatios,
bgTargets: BGTargets
) {
self.id = id
self.name = name
self.basalProfile = basalProfile
self.insulinSensitivities = insulinSensitivities
self.carbRatios = carbRatios
self.bgTargets = bgTargets
}

static func == (lhs: ProfilePreset, rhs: ProfilePreset) -> Bool {
lhs.id == rhs.id
}
}

extension ProfilePreset {
private enum CodingKeys: String, CodingKey {
case id
case name
case basalProfile = "basal_profile"
case insulinSensitivities = "insulin_sensitivities"
case carbRatios = "carb_ratios"
case bgTargets = "bg_targets"
}

var totalDailyBasal: Decimal {
basalProfile.enumerated().reduce(Decimal.zero) { result, entry in
let current = entry.element
let nextMinutes: Int
if entry.offset + 1 < basalProfile.count {
nextMinutes = basalProfile[entry.offset + 1].minutes
} else {
nextMinutes = 24 * 60
}
let durationHours = Decimal(nextMinutes - current.minutes) / 60
return result + current.rate * durationHours
}
}
}
4 changes: 4 additions & 0 deletions Trio/Sources/Models/TrioCustomOrefVariables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct TrioCustomOrefVariables: JSON, Equatable {
var end: Decimal
var smbMinutes: Decimal
var uamMinutes: Decimal
var disableDynamicISF: Bool

init(
average_total_data: Decimal,
Expand All @@ -43,6 +44,7 @@ struct TrioCustomOrefVariables: JSON, Equatable {
end: Decimal,
smbMinutes: Decimal,
uamMinutes: Decimal,
disableDynamicISF: Bool,
) {
self.average_total_data = average_total_data
self.weightedAverage = weightedAverage
Expand All @@ -64,6 +66,7 @@ struct TrioCustomOrefVariables: JSON, Equatable {
self.end = end
self.smbMinutes = smbMinutes
self.uamMinutes = uamMinutes
self.disableDynamicISF = disableDynamicISF
}
}

Expand All @@ -89,5 +92,6 @@ extension TrioCustomOrefVariables {
case end
case smbMinutes
case uamMinutes
case disableDynamicISF
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ extension Adjustments.StateModel {
start: start,
end: end,
smbMinutes: smbMinutes,
uamMinutes: uamMinutes
uamMinutes: uamMinutes,
disableDynamicISF: disableDynamicISF
)

// First disable all Overrides
Expand Down Expand Up @@ -154,7 +155,8 @@ extension Adjustments.StateModel {
start: start,
end: end,
smbMinutes: smbMinutes,
uamMinutes: uamMinutes
uamMinutes: uamMinutes,
disableDynamicISF: disableDynamicISF
)

async let storeOverride: () = overrideStorage.storeOverride(override: preset)
Expand Down Expand Up @@ -324,6 +326,7 @@ extension Adjustments.StateModel {
smbMinutes = defaultSmbMinutes
uamMinutes = defaultUamMinutes
target = currentGlucoseTarget
disableDynamicISF = false
}

/// Rounds a target value to the nearest step.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extension Adjustments {
var end: Decimal = 0
var smbMinutes: Decimal = 0
var uamMinutes: Decimal = 0
var disableDynamicISF: Bool = false
var defaultSmbMinutes: Decimal = 0
var defaultUamMinutes: Decimal = 0
var selectedTab: Tab = .overrides
Expand Down
Loading