diff --git a/Cartfile b/Cartfile index 4f8e32a7af..339f6acd46 100644 --- a/Cartfile +++ b/Cartfile @@ -1,7 +1,7 @@ -github "LoopKit/LoopKit" == 1.5.6 +github "LoopKit/LoopKit" == 2.0 github "LoopKit/CGMBLEKit" == 2.1 github "i-schuetz/SwiftCharts" == 0.6.1 github "mddub/dexcom-share-client-swift" == 0.4.1 github "mddub/G4ShareSpy" == 0.3.3 -github "ps2/rileylink_ios" == 2.0.0 +github "ps2/rileylink_ios" == 2.0.2 github "LoopKit/Amplitude-iOS" "decreepify" diff --git a/Cartfile.resolved b/Cartfile.resolved index 5b46c41bb2..8827b4175d 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,7 +1,7 @@ github "LoopKit/Amplitude-iOS" "2137d5fd44bf630ed33e1e72d7af6d8f8612f270" github "LoopKit/CGMBLEKit" "v2.1.0" -github "LoopKit/LoopKit" "v1.5.6" +github "LoopKit/LoopKit" "v2.0" github "i-schuetz/SwiftCharts" "6b55a26a7b0b95e49202ddc1db5404702fce114f" github "mddub/G4ShareSpy" "v0.3.3" github "mddub/dexcom-share-client-swift" "v0.4.1" -github "ps2/rileylink_ios" "v2.0.0" +github "ps2/rileylink_ios" "v2.0.2" diff --git a/Carthage/Build/.LoopKit.version b/Carthage/Build/.LoopKit.version index 6777a46027..9a5d619c12 100644 --- a/Carthage/Build/.LoopKit.version +++ b/Carthage/Build/.LoopKit.version @@ -3,28 +3,23 @@ ], "watchOS" : [ - + { + "name" : "LoopKit", + "hash" : "20c485ddd0021810833b211f718c8070cc0b631cac07055af471c8a3f6a15d80" + } ], "tvOS" : [ ], - "commitish" : "v1.5.6", + "commitish" : "v2.0", "iOS" : [ { - "name" : "GlucoseKit", - "hash" : "1ef4ccb9582a5a31643443c4e5c8d0fef7ef760c30cd09f545508e6a8458ae92" - }, - { - "name" : "InsulinKit", - "hash" : "15de73844cdbc5e2e1277ab01ac5d39c8085f5aeb6718aab4a8257c1943c902e" + "name" : "LoopKitUI", + "hash" : "6041aca0e5f6d07c1cdc7a6608ab4c2cfa436ae59f9e3f65e881f5c39700b289" }, { "name" : "LoopKit", - "hash" : "4fc0c5f661d96f375b30647728c1a2ff2164cd41ce046bbb86f8dc86bf9b76a8" - }, - { - "name" : "CarbKit", - "hash" : "aed7066da389d043482db40034f6d63b220b15852d0f6fe7ef9739ee8835b87f" + "hash" : "72a69341b8c7d4b6ded0fec1c67ced7faa2d785a8c8dbe6b18e678a5f1455df1" } ] } \ No newline at end of file diff --git a/Carthage/Build/.rileylink_ios.version b/Carthage/Build/.rileylink_ios.version index 61db1ce0fe..815ba9ad69 100644 --- a/Carthage/Build/.rileylink_ios.version +++ b/Carthage/Build/.rileylink_ios.version @@ -5,37 +5,37 @@ "watchOS" : [ { "name" : "RileyLinkBLEKit", - "hash" : "c94d79d1403870df4539dd531024d5b44333642f28d49f8e9f4e26fbad42fd7a" + "hash" : "945d71a3404e1719e190b2c8d0bcada86fc56430459ee061d5ef8ee18cc64278" } ], "tvOS" : [ ], - "commitish" : "v2.0.0", + "commitish" : "v2.0.2", "iOS" : [ { "name" : "Crypto", - "hash" : "03768a89eb61f55cc386ae4586048ae851d61373da6868aab905db2a2586efc7" + "hash" : "307a074bb6612029834159e536ac793e29a3ca4924f9be05788596569771a8d7" }, { - "name" : "RileyLinkKitUI", - "hash" : "dc1035fdadd445d12f383f01c10225b62aa7eca1f4da9016420d1835487628bb" + "name" : "RileyLinkKit", + "hash" : "862e23540e3f6f52ca32fe17bf43b7a6aa075ed11235c472d46165ec85610ca1" }, { - "name" : "RileyLinkKit", - "hash" : "69fd21c5cd31ca8fe4611b01139780b1df32e71400a6fd91ebc865d85791b0a5" + "name" : "RileyLinkBLEKit", + "hash" : "37b0e43fa19b5893251fcb09cd9cec6c9b12b78ec70e85439adf9f3924817f13" }, { - "name" : "NightscoutUploadKit", - "hash" : "d3fe0bc023a0a275dddec6bba616ff38239acf44ee71879e270a3f8690e4961d" + "name" : "RileyLinkKitUI", + "hash" : "f99d44ea3c18c72fcfa49e8ec79906dec2a820e03d00c4dcd7d84408293d4eb7" }, { - "name" : "RileyLinkBLEKit", - "hash" : "a95573627d6ad9a853c620938e53e97d4c054553fde4af097a489038b020fd2f" + "name" : "NightscoutUploadKit", + "hash" : "c8e94505a0006eb0687824099064283fe2bc657efd6eccf0b1a77f72c0a26e11" }, { "name" : "MinimedKit", - "hash" : "c5f8ad60aea1a15646ed78afcb485435b55cb6e5b54d7d299d2415e5fa74cf38" + "hash" : "18315d9c754c0c82fd13616ec082362d853c59923922711350a64436fd26b833" } ] } \ No newline at end of file diff --git a/Carthage/Build/iOS/CarbKit.framework/Assets.car b/Carthage/Build/iOS/CarbKit.framework/Assets.car index 9a30a8fa07..28e4ef8533 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Assets.car and b/Carthage/Build/iOS/CarbKit.framework/Assets.car differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit b/Carthage/Build/iOS/CarbKit.framework/CarbKit index fec280e936..0f02f7a367 100755 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit and b/Carthage/Build/iOS/CarbKit.framework/CarbKit differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/objects-11.0+.nib index 0486bfe4ee..67a47818c3 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/runtime.nib index cfa3f7f0e0..2c1473c336 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbAbsorptionInputController.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/objects-11.0+.nib index 377d06b04d..293e5dad52 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/runtime.nib index fa4f7c7d8e..debfc819ae 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryEditViewController.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/objects-11.0+.nib index c5732723bd..3cb7c32cce 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/runtime.nib index 2fa8dbae67..cd24a3d75e 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/CarbEntryTableViewController.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/objects-11.0+.nib index 1ca760e93e..45c9684b9f 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/runtime.nib index e45e7b27f3..cc241e4479 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/objects-11.0+.nib index c3f36895b5..eb42ed55de 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/runtime.nib index 8611f33726..9959b7e409 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/objects-11.0+.nib index bb0d54205d..b11a78eb3d 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/runtime.nib index 4e6d64c350..432cc885fb 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/objects-11.0+.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/objects-11.0+.nib index c43b9bdc4f..3f9539be16 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/objects-11.0+.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/objects-11.0+.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/runtime.nib b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/runtime.nib index 9952806b2b..3b97ec04cd 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/runtime.nib and b/Carthage/Build/iOS/CarbKit.framework/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib/runtime.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/DatePickerTableViewCell.nib b/Carthage/Build/iOS/CarbKit.framework/DatePickerTableViewCell.nib index 02002de103..cbedff30c1 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/DatePickerTableViewCell.nib and b/Carthage/Build/iOS/CarbKit.framework/DatePickerTableViewCell.nib differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Headers/CarbKit-Swift.h b/Carthage/Build/iOS/CarbKit.framework/Headers/CarbKit-Swift.h index f64955a0e9..58e685e56f 100644 --- a/Carthage/Build/iOS/CarbKit.framework/Headers/CarbKit-Swift.h +++ b/Carthage/Build/iOS/CarbKit.framework/Headers/CarbKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/CarbKit.framework/Info.plist b/Carthage/Build/iOS/CarbKit.framework/Info.plist index 081e65c882..cd136e95df 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Info.plist and b/Carthage/Build/iOS/CarbKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftdoc index f280575a1e..701363d28f 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftmodule index cb9e02b1b2..b05552e15e 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftdoc index 0afc32a22d..c5add95c7c 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftmodule index 3bae421e9a..7fe79de896 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftdoc index 2625653fae..1d8fbe204b 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftmodule index 3bb540a1c9..15a5f62e7c 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftdoc index 21a4c45026..1feeeb4a5f 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftmodule index 5460cbc3e1..3f3ab75a01 100644 Binary files a/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/CarbKit.framework/Modules/CarbKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/Crypto.framework/Crypto b/Carthage/Build/iOS/Crypto.framework/Crypto index 3e1d7d6d30..c8ff5e322b 100755 Binary files a/Carthage/Build/iOS/Crypto.framework/Crypto and b/Carthage/Build/iOS/Crypto.framework/Crypto differ diff --git a/Carthage/Build/iOS/Crypto.framework/Info.plist b/Carthage/Build/iOS/Crypto.framework/Info.plist index 966cd811ab..2ea6f0caff 100644 Binary files a/Carthage/Build/iOS/Crypto.framework/Info.plist and b/Carthage/Build/iOS/Crypto.framework/Info.plist differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/GlucoseKit b/Carthage/Build/iOS/GlucoseKit.framework/GlucoseKit index 89ee4e02d4..56c9e925ef 100755 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/GlucoseKit and b/Carthage/Build/iOS/GlucoseKit.framework/GlucoseKit differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Headers/GlucoseKit-Swift.h b/Carthage/Build/iOS/GlucoseKit.framework/Headers/GlucoseKit-Swift.h index 29e2d646ee..80879e9cea 100644 --- a/Carthage/Build/iOS/GlucoseKit.framework/Headers/GlucoseKit-Swift.h +++ b/Carthage/Build/iOS/GlucoseKit.framework/Headers/GlucoseKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Info.plist b/Carthage/Build/iOS/GlucoseKit.framework/Info.plist index 816d699ec2..1badf4e266 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Info.plist and b/Carthage/Build/iOS/GlucoseKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftdoc index 912099f682..c889a22deb 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftmodule index d45c871351..99ef4da5d7 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftdoc index 3fa79dd5bc..6c6442bc32 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftmodule index 5bfc73a677..04a1ff8bc4 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftdoc index 0d21ad5e50..a202c9dc36 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftmodule index 67356f2a5c..8b139b93aa 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftdoc index aa1836f17c..6cbbfb3c78 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftmodule index fd10dc28a6..38a9d0a5be 100644 Binary files a/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/GlucoseKit.framework/Modules/GlucoseKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib b/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib index f5ac10e31e..8ca90af616 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib and b/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib b/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib index 73ab9d38c7..3e7699045d 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib and b/Carthage/Build/iOS/InsulinKit.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Headers/InsulinKit-Swift.h b/Carthage/Build/iOS/InsulinKit.framework/Headers/InsulinKit-Swift.h index cd3119532f..237233111f 100644 --- a/Carthage/Build/iOS/InsulinKit.framework/Headers/InsulinKit-Swift.h +++ b/Carthage/Build/iOS/InsulinKit.framework/Headers/InsulinKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/InsulinKit.framework/Info.plist b/Carthage/Build/iOS/InsulinKit.framework/Info.plist index 8994736d76..a8ef9d1f64 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Info.plist and b/Carthage/Build/iOS/InsulinKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/InsulinKit b/Carthage/Build/iOS/InsulinKit.framework/InsulinKit index 50b0bc1304..a565735a7b 100755 Binary files a/Carthage/Build/iOS/InsulinKit.framework/InsulinKit and b/Carthage/Build/iOS/InsulinKit.framework/InsulinKit differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftdoc index e861493884..0a17b0a500 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftmodule index 8c5f8d49d6..c538780c0d 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftdoc index 09332307f6..c252f86d4a 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftmodule index 9d01099fe5..572e7bf5c6 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftdoc index 6e5f5ee129..46f72431ac 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftmodule index eaafed5888..fb4da84b55 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftdoc index d5c39cd5a9..a8d8ac3289 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftmodule index 7de63982a3..7a518a15f1 100644 Binary files a/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/InsulinKit.framework/Modules/InsulinKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeOverrideTableViewCell.nib b/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeOverrideTableViewCell.nib deleted file mode 100644 index e2ca39c33b..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeOverrideTableViewCell.nib and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeTableViewCell.nib b/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeTableViewCell.nib deleted file mode 100644 index fdbef1acfb..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/GlucoseRangeTableViewCell.nib and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Headers/LoopKit-Swift.h b/Carthage/Build/iOS/LoopKit.framework/Headers/LoopKit-Swift.h index 605b19b620..378e7ce864 100644 --- a/Carthage/Build/iOS/LoopKit.framework/Headers/LoopKit-Swift.h +++ b/Carthage/Build/iOS/LoopKit.framework/Headers/LoopKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" @@ -163,9 +163,8 @@ typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); # define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) #endif #if __has_feature(modules) -@import UIKit; +@import CoreData; @import Foundation; -@import CoreGraphics; @import HealthKit; #endif @@ -184,89 +183,64 @@ typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); # pragma pop_macro("any") #endif -@class NSCoder; -@class NSBundle; +@class NSEntityDescription; +@class NSManagedObjectContext; -SWIFT_CLASS("_TtC7LoopKit29CommandResponseViewController") -@interface CommandResponseViewController : UIViewController -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; -- (void)loadView; -- (void)viewDidLoad; -- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +SWIFT_CLASS("_TtC7LoopKit16CachedCarbObject") +@interface CachedCarbObject : NSManagedObject +- (nonnull instancetype)initWithEntity:(NSEntityDescription * _Nonnull)entity insertIntoManagedObjectContext:(NSManagedObjectContext * _Nullable)context OBJC_DESIGNATED_INITIALIZER; @end -@class UIActivityViewController; -@interface CommandResponseViewController (SWIFT_EXTENSION(LoopKit)) -- (id _Nonnull)activityViewControllerPlaceholderItem:(UIActivityViewController * _Nonnull)activityViewController SWIFT_WARN_UNUSED_RESULT; -- (id _Nullable)activityViewController:(UIActivityViewController * _Nonnull)activityViewController itemForActivityType:(UIActivityType _Nullable)activityType SWIFT_WARN_UNUSED_RESULT; -- (NSString * _Nonnull)activityViewController:(UIActivityViewController * _Nonnull)activityViewController subjectForActivityType:(UIActivityType _Nullable)activityType SWIFT_WARN_UNUSED_RESULT; -@end -@class UITableView; -@class UITableViewCell; - -SWIFT_CLASS("_TtC7LoopKit37DailyValueScheduleTableViewController") -@interface DailyValueScheduleTableViewController : UITableViewController -- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; -- (void)viewDidLoad; -- (void)setEditing:(BOOL)editing animated:(BOOL)animated; -- (void)viewWillDisappear:(BOOL)animated; -- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; -- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (BOOL)tableView:(UITableView * _Nonnull)tableView canMoveRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (CGFloat)tableView:(UITableView * _Nonnull)tableView heightForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (BOOL)tableView:(UITableView * _Nonnull)tableView shouldHighlightRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (void)tableView:(UITableView * _Nonnull)tableView didDeselectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (NSIndexPath * _Nonnull)tableView:(UITableView * _Nonnull)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toProposedIndexPath:(NSIndexPath * _Nonnull)proposedDestinationIndexPath SWIFT_WARN_UNUSED_RESULT; -- (nonnull instancetype)initWithStyle:(UITableViewStyle)style SWIFT_UNAVAILABLE; -- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@class NSNumber; +@class NSDate; + +@interface CachedCarbObject (SWIFT_EXTENSION(LoopKit)) +@property (nonatomic, strong) NSNumber * _Nullable primitiveAbsorptionTime; +@property (nonatomic) BOOL createdByCurrentApp; +@property (nonatomic, copy) NSString * _Nullable externalID; +@property (nonatomic, copy) NSString * _Nullable foodType; +@property (nonatomic) double grams; +@property (nonatomic, strong) NSDate * _Nullable primitiveStartDate; +@property (nonatomic, strong) NSNumber * _Nullable primitiveUploadState; +@property (nonatomic, copy) NSUUID * _Nullable uuid; +@property (nonatomic, copy) NSString * _Nullable syncIdentifier; +@property (nonatomic) int32_t syncVersion; @end -SWIFT_CLASS("_TtC7LoopKit38SingleValueScheduleTableViewController") -@interface SingleValueScheduleTableViewController : DailyValueScheduleTableViewController -- (void)viewDidLoad; -- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (void)tableView:(UITableView * _Nonnull)tableView moveRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toIndexPath:(NSIndexPath * _Nonnull)destinationIndexPath; -- (NSIndexPath * _Nonnull)tableView:(UITableView * _Nonnull)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toProposedIndexPath:(NSIndexPath * _Nonnull)proposedDestinationIndexPath SWIFT_WARN_UNUSED_RESULT; -- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +SWIFT_CLASS("_TtC7LoopKit19CachedGlucoseObject") +@interface CachedGlucoseObject : NSManagedObject +- (nonnull instancetype)initWithEntity:(NSEntityDescription * _Nonnull)entity insertIntoManagedObjectContext:(NSManagedObjectContext * _Nullable)context OBJC_DESIGNATED_INITIALIZER; @end -SWIFT_CLASS("_TtC7LoopKit40DailyQuantityScheduleTableViewController") -@interface DailyQuantityScheduleTableViewController : SingleValueScheduleTableViewController -- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; + + +@interface CachedGlucoseObject (SWIFT_EXTENSION(LoopKit)) +@property (nonatomic, copy) NSUUID * _Nullable uuid; +@property (nonatomic, copy) NSString * _Nullable syncIdentifier; +@property (nonatomic) int32_t syncVersion; +@property (nonatomic, strong) NSNumber * _Nullable primitiveUploadState; +@property (nonatomic) double value; +@property (nonatomic, copy) NSString * _Nullable unitString; +@property (nonatomic, strong) NSDate * _Nullable primitiveStartDate; +@property (nonatomic, copy) NSString * _Nullable provenanceIdentifier; +@property (nonatomic) BOOL isDisplayOnly; @end +SWIFT_CLASS("_TtC7LoopKit17DeletedCarbObject") +@interface DeletedCarbObject : NSManagedObject +- (nonnull instancetype)initWithEntity:(NSEntityDescription * _Nonnull)entity insertIntoManagedObjectContext:(NSManagedObjectContext * _Nullable)context OBJC_DESIGNATED_INITIALIZER; +@end + -SWIFT_CLASS("_TtC7LoopKit39GlucoseRangeScheduleTableViewController") -@interface GlucoseRangeScheduleTableViewController : DailyValueScheduleTableViewController -- (void)viewDidLoad; -- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; -- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (void)tableView:(UITableView * _Nonnull)tableView moveRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toIndexPath:(NSIndexPath * _Nonnull)destinationIndexPath; -- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (BOOL)tableView:(UITableView * _Nonnull)tableView canMoveRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForHeaderInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (BOOL)tableView:(UITableView * _Nonnull)tableView shouldHighlightRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; -- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@interface DeletedCarbObject (SWIFT_EXTENSION(LoopKit)) +@property (nonatomic, copy) NSString * _Nullable externalID; +@property (nonatomic, strong) NSNumber * _Nullable primitiveUploadState; +@property (nonatomic, strong) NSDate * _Nullable startDate; @end @@ -280,26 +254,62 @@ SWIFT_CLASS("_TtC7LoopKit39GlucoseRangeScheduleTableViewController") -@class UITextField; -SWIFT_CLASS("_TtC7LoopKit28TextFieldTableViewController") -@interface TextFieldTableViewController : UITableViewController -- (nonnull instancetype)init; -- (void)viewDidLoad; -- (void)viewDidAppear:(BOOL)animated; -- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; -- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForFooterInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; -- (BOOL)textFieldShouldEndEditing:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; -- (BOOL)textFieldShouldReturn:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; -- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; -- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; + + + + + + + + + + + +SWIFT_CLASS("_TtC7LoopKit9PumpEvent") +@interface PumpEvent : NSManagedObject +- (void)awakeFromInsert; +- (nonnull instancetype)initWithEntity:(NSEntityDescription * _Nonnull)entity insertIntoManagedObjectContext:(NSManagedObjectContext * _Nullable)context OBJC_DESIGNATED_INITIALIZER; +@end + + + + + + + + +@interface PumpEvent (SWIFT_EXTENSION(LoopKit)) +@property (nonatomic, copy) NSDate * _Null_unspecified createdAt; +@property (nonatomic, copy) NSDate * _Null_unspecified date; +@property (nonatomic, copy) NSString * _Nullable primitiveDoseType; +@property (nonatomic, strong) NSNumber * _Nullable primitiveDuration; +@property (nonatomic, copy) NSString * _Nullable primitiveType; +@property (nonatomic, copy) NSString * _Nullable primitiveUnit; +@property (nonatomic, strong) NSNumber * _Nullable primitiveUploaded; +@property (nonatomic, strong) NSNumber * _Nullable primitiveValue; +@property (nonatomic, copy) NSData * _Nullable raw; +@property (nonatomic, copy) NSString * _Nullable title; +@end + + +SWIFT_CLASS("_TtC7LoopKit9Reservoir") +@interface Reservoir : NSManagedObject +- (void)awakeFromInsert; +- (nonnull instancetype)initWithEntity:(NSEntityDescription * _Nonnull)entity insertIntoManagedObjectContext:(NSManagedObjectContext * _Nullable)context OBJC_DESIGNATED_INITIALIZER; @end +@interface Reservoir (SWIFT_EXTENSION(LoopKit)) +@property (nonatomic, copy) NSDate * _Null_unspecified createdAt; +@property (nonatomic, copy) NSDate * _Null_unspecified date; +@property (nonatomic, strong) NSNumber * _Nullable primitiveVolume; +@property (nonatomic, copy) NSData * _Nullable raw; +@end + + #if __has_attribute(external_source_symbol) # pragma clang attribute pop diff --git a/Carthage/Build/iOS/LoopKit.framework/Info.plist b/Carthage/Build/iOS/LoopKit.framework/Info.plist index 3e0a932f94..28cfe6931f 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Info.plist and b/Carthage/Build/iOS/LoopKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/LoopKit.framework/LoopKit b/Carthage/Build/iOS/LoopKit.framework/LoopKit index 220f81f8e0..ddb34988b8 100755 Binary files a/Carthage/Build/iOS/LoopKit.framework/LoopKit and b/Carthage/Build/iOS/LoopKit.framework/LoopKit differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Model.momd/Model.mom b/Carthage/Build/iOS/LoopKit.framework/Model.momd/Model.mom new file mode 100644 index 0000000000..fc6469d259 Binary files /dev/null and b/Carthage/Build/iOS/LoopKit.framework/Model.momd/Model.mom differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Model.momd/VersionInfo.plist b/Carthage/Build/iOS/LoopKit.framework/Model.momd/VersionInfo.plist new file mode 100644 index 0000000000..de3254f80b Binary files /dev/null and b/Carthage/Build/iOS/LoopKit.framework/Model.momd/VersionInfo.plist differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftdoc deleted file mode 100644 index 6bd298961d..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftdoc and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftmodule deleted file mode 100644 index c96ec396fe..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm.swiftmodule and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftdoc index c1b17ee3d7..fac322b8b1 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftmodule index db3dca3c5c..ede7162bf8 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftdoc deleted file mode 100644 index b2c27d5031..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftdoc and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftmodule deleted file mode 100644 index 83fd0068ae..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/i386.swiftmodule and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftdoc index b9c7e5d8eb..9db3fa642c 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftmodule index db50dbbd0b..c962fb7efb 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/LoopKit.framework/Modules/LoopKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/LoopKit.framework/RepeatingScheduleValueTableViewCell.nib b/Carthage/Build/iOS/LoopKit.framework/RepeatingScheduleValueTableViewCell.nib deleted file mode 100644 index 20fa2a7277..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/RepeatingScheduleValueTableViewCell.nib and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/TextFieldTableViewCell.nib b/Carthage/Build/iOS/LoopKit.framework/TextFieldTableViewCell.nib deleted file mode 100644 index 18cfa641fa..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/TextFieldTableViewCell.nib and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/es.lproj/Localizable.strings b/Carthage/Build/iOS/LoopKit.framework/es.lproj/Localizable.strings index b380a13ae7..74e0bc5524 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/es.lproj/Localizable.strings and b/Carthage/Build/iOS/LoopKit.framework/es.lproj/Localizable.strings differ diff --git a/Carthage/Build/iOS/LoopKit.framework/es.lproj/LoopKit.strings b/Carthage/Build/iOS/LoopKit.framework/es.lproj/LoopKit.strings deleted file mode 100644 index 4f978a1855..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/es.lproj/LoopKit.strings and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/ru.lproj/Localizable.strings b/Carthage/Build/iOS/LoopKit.framework/ru.lproj/Localizable.strings index 225fd44646..58b857bb5e 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/ru.lproj/Localizable.strings and b/Carthage/Build/iOS/LoopKit.framework/ru.lproj/Localizable.strings differ diff --git a/Carthage/Build/iOS/LoopKit.framework/ru.lproj/LoopKit.strings b/Carthage/Build/iOS/LoopKit.framework/ru.lproj/LoopKit.strings deleted file mode 100644 index d40428e2a1..0000000000 Binary files a/Carthage/Build/iOS/LoopKit.framework/ru.lproj/LoopKit.strings and /dev/null differ diff --git a/Carthage/Build/iOS/LoopKit.framework/Assets.car b/Carthage/Build/iOS/LoopKitUI.framework/Assets.car similarity index 58% rename from Carthage/Build/iOS/LoopKit.framework/Assets.car rename to Carthage/Build/iOS/LoopKitUI.framework/Assets.car index 19ab224fb1..a64c324d0f 100644 Binary files a/Carthage/Build/iOS/LoopKit.framework/Assets.car and b/Carthage/Build/iOS/LoopKitUI.framework/Assets.car differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbAbsorptionInputController.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbAbsorptionInputController.nib new file mode 100644 index 0000000000..129a7faf7b Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbAbsorptionInputController.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryEditViewController.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryEditViewController.nib new file mode 100644 index 0000000000..f2f8834b4d Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryEditViewController.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryTableViewController.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryTableViewController.nib new file mode 100644 index 0000000000..4cbdb9a1b4 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/CarbEntryTableViewController.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/Info.plist b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/Info.plist new file mode 100644 index 0000000000..a6103f40b1 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/Info.plist differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib new file mode 100644 index 0000000000..262aede15b Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/LyL-9U-twn-view-9Ci-XW-6nA.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib new file mode 100644 index 0000000000..db3e8addc7 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/QAc-uE-L5K-view-ZAF-8o-e2g.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib new file mode 100644 index 0000000000..df1c320cb8 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/UINavigationController-wgu-gT-TgV.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib new file mode 100644 index 0000000000..973bb923b2 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/CarbKit.storyboardc/rUL-yg-cFX-view-b1s-8o-0Wp.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/Info.plist b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/Info.plist new file mode 100644 index 0000000000..67202dc4c9 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/Info.plist differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib new file mode 100644 index 0000000000..fa5962ec77 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/UITableViewController-jGX-GA-nlH.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib new file mode 100644 index 0000000000..404f3727ce Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Base.lproj/InsulinKit.storyboardc/jGX-GA-nlH-view-ccM-3y-LQM.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/DateAndDurationTableViewCell.nib b/Carthage/Build/iOS/LoopKitUI.framework/DateAndDurationTableViewCell.nib new file mode 100644 index 0000000000..75fa40c1ee Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/DateAndDurationTableViewCell.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeOverrideTableViewCell.nib b/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeOverrideTableViewCell.nib new file mode 100644 index 0000000000..ddf5075a2d Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeOverrideTableViewCell.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeTableViewCell.nib b/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeTableViewCell.nib new file mode 100644 index 0000000000..60a8344b63 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/GlucoseRangeTableViewCell.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI-Swift.h b/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI-Swift.h new file mode 100644 index 0000000000..5a16ec1963 --- /dev/null +++ b/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI-Swift.h @@ -0,0 +1,395 @@ +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open))) +# else +# define SWIFT_ENUM_ATTR +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if __has_feature(modules) +@import UIKit; +@import Foundation; +@import HealthKit; +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="LoopKitUI",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +@class UITableView; +@class UITableViewCell; +@class NSBundle; +@class NSCoder; + +SWIFT_CLASS("_TtC9LoopKitUI27CarbEntryEditViewController") +@interface CarbEntryEditViewController : UITableViewController +- (void)viewDidLoad; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForFooterInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (BOOL)shouldPerformSegueWithIdentifier:(NSString * _Nonnull)identifier sender:(id _Nullable)sender SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + + + + + + + + +@class UIStoryboardSegue; + +SWIFT_CLASS("_TtC9LoopKitUI28CarbEntryTableViewController") +@interface CarbEntryTableViewController : UITableViewController +- (void)viewDidLoad; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewDidAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)prepareForSegue:(UIStoryboardSegue * _Nonnull)segue sender:(id _Nullable)sender; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC9LoopKitUI29CommandResponseViewController") +@interface CommandResponseViewController : UIViewController +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +- (void)loadView; +- (void)viewDidLoad; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil SWIFT_UNAVAILABLE; +@end + + +SWIFT_CLASS("_TtC9LoopKitUI37DailyValueScheduleTableViewController") +@interface DailyValueScheduleTableViewController : UITableViewController +- (nonnull instancetype)init; +- (void)viewDidLoad; +- (void)setEditing:(BOOL)editing animated:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canMoveRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (BOOL)tableView:(UITableView * _Nonnull)tableView shouldHighlightRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView didDeselectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (NSIndexPath * _Nonnull)tableView:(UITableView * _Nonnull)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toProposedIndexPath:(NSIndexPath * _Nonnull)proposedDestinationIndexPath SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC9LoopKitUI38SingleValueScheduleTableViewController") +@interface SingleValueScheduleTableViewController : DailyValueScheduleTableViewController +- (void)viewDidLoad; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForFooterInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (void)tableView:(UITableView * _Nonnull)tableView moveRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toIndexPath:(NSIndexPath * _Nonnull)destinationIndexPath; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (NSIndexPath * _Nonnull)tableView:(UITableView * _Nonnull)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toProposedIndexPath:(NSIndexPath * _Nonnull)proposedDestinationIndexPath SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC9LoopKitUI40DailyQuantityScheduleTableViewController") +@interface DailyQuantityScheduleTableViewController : SingleValueScheduleTableViewController +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + + +SWIFT_CLASS("_TtC9LoopKitUI39GlucoseRangeScheduleTableViewController") +@interface GlucoseRangeScheduleTableViewController : DailyValueScheduleTableViewController +- (void)viewDidLoad; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (void)tableView:(UITableView * _Nonnull)tableView moveRowAtIndexPath:(NSIndexPath * _Nonnull)sourceIndexPath toIndexPath:(NSIndexPath * _Nonnull)destinationIndexPath; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canMoveRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForHeaderInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView shouldHighlightRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + + + + + + + +SWIFT_CLASS("_TtC9LoopKitUI34InsulinDeliveryTableViewController") +@interface InsulinDeliveryTableViewController : UITableViewController +- (void)viewDidLoad; +- (void)viewWillAppear:(BOOL)animated; +- (void)viewDidAppear:(BOOL)animated; +- (void)viewWillDisappear:(BOOL)animated; +- (void)viewDidDisappear:(BOOL)animated; +- (void)setEditing:(BOOL)editing animated:(BOOL)animated; +- (NSInteger)numberOfSectionsInTableView:(UITableView * _Nonnull)tableView SWIFT_WARN_UNUSED_RESULT; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (BOOL)tableView:(UITableView * _Nonnull)tableView canEditRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + +@class UITraitCollection; + +SWIFT_CLASS("_TtC9LoopKitUI23TextButtonTableViewCell") +@interface TextButtonTableViewCell : UITableViewCell +- (nonnull instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString * _Nullable)reuseIdentifier OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +- (void)tintColorDidChange; +- (void)traitCollectionDidChange:(UITraitCollection * _Nullable)previousTraitCollection; +@end + +@class UILabel; +@class UITextField; + +SWIFT_CLASS("_TtC9LoopKitUI22TextFieldTableViewCell") +@interface TextFieldTableViewCell : UITableViewCell +@property (nonatomic, weak) IBOutlet UILabel * _Nullable unitLabel; +@property (nonatomic, weak) IBOutlet UITextField * _Null_unspecified textField; +- (void)prepareForReuse; +- (void)textFieldDidBeginEditing:(UITextField * _Nonnull)textField; +- (void)textFieldDidEndEditing:(UITextField * _Nonnull)textField; +- (nonnull instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString * _Nullable)reuseIdentifier OBJC_DESIGNATED_INITIALIZER SWIFT_AVAILABILITY(ios,introduced=3.0); +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + +SWIFT_CLASS("_TtC9LoopKitUI28TextFieldTableViewController") +@interface TextFieldTableViewController : UITableViewController +- (nonnull instancetype)init; +- (void)viewDidLoad; +- (void)viewDidAppear:(BOOL)animated; +- (NSInteger)tableView:(UITableView * _Nonnull)tableView numberOfRowsInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (UITableViewCell * _Nonnull)tableView:(UITableView * _Nonnull)tableView cellForRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath SWIFT_WARN_UNUSED_RESULT; +- (NSString * _Nullable)tableView:(UITableView * _Nonnull)tableView titleForFooterInSection:(NSInteger)section SWIFT_WARN_UNUSED_RESULT; +- (void)tableView:(UITableView * _Nonnull)tableView didSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath; +- (BOOL)textFieldShouldEndEditing:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; +- (BOOL)textFieldShouldReturn:(UITextField * _Nonnull)textField SWIFT_WARN_UNUSED_RESULT; +- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; +@end + + + + +@interface UIInputView (SWIFT_EXTENSION(LoopKitUI)) +@property (nonatomic, readonly) BOOL enableInputClicksWhenVisible; +@end + + + + + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI.h b/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI.h new file mode 100644 index 0000000000..6804772d54 --- /dev/null +++ b/Carthage/Build/iOS/LoopKitUI.framework/Headers/LoopKitUI.h @@ -0,0 +1,19 @@ +// +// LoopKitUI.h +// LoopKitUI +// +// Created by Nathan Racklyeft on 1/28/18. +// Copyright © 2018 LoopKit Authors. All rights reserved. +// + +#import + +//! Project version number for LoopKitUI. +FOUNDATION_EXPORT double LoopKitUIVersionNumber; + +//! Project version string for LoopKitUI. +FOUNDATION_EXPORT const unsigned char LoopKitUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Info.plist b/Carthage/Build/iOS/LoopKitUI.framework/Info.plist new file mode 100644 index 0000000000..7fd9cc9248 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Info.plist differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/LoopKitUI b/Carthage/Build/iOS/LoopKitUI.framework/LoopKitUI new file mode 100755 index 0000000000..583e53c3a3 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/LoopKitUI differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftdoc new file mode 100644 index 0000000000..aa417371ad Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftmodule new file mode 100644 index 0000000000..d1136fcd74 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000000..fcfd39db4f Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000000..18a676c953 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/Modules/LoopKitUI.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/Modules/module.modulemap b/Carthage/Build/iOS/LoopKitUI.framework/Modules/module.modulemap new file mode 100644 index 0000000000..62e924032e --- /dev/null +++ b/Carthage/Build/iOS/LoopKitUI.framework/Modules/module.modulemap @@ -0,0 +1,11 @@ +framework module LoopKitUI { + umbrella header "LoopKitUI.h" + + export * + module * { export * } +} + +module LoopKitUI.Swift { + header "LoopKitUI-Swift.h" + requires objc +} diff --git a/Carthage/Build/iOS/LoopKitUI.framework/RepeatingScheduleValueTableViewCell.nib b/Carthage/Build/iOS/LoopKitUI.framework/RepeatingScheduleValueTableViewCell.nib new file mode 100644 index 0000000000..c2bb56b2b6 Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/RepeatingScheduleValueTableViewCell.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/TextFieldTableViewCell.nib b/Carthage/Build/iOS/LoopKitUI.framework/TextFieldTableViewCell.nib new file mode 100644 index 0000000000..502fa1d9de Binary files /dev/null and b/Carthage/Build/iOS/LoopKitUI.framework/TextFieldTableViewCell.nib differ diff --git a/Carthage/Build/iOS/LoopKitUI.framework/es.lproj/InsulinKit.strings b/Carthage/Build/iOS/LoopKitUI.framework/es.lproj/InsulinKit.strings new file mode 100644 index 0000000000..95b5d697c7 --- /dev/null +++ b/Carthage/Build/iOS/LoopKitUI.framework/es.lproj/InsulinKit.strings @@ -0,0 +1,30 @@ +/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ +"7Fi-wD-gf2.text" = "Título"; + +/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ +"7Fy-gG-Zof.text" = "..."; + +/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ +"9jm-X6-3QA.text" = "Detalle"; + +/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ +"PZQ-gO-084.text" = "..."; + +/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ +"TyZ-xm-mVN.segmentTitles[0]" = "Reservorio"; + +/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ +"TyZ-xm-mVN.segmentTitles[1]" = "Historia de eventos"; + +/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ +"dZi-Ta-IHm.text" = "U IOB"; + +/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ +"jSc-64-2tZ.text" = "No hay microinfusadora configurada"; + +/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ +"kys-by-14s.text" = "U Total"; + +/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ +"vls-EW-uwI.title" = "Administración de insulina"; + diff --git a/Carthage/Build/iOS/LoopKitUI.framework/ru.lproj/InsulinKit.strings b/Carthage/Build/iOS/LoopKitUI.framework/ru.lproj/InsulinKit.strings new file mode 100644 index 0000000000..98b4eadf6a --- /dev/null +++ b/Carthage/Build/iOS/LoopKitUI.framework/ru.lproj/InsulinKit.strings @@ -0,0 +1,30 @@ +/* Class = "UILabel"; text = "Title"; ObjectID = "7Fi-wD-gf2"; */ +"7Fi-wD-gf2.text" = "Название"; + +/* Class = "UILabel"; text = "..."; ObjectID = "7Fy-gG-Zof"; */ +"7Fy-gG-Zof.text" = "..."; + +/* Class = "UILabel"; text = "Detail"; ObjectID = "9jm-X6-3QA"; */ +"9jm-X6-3QA.text" = "Детали"; + +/* Class = "UILabel"; text = "..."; ObjectID = "PZQ-gO-084"; */ +"PZQ-gO-084.text" = "..."; + +/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[0] = "Reservoir"; ObjectID = "TyZ-xm-mVN"; */ +"TyZ-xm-mVN.segmentTitles[0]" = "Резервуар"; + +/* Class = "UISegmentedControl"; TyZ-xm-mVN.segmentTitles[1] = "Event History"; ObjectID = "TyZ-xm-mVN"; */ +"TyZ-xm-mVN.segmentTitles[1]" = "История событий"; + +/* Class = "UILabel"; text = "U IOB"; ObjectID = "dZi-Ta-IHm"; */ +"dZi-Ta-IHm.text" = "ед IOB"; + +/* Class = "UILabel"; text = "No pump configured"; ObjectID = "jSc-64-2tZ"; */ +"jSc-64-2tZ.text" = "Нет сконфигурированной помпы"; + +/* Class = "UILabel"; text = "U Total"; ObjectID = "kys-by-14s"; */ +"kys-by-14s.text" = "ед Всего"; + +/* Class = "UINavigationItem"; title = "Insulin Delivery"; ObjectID = "vls-EW-uwI"; */ +"vls-EW-uwI.title" = "Подача инсулина"; + diff --git a/Carthage/Build/iOS/MinimedKit.framework/Headers/MinimedKit-Swift.h b/Carthage/Build/iOS/MinimedKit.framework/Headers/MinimedKit-Swift.h index 93606bd677..382b31c857 100644 --- a/Carthage/Build/iOS/MinimedKit.framework/Headers/MinimedKit-Swift.h +++ b/Carthage/Build/iOS/MinimedKit.framework/Headers/MinimedKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/MinimedKit.framework/Info.plist b/Carthage/Build/iOS/MinimedKit.framework/Info.plist index 92cc757b5e..7c4b50989c 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Info.plist and b/Carthage/Build/iOS/MinimedKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/MinimedKit b/Carthage/Build/iOS/MinimedKit.framework/MinimedKit index d84e493e3d..1bfa83d5b6 100755 Binary files a/Carthage/Build/iOS/MinimedKit.framework/MinimedKit and b/Carthage/Build/iOS/MinimedKit.framework/MinimedKit differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftdoc index b564fce1c8..9ebd09f00b 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftmodule index f2b3b0e273..2e203429a7 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftdoc index ce6bf9551b..ebf2de9618 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftmodule index 0f180096a7..ee5e5f97f1 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftdoc index 2bdc4adc89..55237cf27a 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftmodule index 8668c50051..e029702db9 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftdoc index eea7806599..18cc14b599 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftmodule index a5a2164939..4b8b663c5c 100644 Binary files a/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/MinimedKit.framework/Modules/MinimedKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Headers/NightscoutUploadKit-Swift.h b/Carthage/Build/iOS/NightscoutUploadKit.framework/Headers/NightscoutUploadKit-Swift.h index 5bc4b7be48..80c8296e48 100644 --- a/Carthage/Build/iOS/NightscoutUploadKit.framework/Headers/NightscoutUploadKit-Swift.h +++ b/Carthage/Build/iOS/NightscoutUploadKit.framework/Headers/NightscoutUploadKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Info.plist b/Carthage/Build/iOS/NightscoutUploadKit.framework/Info.plist index 05bdf8efd4..66fce2a6d8 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Info.plist and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftdoc index f9ad01ab02..47bf27b590 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftmodule index 3a9353945e..0adf99c78f 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftdoc index 1dcfd3bfc8..45cfdcdd03 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftmodule index 049671c9cc..260878cf57 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftdoc index 58b739fff0..9dee09c2aa 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftmodule index 80f52949c4..fd5bc0e18f 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftdoc index 11f0095f4f..edbf42caad 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftmodule index 46745e245f..147eceddc2 100644 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/NightscoutUploadKit.framework/Modules/NightscoutUploadKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/NightscoutUploadKit.framework/NightscoutUploadKit b/Carthage/Build/iOS/NightscoutUploadKit.framework/NightscoutUploadKit index bfdfcfd5ab..e9e783c286 100755 Binary files a/Carthage/Build/iOS/NightscoutUploadKit.framework/NightscoutUploadKit and b/Carthage/Build/iOS/NightscoutUploadKit.framework/NightscoutUploadKit differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Headers/RileyLinkBLEKit-Swift.h b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Headers/RileyLinkBLEKit-Swift.h index f291e9aff6..2626e671ee 100644 --- a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Headers/RileyLinkBLEKit-Swift.h +++ b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Headers/RileyLinkBLEKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Info.plist b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Info.plist index 607b825d56..e47afc5b70 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Info.plist and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftdoc index cbe667511c..b1a2af4ced 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftmodule index 9ff1531c58..420ad352ba 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftdoc index efa74fdffd..bb351bf434 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftmodule index cba3abdfd0..8647ef050c 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftdoc index b704f724d7..9b998ed996 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftmodule index b987761709..794434b006 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftdoc index 899270802a..f6aad0b57c 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftmodule index bb08da24ee..89d684d9e1 100644 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/Modules/RileyLinkBLEKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkBLEKit.framework/RileyLinkBLEKit b/Carthage/Build/iOS/RileyLinkBLEKit.framework/RileyLinkBLEKit index ed739b996e..30d59635d1 100755 Binary files a/Carthage/Build/iOS/RileyLinkBLEKit.framework/RileyLinkBLEKit and b/Carthage/Build/iOS/RileyLinkBLEKit.framework/RileyLinkBLEKit differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Headers/RileyLinkKit-Swift.h b/Carthage/Build/iOS/RileyLinkKit.framework/Headers/RileyLinkKit-Swift.h index f204a949f5..db76fd479a 100644 --- a/Carthage/Build/iOS/RileyLinkKit.framework/Headers/RileyLinkKit-Swift.h +++ b/Carthage/Build/iOS/RileyLinkKit.framework/Headers/RileyLinkKit-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Info.plist b/Carthage/Build/iOS/RileyLinkKit.framework/Info.plist index 7939db8efa..2169155f6f 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Info.plist and b/Carthage/Build/iOS/RileyLinkKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftdoc index b951c256fc..e52ced9e2e 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftmodule index 069818c359..314dba7ee9 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftdoc index 206ae7c5a1..3808ca7ee3 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftmodule index acf856abfd..92c1d655dd 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftdoc index a9287c28bb..6ffc00e5df 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftmodule index a636df0bf7..3b9badf62c 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftdoc index c891fbf837..f8f5e3f808 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftmodule index 64c21e39d7..5f23098b85 100644 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/RileyLinkKit.framework/Modules/RileyLinkKit.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKit.framework/RileyLinkKit b/Carthage/Build/iOS/RileyLinkKit.framework/RileyLinkKit index 1e6f66fe23..c8b55f8d5d 100755 Binary files a/Carthage/Build/iOS/RileyLinkKit.framework/RileyLinkKit and b/Carthage/Build/iOS/RileyLinkKit.framework/RileyLinkKit differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Headers/RileyLinkKitUI-Swift.h b/Carthage/Build/iOS/RileyLinkKitUI.framework/Headers/RileyLinkKitUI-Swift.h index 1bad713eda..b481be9b02 100644 --- a/Carthage/Build/iOS/RileyLinkKitUI.framework/Headers/RileyLinkKitUI-Swift.h +++ b/Carthage/Build/iOS/RileyLinkKitUI.framework/Headers/RileyLinkKitUI-Swift.h @@ -1,4 +1,4 @@ -// Generated by Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1) +// Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Info.plist b/Carthage/Build/iOS/RileyLinkKitUI.framework/Info.plist index 277931a2e6..e6703986e7 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Info.plist and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Info.plist differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftdoc index ff1e4cdd71..ce543c4bd5 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftdoc and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftmodule index a6529ab2b2..d2be0435b3 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftmodule and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftdoc index 4082c8ca6c..73452bbc0b 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftdoc and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftmodule index fe50a6db5b..6e7df1b5a1 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftmodule and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftdoc index 6a900caf68..bf98083d32 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftdoc and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftmodule index d70d4a8750..ef7832cc03 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftmodule and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftdoc index 9347052a5b..8c7d64163d 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftdoc and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftmodule index 72dbb65486..b2f0e2ff10 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftmodule and b/Carthage/Build/iOS/RileyLinkKitUI.framework/Modules/RileyLinkKitUI.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/RileyLinkKitUI b/Carthage/Build/iOS/RileyLinkKitUI.framework/RileyLinkKitUI index e535b2c3da..7b70955254 100755 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/RileyLinkKitUI and b/Carthage/Build/iOS/RileyLinkKitUI.framework/RileyLinkKitUI differ diff --git a/Carthage/Build/iOS/RileyLinkKitUI.framework/TextFieldTableViewCell.nib b/Carthage/Build/iOS/RileyLinkKitUI.framework/TextFieldTableViewCell.nib index ce1a4b7986..d2ccf8528e 100644 Binary files a/Carthage/Build/iOS/RileyLinkKitUI.framework/TextFieldTableViewCell.nib and b/Carthage/Build/iOS/RileyLinkKitUI.framework/TextFieldTableViewCell.nib differ diff --git a/Common/Extensions/HKUnit.swift b/Common/Extensions/HKUnit.swift index 343c5ef604..d5b0fb727d 100644 --- a/Common/Extensions/HKUnit.swift +++ b/Common/Extensions/HKUnit.swift @@ -21,18 +21,23 @@ extension HKUnit { } } - static func milligramsPerDeciliter() -> HKUnit { + static let milligramsPerDeciliter: HKUnit = { return HKUnit.gramUnit(with: .milli).unitDivided(by: HKUnit.literUnit(with: .deci)) - } + }() - static func millimolesPerLiter() -> HKUnit { + static let millimolesPerLiter: HKUnit = { return HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: HKUnit.liter()) - } - - /// A glucose-centric presentation helper for the localized unit string - var glucoseUnitDisplayString: String { - if self == HKUnit.millimolesPerLiter() { - return NSLocalizedString("mmol/L", comment: "The unit display string for millimoles of glucose per liter") + }() + + var localizedShortUnitString: String { + if self == HKUnit.millimolesPerLiter { + return NSLocalizedString("mmol/L", comment: "The short unit display string for millimoles of glucose per liter") + } else if self == .milligramsPerDeciliter { + return NSLocalizedString("mg/dL", comment: "The short unit display string for milligrams of glucose per decilter") + } else if self == .internationalUnit() { + return NSLocalizedString("U", comment: "The short unit display string for international units of insulin") + } else if self == .gram() { + return NSLocalizedString("g", comment: "The short unit display string for grams") } else { return String(describing: self) } diff --git a/Loop/Extensions/NSUserDefaults.swift b/Common/Extensions/NSUserDefaults.swift similarity index 65% rename from Loop/Extensions/NSUserDefaults.swift rename to Common/Extensions/NSUserDefaults.swift index 88101cb1b5..4ba5a594f5 100644 --- a/Loop/Extensions/NSUserDefaults.swift +++ b/Common/Extensions/NSUserDefaults.swift @@ -8,47 +8,20 @@ import Foundation import LoopKit -import InsulinKit -import MinimedKit import HealthKit +import MinimedKit import RileyLinkKit -extension UserDefaults { - static let appGroup: UserDefaults = { - let shared = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) - let standard = UserDefaults.standard - - // Use an old key as a migration sentinel - if let shared = shared, standard.basalRateSchedule != nil && shared.basalRateSchedule == nil { - shared.basalRateSchedule = standard.basalRateSchedule - shared.carbRatioSchedule = standard.carbRatioSchedule - shared.cgm = standard.cgm - shared.connectedPeripheralIDs = standard.connectedPeripheralIDs - shared.loopSettings = standard.loopSettings - shared.insulinModelSettings = standard.insulinModelSettings - shared.insulinCounteractionEffects = standard.insulinCounteractionEffects - shared.insulinSensitivitySchedule = standard.insulinSensitivitySchedule - shared.preferredInsulinDataSource = standard.preferredInsulinDataSource - shared.batteryChemistry = standard.batteryChemistry - } - - return shared ?? standard - }() -} extension UserDefaults { private enum Key: String { case basalRateSchedule = "com.loudnate.Naterade.BasalRateSchedule" - case batteryChemistry = "com.loopkit.Loop.BatteryChemistry" - case cgmSettings = "com.loopkit.Loop.cgmSettings" case carbRatioSchedule = "com.loudnate.Naterade.CarbRatioSchedule" case connectedPeripheralIDs = "com.loudnate.Naterade.ConnectedPeripheralIDs" - case loopSettings = "com.loopkit.Loop.loopSettings" - case insulinCounteractionEffects = "com.loopkit.Loop.insulinCounteractionEffects" case insulinModelSettings = "com.loopkit.Loop.insulinModelSettings" + case loopSettings = "com.loopkit.Loop.loopSettings" case insulinSensitivitySchedule = "com.loudnate.Naterade.InsulinSensitivitySchedule" - case preferredInsulinDataSource = "com.loudnate.Loop.PreferredInsulinDataSource" case pumpSettings = "com.loopkit.Loop.PumpSettings" case pumpState = "com.loopkit.Loop.PumpState" } @@ -79,48 +52,32 @@ extension UserDefaults { } } - var cgm: CGM? { + var connectedPeripheralIDs: [String] { get { - if let rawValue = dictionary(forKey: Key.cgmSettings.rawValue) { - return CGM(rawValue: rawValue) - } else { - // Migrate the "version 0" case. Further format changes should be handled in the CGM initializer - defer { - removeObject(forKey: "com.loopkit.Loop.G5TransmitterEnabled") - removeObject(forKey: "com.loudnate.Loop.G4ReceiverEnabled") - removeObject(forKey: "com.loopkit.Loop.FetchEnliteDataEnabled") - removeObject(forKey: "com.loudnate.Naterade.TransmitterID") - } - - if bool(forKey: "com.loudnate.Loop.G4ReceiverEnabled") { - self.cgm = .g4 - return .g4 - } - - if bool(forKey: "com.loopkit.Loop.FetchEnliteDataEnabled") { - self.cgm = .enlite - return .enlite - } - - if let transmitterID = string(forKey: "com.loudnate.Naterade.TransmitterID"), transmitterID.count == 6 { - self.cgm = .g5(transmitterID: transmitterID) - return .g5(transmitterID: transmitterID) - } - - return nil - } + return array(forKey: Key.connectedPeripheralIDs.rawValue) as? [String] ?? [] } set { - set(newValue?.rawValue, forKey: Key.cgmSettings.rawValue) + set(newValue, forKey: Key.connectedPeripheralIDs.rawValue) } } - var connectedPeripheralIDs: [String] { + var insulinModelSettings: InsulinModelSettings? { get { - return array(forKey: Key.connectedPeripheralIDs.rawValue) as? [String] ?? [] + if let rawValue = dictionary(forKey: Key.insulinModelSettings.rawValue) { + return InsulinModelSettings(rawValue: rawValue) + } else { + // Migrate the version 0 case + let insulinActionDurationKey = "com.loudnate.Naterade.InsulinActionDuration" + defer { + removeObject(forKey: insulinActionDurationKey) + } + + let value = double(forKey: insulinActionDurationKey) + return value > 0 ? .walsh(WalshInsulinModel(actionDuration: value)) : nil + } } set { - set(newValue, forKey: Key.connectedPeripheralIDs.rawValue) + set(newValue?.rawValue, forKey: Key.insulinModelSettings.rawValue) } } @@ -181,40 +138,6 @@ extension UserDefaults { } } - var insulinModelSettings: InsulinModelSettings? { - get { - if let rawValue = dictionary(forKey: Key.insulinModelSettings.rawValue) { - return InsulinModelSettings(rawValue: rawValue) - } else { - // Migrate the version 0 case - let insulinActionDurationKey = "com.loudnate.Naterade.InsulinActionDuration" - defer { - removeObject(forKey: insulinActionDurationKey) - } - - let value = double(forKey: insulinActionDurationKey) - return value > 0 ? .walsh(WalshInsulinModel(actionDuration: value)) : nil - } - } - set { - set(newValue?.rawValue, forKey: Key.insulinModelSettings.rawValue) - } - } - - var insulinCounteractionEffects: [GlucoseEffectVelocity]? { - get { - guard let rawValue = array(forKey: Key.insulinCounteractionEffects.rawValue) as? [GlucoseEffectVelocity.RawValue] else { - return nil - } - return rawValue.compactMap { - GlucoseEffectVelocity(rawValue: $0) - } - } - set { - set(newValue?.map({ $0.rawValue }), forKey: Key.insulinCounteractionEffects.rawValue) - } - } - var insulinSensitivitySchedule: InsulinSensitivitySchedule? { get { if let rawValue = dictionary(forKey: Key.insulinSensitivitySchedule.rawValue) { @@ -228,19 +151,6 @@ extension UserDefaults { } } - var preferredInsulinDataSource: InsulinDataSource? { - get { - return InsulinDataSource(rawValue: integer(forKey: Key.preferredInsulinDataSource.rawValue)) - } - set { - if let preferredInsulinDataSource = newValue { - set(preferredInsulinDataSource.rawValue, forKey: Key.preferredInsulinDataSource.rawValue) - } else { - removeObject(forKey: Key.preferredInsulinDataSource.rawValue) - } - } - } - var pumpSettings: PumpSettings? { get { if let raw = dictionary(forKey: Key.pumpSettings.rawValue) { @@ -306,18 +216,4 @@ extension UserDefaults { set(newValue?.rawValue, forKey: Key.pumpState.rawValue) } } - - var batteryChemistry: BatteryChemistryType? { - get { - return BatteryChemistryType(rawValue: integer(forKey: Key.batteryChemistry.rawValue)) - } - set { - if let batteryChemistry = newValue { - set(batteryChemistry.rawValue, forKey: Key.batteryChemistry.rawValue) - } else { - removeObject(forKey: Key.batteryChemistry.rawValue) - } - } - } - } diff --git a/Common/Extensions/NumberFormatter.swift b/Common/Extensions/NumberFormatter.swift index 785a185676..51f411ae7d 100644 --- a/Common/Extensions/NumberFormatter.swift +++ b/Common/Extensions/NumberFormatter.swift @@ -20,8 +20,20 @@ extension NumberFormatter { return numberFormatter } + func string(from number: Double) -> String? { + return string(from: NSNumber(value: number)) + } + + func string(from quantity: HKQuantity, unit: HKUnit) -> String? { + return string(from: quantity.doubleValue(for: unit), unit: unit) + } + + func string(from number: Double, unit: HKUnit) -> String? { + return string(from: number, unit: unit.localizedShortUnitString) + } + func string(from number: Double, unit: String) -> String? { - guard let stringValue = string(from: NSNumber(value: number)) else { + guard let stringValue = string(from: number) else { return nil } @@ -38,18 +50,9 @@ extension NumberFormatter { func decibleString(from decibles: Int?) -> String? { if let decibles = decibles { - return string(from: Double(decibles), unit: "dB") + return string(from: Double(decibles), unit: NSLocalizedString("dB", comment: "The short unit display string for decibles")) } else { return nil } } - - func describingGlucose(_ value: Double, for unit: HKUnit) -> String? { - return string(from: value, unit: unit.glucoseUnitDisplayString) - } - - @nonobjc func describingGlucose(_ value: HKQuantity, for unit: HKUnit) -> String? { - return describingGlucose(value.doubleValue(for: unit), for: unit) - } - } diff --git a/Loop/Extensions/OSLog.swift b/Common/Extensions/OSLog.swift similarity index 100% rename from Loop/Extensions/OSLog.swift rename to Common/Extensions/OSLog.swift diff --git a/Common/Extensions/PersistenceController.swift b/Common/Extensions/PersistenceController.swift new file mode 100644 index 0000000000..b32689bb7f --- /dev/null +++ b/Common/Extensions/PersistenceController.swift @@ -0,0 +1,23 @@ +// +// PersistenceController.swift +// Loop +// +// Copyright © 2017 LoopKit Authors. All rights reserved. +// + +import LoopKit + + +extension PersistenceController { + class func controllerInAppGroupDirectory() -> PersistenceController { + let appGroup = Bundle.main.appGroupSuiteName + guard let directoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { + assertionFailure("Could not get a container directory URL. Please ensure App Groups are set up correctly in entitlements.") + return self.init(directoryURL: URL(fileURLWithPath: "/")) + } + + let isReadOnly = Bundle.main.bundleURL.pathExtension == "appex" + + return self.init(directoryURL: directoryURL.appendingPathComponent("com.loopkit.LoopKit", isDirectory: true), isReadOnly: isReadOnly) + } +} diff --git a/Loop/Models/GlucoseThreshold.swift b/Common/Models/GlucoseThreshold.swift similarity index 100% rename from Loop/Models/GlucoseThreshold.swift rename to Common/Models/GlucoseThreshold.swift diff --git a/Loop/Models/Insulin/ExponentialInsulinModelPreset.swift b/Common/Models/Insulin/ExponentialInsulinModelPreset.swift similarity index 99% rename from Loop/Models/Insulin/ExponentialInsulinModelPreset.swift rename to Common/Models/Insulin/ExponentialInsulinModelPreset.swift index f5e6cb4b2a..66644da1b8 100644 --- a/Loop/Models/Insulin/ExponentialInsulinModelPreset.swift +++ b/Common/Models/Insulin/ExponentialInsulinModelPreset.swift @@ -5,7 +5,7 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import InsulinKit +import LoopKit enum ExponentialInsulinModelPreset: String { diff --git a/Loop/Models/Insulin/InsulinModelSettings.swift b/Common/Models/Insulin/InsulinModelSettings.swift similarity index 99% rename from Loop/Models/Insulin/InsulinModelSettings.swift rename to Common/Models/Insulin/InsulinModelSettings.swift index 13aadeee89..0d6eb295c4 100644 --- a/Loop/Models/Insulin/InsulinModelSettings.swift +++ b/Common/Models/Insulin/InsulinModelSettings.swift @@ -5,7 +5,7 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import InsulinKit +import LoopKit enum InsulinModelSettings { diff --git a/Loop/Models/Insulin/WalshInsulinModel.swift b/Common/Models/Insulin/WalshInsulinModel.swift similarity index 98% rename from Loop/Models/Insulin/WalshInsulinModel.swift rename to Common/Models/Insulin/WalshInsulinModel.swift index 860416e76c..50d2f70ad5 100644 --- a/Loop/Models/Insulin/WalshInsulinModel.swift +++ b/Common/Models/Insulin/WalshInsulinModel.swift @@ -5,7 +5,7 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import InsulinKit +import LoopKit extension WalshInsulinModel: RawRepresentable { diff --git a/Loop/Models/LoopSettings.swift b/Common/Models/LoopSettings.swift similarity index 83% rename from Loop/Models/LoopSettings.swift rename to Common/Models/LoopSettings.swift index 24d374a153..fbab2c1656 100644 --- a/Loop/Models/LoopSettings.swift +++ b/Common/Models/LoopSettings.swift @@ -23,23 +23,17 @@ struct LoopSettings { var suspendThreshold: GlucoseThreshold? = nil var retrospectiveCorrectionEnabled = true -} + let retrospectiveCorrectionInterval = TimeInterval(minutes: 30) -// MARK: - Static configuration -extension LoopSettings { - static let idleListeningEnabledDefaults: RileyLinkDevice.IdleListeningState = .enabled(timeout: .minutes(4), channel: 0) -} + /// The amount of time since a given date that data should be considered valid + let recencyInterval = TimeInterval(minutes: 15) + // MARK - Display settings -extension LoopSettings { - var enabledEffects: PredictionInputEffect { - var inputs = PredictionInputEffect.all - if !retrospectiveCorrectionEnabled { - inputs.remove(.retrospection) - } - return inputs - } + let minimumChartWidthPerHour: CGFloat = 50 + + let statusChartMinimumHistoryDisplay: TimeInterval = .hours(1) } diff --git a/Common/Models/StatusExtensionContext.swift b/Common/Models/StatusExtensionContext.swift index eb61df6dbd..c64f5b72cd 100644 --- a/Common/Models/StatusExtensionContext.swift +++ b/Common/Models/StatusExtensionContext.swift @@ -9,18 +9,9 @@ import Foundation import HealthKit +import LoopKit import LoopUI -struct ReservoirContext { - let startDate: Date - let unitVolume: Double - let capacity: Int -} - -struct LoopContext { - let dosingEnabled: Bool - let lastCompleted: Date? -} struct NetBasalContext { let rate: Double @@ -61,54 +52,6 @@ struct PredictedGlucoseContext { } } -extension ReservoirContext: RawRepresentable { - typealias RawValue = [String: Any] - - var rawValue: RawValue { - return [ - "startDate": startDate, - "unitVolume": unitVolume, - "capacity": capacity - ] - } - - init?(rawValue: RawValue) { - guard - let startDate = rawValue["startDate"] as? Date, - let unitVolume = rawValue["unitVolume"] as? Double, - let capacity = rawValue["capacity"] as? Int - else { - return nil - } - - self.startDate = startDate - self.unitVolume = unitVolume - self.capacity = capacity - } -} - -extension LoopContext: RawRepresentable { - typealias RawValue = [String: Any] - - var rawValue: RawValue { - var raw: RawValue = [ - "dosingEnabled": dosingEnabled - ] - raw["lastCompleted"] = lastCompleted - return raw - } - - init?(rawValue: RawValue) { - guard let dosingEnabled = rawValue["dosingEnabled"] as? Bool - else { - return nil - } - - self.dosingEnabled = dosingEnabled - self.lastCompleted = rawValue["lastCompleted"] as? Date - } -} - extension NetBasalContext: RawRepresentable { typealias RawValue = [String: Any] @@ -180,32 +123,6 @@ extension SensorDisplayableContext: RawRepresentable { } } -extension GlucoseContext: RawRepresentable { - typealias RawValue = [String: Any] - - var rawValue: RawValue { - return [ - "value": value, - "unit": unit.unitString, - "startDate": startDate - ] - } - - init?(rawValue: RawValue) { - guard - let value = rawValue["value"] as? Double, - let unitString = rawValue["unit"] as? String, - let startDate = rawValue["startDate"] as? Date - else { - return nil - } - - self.value = value - self.unit = HKUnit(from: unitString) - self.startDate = startDate - } -} - extension PredictedGlucoseContext: RawRepresentable { typealias RawValue = [String: Any] @@ -235,45 +152,14 @@ extension PredictedGlucoseContext: RawRepresentable { } } -extension DatedRangeContext: RawRepresentable { - public typealias RawValue = [String: Any] - - public var rawValue: RawValue { - return [ - "startDate": startDate, - "endDate": endDate, - "minValue": minValue, - "maxValue": maxValue - ] - } - - public init?(rawValue: RawValue) { - guard - let startDate = rawValue["startDate"] as? Date, - let endDate = rawValue["endDate"] as? Date, - let minValue = rawValue["minValue"] as? Double, - let maxValue = rawValue["maxValue"] as? Double - else { - return nil - } - - self.init(startDate: startDate, endDate: endDate, minValue: minValue, maxValue: maxValue) - } -} - struct StatusExtensionContext: RawRepresentable { typealias RawValue = [String: Any] private let version = 4 - var glucose: [GlucoseContext]? var predictedGlucose: PredictedGlucoseContext? - var reservoir: ReservoirContext? - var loop: LoopContext? + var lastLoopCompleted: Date? var netBasal: NetBasalContext? var batteryPercentage: Double? - var activeInsulin: Double? - var targetRanges: [DatedRangeContext]? - var temporaryOverride: DatedRangeContext? var sensor: SensorDisplayableContext? init() { } @@ -283,38 +169,17 @@ struct StatusExtensionContext: RawRepresentable { return nil } - if let rawValue = rawValue["glucose"] as? [GlucoseContext.RawValue] { - glucose = rawValue.compactMap({return GlucoseContext(rawValue: $0)}) - } - if let rawValue = rawValue["predictedGlucose"] as? PredictedGlucoseContext.RawValue { predictedGlucose = PredictedGlucoseContext(rawValue: rawValue) } - if let rawValue = rawValue["reservoir"] as? ReservoirContext.RawValue { - reservoir = ReservoirContext(rawValue: rawValue) - } - - if let rawValue = rawValue["loop"] as? LoopContext.RawValue { - loop = LoopContext(rawValue: rawValue) - } - if let rawValue = rawValue["netBasal"] as? NetBasalContext.RawValue { netBasal = NetBasalContext(rawValue: rawValue) } + lastLoopCompleted = rawValue["lastLoopCompleted"] as? Date batteryPercentage = rawValue["batteryPercentage"] as? Double - activeInsulin = rawValue["activeInsulin"] as? Double - - if let rawValue = rawValue["targetRanges"] as? [DatedRangeContext.RawValue] { - targetRanges = rawValue.compactMap({return DatedRangeContext(rawValue: $0)}) - } - - if let rawValue = rawValue["temporaryOverride"] as? DatedRangeContext.RawValue { - temporaryOverride = DatedRangeContext(rawValue: rawValue) - } - if let rawValue = rawValue["sensor"] as? SensorDisplayableContext.RawValue { sensor = SensorDisplayableContext(rawValue: rawValue) } @@ -325,15 +190,10 @@ struct StatusExtensionContext: RawRepresentable { "version": version ] - raw["glucose"] = glucose?.map({return $0.rawValue}) raw["predictedGlucose"] = predictedGlucose?.rawValue - raw["reservoir"] = reservoir?.rawValue - raw["loop"] = loop?.rawValue + raw["lastLoopCompleted"] = lastLoopCompleted raw["netBasal"] = netBasal?.rawValue raw["batteryPercentage"] = batteryPercentage - raw["activeInsulin"] = activeInsulin - raw["targetRanges"] = targetRanges?.map({return $0.rawValue}) - raw["temporaryOverride"] = temporaryOverride?.rawValue raw["sensor"] = sensor?.rawValue return raw } diff --git a/Common/Models/WatchContext.swift b/Common/Models/WatchContext.swift index f28140d222..c79a60eced 100644 --- a/Common/Models/WatchContext.swift +++ b/Common/Models/WatchContext.swift @@ -59,11 +59,11 @@ final class WatchContext: NSObject, RawRepresentable { } if let glucoseValue = rawValue["gv"] as? Double { - glucose = HKQuantity(unit: preferredGlucoseUnit ?? .milligramsPerDeciliter(), doubleValue: glucoseValue) + glucose = HKQuantity(unit: preferredGlucoseUnit ?? .milligramsPerDeciliter, doubleValue: glucoseValue) } if let glucoseValue = rawValue["egv"] as? Double { - eventualGlucose = HKQuantity(unit: preferredGlucoseUnit ?? .milligramsPerDeciliter(), doubleValue: glucoseValue) + eventualGlucose = HKQuantity(unit: preferredGlucoseUnit ?? .milligramsPerDeciliter, doubleValue: glucoseValue) } glucoseTrendRawValue = rawValue["gt"] as? Int @@ -102,7 +102,7 @@ final class WatchContext: NSObject, RawRepresentable { raw["bp"] = batteryPercentage raw["cob"] = COB - let unit = preferredGlucoseUnit ?? .milligramsPerDeciliter() + let unit = preferredGlucoseUnit ?? .milligramsPerDeciliter raw["egv"] = eventualGlucose?.doubleValue(for: unit) raw["gu"] = preferredGlucoseUnit?.unitString raw["gv"] = glucose?.doubleValue(for: unit) diff --git a/DoseMathTests/DoseMathTests.swift b/DoseMathTests/DoseMathTests.swift index f54990834b..9b2718701a 100644 --- a/DoseMathTests/DoseMathTests.swift +++ b/DoseMathTests/DoseMathTests.swift @@ -8,7 +8,6 @@ import XCTest import HealthKit -import InsulinKit import LoopKit @@ -62,7 +61,7 @@ class RecommendTempBasalTests: XCTestCase { return fixture.map { return GlucoseFixtureValue( startDate: dateFormatter.date(from: $0["date"] as! String)!, - quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: $0["amount"] as! Double) + quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: $0["amount"] as! Double) ) } } @@ -82,15 +81,15 @@ class RecommendTempBasalTests: XCTestCase { } var glucoseTargetRange: GlucoseRangeSchedule { - return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! + return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! } var insulinSensitivitySchedule: InsulinSensitivitySchedule { - return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 60.0)])! + return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 60.0)])! } var suspendThreshold: GlucoseThreshold { - return GlucoseThreshold(unit: HKUnit.milligramsPerDeciliter(), value: 55) + return GlucoseThreshold(unit: HKUnit.milligramsPerDeciliter, value: 55) } var insulinModel: InsulinModel { @@ -366,7 +365,7 @@ class RecommendTempBasalTests: XCTestCase { XCTAssertEqual(TimeInterval(minutes: 30), dose!.duration) // Use mmol sensitivity value - let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: HKUnit.millimolesPerLiter(), dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 3.33)])! + let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: HKUnit.millimolesPerLiter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 3.33)])! dose = glucose.recommendedTempBasal( to: glucoseTargetRange, @@ -448,7 +447,7 @@ class RecommendBolusTests: XCTestCase { return fixture.map { return GlucoseFixtureValue( startDate: dateFormatter.date(from: $0["date"] as! String)!, - quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: $0["amount"] as! Double) + quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter, doubleValue: $0["amount"] as! Double) ) } } @@ -468,15 +467,15 @@ class RecommendBolusTests: XCTestCase { } var glucoseTargetRange: GlucoseRangeSchedule { - return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! + return GlucoseRangeSchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: TimeInterval(0), value: DoubleRange(minValue: 90, maxValue: 120))], overrideRanges: [:])! } var insulinSensitivitySchedule: InsulinSensitivitySchedule { - return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 60.0)])! + return InsulinSensitivitySchedule(unit: HKUnit.milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 60.0)])! } var suspendThreshold: GlucoseThreshold { - return GlucoseThreshold(unit: HKUnit.milligramsPerDeciliter(), value: 55) + return GlucoseThreshold(unit: HKUnit.milligramsPerDeciliter, value: 55) } var insulinModel: InsulinModel { @@ -567,7 +566,7 @@ class RecommendBolusTests: XCTestCase { XCTAssertEqual(1.575, dose.amount) if case BolusRecommendationNotice.currentGlucoseBelowTarget(let glucose) = dose.notice! { - XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter()), 60) + XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter), 60) } else { XCTFail("Expected currentGlucoseBelowTarget, but got \(dose.notice!)") } @@ -580,7 +579,7 @@ class RecommendBolusTests: XCTestCase { let dose = glucose.recommendedBolus( to: glucoseTargetRange, at: glucose.first!.startDate, - suspendThreshold: HKQuantity(unit: .milligramsPerDeciliter(), doubleValue: 70), + suspendThreshold: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 70), sensitivity: insulinSensitivitySchedule, model: insulinModel, pendingInsulin: 0, @@ -590,7 +589,7 @@ class RecommendBolusTests: XCTestCase { XCTAssertEqual(0, dose.amount) if case BolusRecommendationNotice.glucoseBelowSuspendThreshold(let glucose) = dose.notice! { - XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter()), 60) + XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter), 60) } else { XCTFail("Expected currentGlucoseBelowTarget, but got \(dose.notice!)") } @@ -613,7 +612,7 @@ class RecommendBolusTests: XCTestCase { XCTAssertEqual(0, dose.amount) if case BolusRecommendationNotice.glucoseBelowSuspendThreshold(let glucose) = dose.notice! { - XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter()), 60) + XCTAssertEqual(glucose.quantity.doubleValue(for: .milligramsPerDeciliter), 60) } else { XCTFail("Expected currentGlucoseBelowTarget, but got \(dose.notice!)") } @@ -737,7 +736,7 @@ class RecommendBolusTests: XCTestCase { let dose = glucose.recommendedBolus( to: glucoseTargetRange, at: glucose.first!.startDate, - suspendThreshold: HKQuantity(unit: .milligramsPerDeciliter(), doubleValue: 0), + suspendThreshold: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 0), sensitivity: insulinSensitivitySchedule, model: ExponentialInsulinModel(actionDuration: 21600.0, peakActivityTime: 4500.0), pendingInsulin: 0, @@ -763,7 +762,7 @@ class RecommendBolusTests: XCTestCase { XCTAssertEqual(1.25, dose.amount) // Use mmol sensitivity value - let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: HKUnit.millimolesPerLiter(), dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 10.0 / 3)])! + let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: HKUnit.millimolesPerLiter, dailyItems: [RepeatingScheduleValue(startTime: 0.0, value: 10.0 / 3)])! dose = glucose.recommendedBolus( to: glucoseTargetRange, diff --git a/Loop Status Extension/DatedRangedContextCalculator.swift b/Loop Status Extension/DatedRangedContextCalculator.swift deleted file mode 100644 index e6f75d02d2..0000000000 --- a/Loop Status Extension/DatedRangedContextCalculator.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// DateRangedContextCalculator.swift -// Loop -// -// Created by Bharat Mediratta on 3/21/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import SwiftCharts - -import LoopUI - -class DatedRangeContextCalculator: TargetPointsCalculator { - - var targetRanges: [DatedRangeContext]? - var temporaryOverride: DatedRangeContext? - - var glucosePoints: [ChartPoint] = [] - var overridePoints: [ChartPoint] = [] - var overrideDurationPoints: [ChartPoint] = [] - - init(targetRanges: [DatedRangeContext]?, temporaryOverride: DatedRangeContext?) { - self.targetRanges = targetRanges - self.temporaryOverride = temporaryOverride - } - - func calculate(_ xAxisValues: [ChartAxisValue]?) { - if let xAxisValues = xAxisValues, xAxisValues.count > 1, - let targetRanges = targetRanges - { - glucosePoints = ChartPoint.pointsForDatedRanges(targetRanges, xAxisValues: xAxisValues) - - if let override = temporaryOverride { - overridePoints = ChartPoint.pointsForDatedRangeOverride(override, xAxisValues: xAxisValues) - overrideDurationPoints = ChartPoint.pointsForDatedRangeOverrideDuration(override, xAxisValues: xAxisValues) - } else { - overridePoints = [] - overrideDurationPoints = [] - } - } - } -} diff --git a/Loop Status Extension/StatusViewController.swift b/Loop Status Extension/StatusViewController.swift index d388476b90..7b5aa93db9 100644 --- a/Loop Status Extension/StatusViewController.swift +++ b/Loop Status Extension/StatusViewController.swift @@ -8,6 +8,7 @@ import CoreData import HealthKit +import LoopKit import LoopUI import NotificationCenter import UIKit @@ -51,19 +52,41 @@ class StatusViewController: UIViewController, NCWidgetProviding { ) charts.glucoseDisplayRange = ( - min: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 100), - max: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 175) + min: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 100), + max: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 175) ) return charts }() var statusExtensionContext: StatusExtensionContext? - var defaults: UserDefaults? - final var observationContext = 1 + + lazy var defaults = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) + + private var observers: [Any] = [] + + lazy var healthStore = HKHealthStore() + + lazy var cacheStore = PersistenceController.controllerInAppGroupDirectory() + + lazy var glucoseStore = GlucoseStore( + healthStore: healthStore, + cacheStore: cacheStore, + observationEnabled: false + ) + + lazy var doseStore = DoseStore( + healthStore: healthStore, + cacheStore: cacheStore, + observationEnabled: false, + insulinModel: defaults?.insulinModelSettings?.model, + basalProfile: defaults?.basalRateSchedule, + insulinSensitivitySchedule: defaults?.insulinSensitivitySchedule + ) override func viewDidLoad() { super.viewDidLoad() + subtitleLabel.isHidden = true subtitleLabel.textColor = .subtitleLabelColor insulinLabel.isHidden = true @@ -72,28 +95,28 @@ class StatusViewController: UIViewController, NCWidgetProviding { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(openLoopApp(_:))) view.addGestureRecognizer(tapGestureRecognizer) - defaults = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) - if let defaults = defaults { - defaults.addObserver( - self, - forKeyPath: defaults.statusExtensionContextObservableKey, - options: [], - context: &observationContext - ) + self.charts.prerender() + glucoseChartContentView.chartGenerator = { [weak self] (frame) in + return self?.charts.glucoseChartWithFrame(frame)?.view } - self.charts.prerender() - glucoseChartContentView.chartGenerator = { [unowned self] (frame) in - return self.charts.glucoseChartWithFrame(frame)?.view + extensionContext?.widgetLargestAvailableDisplayMode = .expanded + + switch extensionContext?.widgetActiveDisplayMode ?? .compact { + case .compact: + glucoseChartContentView.isHidden = true + case .expanded: + glucoseChartContentView.isHidden = false } - self.extensionContext?.widgetLargestAvailableDisplayMode = NCWidgetDisplayMode.expanded - glucoseChartContentView.isHidden = self.extensionContext?.widgetActiveDisplayMode != .expanded + observers = [ + // TODO: Observe cross-process notifications of Loop status updating + ] } deinit { - if let defaults = defaults { - defaults.removeObserver(self, forKeyPath: defaults.statusExtensionContextObservableKey, context: &observationContext) + for observer in observers { + NotificationCenter.default.removeObserver(observer) } } @@ -116,15 +139,6 @@ class StatusViewController: UIViewController, NCWidgetProviding { self.glucoseChartContentView.isHidden = self.extensionContext?.widgetActiveDisplayMode != .expanded }) } - - override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - guard context == &observationContext else { - super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) - return - } - - update() - } @objc private func openLoopApp(_: Any) { if let url = Bundle.main.mainAppUrl { @@ -139,115 +153,160 @@ class StatusViewController: UIViewController, NCWidgetProviding { @discardableResult func update() -> NCUpdateResult { - guard let context = defaults?.statusExtensionContext else { - return NCUpdateResult.failed - } - if let lastGlucose = context.glucose?.last { - hudView.glucoseHUD.setGlucoseQuantity(lastGlucose.value, - at: lastGlucose.startDate, - unit: lastGlucose.unit, - sensor: context.sensor - ) - } - - if let batteryPercentage = context.batteryPercentage { - hudView.batteryHUD.batteryLevel = Double(batteryPercentage) - } - - if let reservoir = context.reservoir { - hudView.reservoirVolumeHUD.reservoirLevel = min(1, max(0, Double(reservoir.unitVolume / Double(reservoir.capacity)))) - hudView.reservoirVolumeHUD.setReservoirVolume(volume: reservoir.unitVolume, at: reservoir.startDate) - } + subtitleLabel.isHidden = true + insulinLabel.isHidden = true + + let group = DispatchGroup() - if let netBasal = context.netBasal { - hudView.basalRateHUD.setNetBasalRate(netBasal.rate, percent: netBasal.percentage, at: netBasal.start) + var activeInsulin: Double? + var lastReservoirValue: ReservoirValue? + var glucose: [StoredGlucoseSample] = [] + + group.enter() + doseStore.insulinOnBoard(at: Date()) { (result) in + switch result { + case .success(let iobValue): + activeInsulin = iobValue.value + case .failure: + activeInsulin = nil + } + group.leave() } - if let loop = context.loop { - hudView.loopCompletionHUD.dosingEnabled = loop.dosingEnabled - hudView.loopCompletionHUD.lastLoopCompleted = loop.lastCompleted + group.enter() + doseStore.getReservoirValues(since: .distantPast, limit: 1) { (result) in + switch result { + case .success(let values): + lastReservoirValue = values.first + case .failure: + lastReservoirValue = nil + } + group.leave() } - subtitleLabel.isHidden = true - insulinLabel.isHidden = true + charts.startDate = Calendar.current.nextDate(after: Date(timeIntervalSinceNow: .minutes(-5)), matching: DateComponents(minute: 0), matchingPolicy: .strict, direction: .backward) ?? Date() + + // Showing the whole history plus full prediction in the glucose plot + // is a little crowded, so limit it to three hours in the future: + charts.maxEndDate = charts.startDate.addingTimeInterval(TimeInterval(hours: 3)) - let dateFormatter: DateFormatter = { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - return dateFormatter - }() - - let insulinFormatter: NumberFormatter = { - let numberFormatter = NumberFormatter() - - numberFormatter.numberStyle = .decimal - numberFormatter.minimumFractionDigits = 1 - numberFormatter.maximumFractionDigits = 1 - - return numberFormatter - }() - - if let activeInsulin = context.activeInsulin, let valueStr = insulinFormatter.string(from:NSNumber(value:activeInsulin)) - { - insulinLabel.text = String(format: NSLocalizedString( - "IOB %1$@ U", - comment: "The subtitle format describing units of active insulin. (1: localized insulin value description)"), - valueStr) - insulinLabel.isHidden = false + group.enter() + glucoseStore.getCachedGlucoseSamples(start: charts.startDate) { (result) in + glucose = result + group.leave() } - - if let glucose = context.glucose, - glucose.count > 0 { - let unit = glucose[0].unit + + group.notify(queue: .main) { + guard let defaults = self.defaults, let context = defaults.statusExtensionContext else { + return + } + + if let batteryPercentage = context.batteryPercentage { + self.hudView.batteryHUD.batteryLevel = Double(batteryPercentage) + } + + if let reservoir = lastReservoirValue, + let capacity = defaults.pumpState?.pumpModel?.reservoirCapacity + { + self.hudView.reservoirVolumeHUD.reservoirLevel = min(1, max(0, Double(reservoir.unitVolume / Double(capacity)))) + self.hudView.reservoirVolumeHUD.setReservoirVolume(volume: reservoir.unitVolume, at: reservoir.startDate) + } + + if let netBasal = context.netBasal { + self.hudView.basalRateHUD.setNetBasalRate(netBasal.rate, percent: netBasal.percentage, at: netBasal.start) + } + + self.hudView.loopCompletionHUD.dosingEnabled = defaults.loopSettings?.dosingEnabled ?? false + + if let lastCompleted = context.lastLoopCompleted { + self.hudView.loopCompletionHUD.lastLoopCompleted = lastCompleted + } + + if let activeInsulin = activeInsulin { + let insulinFormatter: NumberFormatter = { + let numberFormatter = NumberFormatter() + + numberFormatter.numberStyle = .decimal + numberFormatter.minimumFractionDigits = 1 + numberFormatter.maximumFractionDigits = 1 + + return numberFormatter + }() + + if let valueStr = insulinFormatter.string(from: activeInsulin) { + self.insulinLabel.text = String(format: NSLocalizedString("IOB %1$@ U", + comment: "The subtitle format describing units of active insulin. (1: localized insulin value description)"), + valueStr + ) + self.insulinLabel.isHidden = false + } + } + + guard let unit = context.predictedGlucose?.unit else { + return + } + + if let lastGlucose = glucose.last { + self.hudView.glucoseHUD.setGlucoseQuantity( + lastGlucose.quantity.doubleValue(for: unit), + at: lastGlucose.startDate, + unit: unit, + sensor: context.sensor + ) + } + let glucoseFormatter = NumberFormatter.glucoseFormatter(for: unit) - charts.glucoseUnit = unit - charts.glucosePoints = glucose.map { + let dateFormatter: DateFormatter = { + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .none + dateFormatter.timeStyle = .short + + return dateFormatter + }() + + self.charts.glucoseUnit = unit + self.charts.glucosePoints = glucose.map { ChartPoint( x: ChartAxisValueDate(date: $0.startDate, formatter: dateFormatter), - y: ChartAxisValueDoubleUnit($0.value, unitString: unit.unitString, formatter: glucoseFormatter) + y: ChartAxisValueDoubleUnit($0.quantity.doubleValue(for: unit), unitString: unit.localizedShortUnitString, formatter: glucoseFormatter) ) } - // Anchor the start date of the chart to the earliest date we have in our historical glucose - if let first = glucose.first { - charts.startDate = first.startDate - } - - // Showing the whole history plus full prediction in the glucose plot - // is a little crowded, so limit it to three hours in the future: - charts.maxEndDate = Date().addingTimeInterval(TimeInterval(hours: 3)) - if let predictedGlucose = context.predictedGlucose?.samples { - charts.predictedGlucosePoints = predictedGlucose.map { + self.charts.predictedGlucosePoints = predictedGlucose.map { ChartPoint( x: ChartAxisValueDate(date: $0.startDate, formatter: dateFormatter), - y: ChartAxisValueDoubleUnit($0.quantity.doubleValue(for: unit), unitString: unit.unitString, formatter: glucoseFormatter) + y: ChartAxisValueDoubleUnit($0.quantity.doubleValue(for: unit), unitString: unit.localizedShortUnitString, formatter: glucoseFormatter) ) } if let eventualGlucose = predictedGlucose.last { - let formatter = NumberFormatter.glucoseFormatter(for: eventualGlucose.unit) - - if let eventualGlucoseNumberString = formatter.string(from: NSNumber(value: eventualGlucose.quantity.doubleValue(for: unit))) { - subtitleLabel.text = String( + if let eventualGlucoseNumberString = glucoseFormatter.string(from: eventualGlucose.quantity.doubleValue(for: unit)) { + self.subtitleLabel.text = String( format: NSLocalizedString( "Eventually %1$@ %2$@", - comment: "The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description)"), + comment: "The subtitle format describing eventual glucose. (1: localized glucose value description) (2: localized glucose units description)" + ), eventualGlucoseNumberString, - unit.glucoseUnitDisplayString + unit.localizedShortUnitString ) - subtitleLabel.isHidden = false + self.subtitleLabel.isHidden = false } } } - charts.targetPointsCalculator = DatedRangeContextCalculator(targetRanges: context.targetRanges, temporaryOverride: context.temporaryOverride) + self.charts.targetGlucoseSchedule = defaults.loopSettings?.glucoseTargetRangeSchedule - charts.prerender() - glucoseChartContentView.reloadChart() + self.charts.prerender() + self.glucoseChartContentView.reloadChart() + } + + switch extensionContext?.widgetActiveDisplayMode ?? .compact { + case .compact: + glucoseChartContentView.isHidden = true + case .expanded: + glucoseChartContentView.isHidden = false } // Right now we always act as if there's new data. diff --git a/Loop.xcconfig b/Loop.xcconfig index d092e89a38..ab57d0d2a7 100644 --- a/Loop.xcconfig +++ b/Loop.xcconfig @@ -6,6 +6,6 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -// Change this on first setup to your own unique organization identifier in -// reverse-domain name syntax. -MAIN_APP_BUNDLE_IDENTIFIER = com.loopkit +// This is automatically disambiguated by development team, but you may choose to change this to +// support running multiple apps simultaneously. +MAIN_APP_BUNDLE_IDENTIFIER = com.${DEVELOPMENT_TEAM}.loopkit diff --git a/Loop.xcodeproj/project.pbxproj b/Loop.xcodeproj/project.pbxproj index 432d6944b7..8e416f2a58 100644 --- a/Loop.xcodeproj/project.pbxproj +++ b/Loop.xcodeproj/project.pbxproj @@ -15,6 +15,14 @@ 43076BF31DFDBC4B0012A723 /* it.lproj in Resources */ = {isa = PBXBuildFile; fileRef = 43076BF21DFDBC4B0012A723 /* it.lproj */; }; 4309786C1E73D2F500BEBC82 /* it.lproj in Resources */ = {isa = PBXBuildFile; fileRef = 4309786B1E73D2F500BEBC82 /* it.lproj */; }; 4309786E1E73DAD100BEBC82 /* CGM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4309786D1E73DAD100BEBC82 /* CGM.swift */; }; + 430B298A2041F54A00BA9F93 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; + 430B298B2041F55700BA9F93 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */; }; + 430B298E2041F56500BA9F93 /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; + 430B298F2041F56500BA9F93 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; + 430B29902041F57000BA9F93 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; + 430B29912041F57200BA9F93 /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298C2041F56500BA9F93 /* LoopSettings.swift */; }; + 430B29932041F5B300BA9F93 /* UserDefaults+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29922041F5B200BA9F93 /* UserDefaults+Loop.swift */; }; + 430B29952041F5CB00BA9F93 /* LoopSettings+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B29942041F5CB00BA9F93 /* LoopSettings+Loop.swift */; }; 430D85891F44037000AF2D4F /* HUDViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430D85881F44037000AF2D4F /* HUDViewTableViewCell.swift */; }; 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; 430DA5901D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58F1D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift */; }; @@ -22,6 +30,7 @@ 4315D2871CA5CC3B00589052 /* CarbEntryEditTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2861CA5CC3B00589052 /* CarbEntryEditTableViewController.swift */; }; 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */; }; 431A8C401EC6E8AB00823B9C /* CircleMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431A8C3F1EC6E8AB00823B9C /* CircleMaskView.swift */; }; + 431E73481FF95A900069B5F7 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; 4326BA641F3A44D9007CCAD4 /* ChartLineModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4326BA631F3A44D9007CCAD4 /* ChartLineModel.swift */; }; 4328E01A1CFBE1DA00E199AA /* StatusInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4328E0151CFBE1DA00E199AA /* StatusInterfaceController.swift */; }; 4328E01B1CFBE1DA00E199AA /* BolusInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4328E0161CFBE1DA00E199AA /* BolusInterfaceController.swift */; }; @@ -39,9 +48,12 @@ 433EA4C41D9F71C800CD78FB /* CommandResponseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433EA4C31D9F71C800CD78FB /* CommandResponseViewController.swift */; }; 4341F4EB1EDB92AC001C936B /* LogglyService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4341F4EA1EDB92AC001C936B /* LogglyService.swift */; }; 43441A9C1EDB34810087958C /* StatusExtensionContext+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43441A9B1EDB34810087958C /* StatusExtensionContext+LoopKit.swift */; }; - 43441AA01EDB4D390087958C /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43441A9F1EDB4D390087958C /* OSLog.swift */; }; 4346D1E71C77F5FE00ABAFE3 /* ChartTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4346D1E61C77F5FE00ABAFE3 /* ChartTableViewCell.swift */; }; - 4346D1F61C78501000ABAFE3 /* ChartPoint+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4346D1F51C78501000ABAFE3 /* ChartPoint+Loop.swift */; }; + 434B288420661D29000EE07B /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 434B288520661D29000EE07B /* LoopKit.framework */; }; + 434B2886206628B3000EE07B /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431E73471FF95A900069B5F7 /* PersistenceController.swift */; }; + 434B2887206B4F07000EE07B /* WalshInsulinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6261F37AE5600C320C7 /* WalshInsulinModel.swift */; }; + 434B2888206B4F0A000EE07B /* InsulinModelSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6281F37B01300C320C7 /* InsulinModelSettings.swift */; }; + 434B2889206B4F0C000EE07B /* ExponentialInsulinModelPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435CB6241F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift */; }; 434F54571D287FDB002A9274 /* NibLoadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434F54561D287FDB002A9274 /* NibLoadable.swift */; }; 434F54591D28805E002A9274 /* ButtonTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 434F54581D28805E002A9274 /* ButtonTableViewCell.xib */; }; 434F545B1D2880D4002A9274 /* AuthenticationTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 434F545A1D2880D4002A9274 /* AuthenticationTableViewCell.xib */; }; @@ -66,11 +78,16 @@ 436A0DA51D236A2A00104B24 /* LoopError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436A0DA41D236A2A00104B24 /* LoopError.swift */; }; 436D9BF81F6F4EA100CFA75F /* recommended_temp_start_low_end_just_above_range.json in Resources */ = {isa = PBXBuildFile; fileRef = 436D9BF71F6F4EA100CFA75F /* recommended_temp_start_low_end_just_above_range.json */; }; 436FACEE1D0BA636004E2427 /* InsulinDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436FACED1D0BA636004E2427 /* InsulinDataSource.swift */; }; + 4374B5EF209D84BF00D17AA8 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; + 4374B5F0209D857E00D17AA8 /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5EE209D84BE00D17AA8 /* OSLog.swift */; }; + 4374B5F2209D897600D17AA8 /* Locked.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4374B5F1209D897600D17AA8 /* Locked.swift */; }; 43776F901B8022E90074EA36 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43776F8F1B8022E90074EA36 /* AppDelegate.swift */; }; 43776F971B8022E90074EA36 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43776F951B8022E90074EA36 /* Main.storyboard */; }; 43776F991B8022E90074EA36 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 43776F981B8022E90074EA36 /* Assets.xcassets */; }; 437AFEE42035252A008C4892 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 434AB0B11CBB4C3300422F4A /* RileyLinkBLEKit.framework */; }; 437AFEE520352591008C4892 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F70C1DD1DE8DCA7006380B7 /* NotificationCenter.framework */; }; + 437AFEE7203688CF008C4892 /* LoopKitUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 437AFEE6203688CF008C4892 /* LoopKitUI.framework */; }; + 437AFEE8203689FE008C4892 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; 437CCADA1D284ADF0075D2C3 /* AuthenticationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437CCAD91D284ADF0075D2C3 /* AuthenticationTableViewCell.swift */; }; 437CCADC1D284B830075D2C3 /* ButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437CCADB1D284B830075D2C3 /* ButtonTableViewCell.swift */; }; 437CCADE1D2858FD0075D2C3 /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437CCADD1D2858FD0075D2C3 /* AuthenticationViewController.swift */; }; @@ -119,9 +136,9 @@ 43C0944A1CACCC73001F6403 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C094491CACCC73001F6403 /* NotificationManager.swift */; }; 43C246A81D89990F0031F8D1 /* Crypto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C246A71D89990F0031F8D1 /* Crypto.framework */; }; 43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */; }; + 43C3B6ED20B884500026CAFA /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */; }; 43C418B51CE0575200405B6A /* ShareGlucose+GlucoseKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C418B41CE0575200405B6A /* ShareGlucose+GlucoseKit.swift */; }; 43C513191E864C4E001547C7 /* GlucoseRangeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43C513181E864C4E001547C7 /* GlucoseRangeSchedule.swift */; }; - 43C6407C1DA051850093E25D /* InsulinKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43C6407B1DA051850093E25D /* InsulinKit.framework */; }; 43CA93371CB98079000026B5 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43CA93361CB98079000026B5 /* MinimedKit.framework */; }; 43CB2B2B1D924D450079823D /* WCSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CB2B2A1D924D450079823D /* WCSession.swift */; }; 43CE7CDE1CA8B63E003CC1B0 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CE7CDD1CA8B63E003CC1B0 /* Data.swift */; }; @@ -129,7 +146,6 @@ 43D2E8231F00425400AE5CBF /* BolusViewController+LoopDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D2E8221F00425400AE5CBF /* BolusViewController+LoopDataManager.swift */; }; 43D381621EBD9759007F8C8F /* HeaderValuesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D381611EBD9759007F8C8F /* HeaderValuesTableViewCell.swift */; }; 43D848B01E7DCBE100DADCBC /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D848AF1E7DCBE100DADCBC /* Result.swift */; }; - 43D848B21E7DF42500DADCBC /* LoopSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D848B11E7DF42500DADCBC /* LoopSettings.swift */; }; 43DBF04C1C93B8D700B3C386 /* BolusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DBF04B1C93B8D700B3C386 /* BolusViewController.swift */; }; 43DBF0531C93EC8200B3C386 /* DeviceDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DBF0521C93EC8200B3C386 /* DeviceDataManager.swift */; }; 43DBF0591C93F73800B3C386 /* CarbEntryTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43DBF0581C93F73800B3C386 /* CarbEntryTableViewController.swift */; }; @@ -157,8 +173,8 @@ 43E2D9171D2226BD004DA55F /* LoopKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 43E2D9191D222759004DA55F /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; 43E3449F1B9D68E900C85C07 /* StatusTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E3449E1B9D68E900C85C07 /* StatusTableViewController.swift */; }; - 43E344A41B9E1B1C00C85C07 /* NSUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E344A31B9E1B1C00C85C07 /* NSUserDefaults.swift */; }; 43E397A31D56B9E40028E321 /* Glucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E397A21D56B9E40028E321 /* Glucose.swift */; }; + 43E5292B205F718500ACEB3B /* SensorValueGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43E5292A205F718500ACEB3B /* SensorValueGlucoseEvent.swift */; }; 43E93FB51E4675E800EAB8DB /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */; }; 43E93FB61E469A4000EAB8DB /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */; }; 43E93FB71E469A5100EAB8DB /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F526D5E1DF2459000A04910 /* HKUnit.swift */; }; @@ -170,8 +186,6 @@ 43F5C2DB1B92A5E1003EB13D /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F5C2DA1B92A5E1003EB13D /* SettingsTableViewController.swift */; }; 43F64DD91D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F64DD81D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift */; }; 43F78D261C8FC000002152D1 /* DoseMath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F78D251C8FC000002152D1 /* DoseMath.swift */; }; - 43F78D4C1C914197002152D1 /* CarbKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D481C914197002152D1 /* CarbKit.framework */; }; - 43F78D4D1C914197002152D1 /* GlucoseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D491C914197002152D1 /* GlucoseKit.framework */; }; 43F78D4F1C914197002152D1 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; 43FCBBC21E51710B00343C1B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 43776F9A1B8022E90074EA36 /* LaunchScreen.storyboard */; }; 4D3B40041D4A9E1A00BC6334 /* G4ShareSpy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */; }; @@ -179,8 +193,6 @@ 4F08DE8F1E7BB871006741EA /* CollectionType+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F08DE8E1E7BB871006741EA /* CollectionType+Loop.swift */; }; 4F08DE9B1E7BC4ED006741EA /* SwiftCharts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4346D1EF1C781BEA00ABAFE3 /* SwiftCharts.framework */; }; 4F08DE9D1E81D0E9006741EA /* StatusChartsManager+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430C1ABC1E5568A80067F1AE /* StatusChartsManager+LoopKit.swift */; }; - 4F08DEA11E81D90F006741EA /* GlucoseRangeScheduleCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F08DEA01E81D90F006741EA /* GlucoseRangeScheduleCalculator.swift */; }; - 4F08DEA31E81E12D006741EA /* DatedRangedContextCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F08DEA21E81E12D006741EA /* DatedRangedContextCalculator.swift */; }; 4F20AE621E6B879C00D07A06 /* ReservoirVolumeHUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437CEEC71CD84CBB003C8C80 /* ReservoirVolumeHUDView.swift */; }; 4F20AE631E6B87B100D07A06 /* ChartContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4313EDDF1D8A6BF90060FA79 /* ChartContainerView.swift */; }; 4F2C15741E0209F500E160D4 /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439897341CD2F7DE00223065 /* NSTimeInterval.swift */; }; @@ -193,7 +205,6 @@ 4F2C15951E09BF3C00E160D4 /* HUDView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4F2C15941E09BF3C00E160D4 /* HUDView.xib */; }; 4F2C15971E09E94E00E160D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4F2C15961E09E94E00E160D4 /* Assets.xcassets */; }; 4F2C159A1E0C9E5600E160D4 /* LoopUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4F75288B1DFE1DC600C322D6 /* LoopUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 4F526D5D1DF0FD6500A04910 /* InsulinKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 43C6407B1DA051850093E25D /* InsulinKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4F526D611DF8D9A900A04910 /* NetBasal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F526D601DF8D9A900A04910 /* NetBasal.swift */; }; 4F526D621DF9D95200A04910 /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; 4F6663941E905FD2009E74FC /* ChartColorPalette+Loop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6663931E905FD2009E74FC /* ChartColorPalette+Loop.swift */; }; @@ -253,14 +264,12 @@ 894F71E21FFEC4D8007D365C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 894F71E11FFEC4D8007D365C /* Assets.xcassets */; }; C10428971D17BAD400DD539A /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10428961D17BAD400DD539A /* NightscoutUploadKit.framework */; }; C10B28461EA9BA5E006EA1FC /* far_future_high_bg_forecast.json in Resources */ = {isa = PBXBuildFile; fileRef = C10B28451EA9BA5E006EA1FC /* far_future_high_bg_forecast.json */; }; - C11C87DD1E21E53500BB71D3 /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178249D1E19B62300D9D25C /* GlucoseThreshold.swift */; }; C11C87DE1E21EAAD00BB71D3 /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F526D5E1DF2459000A04910 /* HKUnit.swift */; }; C12F21A71DFA79CB00748193 /* recommend_temp_basal_very_low_end_in_range.json in Resources */ = {isa = PBXBuildFile; fileRef = C12F21A61DFA79CB00748193 /* recommend_temp_basal_very_low_end_in_range.json */; }; C13BAD941E8009B000050CB5 /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */; }; C15713821DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15713811DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift */; }; C178249A1E1999FA00D9D25C /* CaseCountable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17824991E1999FA00D9D25C /* CaseCountable.swift */; }; C17824A01E19CF9800D9D25C /* GlucoseThresholdTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178249F1E19CF9800D9D25C /* GlucoseThresholdTableViewController.swift */; }; - C17824A11E19E8C200D9D25C /* GlucoseThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = C178249D1E19B62300D9D25C /* GlucoseThreshold.swift */; }; C17824A31E19EAB600D9D25C /* recommend_temp_basal_start_very_low_end_high.json in Resources */ = {isa = PBXBuildFile; fileRef = C17824A21E19EAB600D9D25C /* recommend_temp_basal_start_very_low_end_high.json */; }; C17824A51E1AD4D100D9D25C /* BolusRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17824A41E1AD4D100D9D25C /* BolusRecommendation.swift */; }; C17824A61E1AF91F00D9D25C /* BolusRecommendation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17824A41E1AD4D100D9D25C /* BolusRecommendation.swift */; }; @@ -366,7 +375,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 4F526D5D1DF0FD6500A04910 /* InsulinKit.framework in CopyFiles */, 43E2D9171D2226BD004DA55F /* LoopKit.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; @@ -392,6 +400,11 @@ 43076BF21DFDBC4B0012A723 /* it.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; path = it.lproj; sourceTree = ""; }; 4309786B1E73D2F500BEBC82 /* it.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; path = it.lproj; sourceTree = ""; }; 4309786D1E73DAD100BEBC82 /* CGM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGM.swift; sourceTree = ""; }; + 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaults.swift; sourceTree = ""; }; + 430B298C2041F56500BA9F93 /* LoopSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopSettings.swift; sourceTree = ""; }; + 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseThreshold.swift; sourceTree = ""; }; + 430B29922041F5B200BA9F93 /* UserDefaults+Loop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Loop.swift"; sourceTree = ""; }; + 430B29942041F5CB00BA9F93 /* LoopSettings+Loop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LoopSettings+Loop.swift"; sourceTree = ""; }; 430C1ABC1E5568A80067F1AE /* StatusChartsManager+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "StatusChartsManager+LoopKit.swift"; sourceTree = ""; }; 430D85881F44037000AF2D4F /* HUDViewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HUDViewTableViewCell.swift; sourceTree = ""; }; 430DA58D1D4AEC230097D1CA /* NSBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSBundle.swift; sourceTree = ""; }; @@ -401,6 +414,7 @@ 4315D2861CA5CC3B00589052 /* CarbEntryEditTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbEntryEditTableViewController.swift; sourceTree = ""; }; 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DiagnosticLogger+LoopKit.swift"; sourceTree = ""; }; 431A8C3F1EC6E8AB00823B9C /* CircleMaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircleMaskView.swift; sourceTree = ""; }; + 431E73471FF95A900069B5F7 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = ""; }; 4326BA631F3A44D9007CCAD4 /* ChartLineModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartLineModel.swift; sourceTree = ""; }; 4328E0151CFBE1DA00E199AA /* StatusInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusInterfaceController.swift; sourceTree = ""; }; 4328E0161CFBE1DA00E199AA /* BolusInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusInterfaceController.swift; sourceTree = ""; }; @@ -419,11 +433,10 @@ 433EA4C31D9F71C800CD78FB /* CommandResponseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandResponseViewController.swift; sourceTree = ""; }; 4341F4EA1EDB92AC001C936B /* LogglyService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogglyService.swift; sourceTree = ""; }; 43441A9B1EDB34810087958C /* StatusExtensionContext+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "StatusExtensionContext+LoopKit.swift"; sourceTree = ""; }; - 43441A9F1EDB4D390087958C /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; 4346D1E61C77F5FE00ABAFE3 /* ChartTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ChartTableViewCell.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 4346D1EF1C781BEA00ABAFE3 /* SwiftCharts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCharts.framework; path = Carthage/Build/iOS/SwiftCharts.framework; sourceTree = SOURCE_ROOT; }; - 4346D1F51C78501000ABAFE3 /* ChartPoint+Loop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ChartPoint+Loop.swift"; sourceTree = ""; }; 434AB0B11CBB4C3300422F4A /* RileyLinkBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RileyLinkBLEKit.framework; path = Carthage/Build/iOS/RileyLinkBLEKit.framework; sourceTree = SOURCE_ROOT; }; + 434B288520661D29000EE07B /* LoopKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LoopKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 434F54561D287FDB002A9274 /* NibLoadable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NibLoadable.swift; sourceTree = ""; }; 434F54581D28805E002A9274 /* ButtonTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ButtonTableViewCell.xib; sourceTree = ""; }; 434F545A1D2880D4002A9274 /* AuthenticationTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AuthenticationTableViewCell.xib; sourceTree = ""; }; @@ -447,11 +460,14 @@ 436A0DA41D236A2A00104B24 /* LoopError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopError.swift; sourceTree = ""; }; 436D9BF71F6F4EA100CFA75F /* recommended_temp_start_low_end_just_above_range.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = recommended_temp_start_low_end_just_above_range.json; sourceTree = ""; }; 436FACED1D0BA636004E2427 /* InsulinDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinDataSource.swift; sourceTree = ""; }; + 4374B5EE209D84BE00D17AA8 /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; + 4374B5F1209D897600D17AA8 /* Locked.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Locked.swift; sourceTree = ""; }; 43776F8C1B8022E90074EA36 /* Loop.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Loop.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43776F8F1B8022E90074EA36 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43776F961B8022E90074EA36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43776F981B8022E90074EA36 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43776F9B1B8022E90074EA36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 437AFEE6203688CF008C4892 /* LoopKitUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LoopKitUI.framework; path = Carthage/Build/iOS/LoopKitUI.framework; sourceTree = ""; }; 437CCAD91D284ADF0075D2C3 /* AuthenticationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTableViewCell.swift; sourceTree = ""; }; 437CCADB1D284B830075D2C3 /* ButtonTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonTableViewCell.swift; sourceTree = ""; }; 437CCADD1D2858FD0075D2C3 /* AuthenticationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = ""; }; @@ -511,7 +527,6 @@ 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEffectVelocity.swift; sourceTree = ""; }; 43C418B41CE0575200405B6A /* ShareGlucose+GlucoseKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ShareGlucose+GlucoseKit.swift"; sourceTree = ""; }; 43C513181E864C4E001547C7 /* GlucoseRangeSchedule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseRangeSchedule.swift; sourceTree = ""; }; - 43C6407B1DA051850093E25D /* InsulinKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InsulinKit.framework; path = Carthage/Build/iOS/InsulinKit.framework; sourceTree = ""; }; 43CA93361CB98079000026B5 /* MinimedKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MinimedKit.framework; path = Carthage/Build/iOS/MinimedKit.framework; sourceTree = SOURCE_ROOT; }; 43CB2B2A1D924D450079823D /* WCSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WCSession.swift; sourceTree = ""; }; 43CE7CDD1CA8B63E003CC1B0 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; @@ -520,7 +535,6 @@ 43D381611EBD9759007F8C8F /* HeaderValuesTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderValuesTableViewCell.swift; sourceTree = ""; }; 43D533BB1CFD1DD7009E3085 /* WatchApp Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "WatchApp Extension.entitlements"; sourceTree = ""; }; 43D848AF1E7DCBE100DADCBC /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; - 43D848B11E7DF42500DADCBC /* LoopSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoopSettings.swift; sourceTree = ""; }; 43DBF04B1C93B8D700B3C386 /* BolusViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BolusViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43DBF0521C93EC8200B3C386 /* DeviceDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DeviceDataManager.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43DBF0581C93F73800B3C386 /* CarbEntryTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbEntryTableViewController.swift; sourceTree = ""; }; @@ -547,8 +561,8 @@ 43E2D90B1D20C581004DA55F /* LoopTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoopTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43E2D90F1D20C581004DA55F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43E3449E1B9D68E900C85C07 /* StatusTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = StatusTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - 43E344A31B9E1B1C00C85C07 /* NSUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSUserDefaults.swift; sourceTree = ""; }; 43E397A21D56B9E40028E321 /* Glucose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Glucose.swift; sourceTree = ""; }; + 43E5292A205F718500ACEB3B /* SensorValueGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValueGlucoseEvent.swift; sourceTree = ""; }; 43EA285E1D50ED3D001BC233 /* GlucoseTrend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseTrend.swift; sourceTree = ""; }; 43EA28611D517E42001BC233 /* SensorDisplayable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorDisplayable.swift; sourceTree = ""; }; 43EDEE6B1CF2E12A00393BE3 /* Loop.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Loop.entitlements; sourceTree = ""; }; @@ -561,8 +575,6 @@ 43F5C2DA1B92A5E1003EB13D /* SettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SettingsTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 43F64DD81D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleSubtitleTableViewCell.swift; sourceTree = ""; }; 43F78D251C8FC000002152D1 /* DoseMath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoseMath.swift; sourceTree = ""; }; - 43F78D481C914197002152D1 /* CarbKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CarbKit.framework; path = Carthage/Build/iOS/CarbKit.framework; sourceTree = ""; }; - 43F78D491C914197002152D1 /* GlucoseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GlucoseKit.framework; path = Carthage/Build/iOS/GlucoseKit.framework; sourceTree = ""; }; 43F78D4B1C914197002152D1 /* LoopKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LoopKit.framework; path = Carthage/Build/iOS/LoopKit.framework; sourceTree = SOURCE_ROOT; }; 43FBEDD71D73843700B21F22 /* LevelMaskView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LevelMaskView.swift; sourceTree = ""; }; 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = G4ShareSpy.framework; path = Carthage/Build/iOS/G4ShareSpy.framework; sourceTree = SOURCE_ROOT; }; @@ -573,8 +585,6 @@ 4F08DE831E7BB70B006741EA /* ChartPointsScatterDownTrianglesLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartPointsScatterDownTrianglesLayer.swift; sourceTree = ""; }; 4F08DE841E7BB70B006741EA /* ChartPointsTouchHighlightLayerViewCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartPointsTouchHighlightLayerViewCache.swift; sourceTree = ""; }; 4F08DE8E1E7BB871006741EA /* CollectionType+Loop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CollectionType+Loop.swift"; sourceTree = ""; }; - 4F08DEA01E81D90F006741EA /* GlucoseRangeScheduleCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseRangeScheduleCalculator.swift; sourceTree = ""; }; - 4F08DEA21E81E12D006741EA /* DatedRangedContextCalculator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatedRangedContextCalculator.swift; sourceTree = ""; }; 4F2C15801E0495B200E160D4 /* WatchContext+WatchApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WatchContext+WatchApp.swift"; sourceTree = ""; }; 4F2C15921E09BF2C00E160D4 /* HUDView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HUDView.swift; sourceTree = ""; }; 4F2C15941E09BF3C00E160D4 /* HUDView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HUDView.xib; sourceTree = ""; }; @@ -637,7 +647,6 @@ C12F21A61DFA79CB00748193 /* recommend_temp_basal_very_low_end_in_range.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = recommend_temp_basal_very_low_end_in_range.json; sourceTree = ""; }; C15713811DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MealBolusNightscoutTreatment.swift; sourceTree = ""; }; C17824991E1999FA00D9D25C /* CaseCountable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaseCountable.swift; sourceTree = ""; }; - C178249D1E19B62300D9D25C /* GlucoseThreshold.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseThreshold.swift; sourceTree = ""; }; C178249F1E19CF9800D9D25C /* GlucoseThresholdTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseThresholdTableViewController.swift; sourceTree = ""; }; C17824A21E19EAB600D9D25C /* recommend_temp_basal_start_very_low_end_high.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = recommend_temp_basal_start_very_low_end_high.json; sourceTree = ""; }; C17824A41E1AD4D100D9D25C /* BolusRecommendation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusRecommendation.swift; sourceTree = ""; }; @@ -662,13 +671,11 @@ files = ( 4F7528941DFE1E9500C322D6 /* LoopUI.framework in Frameworks */, 434FB6461D68F1CD007B9C70 /* Amplitude.framework in Frameworks */, - 43F78D4C1C914197002152D1 /* CarbKit.framework in Frameworks */, 43C246A81D89990F0031F8D1 /* Crypto.framework in Frameworks */, 4D3B40041D4A9E1A00BC6334 /* G4ShareSpy.framework in Frameworks */, - 43F78D4D1C914197002152D1 /* GlucoseKit.framework in Frameworks */, 43F5C2C91B929C09003EB13D /* HealthKit.framework in Frameworks */, - 43C6407C1DA051850093E25D /* InsulinKit.framework in Frameworks */, 43F78D4F1C914197002152D1 /* LoopKit.framework in Frameworks */, + 437AFEE7203688CF008C4892 /* LoopKitUI.framework in Frameworks */, 43CA93371CB98079000026B5 /* MinimedKit.framework in Frameworks */, C10428971D17BAD400DD539A /* NightscoutUploadKit.framework in Frameworks */, 437AFEE42035252A008C4892 /* RileyLinkBLEKit.framework in Frameworks */, @@ -708,6 +715,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 434B288420661D29000EE07B /* LoopKit.framework in Frameworks */, 4F7528951DFE1E9B00C322D6 /* LoopUI.framework in Frameworks */, 437AFEE520352591008C4892 /* NotificationCenter.framework in Frameworks */, ); @@ -717,6 +725,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 437AFEE8203689FE008C4892 /* LoopKit.framework in Frameworks */, 4FB76FB01E8C3E8000B39636 /* SwiftCharts.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -764,7 +773,6 @@ 43757D131C06F26C00910CB9 /* Models */ = { isa = PBXGroup; children = ( - 43673E2E1F37BDA10058AC7C /* Insulin */, 43880F961D9D8052009061A8 /* ServiceAuthentication */, 43DE92601C555C26001FFDE1 /* AbsorptionTimeType+CarbKit.swift */, C17824A41E1AD4D100D9D25C /* BolusRecommendation.swift */, @@ -773,10 +781,10 @@ 43E397A21D56B9E40028E321 /* Glucose.swift */, 43C2FAE01EB656A500364AFF /* GlucoseEffectVelocity.swift */, 4D5B7A4A1D457CCA00796CA9 /* GlucoseG4.swift */, - C178249D1E19B62300D9D25C /* GlucoseThreshold.swift */, 436FACED1D0BA636004E2427 /* InsulinDataSource.swift */, + 4374B5F1209D897600D17AA8 /* Locked.swift */, 436A0DA41D236A2A00104B24 /* LoopError.swift */, - 43D848B11E7DF42500DADCBC /* LoopSettings.swift */, + 430B29942041F5CB00BA9F93 /* LoopSettings+Loop.swift */, 430DA58F1D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift */, 4F526D601DF8D9A900A04910 /* NetBasal.swift */, 438D42F81D7C88BC003244B0 /* PredictionInputEffect.swift */, @@ -944,7 +952,6 @@ children = ( C17824991E1999FA00D9D25C /* CaseCountable.swift */, 4F6663931E905FD2009E74FC /* ChartColorPalette+Loop.swift */, - 4346D1F51C78501000ABAFE3 /* ChartPoint+Loop.swift */, 4389916A1E91B689000EEF90 /* ChartSettings+Loop.swift */, 4F08DE8E1E7BB871006741EA /* CollectionType+Loop.swift */, 43CE7CDD1CA8B63E003CC1B0 /* Data.swift */, @@ -953,14 +960,14 @@ C15713811DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift */, 438172D81F4E9E37003C3328 /* NewPumpEvent.swift */, 43CEE6E51E56AFD400CB9116 /* NightscoutUploader.swift */, - 43E344A31B9E1B1C00C85C07 /* NSUserDefaults.swift */, - 43441A9F1EDB4D390087958C /* OSLog.swift */, 4381D2251F3C0FDD004ACCF9 /* RileyLinkDevice.swift */, + 43E5292A205F718500ACEB3B /* SensorValueGlucoseEvent.swift */, 43BFF0CA1E466C0900FF19A9 /* StateColorPalette.swift */, 43F41C361D3BF32400C11ED6 /* UIAlertController.swift */, 43BFF0BB1E45C80600FF19A9 /* UIColor+Loop.swift */, 437CEEE31CDE5C0A003C8C80 /* UIImage.swift */, 434FF1ED1CF27EEF000DB779 /* UITableViewCell.swift */, + 430B29922041F5B200BA9F93 /* UserDefaults+Loop.swift */, ); path = Extensions; sourceTree = ""; @@ -1019,7 +1026,6 @@ 43F4EF1C1BA2A57600526CE1 /* DiagnosticLogger.swift */, 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */, 43F78D251C8FC000002152D1 /* DoseMath.swift */, - 4F08DEA01E81D90F006741EA /* GlucoseRangeScheduleCalculator.swift */, 43E2D8C51D204678004DA55F /* KeychainManager.swift */, 43E2D8C71D208D5B004DA55F /* KeychainManager+Loop.swift */, 43A567681C94880B00334FAC /* LoopDataManager.swift */, @@ -1050,7 +1056,6 @@ 7D7076371FE06EDE004AC8EA /* Localizable.strings */, 4F70C1FD1DE8E662006380B7 /* Loop Status Extension.entitlements */, 4F70C1E51DE8DCA7006380B7 /* Info.plist */, - 4F08DEA21E81E12D006741EA /* DatedRangedContextCalculator.swift */, 43BFF0CC1E466C8400FF19A9 /* StateColorPalette.swift */, 4F70C1E01DE8DCA7006380B7 /* StatusViewController.swift */, 43BFF0BE1E45C8EA00FF19A9 /* UIColor+Widget.swift */, @@ -1141,10 +1146,13 @@ 4FF4D0FB1E1834C400846527 /* Models */ = { isa = PBXGroup; children = ( + 43673E2E1F37BDA10058AC7C /* Insulin */, 435400301C9F744E00D5819C /* BolusSuggestionUserInfo.swift */, 43DE92581C5479E4001FFDE1 /* CarbEntryUserInfo.swift */, 894B91CC1FF9F45900DA65F5 /* GlucoseRangeScheduleOverrideUserInfo.swift */, + 430B298D2041F56500BA9F93 /* GlucoseThreshold.swift */, 43EA285E1D50ED3D001BC233 /* GlucoseTrend.swift */, + 430B298C2041F56500BA9F93 /* LoopSettings.swift */, 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */, 4F70C2111DE900EA006380B7 /* StatusExtensionContext.swift */, 4FF4D0FF1E18374700846527 /* WatchContext.swift */, @@ -1160,8 +1168,11 @@ 434F54561D287FDB002A9274 /* NibLoadable.swift */, 430DA58D1D4AEC230097D1CA /* NSBundle.swift */, 439897341CD2F7DE00223065 /* NSTimeInterval.swift */, + 430B29892041F54A00BA9F93 /* NSUserDefaults.swift */, 4FC8C8001DEB93E400A1452E /* NSUserDefaults+StatusExtension.swift */, 43BFF0B31E45C1BE00FF19A9 /* NumberFormatter.swift */, + 4374B5EE209D84BE00D17AA8 /* OSLog.swift */, + 431E73471FF95A900069B5F7 /* PersistenceController.swift */, 43BFF0B11E45C18400FF19A9 /* UIColor.swift */, 43BFF0C31E4659E700FF19A9 /* UIColor+HIG.swift */, ); @@ -1171,17 +1182,16 @@ 968DCD53F724DE56FFE51920 /* Frameworks */ = { isa = PBXGroup; children = ( + 434B288520661D29000EE07B /* LoopKit.framework */, C18852E12082AB1A00BECC8C /* RileyLinkKitUI.framework */, 4353D177203D4DDA007B4ECD /* CoreBluetooth.framework */, 4353D175203D4D3C007B4ECD /* HealthKit.framework */, 434FB6451D68F1CD007B9C70 /* Amplitude.framework */, - 43F78D481C914197002152D1 /* CarbKit.framework */, 43C246A71D89990F0031F8D1 /* Crypto.framework */, 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */, - 43F78D491C914197002152D1 /* GlucoseKit.framework */, 43F5C2C81B929C09003EB13D /* HealthKit.framework */, - 43C6407B1DA051850093E25D /* InsulinKit.framework */, 43F78D4B1C914197002152D1 /* LoopKit.framework */, + 437AFEE6203688CF008C4892 /* LoopKitUI.framework */, 43CA93361CB98079000026B5 /* MinimedKit.framework */, C10428961D17BAD400DD539A /* NightscoutUploadKit.framework */, 4F70C1DD1DE8DCA7006380B7 /* NotificationCenter.framework */, @@ -1564,9 +1574,6 @@ ); inputPaths = ( "$(SRCROOT)/Carthage/Build/iOS/CGMBLEKit.framework", - "$(SRCROOT)/Carthage/Build/iOS/CarbKit.framework", - "$(SRCROOT)/Carthage/Build/iOS/GlucoseKit.framework", - "$(SRCROOT)/Carthage/Build/iOS/InsulinKit.framework", "$(SRCROOT)/Carthage/Build/iOS/LoopKit.framework", "$(SRCROOT)/Carthage/Build/iOS/SwiftCharts.framework", "$(SRCROOT)/Carthage/Build/iOS/MinimedKit.framework", @@ -1578,13 +1585,11 @@ "$(SRCROOT)/Carthage/Build/iOS/Crypto.framework", "$(SRCROOT)/Carthage/Build/iOS/G4ShareSpy.framework", "$(SRCROOT)/Carthage/Build/iOS/RileyLinkKitUI.framework", + "$(SRCROOT)/Carthage/Build/iOS/LoopKitUI.framework", ); name = "Copy Frameworks with Carthage"; outputPaths = ( "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CGMBLEKit.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/CarbKit.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/GlucoseKit.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/InsulinKit.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/LoopKit.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/SwiftCharts.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/MinimedKit.framework", @@ -1596,6 +1601,7 @@ "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Crypto.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/G4ShareSpy.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RileyLinkKitUI.framework", + "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/LoopKitUI.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1614,21 +1620,23 @@ 43441A9C1EDB34810087958C /* StatusExtensionContext+LoopKit.swift in Sources */, 4FF4D1001E18374700846527 /* WatchContext.swift in Sources */, 4381D2261F3C0FDD004ACCF9 /* RileyLinkDevice.swift in Sources */, + 430B298A2041F54A00BA9F93 /* NSUserDefaults.swift in Sources */, 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */, 43C418B51CE0575200405B6A /* ShareGlucose+GlucoseKit.swift in Sources */, 4F2C15821E074FC600E160D4 /* NSTimeInterval.swift in Sources */, 4311FB9B1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift in Sources */, 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */, + 43E5292B205F718500ACEB3B /* SensorValueGlucoseEvent.swift in Sources */, 43C513191E864C4E001547C7 /* GlucoseRangeSchedule.swift in Sources */, 43A51E1F1EB6D62A000736CC /* CarbAbsorptionViewController.swift in Sources */, 43776F901B8022E90074EA36 /* AppDelegate.swift in Sources */, 437CCADA1D284ADF0075D2C3 /* AuthenticationTableViewCell.swift in Sources */, 439BED2E1E760BC600B0AED5 /* EnliteCGMManager.swift in Sources */, + 430B29932041F5B300BA9F93 /* UserDefaults+Loop.swift in Sources */, 4341F4EB1EDB92AC001C936B /* LogglyService.swift in Sources */, 43CE7CDE1CA8B63E003CC1B0 /* Data.swift in Sources */, 43BFF0CB1E466C0900FF19A9 /* StateColorPalette.swift in Sources */, 43F5C2DB1B92A5E1003EB13D /* SettingsTableViewController.swift in Sources */, - C11C87DD1E21E53500BB71D3 /* GlucoseThreshold.swift in Sources */, 434FF1EA1CF26C29000DB779 /* IdentifiableClass.swift in Sources */, 437CCADE1D2858FD0075D2C3 /* AuthenticationViewController.swift in Sources */, 43A5676B1C96155700334FAC /* SwitchTableViewCell.swift in Sources */, @@ -1638,7 +1646,6 @@ 43B260491ED248FB008CAA77 /* CarbEntryTableViewCell.swift in Sources */, 4302F4E11D4E9C8900F0FCAF /* TextFieldTableViewController.swift in Sources */, 435CB6271F37AE5600C320C7 /* WalshInsulinModel.swift in Sources */, - 43E344A41B9E1B1C00C85C07 /* NSUserDefaults.swift in Sources */, 43045E581F25AC1700FD9CE1 /* RileyLinkDeviceManager.swift in Sources */, 43F64DD91D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift in Sources */, C15713821DAC6983005BC4D2 /* MealBolusNightscoutTreatment.swift in Sources */, @@ -1646,6 +1653,7 @@ 43E3449F1B9D68E900C85C07 /* StatusTableViewController.swift in Sources */, 43DBF0531C93EC8200B3C386 /* DeviceDataManager.swift in Sources */, 43E2D8C81D208D5B004DA55F /* KeychainManager+Loop.swift in Sources */, + 430B298F2041F56500BA9F93 /* GlucoseThreshold.swift in Sources */, C17824A01E19CF9800D9D25C /* GlucoseThresholdTableViewController.swift in Sources */, 435CB6251F37ABFC00C320C7 /* ExponentialInsulinModelPreset.swift in Sources */, 4346D1E71C77F5FE00ABAFE3 /* ChartTableViewCell.swift in Sources */, @@ -1666,9 +1674,9 @@ 4309786E1E73DAD100BEBC82 /* CGM.swift in Sources */, 43F5173D1D713DB0000FA422 /* RadioSelectionTableViewController.swift in Sources */, C178249A1E1999FA00D9D25C /* CaseCountable.swift in Sources */, - 4F08DEA11E81D90F006741EA /* GlucoseRangeScheduleCalculator.swift in Sources */, 43DBF04C1C93B8D700B3C386 /* BolusViewController.swift in Sources */, 4FB76FBB1E8C42CF00B39636 /* UIColor.swift in Sources */, + 4374B5EF209D84BF00D17AA8 /* OSLog.swift in Sources */, 4F6663941E905FD2009E74FC /* ChartColorPalette+Loop.swift in Sources */, 4328E0351CFC0AE100E199AA /* WatchDataManager.swift in Sources */, 43D381621EBD9759007F8C8F /* HeaderValuesTableViewCell.swift in Sources */, @@ -1689,7 +1697,7 @@ 433EA4C41D9F71C800CD78FB /* CommandResponseViewController.swift in Sources */, 43D2E8231F00425400AE5CBF /* BolusViewController+LoopDataManager.swift in Sources */, 434F545F1D288345002A9274 /* ShareService.swift in Sources */, - 43441AA01EDB4D390087958C /* OSLog.swift in Sources */, + 430B29952041F5CB00BA9F93 /* LoopSettings+Loop.swift in Sources */, 43CEE6E61E56AFD400CB9116 /* NightscoutUploader.swift in Sources */, 4328E0331CFC091100E199AA /* WatchContext+LoopKit.swift in Sources */, 4F526D611DF8D9A900A04910 /* NetBasal.swift in Sources */, @@ -1697,6 +1705,7 @@ 436A0DA51D236A2A00104B24 /* LoopError.swift in Sources */, 435CB6231F37967800C320C7 /* InsulinModelSettingsViewController.swift in Sources */, 43E2D8C61D204678004DA55F /* KeychainManager.swift in Sources */, + 431E73481FF95A900069B5F7 /* PersistenceController.swift in Sources */, 439BED2C1E760A7A00B0AED5 /* DexCGMManager.swift in Sources */, 433EA4C21D9F39C900CD78FB /* PumpIDTableViewController.swift in Sources */, 43F78D261C8FC000002152D1 /* DoseMath.swift in Sources */, @@ -1709,16 +1718,16 @@ 439897371CD2F80600223065 /* AnalyticsManager.swift in Sources */, 430D85891F44037000AF2D4F /* HUDViewTableViewCell.swift in Sources */, 43A51E211EB6DBDD000736CC /* ChartsTableViewController.swift in Sources */, - 4346D1F61C78501000ABAFE3 /* ChartPoint+Loop.swift in Sources */, 438849EE1D2A1EBB003B3F23 /* MLabService.swift in Sources */, - 43D848B21E7DF42500DADCBC /* LoopSettings.swift in Sources */, 438D42FB1D7D11A4003244B0 /* PredictionInputEffectTableViewCell.swift in Sources */, 43F4EF1D1BA2A57600526CE1 /* DiagnosticLogger.swift in Sources */, 432E73CB1D24B3D6009AD15D /* RemoteDataManager.swift in Sources */, 43DE92591C5479E4001FFDE1 /* CarbEntryUserInfo.swift in Sources */, 434F54631D28DD80002A9274 /* ValidatingIndicatorView.swift in Sources */, 43DE92611C555C26001FFDE1 /* AbsorptionTimeType+CarbKit.swift in Sources */, + 430B298E2041F56500BA9F93 /* LoopSettings.swift in Sources */, 43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */, + 4374B5F2209D897600D17AA8 /* Locked.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1757,7 +1766,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C17824A11E19E8C200D9D25C /* GlucoseThreshold.swift in Sources */, + 43C3B6ED20B884500026CAFA /* GlucoseThreshold.swift in Sources */, 43947D731F529FAA00A07D31 /* GlucoseRangeSchedule.swift in Sources */, 43E2D8DC1D20C049004DA55F /* DoseMath.swift in Sources */, 43E2D8DB1D20C03B004DA55F /* NSTimeInterval.swift in Sources */, @@ -1781,17 +1790,23 @@ buildActionMask = 2147483647; files = ( 4FAC02541E22F6B20087A773 /* NSTimeInterval.swift in Sources */, + 434B2888206B4F0A000EE07B /* InsulinModelSettings.swift in Sources */, 4FB76FBA1E8C42CE00B39636 /* UIColor.swift in Sources */, 4F2C15831E0757E600E160D4 /* HKUnit.swift in Sources */, + 430B29902041F57000BA9F93 /* GlucoseThreshold.swift in Sources */, + 434B2887206B4F07000EE07B /* WalshInsulinModel.swift in Sources */, 43E93FB51E4675E800EAB8DB /* NumberFormatter.swift in Sources */, 43BFF0CD1E466C8400FF19A9 /* StateColorPalette.swift in Sources */, - 4F08DEA31E81E12D006741EA /* DatedRangedContextCalculator.swift in Sources */, + 430B29912041F57200BA9F93 /* LoopSettings.swift in Sources */, 4F526D621DF9D95200A04910 /* NSBundle.swift in Sources */, 4FC8C8021DEB943800A1452E /* NSUserDefaults+StatusExtension.swift in Sources */, + 434B2889206B4F0C000EE07B /* ExponentialInsulinModelPreset.swift in Sources */, + 434B2886206628B3000EE07B /* PersistenceController.swift in Sources */, 43BFF0C71E465A4F00FF19A9 /* UIColor+HIG.swift in Sources */, 43BFF0BF1E45C8EA00FF19A9 /* UIColor+Widget.swift in Sources */, 4F70C2121DE900EA006380B7 /* StatusExtensionContext.swift in Sources */, 4F70C1E11DE8DCA7006380B7 /* StatusViewController.swift in Sources */, + 430B298B2041F55700BA9F93 /* NSUserDefaults.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1805,6 +1820,7 @@ 436961911F19D11E00447E89 /* ChartPointsContextFillLayer.swift in Sources */, 4FF4D0F81E1725B000846527 /* NibLoadable.swift in Sources */, 4326BA641F3A44D9007CCAD4 /* ChartLineModel.swift in Sources */, + 4374B5F0209D857E00D17AA8 /* OSLog.swift in Sources */, 4F7528AA1DFE215100C322D6 /* HKUnit.swift in Sources */, 4F7528A91DFE212600C322D6 /* GlucoseTrend.swift in Sources */, 4F7528A71DFE20CE00C322D6 /* SensorDisplayable.swift in Sources */, @@ -2077,7 +2093,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.1; MAIN_APP_BUNDLE_IDENTIFIER = "$(inherited).Loop"; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -2086,7 +2102,7 @@ SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; WARNING_CFLAGS = "-Wall"; - WATCHOS_DEPLOYMENT_TARGET = 3.2; + WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Debug; }; @@ -2138,7 +2154,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.1; MAIN_APP_BUNDLE_IDENTIFIER = "$(inherited).Loop"; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; @@ -2147,7 +2163,7 @@ TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = "-Wall"; - WATCHOS_DEPLOYMENT_TARGET = 3.2; + WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Release; }; diff --git a/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme b/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme index 301b74132b..6eb351a805 100644 --- a/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme +++ b/Loop.xcodeproj/xcshareddata/xcschemes/Loop.xcscheme @@ -39,6 +39,16 @@ ReferencedContainer = "container:Loop.xcodeproj"> + + + + - + @@ -955,7 +955,7 @@ - + diff --git a/Loop/Extensions/ChartPoint+Loop.swift b/Loop/Extensions/ChartPoint+Loop.swift deleted file mode 100644 index 4868e18ca7..0000000000 --- a/Loop/Extensions/ChartPoint+Loop.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// ChartPoint.swift -// Naterade -// -// Created by Nathan Racklyeft on 2/19/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import Foundation -import HealthKit -import LoopKit -import SwiftCharts -import LoopUI - - -extension ChartPoint { - static func pointsForGlucoseRangeSchedule(_ glucoseRangeSchedule: GlucoseRangeSchedule, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { - let targetRanges = glucoseRangeSchedule.between( - start: ChartAxisValueDate.dateFromScalar(xAxisValues.first!.scalar), - end: ChartAxisValueDate.dateFromScalar(xAxisValues.last!.scalar) - ).map { (scheduleValue) -> DatedRangeContext in - let range = scheduleValue.value.rangeWithMinimumIncremement(glucoseRangeSchedule.unit.chartableIncrement) - - return DatedRangeContext( - startDate: scheduleValue.startDate, - endDate: scheduleValue.endDate, - minValue: range.minValue, - maxValue: range.maxValue - ) - } - - return ChartPoint.pointsForDatedRanges(targetRanges, xAxisValues: xAxisValues) - } - - static func pointsForGlucoseRangeScheduleOverrideDuration(_ override: GlucoseRangeSchedule.Override, unit: HKUnit, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { - let range = override.value.rangeWithMinimumIncremement(unit.chartableIncrement) - - return ChartPoint.pointsForDatedRangeOverrideDuration( - DatedRangeContext(startDate: override.start, endDate: override.end ?? .distantFuture, minValue: range.minValue, maxValue: range.maxValue), - xAxisValues: xAxisValues) - } - - static func pointsForGlucoseRangeScheduleOverride(_ override: GlucoseRangeSchedule.Override, unit: HKUnit, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { - let range = override.value.rangeWithMinimumIncremement(unit.chartableIncrement) - - return ChartPoint.pointsForDatedRangeOverride( - DatedRangeContext(startDate: override.start, endDate: override.end ?? .distantFuture, minValue: range.minValue, maxValue: range.maxValue), - xAxisValues: xAxisValues) - } -} - - - -extension ChartPoint: TimelineValue { - public var startDate: Date { - if let dateValue = x as? ChartAxisValueDate { - return dateValue.date - } else { - return Date.distantPast - } - } -} - - -private extension DoubleRange { - func rangeWithMinimumIncremement(_ increment: Double) -> DoubleRange { - var minValue = self.minValue - var maxValue = self.maxValue - - if (maxValue - minValue) < .ulpOfOne { - minValue -= increment - maxValue += increment - } - - return DoubleRange(minValue: minValue, maxValue: maxValue) - } -} diff --git a/Loop/Extensions/DoseStore.swift b/Loop/Extensions/DoseStore.swift index d5b0fd09bc..89cb286982 100644 --- a/Loop/Extensions/DoseStore.swift +++ b/Loop/Extensions/DoseStore.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import InsulinKit +import LoopKit import MinimedKit @@ -24,7 +24,7 @@ extension LoopDataManager { for event in pumpEvents { var dose: DoseEntry? - var eventType: InsulinKit.PumpEventType? + var eventType: LoopKit.PumpEventType? switch event.pumpEvent { case let bolus as BolusNormalPumpEvent: diff --git a/Loop/Extensions/MealBolusNightscoutTreatment.swift b/Loop/Extensions/MealBolusNightscoutTreatment.swift index dc7d940dd8..a0d45089cc 100644 --- a/Loop/Extensions/MealBolusNightscoutTreatment.swift +++ b/Loop/Extensions/MealBolusNightscoutTreatment.swift @@ -7,12 +7,12 @@ // import Foundation +import LoopKit import NightscoutUploadKit -import CarbKit import HealthKit extension MealBolusNightscoutTreatment { - public convenience init(carbEntry: CarbEntry) { + public convenience init(carbEntry: StoredCarbEntry) { let carbGrams = carbEntry.quantity.doubleValue(for: HKUnit.gram()) self.init(timestamp: carbEntry.startDate, enteredBy: "loop://\(UIDevice.current.name)", id: carbEntry.externalID, carbs: lround(carbGrams), absorptionTime: carbEntry.absorptionTime, foodType: carbEntry.foodType) } diff --git a/Loop/Extensions/NewPumpEvent.swift b/Loop/Extensions/NewPumpEvent.swift index 9c622af413..52432cf229 100644 --- a/Loop/Extensions/NewPumpEvent.swift +++ b/Loop/Extensions/NewPumpEvent.swift @@ -5,7 +5,7 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import InsulinKit +import LoopKit extension NewPumpEvent { diff --git a/Loop/Extensions/NightscoutUploader.swift b/Loop/Extensions/NightscoutUploader.swift index bc913138f3..dab1795786 100644 --- a/Loop/Extensions/NightscoutUploader.swift +++ b/Loop/Extensions/NightscoutUploader.swift @@ -5,66 +5,79 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import CarbKit import CoreData -import InsulinKit +import LoopKit import MinimedKit import NightscoutUploadKit extension NightscoutUploader: CarbStoreSyncDelegate { static let logger = DiagnosticLogger.shared!.forCategory("NightscoutUploader") - - - public func carbStore(_ carbStore: CarbStore, hasEntriesNeedingUpload entries: [CarbEntry], completion: @escaping ([String]) -> Void) { - let nsCarbEntries = entries.map({ MealBolusNightscoutTreatment(carbEntry: $0)}) - upload(nsCarbEntries) { (result) in + public func carbStore(_ carbStore: CarbStore, hasEntriesNeedingUpload entries: [StoredCarbEntry], completion: @escaping ([StoredCarbEntry]) -> Void) { + var created = [StoredCarbEntry]() + var modified = [StoredCarbEntry]() + + for entry in entries { + if entry.externalID != nil { + modified.append(entry) + } else { + created.append(entry) + } + } + + upload(created.map { MealBolusNightscoutTreatment(carbEntry: $0) }) { (result) in switch result { case .success(let ids): - // Pass new ids back - completion(ids) + for (index, id) in ids.enumerated() { + created[index].externalID = id + created[index].isUploaded = true + } + completion(created) case .failure(let error): NightscoutUploader.logger.error(error) - completion([]) + completion(created) } } - } - - public func carbStore(_ carbStore: CarbStore, hasModifiedEntries entries: [CarbEntry], completion: @escaping (_ uploadedObjects: [String]) -> Void) { - - let nsCarbEntries = entries.map({ MealBolusNightscoutTreatment(carbEntry: $0)}) - modifyTreatments(nsCarbEntries) { (error) in + modifyTreatments(modified.map { MealBolusNightscoutTreatment(carbEntry: $0) }) { (error) in if let error = error { NightscoutUploader.logger.error(error) - completion([]) } else { - completion(entries.map { $0.externalID ?? "" } ) + for index in modified.startIndex.. Void) { + public func carbStore(_ carbStore: CarbStore, hasDeletedEntries entries: [DeletedCarbEntry], completion: @escaping ([DeletedCarbEntry]) -> Void) { + var deleted = entries - deleteTreatmentsById(ids) { (error) in + deleteTreatmentsById(deleted.map { $0.externalID }) { (error) in if let error = error { NightscoutUploader.logger.error(error) } else { - completion(ids) + for index in deleted.startIndex..) -> Void) { - var objectIDs = [NSManagedObjectID]() + func upload(_ events: [PersistedPumpEvent], from pumpModel: PumpModel, completion: @escaping (NightscoutUploadKit.Either<[URL], Error>) -> Void) { + var objectIDURLs = [URL]() var timestampedPumpEvents = [TimestampedHistoryEvent]() for event in events { - objectIDs.append(event.objectID) + objectIDURLs.append(event.objectIDURL) if let raw = event.raw, raw.count > 0, let type = MinimedKit.PumpEventType(rawValue: raw[0])?.eventType, let pumpEvent = type.init(availableData: raw, pumpModel: pumpModel) { timestampedPumpEvents.append(TimestampedHistoryEvent(pumpEvent: pumpEvent, date: event.date)) @@ -76,7 +89,7 @@ extension NightscoutUploader { self.upload(nsEvents) { (result) in switch result { case .success( _): - completion(.success(objectIDs)) + completion(.success(objectIDURLs)) case .failure(let error): completion(.failure(error)) } diff --git a/Loop/Extensions/SensorValueGlucoseEvent.swift b/Loop/Extensions/SensorValueGlucoseEvent.swift new file mode 100644 index 0000000000..f20b7da6c6 --- /dev/null +++ b/Loop/Extensions/SensorValueGlucoseEvent.swift @@ -0,0 +1,28 @@ +// +// SensorValueGlucoseEvent.swift +// Loop +// +// Copyright © 2018 LoopKit Authors. All rights reserved. +// + +import MinimedKit + + +extension SensorValueGlucoseEvent { + var glucoseSyncIdentifier: String? { + let date = timestamp + + guard + let year = date.year, + let month = date.month, + let day = date.day, + let hour = date.hour, + let minute = date.minute, + let second = date.second + else { + return nil + } + + return "\(year)-\(month)-\(day) \(hour)-\(minute)-\(second)" + } +} diff --git a/Loop/Extensions/UserDefaults+Loop.swift b/Loop/Extensions/UserDefaults+Loop.swift new file mode 100644 index 0000000000..afd14bf8ee --- /dev/null +++ b/Loop/Extensions/UserDefaults+Loop.swift @@ -0,0 +1,108 @@ +// +// UserDefaults+Loop.swift +// Loop +// +// Copyright © 2018 LoopKit Authors. All rights reserved. +// + +import Foundation +import LoopKit +import MinimedKit +import RileyLinkKit + + +extension UserDefaults { + static let appGroup: UserDefaults = { + let shared = UserDefaults(suiteName: Bundle.main.appGroupSuiteName) + let standard = UserDefaults.standard + + // Use an old key as a migration sentinel + if let shared = shared, standard.basalRateSchedule != nil && shared.basalRateSchedule == nil { + shared.basalRateSchedule = standard.basalRateSchedule + shared.carbRatioSchedule = standard.carbRatioSchedule + shared.cgm = standard.cgm + shared.connectedPeripheralIDs = standard.connectedPeripheralIDs + shared.loopSettings = standard.loopSettings + shared.insulinModelSettings = standard.insulinModelSettings + shared.insulinSensitivitySchedule = standard.insulinSensitivitySchedule + shared.preferredInsulinDataSource = standard.preferredInsulinDataSource + shared.batteryChemistry = standard.batteryChemistry + } + + shared?.removeObject(forKey: "com.loopkit.Loop.insulinCounteractionEffects") + + return shared ?? standard + }() +} + + +extension UserDefaults { + private enum Key: String { + case batteryChemistry = "com.loopkit.Loop.BatteryChemistry" + case cgmSettings = "com.loopkit.Loop.cgmSettings" + case preferredInsulinDataSource = "com.loudnate.Loop.PreferredInsulinDataSource" + } + + + var cgm: CGM? { + get { + if let rawValue = dictionary(forKey: Key.cgmSettings.rawValue) { + return CGM(rawValue: rawValue) + } else { + // Migrate the "version 0" case. Further format changes should be handled in the CGM initializer + defer { + removeObject(forKey: "com.loopkit.Loop.G5TransmitterEnabled") + removeObject(forKey: "com.loudnate.Loop.G4ReceiverEnabled") + removeObject(forKey: "com.loopkit.Loop.FetchEnliteDataEnabled") + removeObject(forKey: "com.loudnate.Naterade.TransmitterID") + } + + if bool(forKey: "com.loudnate.Loop.G4ReceiverEnabled") { + self.cgm = .g4 + return .g4 + } + + if bool(forKey: "com.loopkit.Loop.FetchEnliteDataEnabled") { + self.cgm = .enlite + return .enlite + } + + if let transmitterID = string(forKey: "com.loudnate.Naterade.TransmitterID"), transmitterID.count == 6 { + self.cgm = .g5(transmitterID: transmitterID) + return .g5(transmitterID: transmitterID) + } + + return nil + } + } + set { + set(newValue?.rawValue, forKey: Key.cgmSettings.rawValue) + } + } + + var preferredInsulinDataSource: InsulinDataSource? { + get { + return InsulinDataSource(rawValue: integer(forKey: Key.preferredInsulinDataSource.rawValue)) + } + set { + if let preferredInsulinDataSource = newValue { + set(preferredInsulinDataSource.rawValue, forKey: Key.preferredInsulinDataSource.rawValue) + } else { + removeObject(forKey: Key.preferredInsulinDataSource.rawValue) + } + } + } + + var batteryChemistry: BatteryChemistryType? { + get { + return BatteryChemistryType(rawValue: integer(forKey: Key.batteryChemistry.rawValue)) + } + set { + if let batteryChemistry = newValue { + set(batteryChemistry.rawValue, forKey: Key.batteryChemistry.rawValue) + } else { + removeObject(forKey: Key.batteryChemistry.rawValue) + } + } + } +} diff --git a/Loop/Managers/AnalyticsManager.swift b/Loop/Managers/AnalyticsManager.swift index fe08839154..baaa444257 100644 --- a/Loop/Managers/AnalyticsManager.swift +++ b/Loop/Managers/AnalyticsManager.swift @@ -101,13 +101,7 @@ final class AnalyticsManager: IdentifiableClass { logEvent("Insulin sensitivity change") } - func didChangeGlucoseTargetRangeSchedule() { - logEvent("Glucose target range change") - } - func didChangeLoopSettings(from oldValue: LoopSettings, to newValue: LoopSettings) { - logEvent("Loop settings change", outOfSession: true) - if newValue.maximumBasalRatePerHour != oldValue.maximumBasalRatePerHour { logEvent("Maximum basal rate change") } @@ -127,6 +121,16 @@ final class AnalyticsManager: IdentifiableClass { if newValue.retrospectiveCorrectionEnabled != oldValue.retrospectiveCorrectionEnabled { logEvent("Retrospective correction enabled change") } + + if newValue.glucoseTargetRangeSchedule != oldValue.glucoseTargetRangeSchedule { + if newValue.glucoseTargetRangeSchedule?.timeZone != oldValue.glucoseTargetRangeSchedule?.timeZone { + self.punpTimeZoneDidChange() + } else if newValue.glucoseTargetRangeSchedule?.override != oldValue.glucoseTargetRangeSchedule?.override { + logEvent("Glucose target range override change", outOfSession: true) + } else { + logEvent("Glucose target range change") + } + } } // MARK: - Loop Events diff --git a/Loop/Managers/CGM/CGMManager.swift b/Loop/Managers/CGM/CGMManager.swift index 82424119b3..28cbb4c78d 100644 --- a/Loop/Managers/CGM/CGMManager.swift +++ b/Loop/Managers/CGM/CGMManager.swift @@ -6,6 +6,7 @@ // import HealthKit +import LoopKit import LoopUI @@ -16,7 +17,7 @@ import LoopUI /// - error: An error occurred while receiving or store data enum CGMResult { case noData - case newData([(quantity: HKQuantity, date: Date, isDisplayOnly: Bool)]) + case newData([NewGlucoseSample]) case error(Error) } diff --git a/Loop/Managers/CGM/DexCGMManager.swift b/Loop/Managers/CGM/DexCGMManager.swift index 30fd0fbaa3..3fb10a830a 100644 --- a/Loop/Managers/CGM/DexCGMManager.swift +++ b/Loop/Managers/CGM/DexCGMManager.swift @@ -7,6 +7,7 @@ import G4ShareSpy import HealthKit +import LoopKit import LoopUI import ShareClient import CGMBLEKit @@ -94,7 +95,7 @@ final class ShareClientManager: CGMManager { // Ignore glucose values that are up to a minute newer than our previous value, to account for possible time shifting in Share data let startDate = self.delegate?.startDateToFilterNewData(for: self)?.addingTimeInterval(TimeInterval(minutes: 1)) let newGlucose = glucose.filterDateRange(startDate, nil).filter({ $0.isStateValid }).map { - return (quantity: $0.quantity, date: $0.startDate, isDisplayOnly: false) + return NewGlucoseSample(date: $0.startDate, quantity: $0.quantity, isDisplayOnly: false, syncIdentifier: "\($0.startDate.timeIntervalSince1970)", device: self.device) } self.latestBackfill = glucose.first @@ -116,10 +117,6 @@ final class ShareClientManager: CGMManager { final class G5CGMManager: DexCGMManager, TransmitterDelegate { - func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { - // Not implemented yet - } - private let transmitter: Transmitter? let logger = DiagnosticLogger.shared!.forCategory("G5CGMManager") @@ -230,8 +227,36 @@ final class G5CGMManager: DexCGMManager, TransmitterDelegate { } self.delegate?.cgmManager(self, didUpdateWith: .newData([ - (quantity: quantity, date: glucose.readDate, isDisplayOnly: glucose.isDisplayOnly) - ])) + NewGlucoseSample( + date: glucose.readDate, + quantity: quantity, + isDisplayOnly: glucose.isDisplayOnly, + syncIdentifier: glucose.syncIdentifier, + device: device + ) + ])) + } + + func transmitter(_ transmitter: Transmitter, didReadBackfill glucose: [Glucose]) { + let samples = glucose.compactMap { (glucose) -> NewGlucoseSample? in + guard glucose != latestReading, glucose.state.hasReliableGlucose, let quantity = glucose.glucose else { + return nil + } + + return NewGlucoseSample( + date: glucose.readDate, + quantity: quantity, + isDisplayOnly: glucose.isDisplayOnly, + syncIdentifier: glucose.syncIdentifier, + device: device + ) + } + + guard samples.count > 0 else { + return + } + + self.delegate?.cgmManager(self, didUpdateWith: .newData(samples)) } func transmitter(_ transmitter: Transmitter, didReadUnknownData data: Data) { @@ -322,7 +347,7 @@ final class G4CGMManager: DexCGMManager, ReceiverDelegate { let validGlucose = glucoseHistory.filter({ $0.isStateValid }).filterDateRange(includeAfter, nil).map({ - (quantity: $0.quantity, date: $0.startDate, isDisplayOnly: $0.isDisplayOnly) + NewGlucoseSample(date: $0.startDate, quantity: $0.quantity, isDisplayOnly: $0.isDisplayOnly, syncIdentifier: String(describing: $0.sequence), device: self.device) }) self.delegate?.cgmManager(self, didUpdateWith: .newData(validGlucose)) diff --git a/Loop/Managers/CGM/EnliteCGMManager.swift b/Loop/Managers/CGM/EnliteCGMManager.swift index 25a9c23358..87df81b2d0 100644 --- a/Loop/Managers/CGM/EnliteCGMManager.swift +++ b/Loop/Managers/CGM/EnliteCGMManager.swift @@ -7,6 +7,7 @@ // import HealthKit +import LoopKit import LoopUI import MinimedKit import RileyLinkKit @@ -49,15 +50,15 @@ final class EnliteCGMManager: CGMManager { self.sensorState = EnliteSensorDisplayable(latestSensorEvent) } - let unit = HKUnit.milligramsPerDeciliter() - let glucoseValues = events + let unit = HKUnit.milligramsPerDeciliter + let glucoseValues: [NewGlucoseSample] = events // TODO: Is the { $0.date > latestGlucoseDate } filter duplicative? .filter({ $0.glucoseEvent is SensorValueGlucoseEvent && $0.date > latestGlucoseDate }) - .map({ (e:TimestampedGlucoseEvent) -> (quantity: HKQuantity, date: Date, isDisplayOnly: Bool) in - let glucoseEvent = e.glucoseEvent as! SensorValueGlucoseEvent + .map { + let glucoseEvent = $0.glucoseEvent as! SensorValueGlucoseEvent let quantity = HKQuantity(unit: unit, doubleValue: Double(glucoseEvent.sgv)) - return (quantity: quantity, date: e.date, isDisplayOnly: false) - }) + return NewGlucoseSample(date: $0.date, quantity: quantity, isDisplayOnly: false, syncIdentifier: glucoseEvent.glucoseSyncIdentifier ?? UUID().uuidString, device: self.device) + } completion(.newData(glucoseValues)) } catch let error { diff --git a/Loop/Managers/DeviceDataManager.swift b/Loop/Managers/DeviceDataManager.swift index eaa78103e2..d4a6d294a1 100644 --- a/Loop/Managers/DeviceDataManager.swift +++ b/Loop/Managers/DeviceDataManager.swift @@ -7,11 +7,8 @@ // import Foundation -import CarbKit import CoreData -import GlucoseKit import HealthKit -import InsulinKit import LoopKit import LoopUI import MinimedKit @@ -27,6 +24,8 @@ final class DeviceDataManager { let logger = DiagnosticLogger.shared! + private let log = DiagnosticLogger.shared?.forCategory("DeviceManager") + /// Remember the launch date of the app for diagnostic reporting private let launchDate = Date() @@ -61,7 +60,7 @@ final class DeviceDataManager { if let status = latestPumpStatusFromMySentry { return Double(status.batteryRemainingPercent) / 100 } else if let status = latestPumpStatus { - return batteryChemistry.chargeRemaining(voltage: status.batteryVolts) + return batteryChemistry.chargeRemaining(at: status.batteryVolts) } else { return statusExtensionManager.context?.batteryPercentage } @@ -99,7 +98,8 @@ final class DeviceDataManager { // Update the HKDevice to include the name, pump model, or connection status change rileyLinkManager.getDevices { (devices) in devices.firstConnected?.getStatus { (status) in - self.loopManager.doseStore.setDevice(status.device(settings: self.pumpSettings, pumpState: state)) + // Don't assume loopManager has been initialized yet + self.loopManager?.doseStore.device = status.device(settings: self.pumpSettings, pumpState: state) } } } @@ -293,29 +293,35 @@ final class DeviceDataManager { logger.addError("Could not interpret pump clock: \(pumpDateComponents)", fromSource: "RileyLink") } - device.getStatus { (status) in + device.getStatus { (deviceStatus) in // Trigger device status upload, even if something is wrong with pumpStatus self.queue.async { - self.nightscoutDataManager.uploadDeviceStatus(pumpStatus, rileylinkDevice: status, deviceState: self.deviceStates[device.peripheralIdentifier]) + self.nightscoutDataManager.uploadDeviceStatus(pumpStatus, rileylinkDevice: deviceStatus, deviceState: self.deviceStates[device.peripheralIdentifier]) + + if case .active(glucose: let glucose) = status.glucose { + // Enlite data is included + if let date = glucoseDateComponents?.date { + let sample = NewGlucoseSample( + date: date, + quantity: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(glucose)), + isDisplayOnly: false, + syncIdentifier: status.glucoseSyncIdentifier ?? UUID().uuidString, + device: deviceStatus.device(settings: self.pumpSettings, pumpState: self.pumpState) + ) + + self.loopManager.addGlucose([sample]) + } + } } } switch status.glucose { - case .active(glucose: let glucose): - // Enlite data is included - if let date = glucoseDateComponents?.date { - loopManager.addGlucose([( - quantity: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: Double(glucose)), - date: date, - isDisplayOnly: false - )], from: nil) - } case .off: // Enlite is disabled, so assert glucose from another source cgmManager?.fetchNewDataIfNeeded(with: self) { (result) in switch result { case .newData(let values): - self.loopManager.addGlucose(values, from: self.cgmManager?.device) + self.loopManager.addGlucose(values) case .noData: break case .error(let error): @@ -413,7 +419,6 @@ final class DeviceDataManager { ops.runSession(withName: "Fetch Pump History", using: device) { (session) in do { - // TODO: This should isn't safe to access synchronously let startDate = self.loopManager.doseStore.pumpEventQueryAfterDate let (events, model) = try session.getHistoryEvents(since: startDate) @@ -443,7 +448,6 @@ final class DeviceDataManager { } private func isReservoirDataOlderThan(timeIntervalSinceNow: TimeInterval) -> Bool { - // TODO: lastReservoirValue isn't safe to read from any queue var lastReservoirDate = loopManager.doseStore.lastReservoirValue?.startDate ?? .distantPast // Look for reservoir data from MySentry that hasn't yet been written (due to 11-second imposed delay) @@ -468,6 +472,8 @@ final class DeviceDataManager { return } + self.log?.debug("Pump data is stale, fetching.") + rileyLinkManager.getDevices { (devices) in guard let device = devices.firstConnected else { let error = LoopError.connectionError @@ -506,7 +512,7 @@ final class DeviceDataManager { } self.updateReservoirVolume(status.reservoir, at: date, withTimeLeft: nil) - let battery = BatteryStatus(voltage: status.batteryVolts, status: BatteryIndicator(batteryStatus: status.batteryStatus)) + let battery = NightscoutUploadKit.BatteryStatus(voltage: status.batteryVolts.value, status: BatteryIndicator(batteryStatus: status.batteryStatus)) nsPumpStatus = NightscoutUploadKit.PumpStatus(clock: date, pumpID: status.pumpID, iob: nil, battery: battery, suspended: status.suspended, bolusing: status.bolusing, reservoir: status.reservoir) } catch let error { @@ -766,13 +772,13 @@ final class DeviceDataManager { remoteDataManager.delegate = self statusExtensionManager = StatusExtensionDataManager(deviceDataManager: self) loopManager = LoopDataManager( - delegate: self, - lastLoopCompleted: statusExtensionManager.context?.loop?.lastCompleted, + lastLoopCompleted: statusExtensionManager.context?.lastLoopCompleted, lastTempBasal: statusExtensionManager.context?.netBasal?.tempBasal ) watchManager = WatchDataManager(deviceDataManager: self) nightscoutDataManager = NightscoutDataManager(deviceDataManager: self) + loopManager.delegate = self loopManager.carbStore.syncDelegate = remoteDataManager.nightscoutService.uploader loopManager.doseStore.delegate = self // Proliferate PumpModel preferences to DoseStore @@ -797,7 +803,7 @@ extension DeviceDataManager: CGMManagerDelegate { /// TODO: Isolate to queue switch result { case .newData(let values): - loopManager.addGlucose(values, from: manager.device) { _ in + loopManager.addGlucose(values) { _ in self.assertCurrentPumpData() } case .noData: @@ -812,7 +818,6 @@ extension DeviceDataManager: CGMManagerDelegate { } func startDateToFilterNewData(for manager: CGMManager) -> Date? { - // TODO: This shouldn't be safe to access synchronously return loopManager.glucoseStore.latestGlucose?.startDate } } @@ -821,11 +826,11 @@ extension DeviceDataManager: CGMManagerDelegate { extension DeviceDataManager: DoseStoreDelegate { func doseStore(_ doseStore: DoseStore, hasEventsNeedingUpload pumpEvents: [PersistedPumpEvent], - completion completionHandler: @escaping (_ uploadedObjects: [NSManagedObjectID]) -> Void + completion completionHandler: @escaping (_ uploadedObjectIDURLs: [URL]) -> Void ) { /// TODO: Isolate to queue guard let uploader = remoteDataManager.nightscoutService.uploader, let pumpModel = pumpState?.pumpModel else { - completionHandler(pumpEvents.map({ $0.objectID })) + completionHandler(pumpEvents.map({ $0.objectIDURL })) return } @@ -935,6 +940,7 @@ extension DeviceDataManager: CustomDebugStringConvertible { var debugDescription: String { return [ Bundle.main.localizedNameAndVersion, + "", "## DeviceDataManager", "launchDate: \(launchDate)", "cgm: \(String(describing: cgm))", @@ -949,8 +955,11 @@ extension DeviceDataManager: CustomDebugStringConvertible { "pumpState: \(String(reflecting: pumpState))", "preferredInsulinDataSource: \(preferredInsulinDataSource)", "sensorInfo: \(String(reflecting: sensorInfo))", + "", cgmManager != nil ? String(reflecting: cgmManager!) : "", + "", String(reflecting: rileyLinkManager), + "", String(reflecting: statusExtensionManager!), ].joined(separator: "\n") } diff --git a/Loop/Managers/DiagnosticLogger.swift b/Loop/Managers/DiagnosticLogger.swift index bbc1dbbb1c..1914fa2a3e 100644 --- a/Loop/Managers/DiagnosticLogger.swift +++ b/Loop/Managers/DiagnosticLogger.swift @@ -15,7 +15,7 @@ final class DiagnosticLogger { let subsystem: String let version: String - var mLabService: MLabService { + private var mLabService: MLabService { didSet { try! KeychainManager().setMLabDatabaseName(mLabService.databaseName, APIKey: mLabService.APIKey) } @@ -36,11 +36,8 @@ final class DiagnosticLogger { self.version = version remoteLogLevel = isSimulator ? .fault : .info - if let (databaseName, APIKey) = KeychainManager().getMLabCredentials() { - mLabService = MLabService(databaseName: databaseName, APIKey: APIKey) - } else { - mLabService = MLabService(databaseName: nil, APIKey: nil) - } + // Delete the mLab credentials as they're no longer supported + mLabService = MLabService(databaseName: nil, APIKey: nil) let customerToken = KeychainManager().getLogglyCustomerToken() logglyService = LogglyService(customerToken: customerToken) @@ -80,7 +77,7 @@ final class CategoryLogger { self.logger = logger self.category = category - systemLog = OSLog(subsystem: logger.subsystem, category: category) + systemLog = OSLog(category: category) } private func remoteLog(_ type: OSLogType, message: String) { @@ -97,11 +94,6 @@ final class CategoryLogger { } logger.logglyService.client?.send(message, tags: [type.tagName, category]) - - // Legacy mLab logging. To be removed. - if let messageData = try? JSONSerialization.data(withJSONObject: message, options: []) { - logger.mLabService.uploadTaskWithData(messageData, inCollection: category)?.resume() - } } func debug(_ message: [String: Any]) { diff --git a/Loop/Managers/DoseMath.swift b/Loop/Managers/DoseMath.swift index 10c0872e8f..a7c26ef130 100644 --- a/Loop/Managers/DoseMath.swift +++ b/Loop/Managers/DoseMath.swift @@ -7,9 +7,7 @@ // import Foundation -import CarbKit import HealthKit -import InsulinKit import LoopKit diff --git a/Loop/Managers/GlucoseRangeScheduleCalculator.swift b/Loop/Managers/GlucoseRangeScheduleCalculator.swift deleted file mode 100644 index 1422ae31c9..0000000000 --- a/Loop/Managers/GlucoseRangeScheduleCalculator.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// GlucoseRangeScheduleCalculator.swift -// Loop -// -// Created by Bharat Mediratta on 3/21/17. -// Copyright © 2017 LoopKit Authors. All rights reserved. -// - -import Foundation -import LoopKit -import SwiftCharts -import LoopUI - -class GlucoseRangeScheduleCalculator: TargetPointsCalculator { - - var schedule: GlucoseRangeSchedule? - - var glucosePoints: [ChartPoint] = [] - var overridePoints: [ChartPoint] = [] - var overrideDurationPoints: [ChartPoint] = [] - - init(_ schedule: GlucoseRangeSchedule?) { - self.schedule = schedule - } - - func calculate(_ xAxisValues: [ChartAxisValue]?) { - if let xAxisValues = xAxisValues, xAxisValues.count > 1, - let schedule = schedule - { - glucosePoints = ChartPoint.pointsForGlucoseRangeSchedule(schedule, xAxisValues: xAxisValues) - - if let override = schedule.override { - overridePoints = ChartPoint.pointsForGlucoseRangeScheduleOverride(override, unit: schedule.unit, xAxisValues: xAxisValues) - - overrideDurationPoints = ChartPoint.pointsForGlucoseRangeScheduleOverrideDuration(override, unit: schedule.unit, xAxisValues: xAxisValues) - } else { - overridePoints = [] - overrideDurationPoints = [] - } - } - } -} diff --git a/Loop/Managers/LoopDataManager.swift b/Loop/Managers/LoopDataManager.swift index 61a076ace0..2699c3881c 100644 --- a/Loop/Managers/LoopDataManager.swift +++ b/Loop/Managers/LoopDataManager.swift @@ -7,10 +7,7 @@ // import Foundation -import CarbKit -import GlucoseKit import HealthKit -import InsulinKit import LoopKit @@ -24,42 +21,48 @@ final class LoopDataManager { } static let LoopUpdateContextKey = "com.loudnate.Loop.LoopDataManager.LoopUpdateContext" - static let LastLoopCompletedKey = "com.loopkit.Loop.LoopDataManager.LastLoopCompleted" fileprivate typealias GlucoseChange = (start: GlucoseValue, end: GlucoseValue) - let carbStore: CarbStore! + let carbStore: CarbStore let doseStore: DoseStore - let glucoseStore: GlucoseStore! + let glucoseStore: GlucoseStore - unowned let delegate: LoopDataManagerDelegate + weak var delegate: LoopDataManagerDelegate? private let logger: CategoryLogger + // References to registered notification center observers + private var notificationObservers: [Any] = [] + + deinit { + for observer in notificationObservers { + NotificationCenter.default.removeObserver(observer) + } + } + init( - delegate: LoopDataManagerDelegate, lastLoopCompleted: Date?, lastTempBasal: DoseEntry?, basalRateSchedule: BasalRateSchedule? = UserDefaults.appGroup.basalRateSchedule, carbRatioSchedule: CarbRatioSchedule? = UserDefaults.appGroup.carbRatioSchedule, insulinModelSettings: InsulinModelSettings? = UserDefaults.appGroup.insulinModelSettings, - insulinCounteractionEffects: [GlucoseEffectVelocity]? = UserDefaults.appGroup.insulinCounteractionEffects, insulinSensitivitySchedule: InsulinSensitivitySchedule? = UserDefaults.appGroup.insulinSensitivitySchedule, settings: LoopSettings = UserDefaults.appGroup.loopSettings ?? LoopSettings() ) { - self.delegate = delegate self.logger = DiagnosticLogger.shared!.forCategory("LoopDataManager") - self.insulinCounteractionEffects = insulinCounteractionEffects ?? [] - self.lastLoopCompleted = lastLoopCompleted + self.lockedLastLoopCompleted = Locked(lastLoopCompleted) self.lastTempBasal = lastTempBasal self.settings = settings let healthStore = HKHealthStore() + let cacheStore = PersistenceController.controllerInAppGroupDirectory() carbStore = CarbStore( healthStore: healthStore, + cacheStore: cacheStore, defaultAbsorptionTimes: ( fast: TimeInterval(hours: 2), medium: TimeInterval(hours: 3), @@ -71,29 +74,48 @@ final class LoopDataManager { doseStore = DoseStore( healthStore: healthStore, + cacheStore: cacheStore, insulinModel: insulinModelSettings?.model, basalProfile: basalRateSchedule, insulinSensitivitySchedule: insulinSensitivitySchedule ) - glucoseStore = GlucoseStore(healthStore: healthStore) + glucoseStore = GlucoseStore(healthStore: healthStore, cacheStore: cacheStore, cacheLength: .hours(24)) + + cacheStore.delegate = self // Observe changes - carbUpdateObserver = NotificationCenter.default.addObserver( - forName: .CarbEntriesDidUpdate, - object: nil, - queue: nil - ) { (note) -> Void in - self.dataAccessQueue.async { - self.carbEffect = nil - self.carbsOnBoard = nil - self.notify(forChange: .carbs) + notificationObservers = [ + NotificationCenter.default.addObserver( + forName: .CarbEntriesDidUpdate, + object: carbStore, + queue: nil + ) { (note) -> Void in + self.dataAccessQueue.async { + self.logger.info("Received notification of carb entries updating") + + self.carbEffect = nil + self.carbsOnBoard = nil + self.notify(forChange: .carbs) + } + }, + NotificationCenter.default.addObserver( + forName: .GlucoseSamplesDidChange, + object: glucoseStore, + queue: nil + ) { (note) in + self.dataAccessQueue.async { + self.logger.info("Received notification of glucose samples changing") + + self.glucoseMomentumEffect = nil + self.retrospectiveGlucoseChange = nil + + self.notify(forChange: .glucose) + } } - } + ] } - // MARK: - Preferences - /// Loop-related settings /// /// These are not thread-safe. @@ -105,6 +127,122 @@ final class LoopDataManager { } } + // MARK: - Calculation state + + fileprivate let dataAccessQueue: DispatchQueue = DispatchQueue(label: "com.loudnate.Naterade.LoopDataManager.dataAccessQueue", qos: .utility) + + private var carbEffect: [GlucoseEffect]? { + didSet { + predictedGlucose = nil + + // Carb data may be back-dated, so re-calculate the retrospective glucose. + retrospectivePredictedGlucose = nil + } + } + private var insulinEffect: [GlucoseEffect]? { + didSet { + predictedGlucose = nil + } + } + private var glucoseMomentumEffect: [GlucoseEffect]? { + didSet { + predictedGlucose = nil + } + } + private var retrospectiveGlucoseEffect: [GlucoseEffect] = [] { + didSet { + predictedGlucose = nil + } + } + + /// The change in glucose over the reflection time interval (default is 30 min) + fileprivate var retrospectiveGlucoseChange: GlucoseChange? { + didSet { + retrospectivePredictedGlucose = nil + } + } + + fileprivate var predictedGlucose: [GlucoseValue]? { + didSet { + recommendedTempBasal = nil + } + } + fileprivate var retrospectivePredictedGlucose: [GlucoseValue]? { + didSet { + retrospectiveGlucoseEffect = [] + } + } + fileprivate var recommendedTempBasal: (recommendation: TempBasalRecommendation, date: Date)? + fileprivate var recommendedBolus: (recommendation: BolusRecommendation, date: Date)? + + fileprivate var carbsOnBoard: CarbValue? + + fileprivate var lastTempBasal: DoseEntry? + fileprivate var lastRequestedBolus: (units: Double, date: Date)? + + /// The last date at which a loop completed, from prediction to dose (if dosing is enabled) + var lastLoopCompleted: Date? { + get { + return lockedLastLoopCompleted.value + } + set { + lockedLastLoopCompleted.value = newValue + + NotificationManager.scheduleLoopNotRunningNotifications() + AnalyticsManager.shared.loopDidSucceed() + } + } + private let lockedLastLoopCompleted: Locked + + fileprivate var lastLoopError: Error? { + didSet { + if lastLoopError != nil { + AnalyticsManager.shared.loopDidError() + } + } + } + + /// A timeline of average velocity of glucose change counteracting predicted insulin effects + fileprivate var insulinCounteractionEffects: [GlucoseEffectVelocity] = [] { + didSet { + carbEffect = nil + carbsOnBoard = nil + } + } + + // MARK: - Background task management + + private var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid + + private func startBackgroundTask() { + endBackgroundTask() + backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "PersistenceController save") { + self.endBackgroundTask() + } + } + + private func endBackgroundTask() { + if backgroundTask != UIBackgroundTaskInvalid { + UIApplication.shared.endBackgroundTask(backgroundTask) + backgroundTask = UIBackgroundTaskInvalid + } + } +} + +// MARK: Background task management +extension LoopDataManager: PersistenceControllerDelegate { + func persistenceControllerWillSave(_ controller: PersistenceController) { + startBackgroundTask() + } + + func persistenceControllerDidSave(_ controller: PersistenceController, error: PersistenceController.PersistenceControllerError?) { + endBackgroundTask() + } +} + +// MARK: - Preferences +extension LoopDataManager { + /// The daily schedule of basal insulin rates var basalRateSchedule: BasalRateSchedule? { get { @@ -159,15 +297,6 @@ final class LoopDataManager { } } - /// A timeline of average velocity of glucose change counteracting predicted insulin effects - fileprivate var insulinCounteractionEffects: [GlucoseEffectVelocity] { - didSet { - UserDefaults.appGroup.insulinCounteractionEffects = insulinCounteractionEffects - carbEffect = nil - carbsOnBoard = nil - } - } - /// The daily schedule of insulin sensitivity (also known as ISF) /// This is measured in /Unit var insulinSensitivitySchedule: InsulinSensitivitySchedule? { @@ -191,31 +320,37 @@ final class LoopDataManager { } } - /// The amount of time since a given date that data should be considered valid - var recencyInterval = TimeInterval(minutes: 15) - /// Sets a new time zone for a the schedule-based settings /// /// - Parameter timeZone: The time zone func setScheduleTimeZone(_ timeZone: TimeZone) { - self.basalRateSchedule?.timeZone = timeZone - self.carbRatioSchedule?.timeZone = timeZone - self.insulinSensitivitySchedule?.timeZone = timeZone - settings.glucoseTargetRangeSchedule?.timeZone = timeZone - } + if timeZone != basalRateSchedule?.timeZone { + AnalyticsManager.shared.punpTimeZoneDidChange() + basalRateSchedule?.timeZone = timeZone + } - /// All the HealthKit types to be read by stores - var readTypes: Set { - return glucoseStore.readTypes.union( - carbStore.readTypes).union( - doseStore.readTypes) + if timeZone != carbRatioSchedule?.timeZone { + AnalyticsManager.shared.punpTimeZoneDidChange() + carbRatioSchedule?.timeZone = timeZone + } + + if timeZone != insulinSensitivitySchedule?.timeZone { + AnalyticsManager.shared.punpTimeZoneDidChange() + insulinSensitivitySchedule?.timeZone = timeZone + } + + if timeZone != settings.glucoseTargetRangeSchedule?.timeZone { + settings.glucoseTargetRangeSchedule?.timeZone = timeZone + } } - /// All the HealthKit types we to be shared by stores - var shareTypes: Set { - return glucoseStore.shareTypes.union( - carbStore.shareTypes).union( - doseStore.shareTypes) + /// All the HealthKit types to be read and shared by stores + private var sampleTypes: Set { + return Set([ + glucoseStore.sampleType, + carbStore.sampleType, + doseStore.sampleType, + ].compactMap { $0 }) } /// True if any stores require HealthKit authorization @@ -226,46 +361,53 @@ final class LoopDataManager { } /// True if the user has explicitly denied access to any stores' HealthKit types - var sharingDenied: Bool { + private var sharingDenied: Bool { return glucoseStore.sharingDenied || carbStore.sharingDenied || doseStore.sharingDenied } func authorize(_ completion: @escaping () -> Void) { - carbStore.healthStore.requestAuthorization(toShare: shareTypes, read: readTypes) { (success, error) in + // Authorize all types at once for simplicity + carbStore.healthStore.requestAuthorization(toShare: sampleTypes, read: sampleTypes) { (success, error) in + if success { + // Call the individual authorization methods to trigger query creation + self.carbStore.authorize({ _ in }) + self.doseStore.insulinDeliveryStore.authorize({ _ in }) + self.glucoseStore.authorize({ _ in }) + } + completion() } } +} - // MARK: - Intake +// MARK: - Intake +extension LoopDataManager { /// Adds and stores glucose data /// /// - Parameters: - /// - values: The new glucose values to store - /// - device: The device that captured the data + /// - samples: The new glucose samples to store /// - completion: A closure called once upon completion /// - result: The stored glucose values func addGlucose( - _ values: [(quantity: HKQuantity, date: Date, isDisplayOnly: Bool)], - from device: HKDevice?, + _ samples: [NewGlucoseSample], completion: ((_ result: Result<[GlucoseValue]>) -> Void)? = nil ) { - glucoseStore.addGlucoseValues(values, device: device) { (success, values, error) in - if success { - self.dataAccessQueue.async { - self.glucoseMomentumEffect = nil - self.lastGlucoseChange = nil - self.retrospectiveGlucoseChange = nil - self.notify(forChange: .glucose) - } - } + glucoseStore.addGlucose(samples) { (result) in + self.dataAccessQueue.async { + switch result { + case .success(let samples): + if let endDate = samples.sorted(by: { $0.startDate < $1.startDate }).first?.startDate { + // Prune back any counteraction effects for recomputation + self.insulinCounteractionEffects = self.insulinCounteractionEffects.filter { $0.endDate < endDate } + } - if let error = error { - completion?(.failure(error)) - } else { - completion?(.success(values ?? [])) + completion?(.success(samples)) + case .failure(let error): + completion?(.failure(error)) + } } } } @@ -276,20 +418,17 @@ final class LoopDataManager { /// - carbEntry: The new carb value /// - completion: A closure called once upon completion /// - result: The bolus recommendation - func addCarbEntryAndRecommendBolus(_ carbEntry: CarbEntry, replacing replacingEntry: CarbEntry? = nil, completion: @escaping (_ result: Result) -> Void) { - let addCompletion: (Bool, CarbEntry?, CarbStore.CarbStoreError?) -> Void = { (success, _, error) in + func addCarbEntryAndRecommendBolus(_ carbEntry: NewCarbEntry, replacing replacingEntry: StoredCarbEntry? = nil, completion: @escaping (_ result: Result) -> Void) { + let addCompletion: (CarbStoreResult) -> Void = { (result) in self.dataAccessQueue.async { - if success { + switch result { + case .success: // Remove the active pre-meal target override self.settings.glucoseTargetRangeSchedule?.clearOverride(matching: .preMeal) self.carbEffect = nil self.carbsOnBoard = nil - defer { - self.notify(forChange: .carbs) - } - do { try self.update() @@ -297,18 +436,16 @@ final class LoopDataManager { } catch let error { completion(.failure(error)) } - } else if let error = error { + case .failure(let error): completion(.failure(error)) - } else { - completion(.success(nil)) } } } if let replacingEntry = replacingEntry { - carbStore.replaceCarbEntry(replacingEntry, withEntry: carbEntry, resultHandler: addCompletion) + carbStore.replaceCarbEntry(replacingEntry, withEntry: carbEntry, completion: addCompletion) } else { - carbStore.addCarbEntry(carbEntry, resultHandler: addCompletion) + carbStore.addCarbEntry(carbEntry, completion: addCompletion) } } @@ -376,7 +513,7 @@ final class LoopDataManager { /// - lastValue: The previous new stored value /// - areStoredValuesContinuous: Whether the current recent state of the stored reservoir data is considered continuous and reliable for deriving insulin effects after addition of this new value. func addReservoirValue(_ units: Double, at date: Date, completion: @escaping (_ result: Result<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool)>) -> Void) { - doseStore.addReservoirValue(units, atDate: date) { (newValue, previousValue, areStoredValuesContinuous, error) in + doseStore.addReservoirValue(units, at: date) { (newValue, previousValue, areStoredValuesContinuous, error) in if let error = error { completion(.failure(error)) } else if let newValue = newValue { @@ -387,6 +524,11 @@ final class LoopDataManager { self.lastRequestedBolus = nil } + if let newDoseStartDate = previousValue?.startDate { + // Prune back any counteraction effects for recomputation, after the effect delay + self.insulinCounteractionEffects = self.insulinCounteractionEffects.filterDateRange(nil, newDoseStartDate.addingTimeInterval(.minutes(10))) + } + completion(.success(( newValue: newValue, lastValue: previousValue, @@ -445,15 +587,6 @@ final class LoopDataManager { } } - // References to registered notification center observers - private var carbUpdateObserver: Any? - - deinit { - if let observer = carbUpdateObserver { - NotificationCenter.default.removeObserver(observer) - } - } - /// - Throws: /// - LoopError.configurationError /// - LoopError.glucoseTooOld @@ -466,7 +599,7 @@ final class LoopDataManager { // Fetch glucose effects as far back as we want to make retroactive analysis var latestGlucoseDate: Date? updateGroup.enter() - glucoseStore.getCachedGlucoseValues(start: Date(timeIntervalSinceNow: -recencyInterval)) { (values) in + glucoseStore.getCachedGlucoseSamples(start: Date(timeIntervalSinceNow: -settings.recencyInterval)) { (values) in latestGlucoseDate = values.last?.startDate updateGroup.leave() } @@ -476,7 +609,10 @@ final class LoopDataManager { throw LoopError.missingDataError(details: "Glucose data not available", recovery: "Check your CGM data source") } - let retrospectiveStart = lastGlucoseDate.addingTimeInterval(-glucoseStore.reflectionDataInterval) + let retrospectiveStart = lastGlucoseDate.addingTimeInterval(-settings.retrospectiveCorrectionInterval) + + let earliestEffectDate = Date(timeIntervalSinceNow: .hours(-24)) + let nextEffectDate = insulinCounteractionEffects.last?.endDate ?? earliestEffectDate if retrospectiveGlucoseChange == nil { updateGroup.enter() @@ -486,33 +622,17 @@ final class LoopDataManager { } } - if lastGlucoseChange == nil { - updateGroup.enter() - let start = insulinCounteractionEffects.last?.endDate ?? lastGlucoseDate.addingTimeInterval(.minutes(-5.1)) - - glucoseStore.getGlucoseChange(start: start) { (change) in - self.lastGlucoseChange = change - updateGroup.leave() - } - } - if glucoseMomentumEffect == nil { updateGroup.enter() - glucoseStore.getRecentMomentumEffect { (effects, error) -> Void in - if let error = error, effects.count == 0 { - self.logger.error(error) - self.glucoseMomentumEffect = nil - } else { - self.glucoseMomentumEffect = effects - } - + glucoseStore.getRecentMomentumEffect { (effects) -> Void in + self.glucoseMomentumEffect = effects updateGroup.leave() } } if insulinEffect == nil { updateGroup.enter() - doseStore.getGlucoseEffects(start: retrospectiveStart) { (result) -> Void in + doseStore.getGlucoseEffects(start: min(retrospectiveStart, nextEffectDate)) { (result) -> Void in switch result { case .failure(let error): self.logger.error(error) @@ -527,13 +647,17 @@ final class LoopDataManager { _ = updateGroup.wait(timeout: .distantFuture) - if insulinCounteractionEffects.last == nil || - insulinCounteractionEffects.last!.endDate < lastGlucoseDate { - do { - try updateObservedInsulinCounteractionEffects() - } catch let error { - logger.error(error) + if nextEffectDate < lastGlucoseDate, let insulinEffect = insulinEffect { + updateGroup.enter() + self.logger.debug("Fetching counteraction effects after \(nextEffectDate)") + glucoseStore.getCounteractionEffects(start: nextEffectDate, to: insulinEffect) { (velocities) in + self.insulinCounteractionEffects.append(contentsOf: velocities) + self.insulinCounteractionEffects = self.insulinCounteractionEffects.filterDateRange(earliestEffectDate, nil) + + updateGroup.leave() } + + _ = updateGroup.wait(timeout: .distantFuture) } if carbEffect == nil { @@ -590,17 +714,11 @@ final class LoopDataManager { } private func notify(forChange context: LoopUpdateContext) { - var userInfo: [String: Any] = [ - type(of: self).LoopUpdateContextKey: context.rawValue - ] - - if let lastLoopCompleted = lastLoopCompleted { - userInfo[type(of: self).LastLoopCompletedKey] = lastLoopCompleted - } - NotificationCenter.default.post(name: .LoopDataUpdated, object: self, - userInfo: userInfo + userInfo: [ + type(of: self).LoopUpdateContextKey: context.rawValue + ] ) } @@ -667,9 +785,9 @@ final class LoopDataManager { effects.append(self.retrospectiveGlucoseEffect) } - var prediction = LoopMath.predictGlucose(glucose, momentum: momentum, effects: effects) + var prediction = LoopMath.predictGlucose(startingAt: glucose, momentum: momentum, effects: effects) - // Dosing requires prediction entries at as long as the insulin model duration. + // Dosing requires prediction entries at least as long as the insulin model duration. // If our prediciton is shorter than that, then extend it here. let finalDate = glucose.startDate.addingTimeInterval(model.effectDuration) if let last = prediction.last, last.startDate < finalDate { @@ -679,77 +797,6 @@ final class LoopDataManager { return prediction } - // MARK: - Calculation state - - fileprivate let dataAccessQueue: DispatchQueue = DispatchQueue(label: "com.loudnate.Naterade.LoopDataManager.dataAccessQueue", qos: .utility) - - private var carbEffect: [GlucoseEffect]? { - didSet { - predictedGlucose = nil - - // Carb data may be back-dated, so re-calculate the retrospective glucose. - retrospectivePredictedGlucose = nil - } - } - private var insulinEffect: [GlucoseEffect]? { - didSet { - predictedGlucose = nil - } - } - private var glucoseMomentumEffect: [GlucoseEffect]? { - didSet { - predictedGlucose = nil - } - } - private var retrospectiveGlucoseEffect: [GlucoseEffect] = [] { - didSet { - predictedGlucose = nil - } - } - - /// The change in glucose over the reflection time interval (default is 30 min) - fileprivate var retrospectiveGlucoseChange: GlucoseChange? { - didSet { - retrospectivePredictedGlucose = nil - } - } - /// The change in glucose over the last loop interval (5 min) - fileprivate var lastGlucoseChange: GlucoseChange? - - fileprivate var predictedGlucose: [GlucoseValue]? { - didSet { - recommendedTempBasal = nil - recommendedBolus = nil - } - } - fileprivate var retrospectivePredictedGlucose: [GlucoseValue]? { - didSet { - retrospectiveGlucoseEffect = [] - } - } - fileprivate var recommendedTempBasal: (recommendation: TempBasalRecommendation, date: Date)? - - fileprivate var recommendedBolus: (recommendation: BolusRecommendation, date: Date)? - - fileprivate var carbsOnBoard: CarbValue? - - fileprivate var lastTempBasal: DoseEntry? - fileprivate var lastRequestedBolus: (units: Double, date: Date)? - fileprivate var lastLoopCompleted: Date? { - didSet { - NotificationManager.scheduleLoopNotRunningNotifications() - - AnalyticsManager.shared.loopDidSucceed() - } - } - fileprivate var lastLoopError: Error? { - didSet { - if lastLoopError != nil { - AnalyticsManager.shared.loopDidError() - } - } - } - /** Runs the glucose retrospective analysis using the latest effect data. @@ -774,7 +821,7 @@ final class LoopDataManager { // Run a retrospective prediction over the duration of the recorded glucose change, using the current carb and insulin effects let startDate = change.start.startDate let endDate = change.end.endDate - let retrospectivePrediction = LoopMath.predictGlucose(change.start, effects: + let retrospectivePrediction = LoopMath.predictGlucose(startingAt: change.start, effects: carbEffect.filterDateRange(startDate, endDate), insulinEffect.filterDateRange(startDate, endDate) ) @@ -782,61 +829,15 @@ final class LoopDataManager { self.retrospectivePredictedGlucose = retrospectivePrediction guard let lastGlucose = retrospectivePrediction.last else { return } - let glucoseUnit = HKUnit.milligramsPerDeciliter() + let glucoseUnit = HKUnit.milligramsPerDeciliter let velocityUnit = glucoseUnit.unitDivided(by: HKUnit.second()) let discrepancy = change.end.quantity.doubleValue(for: glucoseUnit) - lastGlucose.quantity.doubleValue(for: glucoseUnit) // mg/dL - let velocity = HKQuantity(unit: velocityUnit, doubleValue: discrepancy / change.end.endDate.timeIntervalSince(change.0.endDate)) + let velocity = HKQuantity(unit: velocityUnit, doubleValue: discrepancy / change.end.endDate.timeIntervalSince(change.start.endDate)) let type = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bloodGlucose)! let glucose = HKQuantitySample(type: type, quantity: change.end.quantity, start: change.end.startDate, end: change.end.endDate) - self.retrospectiveGlucoseEffect = LoopMath.decayEffect(from: glucose, atRate: velocity, for: effectDuration) - } - - /// Measure the effects counteracting insulin observed in the CGM glucose. - /// - /// If you assume insulin is "right", this allows for some validation of carb algorithm settings. - /// - /// - Throws: LoopError.missingDataError if effect data isn't available - private func updateObservedInsulinCounteractionEffects() throws { - dispatchPrecondition(condition: .onQueue(dataAccessQueue)) - - guard - let insulinEffect = self.insulinEffect - else { - throw LoopError.missingDataError(details: "Cannot calculate insulin counteraction due to missing input data", recovery: nil) - } - - guard let change = lastGlucoseChange else { - return // Expected case for calibrations - } - - // Predict glucose change using only insulin effects over the last loop interval - let startDate = change.start.startDate - let endDate = change.end.endDate.addingTimeInterval(TimeInterval(minutes: 5)) - let prediction = LoopMath.predictGlucose(change.start, effects: - insulinEffect.filterDateRange(startDate, endDate) - ) - - // Ensure we're not repeating effects - if let lastEffect = insulinCounteractionEffects.last { - guard startDate >= lastEffect.endDate else { - return - } - } - - // Compare that retrospective, insulin-driven prediction to the actual glucose change to - // calculate the effect of all insulin counteraction - guard let lastGlucose = prediction.last else { return } - let glucoseUnit = HKUnit.milligramsPerDeciliter() - let velocityUnit = glucoseUnit.unitDivided(by: HKUnit.second()) - let discrepancy = change.end.quantity.doubleValue(for: glucoseUnit) - lastGlucose.quantity.doubleValue(for: glucoseUnit) // mg/dL - let averageVelocity = HKQuantity(unit: velocityUnit, doubleValue: discrepancy / change.end.endDate.timeIntervalSince(change.start.endDate)) - let effect = GlucoseEffectVelocity(startDate: startDate, endDate: change.end.startDate, quantity: averageVelocity) - - insulinCounteractionEffects.append(effect) - // For now, only keep the last 24 hours of values - insulinCounteractionEffects = insulinCounteractionEffects.filterDateRange(Date(timeIntervalSinceNow: .hours(-24)), nil) + self.retrospectiveGlucoseEffect = glucose.decayEffect(atRate: velocity, for: effectDuration) } /// Runs the glucose prediction on the latest effect data. @@ -861,19 +862,29 @@ final class LoopDataManager { let startDate = Date() - guard startDate.timeIntervalSince(glucose.startDate) <= recencyInterval else { + guard startDate.timeIntervalSince(glucose.startDate) <= settings.recencyInterval else { self.predictedGlucose = nil throw LoopError.glucoseTooOld(date: glucose.startDate) } - guard startDate.timeIntervalSince(pumpStatusDate) <= recencyInterval else { + guard startDate.timeIntervalSince(pumpStatusDate) <= settings.recencyInterval else { self.predictedGlucose = nil throw LoopError.pumpDataTooOld(date: pumpStatusDate) } - guard glucoseMomentumEffect != nil, carbEffect != nil, insulinEffect != nil else { + guard glucoseMomentumEffect != nil else { + self.predictedGlucose = nil + throw LoopError.missingDataError(details: "Momentum effects", recovery: nil) + } + + guard carbEffect != nil else { + self.predictedGlucose = nil + throw LoopError.missingDataError(details: "Carb effects", recovery: nil) + } + + guard insulinEffect != nil else { self.predictedGlucose = nil - throw LoopError.missingDataError(details: "Glucose effects", recovery: nil) + throw LoopError.missingDataError(details: "Insulin effects", recovery: nil) } let predictedGlucose = try predictGlucose(using: settings.enabledEffects) @@ -917,7 +928,7 @@ final class LoopDataManager { } let pendingInsulin = try self.getPendingInsulin() - + let recommendation = predictedGlucose.recommendedBolus( to: glucoseTargetRange, suspendThreshold: settings.suspendThreshold?.quantity, @@ -943,7 +954,7 @@ final class LoopDataManager { return } - delegate.loopDataManager(self, didRecommendBasalChange: recommendedTempBasal) { (result) in + delegate?.loopDataManager(self, didRecommendBasalChange: recommendedTempBasal) { (result) in self.dataAccessQueue.async { switch result { case .success(let basal): @@ -971,9 +982,6 @@ protocol LoopState { /// A timeline of average velocity of glucose change counteracting predicted insulin effects var insulinCounteractionEffects: [GlucoseEffectVelocity] { get } - /// The last date at which a loop completed, from prediction to dose (if dosing is enabled) - var lastLoopCompleted: Date? { get } - /// The last set temp basal var lastTempBasal: DoseEntry? { get } @@ -1024,11 +1032,6 @@ extension LoopDataManager { return loopDataManager.insulinCounteractionEffects } - var lastLoopCompleted: Date? { - dispatchPrecondition(condition: .onQueue(loopDataManager.dataAccessQueue)) - return loopDataManager.lastLoopCompleted - } - var lastTempBasal: DoseEntry? { dispatchPrecondition(condition: .onQueue(loopDataManager.dataAccessQueue)) return loopDataManager.lastTempBasal @@ -1094,54 +1097,50 @@ extension LoopDataManager { var entries = [ "## LoopDataManager", "settings: \(String(reflecting: manager.settings))", - "insulinCounteractionEffects: \(String(reflecting: manager.insulinCounteractionEffects))", - "predictedGlucose: \(state.predictedGlucose ?? [])", + + "insulinCounteractionEffects: [", + "* GlucoseEffectVelocity(start, end, mg/dL/min)", + manager.insulinCounteractionEffects.reduce(into: "", { (entries, entry) in + entries.append("* \(entry.startDate), \(entry.endDate), \(entry.quantity.doubleValue(for: GlucoseEffectVelocity.unit))\n") + }), + "]", + + "predictedGlucose: [", + "* PredictedGlucoseValue(start, mg/dL)", + (state.predictedGlucose ?? []).reduce(into: "", { (entries, entry) in + entries.append("* \(entry.startDate), \(entry.quantity.doubleValue(for: .milligramsPerDeciliter))\n") + }), + "]", + "retrospectivePredictedGlucose: \(state.retrospectivePredictedGlucose ?? [])", + "glucoseMomentumEffect: \(manager.glucoseMomentumEffect ?? [])", + "retrospectiveGlucoseEffect: \(manager.retrospectiveGlucoseEffect)", "recommendedTempBasal: \(String(describing: state.recommendedTempBasal))", "recommendedBolus: \(String(describing: state.recommendedBolus))", "lastBolus: \(String(describing: manager.lastRequestedBolus))", - "lastGlucoseChange: \(String(describing: manager.lastGlucoseChange))", "retrospectiveGlucoseChange: \(String(describing: manager.retrospectiveGlucoseChange))", - "lastLoopCompleted: \(String(describing: state.lastLoopCompleted))", + "lastLoopCompleted: \(String(describing: manager.lastLoopCompleted))", "lastTempBasal: \(String(describing: state.lastTempBasal))", - "carbsOnBoard: \(String(describing: state.carbsOnBoard))" + "carbsOnBoard: \(String(describing: state.carbsOnBoard))", + "error: \(String(describing: state.error))", + "", + "cacheStore: \(String(reflecting: self.glucoseStore.cacheStore))", + "", ] - var loopError = state.error - - // TODO: this should be moved to doseStore.generateDiagnosticReport - self.doseStore.insulinOnBoard(at: Date()) { (result) in - let insulinOnBoard: InsulinValue? - - switch result { - case .success(let value): - insulinOnBoard = value - case .failure(let error): - insulinOnBoard = nil - - if loopError == nil { - loopError = error - } - } - - entries.append("insulinOnBoard: \(String(describing: insulinOnBoard))") - entries.append("error: \(String(describing: loopError))") + self.glucoseStore.generateDiagnosticReport { (report) in + entries.append(report) entries.append("") - self.glucoseStore.generateDiagnosticReport { (report) in + self.carbStore.generateDiagnosticReport { (report) in entries.append(report) entries.append("") - self.carbStore.generateDiagnosticReport { (report) in + self.doseStore.generateDiagnosticReport { (report) in entries.append(report) entries.append("") - self.doseStore.generateDiagnosticReport { (report) in - entries.append(report) - entries.append("") - - completion(entries.joined(separator: "\n")) - } + completion(entries.joined(separator: "\n")) } } } diff --git a/Loop/Managers/NightscoutDataManager.swift b/Loop/Managers/NightscoutDataManager.swift index a773507f84..bafc50aa5b 100644 --- a/Loop/Managers/NightscoutDataManager.swift +++ b/Loop/Managers/NightscoutDataManager.swift @@ -8,9 +8,7 @@ import Foundation import NightscoutUploadKit -import CarbKit import HealthKit -import InsulinKit import LoopKit import RileyLinkKit import RileyLinkBLEKit diff --git a/Loop/Managers/StatusChartsManager+LoopKit.swift b/Loop/Managers/StatusChartsManager+LoopKit.swift index 507f4941c3..2f54ca31ac 100644 --- a/Loop/Managers/StatusChartsManager+LoopKit.swift +++ b/Loop/Managers/StatusChartsManager+LoopKit.swift @@ -8,9 +8,6 @@ import HealthKit -import CarbKit -import GlucoseKit -import InsulinKit import LoopKit import SwiftCharts import LoopUI @@ -28,7 +25,7 @@ extension StatusChartsManager { // MARK: - Glucose private func glucosePointsFromValues(_ glucoseValues: [GlucoseValue]) -> [ChartPoint] { - let unitString = glucoseUnit.glucoseUnitDisplayString + let unitString = glucoseUnit.localizedShortUnitString let formatter = dateFormatter let glucoseFormatter = NumberFormatter.glucoseFormatter(for: glucoseUnit) @@ -86,7 +83,7 @@ extension StatusChartsManager { for entry in doseEntries { let time = entry.endDate.timeIntervalSince(entry.startDate) - if entry.type == .bolus && entry.units > 0 && time < .minutes(5) { + if entry.type == .bolus && entry.netBasalUnits > 0 && time < .minutes(5) { let x = ChartAxisValueDate(date: entry.startDate, formatter: dateFormatter) let y = ChartAxisValueDoubleLog(actualDouble: entry.units, unitString: "U", formatter: doseFormatter) @@ -98,11 +95,12 @@ extension StatusChartsManager { let startX = ChartAxisValueDate(date: entry.startDate, formatter: dateFormatter) let endX = ChartAxisValueDate(date: entry.endDate, formatter: dateFormatter) let zero = ChartAxisValueInt(0) - let value = ChartAxisValueDoubleLog(actualDouble: entry.unitsPerHour, unitString: "U/hour", formatter: doseFormatter) + let rate = entry.netBasalUnitsPerHour + let value = ChartAxisValueDoubleLog(actualDouble: rate, unitString: "U/hour", formatter: doseFormatter) let valuePoints: [ChartPoint] - if entry.unitsPerHour != 0 { + if abs(rate) > .ulpOfOne { valuePoints = [ ChartPoint(x: startX, y: value), ChartPoint(x: endX, y: value) @@ -191,7 +189,7 @@ extension StatusChartsManager { let dateFormatter = self.dateFormatter let decimalFormatter = self.doseFormatter let unit = glucoseUnit.unitDivided(by: .minute()) - let unitString = String(format: NSLocalizedString("%1$@/min", comment: "Format string describing glucose units per minute (1: glucose unit string)"), glucoseUnit.glucoseUnitDisplayString) + let unitString = String(format: NSLocalizedString("%1$@/min", comment: "Format string describing glucose units per minute (1: glucose unit string)"), glucoseUnit.localizedShortUnitString) var insulinCounteractionEffectPoints: [ChartPoint] = [] var allCarbEffectPoints: [ChartPoint] = [] diff --git a/Loop/Managers/StatusExtensionDataManager.swift b/Loop/Managers/StatusExtensionDataManager.swift index 094b4d98dd..e42cbe5264 100644 --- a/Loop/Managers/StatusExtensionDataManager.swift +++ b/Loop/Managers/StatusExtensionDataManager.swift @@ -8,9 +8,7 @@ import HealthKit import UIKit -import CarbKit import LoopKit -import InsulinKit import LoopUI @@ -32,13 +30,13 @@ final class StatusExtensionDataManager { } @objc private func update(_ notification: Notification) { - self.dataManager.loopManager.glucoseStore.preferredUnit() { (unit, error) in - if error == nil, let unit = unit { - self.createContext(glucoseUnit: unit) { (context) in - if let context = context { - self.defaults?.statusExtensionContext = context - } - } + guard let unit = (dataManager.loopManager.glucoseStore.preferredUnit ?? context?.predictedGlucose?.unit) else { + return + } + + createContext(glucoseUnit: unit) { (context) in + if let context = context { + self.defaults?.statusExtensionContext = context } } } @@ -53,7 +51,6 @@ final class StatusExtensionDataManager { // a fully configured app. Inject some baseline debug data to let us test the // experience. This data will be overwritten by actual data below, if available. context.batteryPercentage = 0.25 - context.reservoir = ReservoirContext(startDate: Date(), unitVolume: 160, capacity: 300) context.netBasal = NetBasalContext( rate: 2.1, percentage: 0.6, @@ -63,7 +60,7 @@ final class StatusExtensionDataManager { ) context.predictedGlucose = PredictedGlucoseContext( values: (1...36).map { 89.123 + Double($0 * 5) }, // 3 hours of linear data - unit: HKUnit.milligramsPerDeciliter(), + unit: HKUnit.milligramsPerDeciliter, startDate: Date(), interval: TimeInterval(minutes: 5)) @@ -74,33 +71,10 @@ final class StatusExtensionDataManager { completionHandler(nil) return } - let lastLoopCompleted = state.lastLoopCompleted + let lastLoopCompleted = manager.lastLoopCompleted #endif - context.loop = LoopContext( - dosingEnabled: manager.settings.dosingEnabled, - lastCompleted: lastLoopCompleted - ) - - let updateGroup = DispatchGroup() - - // We can only access the last 30 minutes of data if the device is locked. - // Cap it there so that we have a consistent view in the widget. - let chartStartDate = Date().addingTimeInterval(TimeInterval(minutes: -30)) - let chartEndDate = Date().addingTimeInterval(TimeInterval(hours: 3)) - - updateGroup.enter() - manager.glucoseStore.getCachedGlucoseValues(start: chartStartDate, end: Date()) { - (values) in - context.glucose = values.map({ - return GlucoseContext( - value: $0.quantity.doubleValue(for: glucoseUnit), - unit: glucoseUnit, - startDate: $0.startDate - ) - }) - updateGroup.leave() - } + context.lastLoopCompleted = lastLoopCompleted // Drop the first element in predictedGlucose because it is the currentGlucose // and will have a different interval to the next element @@ -125,56 +99,10 @@ final class StatusExtensionDataManager { context.netBasal = NetBasalContext(rate: netBasal.rate, percentage: netBasal.percent, start: netBasal.start, end: netBasal.end) } - - if let reservoir = manager.doseStore.lastReservoirValue, - let capacity = dataManager.pumpState?.pumpModel?.reservoirCapacity { - context.reservoir = ReservoirContext( - startDate: reservoir.startDate, - unitVolume: reservoir.unitVolume, - capacity: capacity - ) - } - - updateGroup.enter() - manager.doseStore.insulinOnBoard(at: Date()) {(result) in - // This function completes asynchronously, so below - // is a completion that returns a value after eventual - // function completion. Currently the time of update - // isn't used in the code, but could e.g. check how - // recent it is. - switch result { - case .success(let iobValue): - context.activeInsulin = iobValue.value - case .failure: - context.activeInsulin = nil - } - updateGroup.leave() - } if let batteryPercentage = dataManager.pumpBatteryChargeRemaining { context.batteryPercentage = batteryPercentage } - - if let targetRanges = manager.settings.glucoseTargetRangeSchedule { - context.targetRanges = targetRanges.between(start: chartStartDate, end: chartEndDate) - .map { - return DatedRangeContext( - startDate: $0.startDate, - endDate: $0.endDate, - minValue: $0.value.minValue, - maxValue: $0.value.maxValue - ) - } - - if let override = targetRanges.override { - context.temporaryOverride = DatedRangeContext( - startDate: override.start, - endDate: override.end ?? .distantFuture, - minValue: override.value.minValue, - maxValue: override.value.maxValue - ) - } - } if let sensorInfo = dataManager.sensorInfo { context.sensor = SensorDisplayableContext( @@ -185,9 +113,7 @@ final class StatusExtensionDataManager { ) } - updateGroup.notify(queue: DispatchQueue.global(qos: .background)) { - completionHandler(context) - } + completionHandler(context) } } } diff --git a/Loop/Managers/WatchDataManager.swift b/Loop/Managers/WatchDataManager.swift index a20a326050..646b8c39e6 100644 --- a/Loop/Managers/WatchDataManager.swift +++ b/Loop/Managers/WatchDataManager.swift @@ -9,7 +9,6 @@ import HealthKit import UIKit import WatchConnectivity -import CarbKit import LoopKit @@ -81,7 +80,7 @@ final class WatchDataManager: NSObject, WCSessionDelegate { private var lastComplicationContext: WatchContext? private let minTrendDrift: Double = 20 - private lazy var minTrendUnit = HKUnit.milligramsPerDeciliter() + private lazy var minTrendUnit = HKUnit.milligramsPerDeciliter private func sendWatchContext(_ context: WatchContext) { if let session = watchSession, session.isPaired && session.isWatchAppInstalled { @@ -118,36 +117,34 @@ final class WatchDataManager: NSObject, WCSessionDelegate { let glucose = loopManager.glucoseStore.latestGlucose let reservoir = loopManager.doseStore.lastReservoirValue - loopManager.glucoseStore.preferredUnit { (unit, error) in - loopManager.getLoopState { (manager, state) in - let eventualGlucose = state.predictedGlucose?.last - let context = WatchContext(glucose: glucose, eventualGlucose: eventualGlucose, glucoseUnit: unit) - context.reservoir = reservoir?.unitVolume - - context.loopLastRunDate = state.lastLoopCompleted - context.recommendedBolusDose = state.recommendedBolus?.recommendation.amount - context.maxBolus = manager.settings.maximumBolus - - if let glucoseTargetRangeSchedule = manager.settings.glucoseTargetRangeSchedule { - if let override = glucoseTargetRangeSchedule.override { - context.glucoseRangeScheduleOverride = GlucoseRangeScheduleOverrideUserInfo( - context: override.context.correspondingUserInfoContext, - startDate: override.start, - endDate: override.end - ) - } - - let configuredOverrideContexts = self.deviceDataManager.loopManager.settings.glucoseTargetRangeSchedule?.configuredOverrideContexts ?? [] - let configuredUserInfoOverrideContexts = configuredOverrideContexts.map { $0.correspondingUserInfoContext } - context.configuredOverrideContexts = configuredUserInfoOverrideContexts + loopManager.getLoopState { (manager, state) in + let eventualGlucose = state.predictedGlucose?.last + let context = WatchContext(glucose: glucose, eventualGlucose: eventualGlucose, glucoseUnit: manager.glucoseStore.preferredUnit) + context.reservoir = reservoir?.unitVolume + + context.loopLastRunDate = manager.lastLoopCompleted + context.recommendedBolusDose = state.recommendedBolus?.recommendation.amount + context.maxBolus = manager.settings.maximumBolus + + if let glucoseTargetRangeSchedule = manager.settings.glucoseTargetRangeSchedule { + if let override = glucoseTargetRangeSchedule.override { + context.glucoseRangeScheduleOverride = GlucoseRangeScheduleOverrideUserInfo( + context: override.context.correspondingUserInfoContext, + startDate: override.start, + endDate: override.end + ) } - if let trend = self.deviceDataManager.sensorInfo?.trendType { - context.glucoseTrendRawValue = trend.rawValue - } + let configuredOverrideContexts = self.deviceDataManager.loopManager.settings.glucoseTargetRangeSchedule?.configuredOverrideContexts ?? [] + let configuredUserInfoOverrideContexts = configuredOverrideContexts.map { $0.correspondingUserInfoContext } + context.configuredOverrideContexts = configuredUserInfoOverrideContexts + } - completion(context) + if let trend = self.deviceDataManager.sensorInfo?.trendType { + context.glucoseTrendRawValue = trend.rawValue } + + completion(context) } } diff --git a/Loop/Models/AbsorptionTimeType+CarbKit.swift b/Loop/Models/AbsorptionTimeType+CarbKit.swift index daa056eaa5..92d7f17b2a 100644 --- a/Loop/Models/AbsorptionTimeType+CarbKit.swift +++ b/Loop/Models/AbsorptionTimeType+CarbKit.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import CarbKit +import LoopKit extension AbsorptionTimeType { diff --git a/Loop/Models/BolusRecommendation.swift b/Loop/Models/BolusRecommendation.swift index 8f4fb585bb..74165a6b33 100644 --- a/Loop/Models/BolusRecommendation.swift +++ b/Loop/Models/BolusRecommendation.swift @@ -23,11 +23,11 @@ extension BolusRecommendationNotice { switch self { case .glucoseBelowSuspendThreshold(minGlucose: let minGlucose): let glucoseFormatter = NumberFormatter.glucoseFormatter(for: unit) - let bgStr = glucoseFormatter.describingGlucose(minGlucose.quantity, for: unit)! + let bgStr = glucoseFormatter.string(from: minGlucose.quantity, unit: unit)! return String(format: NSLocalizedString("Predicted glucose of %1$@ is below your suspend threshold setting.", comment: "Notice message when recommending bolus when BG is below the suspend threshold. (1: glucose value)"), bgStr) case .currentGlucoseBelowTarget(glucose: let glucose): let glucoseFormatter = NumberFormatter.glucoseFormatter(for: unit) - let bgStr = glucoseFormatter.describingGlucose(glucose.quantity, for: unit)! + let bgStr = glucoseFormatter.string(from: glucose.quantity, unit: unit)! return String(format: NSLocalizedString("Current glucose of %1$@ is below correction range.", comment: "Message when offering bolus recommendation even though bg is below range. (1: glucose value)"), bgStr) case .predictedGlucoseBelowTarget(minGlucose: let minGlucose): let timeFormatter = DateFormatter() @@ -36,7 +36,7 @@ extension BolusRecommendationNotice { let time = timeFormatter.string(from: minGlucose.startDate) let glucoseFormatter = NumberFormatter.glucoseFormatter(for: unit) - let minBGStr = glucoseFormatter.describingGlucose(minGlucose.quantity, for: unit)! + let minBGStr = glucoseFormatter.string(from: minGlucose.quantity, unit: unit)! return String(format: NSLocalizedString("Predicted glucose at %1$@ is %2$@.", comment: "Message when offering bolus recommendation even though bg is below range and minBG is in future. (1: glucose time)(2: glucose number)"), time, minBGStr) } diff --git a/Loop/Models/GlucoseEffectVelocity.swift b/Loop/Models/GlucoseEffectVelocity.swift index 35b7ba4b0f..9557f2fd50 100644 --- a/Loop/Models/GlucoseEffectVelocity.swift +++ b/Loop/Models/GlucoseEffectVelocity.swift @@ -12,7 +12,7 @@ import LoopKit extension GlucoseEffectVelocity: RawRepresentable { public typealias RawValue = [String: Any] - static let unit = HKUnit.milligramsPerDeciliter().unitDivided(by: .minute()) + static let unit = HKUnit.milligramsPerDeciliter.unitDivided(by: .minute()) public init?(rawValue: RawValue) { guard let startDate = rawValue["startDate"] as? Date, diff --git a/Loop/Models/GlucoseG4.swift b/Loop/Models/GlucoseG4.swift index 52e893d7a7..380ad48c1b 100644 --- a/Loop/Models/GlucoseG4.swift +++ b/Loop/Models/GlucoseG4.swift @@ -15,7 +15,7 @@ import LoopUI extension GlucoseG4: GlucoseValue { public var quantity: HKQuantity { - return HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: Double(glucose)) + return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(glucose)) } public var startDate: Date { diff --git a/Loop/Models/Locked.swift b/Loop/Models/Locked.swift new file mode 100644 index 0000000000..fd6e35b104 --- /dev/null +++ b/Loop/Models/Locked.swift @@ -0,0 +1,40 @@ +// +// Locked.swift +// LoopKit +// +// Copyright © 2018 LoopKit Authors. All rights reserved. +// + +import os.lock + + +internal class Locked { + private var lock = os_unfair_lock() + private var _value: T + + init(_ value: T) { + os_unfair_lock_lock(&lock) + defer { os_unfair_lock_unlock(&lock) } + _value = value + } + + var value: T { + get { + os_unfair_lock_lock(&lock) + defer { os_unfair_lock_unlock(&lock) } + return _value + } + set { + os_unfair_lock_lock(&lock) + defer { os_unfair_lock_unlock(&lock) } + _value = newValue + } + } + + func mutate(_ changes: (_ value: inout T) -> Void) -> T { + os_unfair_lock_lock(&lock) + defer { os_unfair_lock_unlock(&lock) } + changes(&_value) + return _value + } +} diff --git a/Loop/Models/LoopSettings+Loop.swift b/Loop/Models/LoopSettings+Loop.swift new file mode 100644 index 0000000000..3f00feb5b3 --- /dev/null +++ b/Loop/Models/LoopSettings+Loop.swift @@ -0,0 +1,25 @@ +// +// LoopSettings+Loop.swift +// Loop +// +// Copyright © 2018 LoopKit Authors. All rights reserved. +// + +import RileyLinkBLEKit + + +// MARK: - Static configuration +extension LoopSettings { + static let idleListeningEnabledDefaults: RileyLinkDevice.IdleListeningState = .enabled(timeout: .minutes(4), channel: 0) +} + + +extension LoopSettings { + var enabledEffects: PredictionInputEffect { + var inputs = PredictionInputEffect.all + if !retrospectiveCorrectionEnabled { + inputs.remove(.retrospection) + } + return inputs + } +} diff --git a/Loop/Models/MySentryPumpStatusMessageBody.swift b/Loop/Models/MySentryPumpStatusMessageBody.swift index 3378af7829..e2d4830fdf 100644 --- a/Loop/Models/MySentryPumpStatusMessageBody.swift +++ b/Loop/Models/MySentryPumpStatusMessageBody.swift @@ -47,4 +47,19 @@ extension MySentryPumpStatusMessageBody: SensorDisplayable { var batteryPercentage: Int { return batteryRemainingPercent } + + var glucoseSyncIdentifier: String? { + guard let date = glucoseDateComponents, + let year = date.year, + let month = date.month, + let day = date.day, + let hour = date.hour, + let minute = date.minute, + let second = date.second + else { + return nil + } + + return "\(year)-\(month)-\(day) \(hour)-\(minute)-\(second)" + } } diff --git a/Loop/Models/NetBasal.swift b/Loop/Models/NetBasal.swift index eb68ecbd91..5070ee8325 100644 --- a/Loop/Models/NetBasal.swift +++ b/Loop/Models/NetBasal.swift @@ -7,9 +7,9 @@ // import Foundation -import InsulinKit import LoopKit + struct NetBasal { let rate: Double let percent: Double diff --git a/Loop/Models/PredictionInputEffect.swift b/Loop/Models/PredictionInputEffect.swift index 9aabe0d918..84900fec02 100644 --- a/Loop/Models/PredictionInputEffect.swift +++ b/Loop/Models/PredictionInputEffect.swift @@ -38,9 +38,9 @@ struct PredictionInputEffect: OptionSet { func localizedDescription(forGlucoseUnit unit: HKUnit) -> String? { switch self { case [.carbs]: - return String(format: NSLocalizedString("Carbs Absorbed (g) ÷ Carb Ratio (g/U) × Insulin Sensitivity (%1$@/U)", comment: "Description of the prediction input effect for carbohydrates. (1: The glucose unit string)"), unit.glucoseUnitDisplayString) + return String(format: NSLocalizedString("Carbs Absorbed (g) ÷ Carb Ratio (g/U) × Insulin Sensitivity (%1$@/U)", comment: "Description of the prediction input effect for carbohydrates. (1: The glucose unit string)"), unit.localizedShortUnitString) case [.insulin]: - return String(format: NSLocalizedString("Insulin Absorbed (U) × Insulin Sensitivity (%1$@/U)", comment: "Description of the prediction input effect for insulin"), unit.glucoseUnitDisplayString) + return String(format: NSLocalizedString("Insulin Absorbed (U) × Insulin Sensitivity (%1$@/U)", comment: "Description of the prediction input effect for insulin"), unit.localizedShortUnitString) case [.momentum]: return NSLocalizedString("15 min glucose regression coefficient (b₁), continued with decay over 30 min", comment: "Description of the prediction input effect for glucose momentum") case [.retrospection]: diff --git a/Loop/Models/ShareGlucose+GlucoseKit.swift b/Loop/Models/ShareGlucose+GlucoseKit.swift index 8b1e46294c..51e7508c2d 100644 --- a/Loop/Models/ShareGlucose+GlucoseKit.swift +++ b/Loop/Models/ShareGlucose+GlucoseKit.swift @@ -19,7 +19,7 @@ extension ShareGlucose: GlucoseValue { } public var quantity: HKQuantity { - return HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: Double(glucose)) + return HKQuantity(unit: .milligramsPerDeciliter, doubleValue: Double(glucose)) } } diff --git a/Loop/Models/StatusExtensionContext+LoopKit.swift b/Loop/Models/StatusExtensionContext+LoopKit.swift index d1601c1cdb..da4ea68887 100644 --- a/Loop/Models/StatusExtensionContext+LoopKit.swift +++ b/Loop/Models/StatusExtensionContext+LoopKit.swift @@ -5,7 +5,8 @@ // Copyright © 2017 LoopKit Authors. All rights reserved. // -import InsulinKit +import LoopKit + extension NetBasalContext { var tempBasal: DoseEntry? { diff --git a/Loop/Models/TransmitterGlucose.swift b/Loop/Models/TransmitterGlucose.swift deleted file mode 100644 index 7985c3b9b8..0000000000 --- a/Loop/Models/TransmitterGlucose.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// TransmitterGlucose.swift -// Loop -// -// Created by Nathan Racklyeft on 5/30/16. -// Copyright © 2016 Nathan Racklyeft. All rights reserved. -// - -import LoopKit -import HealthKit -import xDripG5 - - -struct TransmitterGlucose: GlucoseValue { - let glucoseMessage: GlucoseRxMessage - let startTime: NSTimeInterval - - init?(glucoseMessage: GlucoseRxMessage, startTime: NSTimeInterval?) { - - guard glucoseMessage.state > 5 && glucoseMessage.glucose >= 20, let startTime = startTime else { - return nil - } - - self.glucoseMessage = glucoseMessage - self.startTime = startTime - } - - var quantity: HKQuantity { - return HKQuantity(unit: HKUnit.milligramsPerDeciliterUnit(), doubleValue: Double(glucoseMessage.glucose)) - } - - var startDate: NSDate { - return NSDate(timeIntervalSince1970: startTime).dateByAddingTimeInterval(NSTimeInterval(glucoseMessage.timestamp)) - } -} diff --git a/Loop/Models/WatchContext+LoopKit.swift b/Loop/Models/WatchContext+LoopKit.swift index bf6ac5b603..24a67c6854 100644 --- a/Loop/Models/WatchContext+LoopKit.swift +++ b/Loop/Models/WatchContext+LoopKit.swift @@ -8,7 +8,6 @@ import Foundation import HealthKit -import InsulinKit import LoopKit extension WatchContext { diff --git a/Loop/View Controllers/AuthenticationViewController.swift b/Loop/View Controllers/AuthenticationViewController.swift index 3ebbc04508..f278b2f3d9 100644 --- a/Loop/View Controllers/AuthenticationViewController.swift +++ b/Loop/View Controllers/AuthenticationViewController.swift @@ -30,7 +30,7 @@ final class AuthenticationViewController: UITableViewC }) tableView.reloadSections(IndexSet(integersIn: 0...1), with: .automatic) - authentication.verify { [unowned self] (success, error) in + authentication.verify { (success, error) in DispatchQueue.main.async { UIView.animate(withDuration: 0.25, animations: { self.navigationItem.titleView = nil diff --git a/Loop/View Controllers/BolusViewController.swift b/Loop/View Controllers/BolusViewController.swift index 58d01a89c2..1d74917dd8 100644 --- a/Loop/View Controllers/BolusViewController.swift +++ b/Loop/View Controllers/BolusViewController.swift @@ -35,7 +35,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex spellOutFormatter.numberStyle = .spellOut let amount = bolusRecommendation?.amount ?? 0 - bolusAmountTextField.accessibilityHint = String(format: NSLocalizedString("Recommended Bolus: %@ Units", comment: "Accessibility hint describing recommended bolus units"), spellOutFormatter.string(from: NSNumber(value: amount)) ?? "0") + bolusAmountTextField.accessibilityHint = String(format: NSLocalizedString("Recommended Bolus: %@ Units", comment: "Accessibility hint describing recommended bolus units"), spellOutFormatter.string(from: amount) ?? "0") bolusAmountTextField.becomeFirstResponder() @@ -45,7 +45,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex func generateActiveInsulinDescription(activeInsulin: Double?, pendingInsulin: Double?) -> String { let iobStr: String - if let iob = activeInsulin, let valueStr = insulinFormatter.string(from: NSNumber(value: iob)) + if let iob = activeInsulin, let valueStr = insulinFormatter.string(from: iob) { iobStr = valueStr + " U" } else { @@ -54,7 +54,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex var rval = String(format: NSLocalizedString("Active Insulin: %@", comment: "The string format describing active insulin. (1: localized insulin value description)"), iobStr) - if let pending = pendingInsulin, pending > 0, let pendingStr = insulinFormatter.string(from: NSNumber(value: pending)) + if let pending = pendingInsulin, pending > 0, let pendingStr = insulinFormatter.string(from: pending) { rval += String(format: NSLocalizedString(" (pending: %@)", comment: "The string format appended to active insulin that describes pending insulin. (1: pending insulin)"), pendingStr + " U") } @@ -63,7 +63,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex // MARK: - State - var glucoseUnit: HKUnit = HKUnit.milligramsPerDeciliter() + var glucoseUnit: HKUnit = .milligramsPerDeciliter var bolusRecommendation: BolusRecommendation? = nil { didSet { @@ -86,7 +86,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex didSet { let cobStr: String - if let cob = activeCarbohydrates, let str = integerFormatter.string(from: NSNumber(value: cob)) { + if let cob = activeCarbohydrates, let str = integerFormatter.string(from: cob) { cobStr = str + " g" } else { cobStr = "-" @@ -125,7 +125,7 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex @IBOutlet weak var recommendedBolusAmountLabel: UILabel? { didSet { let amount = bolusRecommendation?.amount ?? 0 - recommendedBolusAmountLabel?.text = bolusUnitsFormatter.string(from: NSNumber(value: amount)) + recommendedBolusAmountLabel?.text = bolusUnitsFormatter.string(from: amount) } } @@ -177,12 +177,12 @@ final class BolusViewController: UITableViewController, IdentifiableClass, UITex bolusAmountTextField.resignFirstResponder() guard let text = bolusAmountTextField?.text, let bolus = bolusUnitsFormatter.number(from: text)?.doubleValue, - let amountString = bolusUnitsFormatter.string(from: NSNumber(value: bolus)) else { + let amountString = bolusUnitsFormatter.string(from: bolus) else { return } guard bolus <= maxBolus else { - presentAlertController(withTitle: NSLocalizedString("Exceeds Maximum Bolus", comment: "The title of the alert describing a maximum bolus validation error"), message: String(format: NSLocalizedString("The maximum bolus amount is %@ Units", comment: "Body of the alert describing a maximum bolus validation error. (1: The localized max bolus value)"), bolusUnitsFormatter.string(from: NSNumber(value: maxBolus)) ?? "")) + presentAlertController(withTitle: NSLocalizedString("Exceeds Maximum Bolus", comment: "The title of the alert describing a maximum bolus validation error"), message: String(format: NSLocalizedString("The maximum bolus amount is %@ Units", comment: "Body of the alert describing a maximum bolus validation error. (1: The localized max bolus value)"), bolusUnitsFormatter.string(from: maxBolus) ?? "")) return } diff --git a/Loop/View Controllers/CarbAbsorptionViewController.swift b/Loop/View Controllers/CarbAbsorptionViewController.swift index 6178a26104..985f040270 100644 --- a/Loop/View Controllers/CarbAbsorptionViewController.swift +++ b/Loop/View Controllers/CarbAbsorptionViewController.swift @@ -8,8 +8,8 @@ import UIKit import HealthKit -import CarbKit import LoopKit +import LoopKitUI import LoopUI @@ -24,29 +24,29 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl super.viewDidLoad() charts.glucoseDisplayRange = ( - min: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 100), - max: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 175) + min: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 100), + max: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 175) ) let notificationCenter = NotificationCenter.default notificationObservers += [ - notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [unowned self] note in + notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [weak self] note in let context = note.userInfo?[LoopDataManager.LoopUpdateContextKey] as! LoopDataManager.LoopUpdateContext.RawValue DispatchQueue.main.async { switch LoopDataManager.LoopUpdateContext(rawValue: context) { case .preferences?: - self.refreshContext.update(with: .targets) + self?.refreshContext.update(with: .targets) case .carbs?: - self.refreshContext.formUnion([.carbs, .glucose]) + self?.refreshContext.formUnion([.carbs, .glucose]) case .glucose?: - self.refreshContext.update(with: .glucose) + self?.refreshContext.update(with: .glucose) default: break } - self.refreshContext.update(with: .status) - self.reloadData(animated: true) + self?.refreshContext.update(with: .status) + self?.reloadData(animated: true) } } ] @@ -82,7 +82,7 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl private var reloading = false - private var carbStatuses: [CarbStatus] = [] + private var carbStatuses: [CarbStatus] = [] private var carbsOnBoard: CarbValue? @@ -121,80 +121,67 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl let shouldUpdateCarbs = currentContext.contains(.carbs) var carbEffects: [GlucoseEffect]? - var carbStatuses: [CarbStatus]? + var carbStatuses: [CarbStatus]? var carbsOnBoard: CarbValue? var carbTotal: CarbValue? + // TODO: Don't always assume currentContext.contains(.status) reloadGroup.enter() - deviceManager.loopManager.glucoseStore.preferredUnit { (unit, error) in - if let unit = unit { - self.charts.glucoseUnit = unit - } - - // TODO: Don't always assume currentContext.contains(.status) - reloadGroup.enter() - self.deviceManager.loopManager.getLoopState { (manager, state) in - if shouldUpdateGlucose || shouldUpdateCarbs { - let insulinCounteractionEffects = state.insulinCounteractionEffects - self.charts.setInsulinCounteractionEffects(state.insulinCounteractionEffects.filterDateRange(chartStartDate, nil)) - - reloadGroup.enter() - manager.carbStore.getCarbStatus(start: listStart, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? insulinCounteractionEffects : nil) { (result) in - switch result { - case .success(let status): - carbStatuses = status - carbsOnBoard = status.clampedCarbsOnBoard - case .failure(let error): - self.deviceManager.logger.addError(error, fromSource: "CarbStore") - retryContext.update(with: .carbs) - } + self.deviceManager.loopManager.getLoopState { (manager, state) in + if shouldUpdateGlucose || shouldUpdateCarbs { + let insulinCounteractionEffects = state.insulinCounteractionEffects + self.charts.setInsulinCounteractionEffects(state.insulinCounteractionEffects.filterDateRange(chartStartDate, nil)) - reloadGroup.leave() - } - - reloadGroup.enter() - manager.carbStore.getGlucoseEffects(start: chartStartDate, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? insulinCounteractionEffects : nil) { (result) in - switch result { - case .success(let effects): - carbEffects = effects - case .failure(let error): - carbEffects = [] - self.deviceManager.logger.addError(error, fromSource: "CarbStore") - retryContext.update(with: .carbs) - } - reloadGroup.leave() + reloadGroup.enter() + manager.carbStore.getCarbStatus(start: listStart, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? insulinCounteractionEffects : nil) { (result) in + switch result { + case .success(let status): + carbStatuses = status + carbsOnBoard = status.getClampedCarbsOnBoard() + case .failure(let error): + self.deviceManager.logger.addError(error, fromSource: "CarbStore") + retryContext.update(with: .carbs) } - } - if currentContext.contains(.targets) { - if let schedule = manager.settings.glucoseTargetRangeSchedule { - self.charts.targetPointsCalculator = GlucoseRangeScheduleCalculator(schedule) - } else { - self.charts.targetPointsCalculator = nil - } + reloadGroup.leave() } - reloadGroup.leave() - } - - if shouldUpdateCarbs { reloadGroup.enter() - self.deviceManager.loopManager.carbStore.getTotalCarbs(since: midnight) { (result) in + manager.carbStore.getGlucoseEffects(start: chartStartDate, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? insulinCounteractionEffects : nil) { (result) in switch result { - case .success(let total): - carbTotal = total + case .success(let effects): + carbEffects = effects case .failure(let error): + carbEffects = [] self.deviceManager.logger.addError(error, fromSource: "CarbStore") retryContext.update(with: .carbs) } - reloadGroup.leave() } } + if currentContext.contains(.targets) { + self.charts.targetGlucoseSchedule = manager.settings.glucoseTargetRangeSchedule + } + reloadGroup.leave() } + if shouldUpdateCarbs { + reloadGroup.enter() + self.deviceManager.loopManager.carbStore.getTotalCarbs(since: midnight) { (result) in + switch result { + case .success(let total): + carbTotal = total + case .failure(let error): + self.deviceManager.logger.addError(error, fromSource: "CarbStore") + retryContext.update(with: .carbs) + } + + reloadGroup.leave() + } + } + reloadGroup.notify(queue: .main) { if let carbEffects = carbEffects { self.charts.setCarbEffects(carbEffects) @@ -294,8 +281,8 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl switch ChartRow(rawValue: indexPath.row)! { case .carbEffect: - cell.chartContentView.chartGenerator = { [unowned self] (frame) in - return self.charts.carbEffectChartWithFrame(frame)?.view + cell.chartContentView.chartGenerator = { [weak self] (frame) in + return self?.charts.carbEffectChartWithFrame(frame)?.view } } @@ -393,7 +380,7 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl format: NSLocalizedString("at %@", comment: "Format fragment for a specific time"), timeFormatter.string(from: carbsOnBoard.startDate) ) - cell.COBValueLabel.text = carbFormatter.string(from: NSNumber(value: carbsOnBoard.quantity.doubleValue(for: unit))) + cell.COBValueLabel.text = carbFormatter.string(from: carbsOnBoard.quantity.doubleValue(for: unit)) // Warn the user if the carbsOnBoard value isn't recent let textColor: UIColor @@ -409,7 +396,7 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl cell.COBDateLabel.textColor = textColor } else { cell.COBDateLabel.text = nil - cell.COBValueLabel.text = carbFormatter.string(from: NSNumber(value: 0)) + cell.COBValueLabel.text = carbFormatter.string(from: 0.0) } if let carbTotal = carbTotal { @@ -417,10 +404,10 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl format: NSLocalizedString("since %@", comment: "Format fragment for a start time"), timeFormatter.string(from: carbTotal.startDate) ) - cell.totalValueLabel.text = carbFormatter.string(from: NSNumber(value: carbTotal.quantity.doubleValue(for: unit))) + cell.totalValueLabel.text = carbFormatter.string(from: carbTotal.quantity.doubleValue(for: unit)) } else { cell.totalDateLabel.text = nil - cell.totalValueLabel.text = carbFormatter.string(from: NSNumber(value: 0)) + cell.totalValueLabel.text = carbFormatter.string(from: 0.0) } } @@ -436,12 +423,13 @@ final class CarbAbsorptionViewController: ChartsTableViewController, Identifiabl public override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let status = carbStatuses[indexPath.row] - deviceManager.loopManager.carbStore.deleteCarbEntry(status.entry) { (success, error) -> Void in + deviceManager.loopManager.carbStore.deleteCarbEntry(status.entry) { (result) -> Void in DispatchQueue.main.async { - if success { - // TODO: CarbStore doesn't automatically post this for deletes - NotificationCenter.default.post(name: .CarbEntriesDidUpdate, object: self) - } else if let error = error { + switch result { + case .success: + self.isEditing = false + break // Notification will trigger update + case .failure(let error): self.refreshContext.update(with: .carbs) self.presentAlertController(with: error) } diff --git a/Loop/View Controllers/CarbEntryEditTableViewController.swift b/Loop/View Controllers/CarbEntryEditTableViewController.swift index 195d940ccb..742ca766ba 100644 --- a/Loop/View Controllers/CarbEntryEditTableViewController.swift +++ b/Loop/View Controllers/CarbEntryEditTableViewController.swift @@ -6,8 +6,8 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import CarbKit +import LoopKitUI extension CarbEntryEditViewController: IdentifiableClass { -} \ No newline at end of file +} diff --git a/Loop/View Controllers/CarbEntryTableViewController.swift b/Loop/View Controllers/CarbEntryTableViewController.swift index 91a275fc37..d2c6698bf9 100644 --- a/Loop/View Controllers/CarbEntryTableViewController.swift +++ b/Loop/View Controllers/CarbEntryTableViewController.swift @@ -6,8 +6,8 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import CarbKit +import LoopKitUI extension CarbEntryTableViewController: IdentifiableClass { -} \ No newline at end of file +} diff --git a/Loop/View Controllers/ChartsTableViewController.swift b/Loop/View Controllers/ChartsTableViewController.swift index ed177810d3..b35cdbab24 100644 --- a/Loop/View Controllers/ChartsTableViewController.swift +++ b/Loop/View Controllers/ChartsTableViewController.swift @@ -7,6 +7,8 @@ import UIKit import LoopUI +import HealthKit +import os.log enum RefreshContext { @@ -73,16 +75,18 @@ extension Set where Element == RefreshContext { /// Abstract class providing boilerplate setup for chart-based table view controllers class ChartsTableViewController: UITableViewController, UIGestureRecognizerDelegate { + private let log = OSLog(category: "ChartsTableViewController") + override func viewDidLoad() { super.viewDidLoad() let notificationCenter = NotificationCenter.default notificationObservers += [ - notificationCenter.addObserver(forName: .UIApplicationWillResignActive, object: UIApplication.shared, queue: .main) { [unowned self] _ in - self.active = false + notificationCenter.addObserver(forName: .UIApplicationWillResignActive, object: UIApplication.shared, queue: .main) { [weak self] _ in + self?.active = false }, - notificationCenter.addObserver(forName: .UIApplicationDidBecomeActive, object: UIApplication.shared, queue: .main) { [unowned self] _ in - self.active = true + notificationCenter.addObserver(forName: .UIApplicationDidBecomeActive, object: UIApplication.shared, queue: .main) { [weak self] _ in + self?.active = true } ] @@ -116,6 +120,7 @@ class ChartsTableViewController: UITableViewController, UIGestureRecognizerDeleg override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) + log.debug("[reloadData] for view transition to size: %@", String(describing: size)) reloadData(animated: false) } @@ -127,21 +132,40 @@ class ChartsTableViewController: UITableViewController, UIGestureRecognizerDeleg // MARK: - State - weak var deviceManager: DeviceDataManager! + weak var deviceManager: DeviceDataManager! { + didSet { + NotificationCenter.default.addObserver(self, selector: #selector(unitPreferencesDidChange(_:)), name: .HKUserPreferencesDidChange, object: deviceManager.loopManager.glucoseStore.healthStore) + } + } + + @objc func unitPreferencesDidChange(_ note: Notification) { + DispatchQueue.main.async { + if let unit = self.deviceManager.loopManager.glucoseStore.preferredUnit { + self.charts.glucoseUnit = unit + } + self.log.debug("[reloadData] for HealthKit unit preference change") + self.reloadData() + } + } var charts = StatusChartsManager(colors: .default, settings: .default) // References to registered notification center observers var notificationObservers: [Any] = [] - var active = true { - didSet { + var active: Bool { + get { + return UIApplication.shared.applicationState == .active + } + set { + log.debug("[reloadData] for app change to active: %d", active) reloadData() } } var visible = false { didSet { + log.debug("[reloadData] for view change to visible: %d", visible) reloadData() } } diff --git a/Loop/View Controllers/CommandResponseViewController.swift b/Loop/View Controllers/CommandResponseViewController.swift index 5fe9ba345b..034d6f76a8 100644 --- a/Loop/View Controllers/CommandResponseViewController.swift +++ b/Loop/View Controllers/CommandResponseViewController.swift @@ -7,17 +7,18 @@ // import Foundation -import LoopKit +import LoopKitUI extension CommandResponseViewController { static func generateDiagnosticReport(dataManager: DeviceDataManager) -> CommandResponseViewController { + let date = Date() let vc = CommandResponseViewController(command: { (completionHandler) in dataManager.loopManager.generateDiagnosticReport { (report) in DispatchQueue.main.async { completionHandler([ "Use the Share button above save this diagnostic report to aid investigating your problem. Issues can be filed at https://github.com/LoopKit/Loop/issues.", - "Generated: \(Date())", + "Generated: \(date)", "", String(reflecting: dataManager), "", @@ -29,6 +30,7 @@ extension CommandResponseViewController { return NSLocalizedString("Loading...", comment: "The loading message for the diagnostic report screen") }) + vc.fileName = "Loop Report \(ISO8601DateFormatter.string(from: date, timeZone: .current, formatOptions: [.withSpaceBetweenDateAndTime, .withInternetDateTime])).md" return vc } diff --git a/Loop/View Controllers/GlucoseThresholdTableViewController.swift b/Loop/View Controllers/GlucoseThresholdTableViewController.swift index 8cbefca243..c6bc294020 100644 --- a/Loop/View Controllers/GlucoseThresholdTableViewController.swift +++ b/Loop/View Controllers/GlucoseThresholdTableViewController.swift @@ -9,7 +9,7 @@ import Foundation import UIKit -import LoopKit +import LoopKitUI import HealthKit @@ -26,10 +26,10 @@ final class GlucoseThresholdTableViewController: TextFieldTableViewController { keyboardType = .decimalPad contextHelp = NSLocalizedString("When current or forecasted glucose is below the suspend threshold, Loop will not recommend a bolus, and will always recommend a temporary basal rate of 0 units per hour.", comment: "Explanation of suspend threshold") - unit = glucoseUnit.glucoseUnitDisplayString + unit = glucoseUnit.localizedShortUnitString if let threshold = threshold { - value = NumberFormatter.glucoseFormatter(for: glucoseUnit).string(from: NSNumber(value: threshold)) + value = NumberFormatter.glucoseFormatter(for: glucoseUnit).string(from: threshold) } } diff --git a/Loop/View Controllers/InsulinDeliveryTableViewController.swift b/Loop/View Controllers/InsulinDeliveryTableViewController.swift index 34b196fd07..4bd534e042 100644 --- a/Loop/View Controllers/InsulinDeliveryTableViewController.swift +++ b/Loop/View Controllers/InsulinDeliveryTableViewController.swift @@ -6,8 +6,8 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import InsulinKit +import LoopKitUI extension InsulinDeliveryTableViewController: IdentifiableClass { -} \ No newline at end of file +} diff --git a/Loop/View Controllers/InsulinModelSettingsViewController.swift b/Loop/View Controllers/InsulinModelSettingsViewController.swift index ffe4256c0c..af4119240c 100644 --- a/Loop/View Controllers/InsulinModelSettingsViewController.swift +++ b/Loop/View Controllers/InsulinModelSettingsViewController.swift @@ -7,7 +7,6 @@ import UIKit import HealthKit -import InsulinKit import LoopKit @@ -49,7 +48,7 @@ class InsulinModelSettingsViewController: ChartsTableViewController, Identifiabl } /// The sensitivity (in glucose units) to use for demonstrating the model - var insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: .milligramsPerDeciliter(), dailyItems: [RepeatingScheduleValue(startTime: 0, value: 40)])! + var insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: .milligramsPerDeciliter, dailyItems: [RepeatingScheduleValue(startTime: 0, value: 40)])! fileprivate let walshModelIndex = 0 @@ -162,7 +161,7 @@ class InsulinModelSettingsViewController: ChartsTableViewController, Identifiabl for (index, model) in allModels.enumerated() { let effects = [bolus].glucoseEffects(insulinModel: model, insulinSensitivity: insulinSensitivitySchedule) - let values = LoopMath.predictGlucose(startingGlucoseSample, effects: effects) + let values = LoopMath.predictGlucose(startingAt: startingGlucoseSample, effects: effects) if selectedModelIndex == index { charts.setSelectedInsulinModelValues(values) diff --git a/Loop/View Controllers/PredictionTableViewController.swift b/Loop/View Controllers/PredictionTableViewController.swift index d8d4ab2904..3c1c125588 100644 --- a/Loop/View Controllers/PredictionTableViewController.swift +++ b/Loop/View Controllers/PredictionTableViewController.swift @@ -26,26 +26,26 @@ class PredictionTableViewController: ChartsTableViewController, IdentifiableClas tableView.cellLayoutMarginsFollowReadableWidth = true charts.glucoseDisplayRange = ( - min: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 60), - max: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 200) + min: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 60), + max: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 200) ) let notificationCenter = NotificationCenter.default notificationObservers += [ - notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [unowned self] note in + notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [weak self] note in let context = note.userInfo?[LoopDataManager.LoopUpdateContextKey] as! LoopDataManager.LoopUpdateContext.RawValue DispatchQueue.main.async { switch LoopDataManager.LoopUpdateContext(rawValue: context) { case .preferences?: - self.refreshContext.formUnion([.status, .targets]) + self?.refreshContext.formUnion([.status, .targets]) case .glucose?: - self.refreshContext.update(with: .glucose) + self?.refreshContext.update(with: .glucose) default: break } - self.reloadData(animated: true) + self?.reloadData(animated: true) } } ] @@ -95,65 +95,49 @@ class PredictionTableViewController: ChartsTableViewController, IdentifiableClas chartStartDate = calendar.nextDate(after: date, matching: components, matchingPolicy: .strict, direction: .backward) ?? date let reloadGroup = DispatchGroup() + var glucoseValues: [StoredGlucoseSample]? - reloadGroup.enter() - deviceManager.loopManager.glucoseStore.preferredUnit { (unit, error) in - if let unit = unit { - self.charts.glucoseUnit = unit + if self.refreshContext.remove(.glucose) != nil { + reloadGroup.enter() + self.deviceManager.loopManager.glucoseStore.getCachedGlucoseSamples(start: self.chartStartDate) { (values) -> Void in + glucoseValues = values + reloadGroup.leave() } + } - if self.refreshContext.remove(.glucose) != nil { - reloadGroup.enter() - self.deviceManager.loopManager.glucoseStore.getGlucoseValues(start: self.chartStartDate) { (result) -> Void in - switch result { - case .failure(let error): - self.deviceManager.logger.addError(error, fromSource: "GlucoseStore") - self.refreshContext.update(with: .glucose) - self.charts.setGlucoseValues([]) - case .success(let values): - self.charts.setGlucoseValues(values) - } - - reloadGroup.leave() - } + // For now, do this every time + _ = self.refreshContext.remove(.status) + reloadGroup.enter() + self.deviceManager.loopManager.getLoopState { (manager, state) in + self.retrospectivePredictedGlucose = state.retrospectivePredictedGlucose + self.charts.setPredictedGlucoseValues(state.predictedGlucose ?? []) + + do { + let glucose = try state.predictGlucose(using: self.selectedInputs) + self.charts.setAlternatePredictedGlucoseValues(glucose) + } catch { + self.refreshContext.update(with: .status) + self.charts.setAlternatePredictedGlucoseValues([]) } - // For now, do this every time - _ = self.refreshContext.remove(.status) - reloadGroup.enter() - self.deviceManager.loopManager.getLoopState { (manager, state) in - self.retrospectivePredictedGlucose = state.retrospectivePredictedGlucose - self.charts.setPredictedGlucoseValues(state.predictedGlucose ?? []) - - do { - let glucose = try state.predictGlucose(using: self.selectedInputs) - self.charts.setAlternatePredictedGlucoseValues(glucose) - } catch { - self.refreshContext.update(with: .status) - self.charts.setAlternatePredictedGlucoseValues([]) - } - - if let lastPoint = self.charts.alternatePredictedGlucosePoints?.last?.y { - self.eventualGlucoseDescription = String(describing: lastPoint) - } else { - self.eventualGlucoseDescription = nil - } - - if self.refreshContext.remove(.targets) != nil { - if let schedule = manager.settings.glucoseTargetRangeSchedule { - self.charts.targetPointsCalculator = GlucoseRangeScheduleCalculator(schedule) - } else { - self.charts.targetPointsCalculator = nil - } - } + if let lastPoint = self.charts.alternatePredictedGlucosePoints?.last?.y { + self.eventualGlucoseDescription = String(describing: lastPoint) + } else { + self.eventualGlucoseDescription = nil + } - reloadGroup.leave() + if self.refreshContext.remove(.targets) != nil { + self.charts.targetGlucoseSchedule = manager.settings.glucoseTargetRangeSchedule } reloadGroup.leave() } reloadGroup.notify(queue: .main) { + if let glucoseValues = glucoseValues { + self.charts.setGlucoseValues(glucoseValues) + } + self.charts.prerender() self.tableView.beginUpdates() @@ -273,7 +257,7 @@ class PredictionTableViewController: ChartsTableViewController, IdentifiableClas let currentGlucose = self.deviceManager.loopManager.glucoseStore.latestGlucose { let formatter = NumberFormatter.glucoseFormatter(for: charts.glucoseUnit) - let values = [startGlucose, endGlucose, currentGlucose].map { formatter.string(from: NSNumber(value: $0.quantity.doubleValue(for: charts.glucoseUnit))) ?? "?" } + let values = [startGlucose, endGlucose, currentGlucose].map { formatter.string(from: $0.quantity.doubleValue(for: charts.glucoseUnit)) ?? "?" } let retro = String( format: NSLocalizedString("Last comparison: %1$@ → %2$@ vs %3$@", comment: "Format string describing retrospective glucose prediction comparison. (1: Previous glucose)(2: Predicted glucose)(3: Actual glucose)"), diff --git a/Loop/View Controllers/PumpIDTableViewController.swift b/Loop/View Controllers/PumpIDTableViewController.swift index 26425795d5..908b5aecc3 100644 --- a/Loop/View Controllers/PumpIDTableViewController.swift +++ b/Loop/View Controllers/PumpIDTableViewController.swift @@ -8,7 +8,8 @@ import UIKit import MinimedKit -import LoopKit +import LoopKitUI + protocol PumpIDTableViewControllerDelegate: TextFieldTableViewControllerDelegate { func pumpIDTableViewControllerDidChangePumpRegion(_ controller: PumpIDTableViewController) diff --git a/Loop/View Controllers/SettingsTableViewController.swift b/Loop/View Controllers/SettingsTableViewController.swift index 9965adefdb..c81e66d99b 100644 --- a/Loop/View Controllers/SettingsTableViewController.swift +++ b/Loop/View Controllers/SettingsTableViewController.swift @@ -8,8 +8,8 @@ import UIKit import HealthKit -import InsulinKit import LoopKit +import LoopKitUI import MinimedKit import RileyLinkBLEKit import RileyLinkKit @@ -52,7 +52,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu updateRSSI() if case .some = dataManager.cgm, dataManager.loopManager.glucoseStore.authorizationRequired { - dataManager.loopManager.glucoseStore.authorize { (success, error) -> Void in + dataManager.loopManager.glucoseStore.authorize { (result) -> Void in // Do nothing for now } } @@ -110,7 +110,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu fileprivate enum ServiceRow: Int, CaseCountable { case nightscout = 0 - case mLab case loggly case amplitude } @@ -134,15 +133,10 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu vc.insulinSensitivitySchedule = insulinSensitivitySchedule } - dataManager.loopManager.glucoseStore.preferredUnit { (unit, error) in - DispatchQueue.main.async { - if let unit = unit { - vc.glucoseUnit = unit - } - - vc.delegate = self - } + if let unit = dataManager.loopManager.glucoseStore.preferredUnit { + vc.glucoseUnit = unit } + vc.delegate = self default: break } @@ -282,7 +276,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu if let carbRatioSchedule = dataManager.loopManager.carbRatioSchedule { let unit = carbRatioSchedule.unit - let value = valueNumberFormatter.string(from: NSNumber(value: carbRatioSchedule.averageQuantity().doubleValue(for: unit))) ?? "—" + let value = valueNumberFormatter.string(from: carbRatioSchedule.averageQuantity().doubleValue(for: unit)) ?? "—" configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ %2$@/U", comment: "Format string for carb ratio average. (1: value)(2: carb unit)"), value, unit) } else { @@ -293,9 +287,10 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu if let insulinSensitivitySchedule = dataManager.loopManager.insulinSensitivitySchedule { let unit = insulinSensitivitySchedule.unit - let value = valueNumberFormatter.string(from: NSNumber(value: insulinSensitivitySchedule.averageQuantity().doubleValue(for: unit))) ?? "—" + let value = valueNumberFormatter.string(from: insulinSensitivitySchedule.averageQuantity().doubleValue(for: unit)) ?? "—" - configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ %2$@/U", comment: "Format string for insulin sensitivity average (1: value)(2: glucose unit)"), value, unit.glucoseUnitDisplayString) + configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ %2$@/U", comment: "Format string for insulin sensitivity average (1: value)(2: glucose unit)"), value, unit.localizedShortUnitString + ) } else { configCell.detailTextLabel?.text = TapToSetString } @@ -305,10 +300,10 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu if let glucoseTargetRangeSchedule = dataManager.loopManager.settings.glucoseTargetRangeSchedule { let unit = glucoseTargetRangeSchedule.unit let value = glucoseTargetRangeSchedule.value(at: Date()) - let minTarget = valueNumberFormatter.string(from: NSNumber(value: value.minValue)) ?? "—" - let maxTarget = valueNumberFormatter.string(from: NSNumber(value: value.maxValue)) ?? "—" + let minTarget = valueNumberFormatter.string(from: value.minValue) ?? "—" + let maxTarget = valueNumberFormatter.string(from: value.maxValue) ?? "—" - configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ – %2$@ %3$@", comment: "Format string for glucose target range. (1: Min target)(2: Max target)(3: glucose unit)"), minTarget, maxTarget, unit.glucoseUnitDisplayString) + configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ – %2$@ %3$@", comment: "Format string for glucose target range. (1: Min target)(2: Max target)(3: glucose unit)"), minTarget, maxTarget, unit.localizedShortUnitString) } else { configCell.detailTextLabel?.text = TapToSetString } @@ -316,8 +311,8 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu configCell.textLabel?.text = NSLocalizedString("Suspend Threshold", comment: "The title text in settings") if let suspendThreshold = dataManager.loopManager.settings.suspendThreshold { - let value = valueNumberFormatter.string(from: NSNumber(value: suspendThreshold.value)) ?? "-" - configCell.detailTextLabel?.text = String(format: NSLocalizedString("%1$@ %2$@", comment: "Format string for current suspend threshold. (1: value)(2: bg unit)"), value, suspendThreshold.unit.glucoseUnitDisplayString) + let value = valueNumberFormatter.string(from: suspendThreshold.value, unit: suspendThreshold.unit) ?? TapToSetString + configCell.detailTextLabel?.text = value } else { configCell.detailTextLabel?.text = TapToSetString } @@ -369,11 +364,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu configCell.textLabel?.text = nightscoutService.title configCell.detailTextLabel?.text = nightscoutService.siteURL?.absoluteString ?? TapToSetString - case .mLab: - let mLabService = dataManager.logger.mLabService - - configCell.textLabel?.text = mLabService.title - configCell.detailTextLabel?.text = mLabService.databaseName ?? TapToSetString case .loggly: let logglyService = dataManager.logger.logglyService @@ -433,7 +423,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu let row = PumpRow(rawValue: indexPath.row)! switch row { case .pumpID: - let vc: LoopKit.TextFieldTableViewController + let vc: LoopKitUI.TextFieldTableViewController switch row { case .pumpID: vc = PumpIDTableViewController(pumpID: dataManager.pumpSettings?.pumpID, region: dataManager.pumpSettings?.pumpRegion) @@ -465,7 +455,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu show(vc, sender: sender) case .g5TransmitterID: - let vc: LoopKit.TextFieldTableViewController + let vc: LoopKitUI.TextFieldTableViewController var value: String? if case .g5(let transmitterID)? = dataManager.cgm { @@ -485,7 +475,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu let row = ConfigurationRow(rawValue: indexPath.row)! switch row { case .maxBasal, .maxBolus: - let vc: LoopKit.TextFieldTableViewController + let vc: LoopKitUI.TextFieldTableViewController switch row { case .maxBasal: @@ -523,6 +513,8 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu scheduleVC.timeZone = schedule.timeZone scheduleVC.scheduleItems = schedule.items scheduleVC.unit = schedule.unit + } else if let timeZone = dataManager.pumpState?.timeZone { + scheduleVC.timeZone = timeZone } show(scheduleVC, sender: sender) @@ -539,15 +531,13 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu show(scheduleVC, sender: sender) } else { - dataManager.loopManager.glucoseStore.preferredUnit { (unit, error) -> Void in - DispatchQueue.main.async { - if let error = error { - self.presentAlertController(with: error) - } else if let unit = unit { - scheduleVC.unit = unit - self.show(scheduleVC, sender: sender) - } - } + if let timeZone = dataManager.pumpState?.timeZone { + scheduleVC.timeZone = timeZone + } + + if let unit = dataManager.loopManager.glucoseStore.preferredUnit { + scheduleVC.unit = unit + self.show(scheduleVC, sender: sender) } } case .glucoseTargetRange: @@ -564,15 +554,13 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu show(scheduleVC, sender: sender) } else { - dataManager.loopManager.glucoseStore.preferredUnit { (unit, error) -> Void in - DispatchQueue.main.async { - if let error = error { - self.presentAlertController(with: error) - } else if let unit = unit { - scheduleVC.unit = unit - self.show(scheduleVC, sender: sender) - } - } + if let timeZone = dataManager.pumpState?.timeZone { + scheduleVC.timeZone = timeZone + } + + if let unit = dataManager.loopManager.glucoseStore.preferredUnit { + scheduleVC.unit = unit + self.show(scheduleVC, sender: sender) } } case .suspendThreshold: @@ -582,20 +570,12 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu vc.indexPath = indexPath vc.title = sender?.textLabel?.text self.show(vc, sender: sender) - } else { - dataManager.loopManager.glucoseStore.preferredUnit { (unit, error) -> Void in - DispatchQueue.main.async { - if let error = error { - self.presentAlertController(with: error) - } else if let unit = unit { - let vc = GlucoseThresholdTableViewController(threshold: nil, glucoseUnit: unit) - vc.delegate = self - vc.indexPath = indexPath - vc.title = sender?.textLabel?.text - self.show(vc, sender: sender) - } - } - } + } else if let unit = dataManager.loopManager.glucoseStore.preferredUnit { + let vc = GlucoseThresholdTableViewController(threshold: nil, glucoseUnit: unit) + vc.delegate = self + vc.indexPath = indexPath + vc.title = sender?.textLabel?.text + self.show(vc, sender: sender) } case .insulinModel: performSegue(withIdentifier: InsulinModelSettingsViewController.className, sender: sender) @@ -643,34 +623,24 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu self.tableView.reloadRows(at: [indexPath], with: .none) } - show(vc, sender: sender) - case .mLab: - let service = dataManager.logger.mLabService - let vc = AuthenticationViewController(authentication: service) - vc.authenticationObserver = { [unowned self] (service) in - self.dataManager.logger.mLabService = service - - self.tableView.reloadRows(at: [indexPath], with: .none) - } - show(vc, sender: sender) case .loggly: let service = dataManager.logger.logglyService let vc = AuthenticationViewController(authentication: service) - vc.authenticationObserver = { [unowned self] (service) in - self.dataManager.logger.logglyService = service + vc.authenticationObserver = { [weak self] (service) in + self?.dataManager.logger.logglyService = service - self.tableView.reloadRows(at: [indexPath], with: .none) + self?.tableView.reloadRows(at: [indexPath], with: .none) } show(vc, sender: sender) case .amplitude: let service = AnalyticsManager.shared.amplitudeService let vc = AuthenticationViewController(authentication: service) - vc.authenticationObserver = { [unowned self] (service) in + vc.authenticationObserver = { [weak self] (service) in AnalyticsManager.shared.amplitudeService = service - self.tableView.reloadRows(at: [indexPath], with: .none) + self?.tableView.reloadRows(at: [indexPath], with: .none) } show(vc, sender: sender) @@ -876,7 +846,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu case .glucoseTargetRange: if let controller = controller as? GlucoseRangeScheduleTableViewController { dataManager.loopManager.settings.glucoseTargetRangeSchedule = GlucoseRangeSchedule(unit: controller.unit, dailyItems: controller.scheduleItems, timeZone: controller.timeZone, overrideRanges: controller.overrideRanges, override: dataManager.loopManager.settings.glucoseTargetRangeSchedule?.override) - AnalyticsManager.shared.didChangeGlucoseTargetRangeSchedule() } case let row: if let controller = controller as? DailyQuantityScheduleTableViewController { @@ -961,8 +930,8 @@ extension SettingsTableViewController: RadioSelectionTableViewControllerDelegate } } -extension SettingsTableViewController: LoopKit.TextFieldTableViewControllerDelegate { - func textFieldTableViewControllerDidEndEditing(_ controller: LoopKit.TextFieldTableViewController) { +extension SettingsTableViewController: LoopKitUI.TextFieldTableViewControllerDelegate { + func textFieldTableViewControllerDidEndEditing(_ controller: LoopKitUI.TextFieldTableViewController) { if let indexPath = controller.indexPath { switch Section(rawValue: indexPath.section)! { case .pump: @@ -1023,7 +992,7 @@ extension SettingsTableViewController: LoopKit.TextFieldTableViewControllerDeleg tableView.reloadData() } - func textFieldTableViewControllerDidReturn(_ controller: LoopKit.TextFieldTableViewController) { + func textFieldTableViewControllerDidReturn(_ controller: LoopKitUI.TextFieldTableViewController) { _ = navigationController?.popViewController(animated: true) } } diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 0d690ffcf0..55e3e70ca5 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -7,13 +7,12 @@ // import UIKit -import CarbKit -import GlucoseKit import HealthKit -import InsulinKit import LoopKit +import LoopKitUI import LoopUI import SwiftCharts +import os.log /// Describes the state within the bolus setting flow @@ -33,45 +32,44 @@ private extension RefreshContext { final class StatusTableViewController: ChartsTableViewController { + private let log = OSLog(category: "StatusTableViewController") + override func viewDidLoad() { super.viewDidLoad() charts.glucoseDisplayRange = ( - min: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 100), - max: HKQuantity(unit: HKUnit.milligramsPerDeciliter(), doubleValue: 175) + min: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 100), + max: HKQuantity(unit: .milligramsPerDeciliter, doubleValue: 175) ) let notificationCenter = NotificationCenter.default notificationObservers += [ - notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [unowned self] note in - let context = note.userInfo?[LoopDataManager.LoopUpdateContextKey] as! LoopDataManager.LoopUpdateContext.RawValue - let lastLoopCompleted = note.userInfo?[LoopDataManager.LastLoopCompletedKey] as? Date + notificationCenter.addObserver(forName: .LoopDataUpdated, object: deviceManager.loopManager, queue: nil) { [weak self] note in + let rawContext = note.userInfo?[LoopDataManager.LoopUpdateContextKey] as! LoopDataManager.LoopUpdateContext.RawValue + let context = LoopDataManager.LoopUpdateContext(rawValue: rawContext) DispatchQueue.main.async { - switch LoopDataManager.LoopUpdateContext(rawValue: context) { + switch context { case .none, .bolus?: - self.refreshContext.formUnion([.status, .insulin]) + self?.refreshContext.formUnion([.status, .insulin]) case .preferences?: - self.refreshContext.formUnion([.status, .targets]) + self?.refreshContext.formUnion([.status, .targets]) case .carbs?: - self.refreshContext.update(with: .carbs) + self?.refreshContext.update(with: .carbs) case .glucose?: - self.refreshContext.formUnion([.glucose, .carbs]) + self?.refreshContext.formUnion([.glucose, .carbs]) case .tempBasal?: - self.refreshContext.update(with: .insulin) - - if let lastLoopCompleted = lastLoopCompleted { - self.hudView?.loopCompletionHUD.lastLoopCompleted = lastLoopCompleted - } + self?.refreshContext.update(with: .insulin) } - self.hudView?.loopCompletionHUD.loopInProgress = false - self.reloadData(animated: true) + self?.hudView?.loopCompletionHUD.loopInProgress = false + self?.log.debug("[reloadData] from notification with context %{public}@", String(describing: context)) + self?.reloadData(animated: true) } }, - notificationCenter.addObserver(forName: .LoopRunning, object: deviceManager.loopManager, queue: nil) { [unowned self] _ in + notificationCenter.addObserver(forName: .LoopRunning, object: deviceManager.loopManager, queue: nil) { [weak self] _ in DispatchQueue.main.async { - self.hudView?.loopCompletionHUD.loopInProgress = true + self?.hudView?.loopCompletionHUD.loopInProgress = true } } ] @@ -119,6 +117,7 @@ final class StatusTableViewController: ChartsTableViewController { if deviceManager.loopManager.authorizationRequired { deviceManager.loopManager.authorize { DispatchQueue.main.async { + self.log.debug("[reloadData] after HealthKit authorization") self.reloadData() } } @@ -145,7 +144,11 @@ final class StatusTableViewController: ChartsTableViewController { // MARK: - State override var active: Bool { - didSet { + get { + return super.active + } + set { + super.active = newValue hudView?.loopCompletionHUD.assertTimer(active) } } @@ -180,113 +183,110 @@ final class StatusTableViewController: ChartsTableViewController { return !landscapeMode && statusRowMode.hasRow } - override func reloadData(animated: Bool = false) { - guard active && visible && !reloading && !refreshContext.isEmpty && !deviceManager.loopManager.authorizationRequired else { - return - } - var currentContext = refreshContext - var retryContext: Set = [] - self.refreshContext = [] - reloading = true + private func updateChartDateRange() { + let settings = deviceManager.loopManager.settings // How far back should we show data? Use the screen size as a guide. - let minimumSegmentWidth: CGFloat = 50 - let availableWidth = (currentContext.newSize ?? self.tableView.bounds.size).width - self.charts.fixedHorizontalMargin - let totalHours = floor(Double(availableWidth / minimumSegmentWidth)) + let availableWidth = (refreshContext.newSize ?? self.tableView.bounds.size).width - self.charts.fixedHorizontalMargin + + let totalHours = floor(Double(availableWidth / settings.minimumChartWidthPerHour)) let futureHours = ceil((deviceManager.loopManager.insulinModelSettings?.model.effectDuration ?? .hours(4)).hours) - let historyHours = max(1, totalHours - futureHours) + let historyHours = max(settings.statusChartMinimumHistoryDisplay.hours, totalHours - futureHours) - var components = DateComponents() - components.minute = 0 let date = Date(timeIntervalSinceNow: -TimeInterval(hours: historyHours)) - let chartStartDate = Calendar.current.nextDate(after: date, matching: components, matchingPolicy: .strict, direction: .backward) ?? date + let chartStartDate = Calendar.current.nextDate(after: date, matching: DateComponents(minute: 0), matchingPolicy: .strict, direction: .backward) ?? date if charts.startDate != chartStartDate { - currentContext.formUnion(RefreshContext.all) + refreshContext.formUnion(RefreshContext.all) } charts.startDate = chartStartDate - charts.maxEndDate = chartStartDate.addingTimeInterval(.hours(totalHours)) + charts.updateEndDate(charts.maxEndDate) + } + + override func reloadData(animated: Bool = false) { + // This should be kept up to date immediately + hudView?.loopCompletionHUD.lastLoopCompleted = deviceManager.loopManager.lastLoopCompleted + + guard !reloading && !deviceManager.loopManager.authorizationRequired else { + return + } + + updateChartDateRange() + redrawCharts() + + guard active && visible && !refreshContext.isEmpty else { + return + } + + log.debug("Reloading data with context: %@", String(describing: refreshContext)) + + let currentContext = refreshContext + var retryContext: Set = [] + self.refreshContext = [] + reloading = true let reloadGroup = DispatchGroup() var lastReservoirValue: ReservoirValue? var newRecommendedTempBasal: (recommendation: TempBasalRecommendation, date: Date)? + var glucoseValues: [StoredGlucoseSample]? + var predictedGlucoseValues: [GlucoseValue]? + var iobValues: [InsulinValue]? + var doseEntries: [DoseEntry]? + var totalDelivery: Double? + var cobValues: [CarbValue]? let bolusState = self.bolusState + let startDate = charts.startDate + // TODO: Don't always assume currentContext.contains(.status) reloadGroup.enter() - deviceManager.loopManager.glucoseStore.preferredUnit { (unit, error) in - if let unit = unit { - self.charts.glucoseUnit = unit + self.deviceManager.loopManager.getLoopState { (manager, state) -> Void in + predictedGlucoseValues = state.predictedGlucose ?? [] + + // Retry this refresh again if predicted glucose isn't available + if state.predictedGlucose == nil { + retryContext.update(with: .status) + } + + /// Update the status HUDs immediately + let netBasal: NetBasal? + let lastLoopCompleted = manager.lastLoopCompleted + let lastLoopError = state.error + + // Net basal rate HUD + let date = state.lastTempBasal?.startDate ?? Date() + if let scheduledBasal = manager.basalRateSchedule?.between(start: date, end: date).first { + netBasal = NetBasal( + lastTempBasal: state.lastTempBasal, + maxBasal: manager.settings.maximumBasalRatePerHour, + scheduledBasal: scheduledBasal + ) + } else { + netBasal = nil } - // TODO: Don't always assume currentContext.contains(.status) - reloadGroup.enter() - self.deviceManager.loopManager.getLoopState { (manager, state) -> Void in - self.charts.setPredictedGlucoseValues(state.predictedGlucose ?? []) - - // Retry this refresh again if predicted glucose isn't available - if state.predictedGlucose == nil { - retryContext.update(with: .status) - } - - /// Update the status HUDs immediately - let netBasal: NetBasal? - let lastLoopCompleted = state.lastLoopCompleted - let lastLoopError = state.error - let dosingEnabled = manager.settings.dosingEnabled - - // Net basal rate HUD - let date = state.lastTempBasal?.startDate ?? Date() - if let scheduledBasal = manager.basalRateSchedule?.between(start: date, end: date).first { - netBasal = NetBasal( - lastTempBasal: state.lastTempBasal, - maxBasal: manager.settings.maximumBasalRatePerHour, - scheduledBasal: scheduledBasal - ) - } else { - netBasal = nil - } - - DispatchQueue.main.async { - self.hudView?.loopCompletionHUD.lastLoopCompleted = lastLoopCompleted - self.hudView?.loopCompletionHUD.dosingEnabled = dosingEnabled - self.lastLoopError = lastLoopError - - if let netBasal = netBasal { - self.hudView?.basalRateHUD.setNetBasalRate(netBasal.rate, percent: netBasal.percent, at: netBasal.start) - } - } - - // Display a recommended basal change only if we haven't completed recently, or we're in open-loop mode - if state.lastLoopCompleted == nil || - state.lastLoopCompleted! < Date(timeIntervalSinceNow: .minutes(-6)) || - !manager.settings.dosingEnabled - { - newRecommendedTempBasal = state.recommendedTempBasal - } + DispatchQueue.main.async { + self.hudView?.loopCompletionHUD.dosingEnabled = manager.settings.dosingEnabled + self.lastLoopError = lastLoopError - if let lastPoint = self.charts.predictedGlucosePoints.last?.y { - self.eventualGlucoseDescription = String(describing: lastPoint) - } else { - self.eventualGlucoseDescription = nil + if let netBasal = netBasal { + self.hudView?.basalRateHUD.setNetBasalRate(netBasal.rate, percent: netBasal.percent, at: netBasal.start) } + } - if currentContext.contains(.targets) { - if let schedule = manager.settings.glucoseTargetRangeSchedule { - self.charts.targetPointsCalculator = GlucoseRangeScheduleCalculator(schedule) - } else { - self.charts.targetPointsCalculator = nil - } - } + // Display a recommended basal change only if we haven't completed recently, or we're in open-loop mode + if lastLoopCompleted == nil || + lastLoopCompleted! < Date(timeIntervalSinceNow: .minutes(-6)) || + !manager.settings.dosingEnabled + { + newRecommendedTempBasal = state.recommendedTempBasal + } - if currentContext.contains(.carbs) { - reloadGroup.enter() - manager.carbStore.getCarbsOnBoardValues(start: chartStartDate, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? state.insulinCounteractionEffects : nil) { (values) in - self.charts.setCOBValues(values) - reloadGroup.leave() - } + if currentContext.contains(.carbs) { + reloadGroup.enter() + manager.carbStore.getCarbsOnBoardValues(start: startDate, effectVelocities: manager.settings.dynamicCarbAbsorptionEnabled ? state.insulinCounteractionEffects : nil) { (values) in + cobValues = values + reloadGroup.leave() } - - reloadGroup.leave() } reloadGroup.leave() @@ -294,43 +294,35 @@ final class StatusTableViewController: ChartsTableViewController { if currentContext.contains(.glucose) { reloadGroup.enter() - self.deviceManager.loopManager.glucoseStore.getGlucoseValues(start: chartStartDate) { (result) -> Void in - switch result { - case .failure(let error): - self.deviceManager.logger.addError(error, fromSource: "GlucoseStore") - retryContext.update(with: .glucose) - self.charts.setGlucoseValues([]) - case .success(let values): - self.charts.setGlucoseValues(values) - } - + self.deviceManager.loopManager.glucoseStore.getCachedGlucoseSamples(start: startDate) { (values) -> Void in + glucoseValues = values reloadGroup.leave() } } if currentContext.contains(.insulin) { reloadGroup.enter() - deviceManager.loopManager.doseStore.getInsulinOnBoardValues(start: chartStartDate) { (result) -> Void in + deviceManager.loopManager.doseStore.getInsulinOnBoardValues(start: startDate) { (result) -> Void in switch result { case .failure(let error): self.deviceManager.logger.addError(error, fromSource: "DoseStore") retryContext.update(with: .insulin) - self.charts.setIOBValues([]) + iobValues = [] case .success(let values): - self.charts.setIOBValues(values) + iobValues = values } reloadGroup.leave() } reloadGroup.enter() - deviceManager.loopManager.doseStore.getNormalizedDoseEntries(start: chartStartDate) { (result) -> Void in + deviceManager.loopManager.doseStore.getNormalizedDoseEntries(start: startDate) { (result) -> Void in switch result { case .failure(let error): self.deviceManager.logger.addError(error, fromSource: "DoseStore") retryContext.update(with: .insulin) - self.charts.setDoseEntries([]) + doseEntries = [] case .success(let doses): - self.charts.setDoseEntries(doses) + doseEntries = doses } reloadGroup.leave() } @@ -340,16 +332,16 @@ final class StatusTableViewController: ChartsTableViewController { switch result { case .failure: retryContext.update(with: .insulin) - self.totalDelivery = nil + totalDelivery = nil case .success(let total): - self.totalDelivery = total.value + totalDelivery = total.value } reloadGroup.leave() } reloadGroup.enter() - deviceManager.loopManager.doseStore.getReservoirValues(since: Date(timeIntervalSinceNow: .minutes(-30))) { (result) in + deviceManager.loopManager.doseStore.getReservoirValues(since: Date(timeIntervalSinceNow: .minutes(-30)), limit: 1) { (result) in switch result { case .success(let values): lastReservoirValue = values.first @@ -365,6 +357,52 @@ final class StatusTableViewController: ChartsTableViewController { preMealMode = deviceManager.loopManager.settings.glucoseTargetRangeSchedule?.overrideEnabledForContext(.preMeal) reloadGroup.notify(queue: .main) { + /// Update the chart data + + // Glucose + if let glucoseValues = glucoseValues { + self.charts.setGlucoseValues(glucoseValues) + } + if let predictedGlucoseValues = predictedGlucoseValues { + self.charts.setPredictedGlucoseValues(predictedGlucoseValues) + } + if let lastPoint = self.charts.predictedGlucosePoints.last?.y { + self.eventualGlucoseDescription = String(describing: lastPoint) + } else { + self.eventualGlucoseDescription = nil + } + if currentContext.contains(.targets) { + self.charts.targetGlucoseSchedule = self.deviceManager.loopManager.settings.glucoseTargetRangeSchedule + } + + // Active Insulin + if let iobValues = iobValues { + self.charts.setIOBValues(iobValues) + } + if let index = self.charts.iobPoints.closestIndexPriorToDate(Date()) { + self.currentIOBDescription = String(describing: self.charts.iobPoints[index].y) + } else { + self.currentIOBDescription = nil + } + + // Insulin Delivery + if let doseEntries = doseEntries { + self.charts.setDoseEntries(doseEntries) + } + if let totalDelivery = totalDelivery { + self.totalDelivery = totalDelivery + } + + // Active Carbohydrates + if let cobValues = cobValues { + self.charts.setCOBValues(cobValues) + } + if let index = self.charts.cobPoints.closestIndexPriorToDate(Date()) { + self.currentCOBDescription = String(describing: self.charts.cobPoints[index].y) + } else { + self.currentCOBDescription = nil + } + self.tableView.beginUpdates() if let hudView = self.hudView { // Glucose HUD @@ -389,21 +427,6 @@ final class StatusTableViewController: ChartsTableViewController { hudView.batteryHUD.batteryLevel = self.deviceManager.pumpBatteryChargeRemaining } - // Fetch the current IOB subtitle - if let index = self.charts.iobPoints.closestIndexPriorToDate(Date()) { - self.currentIOBDescription = String(describing: self.charts.iobPoints[index].y) - } else { - self.currentIOBDescription = nil - } - // Fetch the current COB subtitle - if let index = self.charts.cobPoints.closestIndexPriorToDate(Date()) { - self.currentCOBDescription = String(describing: self.charts.cobPoints[index].y) - } else { - self.currentCOBDescription = nil - } - - self.charts.prerender() - // Show/hide the table view rows let statusRowMode: StatusRowMode? @@ -412,7 +435,6 @@ final class StatusTableViewController: ChartsTableViewController { statusRowMode = nil case .none: if let (recommendation: tempBasal, date: date) = newRecommendedTempBasal { - // TODO: Don't display this if we're in closed mode and the loop recently completed statusRowMode = .recommendedTempBasal(tempBasal: tempBasal, at: date, enacting: false) } else { statusRowMode = .hidden @@ -420,14 +442,8 @@ final class StatusTableViewController: ChartsTableViewController { } self.updateHUDandStatusRows(statusRowMode: statusRowMode, newSize: currentContext.newSize, animated: animated) + self.redrawCharts() - for case let cell as ChartTableViewCell in self.tableView.visibleCells { - cell.reloadChart() - - if let indexPath = self.tableView.indexPath(for: cell) { - self.tableView(self.tableView, updateSubtitleFor: cell, at: indexPath) - } - } self.tableView.endUpdates() self.reloading = false @@ -436,6 +452,7 @@ final class StatusTableViewController: ChartsTableViewController { // Trigger a reload if new context exists. if reloadNow { + self.log.debug("[reloadData] due to context change during previous reload") self.reloadData() } } @@ -542,7 +559,7 @@ final class StatusTableViewController: ChartsTableViewController { // If the rate or date change, reload the row if oldTempBasal != newTempBasal || oldDate != newDate { - self.tableView.reloadRows(at: [statusIndexPath], with: animated ? .top : .none) + self.tableView.reloadRows(at: [statusIndexPath], with: animated ? .fade : .none) } else if let cell = tableView.cellForRow(at: statusIndexPath) { // If only the enacting state changed, update the activity indicator if isEnacting { @@ -556,7 +573,7 @@ final class StatusTableViewController: ChartsTableViewController { case (.enactingBolus, .enactingBolus): break default: - self.tableView.reloadRows(at: [statusIndexPath], with: animated ? .top : .none) + self.tableView.reloadRows(at: [statusIndexPath], with: animated ? .fade : .none) } case (false, true): self.tableView.insertRows(at: [statusIndexPath], with: animated ? .top : .none) @@ -569,6 +586,19 @@ final class StatusTableViewController: ChartsTableViewController { tableView.endUpdates() } + private func redrawCharts() { + tableView.beginUpdates() + self.charts.prerender() + for case let cell as ChartTableViewCell in self.tableView.visibleCells { + cell.reloadChart() + + if let indexPath = self.tableView.indexPath(for: cell) { + self.tableView(self.tableView, updateSubtitleFor: cell, at: indexPath) + } + } + tableView.endUpdates() + } + // MARK: - Toolbar data private var preMealMode: Bool? = nil { @@ -628,23 +658,23 @@ final class StatusTableViewController: ChartsTableViewController { switch ChartRow(rawValue: indexPath.row)! { case .glucose: - cell.chartContentView.chartGenerator = { [unowned self] (frame) in - return self.charts.glucoseChartWithFrame(frame)?.view + cell.chartContentView.chartGenerator = { [weak self] (frame) in + return self?.charts.glucoseChartWithFrame(frame)?.view } cell.titleLabel?.text = NSLocalizedString("Glucose", comment: "The title of the glucose and prediction graph") case .iob: - cell.chartContentView.chartGenerator = { [unowned self] (frame) in - return self.charts.iobChartWithFrame(frame)?.view + cell.chartContentView.chartGenerator = { [weak self] (frame) in + return self?.charts.iobChartWithFrame(frame)?.view } cell.titleLabel?.text = NSLocalizedString("Active Insulin", comment: "The title of the Insulin On-Board graph") case .dose: - cell.chartContentView?.chartGenerator = { [unowned self] (frame) in - return self.charts.doseChartWithFrame(frame)?.view + cell.chartContentView?.chartGenerator = { [weak self] (frame) in + return self?.charts.doseChartWithFrame(frame)?.view } cell.titleLabel?.text = NSLocalizedString("Insulin Delivery", comment: "The title of the insulin delivery graph") case .cob: - cell.chartContentView?.chartGenerator = { [unowned self] (frame) in - return self.charts.cobChartWithFrame(frame)?.view + cell.chartContentView?.chartGenerator = { [weak self] (frame) in + return self?.charts.cobChartWithFrame(frame)?.view } cell.titleLabel?.text = NSLocalizedString("Active Carbohydrates", comment: "The title of the Carbs On-Board graph") } @@ -720,7 +750,7 @@ final class StatusTableViewController: ChartsTableViewController { integerFormatter.maximumFractionDigits = 0 if let total = totalDelivery, - let totalString = integerFormatter.string(from: NSNumber(value: total)) { + let totalString = integerFormatter.string(from: total) { cell.subtitleLabel?.text = String(format: NSLocalizedString("%@ U Total", comment: "The subtitle format describing total insulin. (1: localized insulin total)"), totalString) } else { cell.subtitleLabel?.text = nil @@ -793,6 +823,7 @@ final class StatusTableViewController: ChartsTableViewController { self.presentAlertController(with: error) } else { self.refreshContext.update(with: .status) + self.log.debug("[reloadData] after manually enacting temp basal") self.reloadData() } } @@ -967,6 +998,7 @@ final class StatusTableViewController: ChartsTableViewController { hudView.batteryHUD.stateColors = .pumpStatus refreshContext.update(with: .status) + self.log.debug("[reloadData] after hudView loaded") reloadData() } } diff --git a/Loop/View Controllers/TextFieldTableViewController.swift b/Loop/View Controllers/TextFieldTableViewController.swift index 96bb4e433b..fe7b8378dc 100644 --- a/Loop/View Controllers/TextFieldTableViewController.swift +++ b/Loop/View Controllers/TextFieldTableViewController.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Nathan Racklyeft. All rights reserved. // -import LoopKit +import LoopKitUI import HealthKit diff --git a/LoopUI/Extensions/ChartPoint.swift b/LoopUI/Extensions/ChartPoint.swift index 92d8800fc0..24230d2694 100644 --- a/LoopUI/Extensions/ChartPoint.swift +++ b/LoopUI/Extensions/ChartPoint.swift @@ -7,26 +7,18 @@ // import Foundation +import HealthKit +import LoopKit import SwiftCharts -public struct DatedRangeContext { - public let startDate: Date - public let endDate: Date - public let minValue: Double - public let maxValue: Double - - public init(startDate: Date, endDate: Date, minValue: Double, maxValue: Double) { - self.startDate = startDate - self.endDate = endDate - self.minValue = minValue - self.maxValue = maxValue - } -} - - extension ChartPoint { - public static func pointsForDatedRanges(_ targetRanges: [DatedRangeContext], xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + static func pointsForGlucoseRangeSchedule(_ glucoseRangeSchedule: GlucoseRangeSchedule, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + let targetRanges = glucoseRangeSchedule.between( + start: ChartAxisValueDate.dateFromScalar(xAxisValues.first!.scalar), + end: ChartAxisValueDate.dateFromScalar(xAxisValues.last!.scalar) + ) + let dateFormatter = DateFormatter() var maxPoints: [ChartPoint] = [] @@ -46,8 +38,9 @@ extension ChartPoint { endDate = ChartAxisValueDate(date: targetRanges[index + 1].startDate, formatter: dateFormatter) } - let minValue = ChartAxisValueDouble(range.minValue) - let maxValue = ChartAxisValueDouble(range.maxValue) + let value = range.value.rangeWithMinimumIncremement(glucoseRangeSchedule.unit.chartableIncrement) + let minValue = ChartAxisValueDouble(value.minValue) + let maxValue = ChartAxisValueDouble(value.maxValue) maxPoints += [ ChartPoint(x: startDate, y: maxValue), @@ -63,10 +56,12 @@ extension ChartPoint { return maxPoints + minPoints.reversed() } - public static func pointsForDatedRangeOverrideDuration(_ override: DatedRangeContext, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { + static func pointsForGlucoseRangeScheduleOverride(_ override: GlucoseRangeSchedule.Override, unit: HKUnit, xAxisValues: [ChartAxisValue], extendEndDateToChart: Bool = false) -> [ChartPoint] { + let range = override.value.rangeWithMinimumIncremement(unit.chartableIncrement) let startDate = Date() + let endDate = override.end ?? .distantFuture - guard override.endDate.timeIntervalSince(startDate) > 0, + guard endDate.timeIntervalSince(startDate) > 0, let lastXAxisValue = xAxisValues.last as? ChartAxisValueDate else { return [] @@ -74,9 +69,10 @@ extension ChartPoint { let dateFormatter = DateFormatter() let startDateAxisValue = ChartAxisValueDate(date: startDate, formatter: dateFormatter) - let endDateAxisValue = ChartAxisValueDate(date: min(lastXAxisValue.date, override.endDate), formatter: dateFormatter) - let minValue = ChartAxisValueDouble(override.minValue) - let maxValue = ChartAxisValueDouble(override.maxValue) + let displayEndDate = min(lastXAxisValue.date, extendEndDateToChart ? .distantFuture : endDate) + let endDateAxisValue = ChartAxisValueDate(date: displayEndDate, formatter: dateFormatter) + let minValue = ChartAxisValueDouble(range.minValue) + let maxValue = ChartAxisValueDouble(range.maxValue) return [ ChartPoint(x: startDateAxisValue, y: maxValue), @@ -85,28 +81,31 @@ extension ChartPoint { ChartPoint(x: startDateAxisValue, y: minValue) ] } +} - public static func pointsForDatedRangeOverride(_ override: DatedRangeContext, xAxisValues: [ChartAxisValue]) -> [ChartPoint] { - let startDate = Date() - guard override.endDate.timeIntervalSince(startDate) > 0, - let lastXAxisValue = xAxisValues.last as? ChartAxisValueDate - else { - return [] + +extension ChartPoint: TimelineValue { + public var startDate: Date { + if let dateValue = x as? ChartAxisValueDate { + return dateValue.date + } else { + return Date.distantPast } + } +} - let dateFormatter = DateFormatter() - let startDateAxisValue = ChartAxisValueDate(date: startDate, formatter: dateFormatter) - let endDateAxisValue = ChartAxisValueDate(date: lastXAxisValue.date, formatter: dateFormatter) - let minValue = ChartAxisValueDouble(override.minValue) - let maxValue = ChartAxisValueDouble(override.maxValue) - return [ - ChartPoint(x: startDateAxisValue, y: maxValue), - ChartPoint(x: endDateAxisValue, y: maxValue), - ChartPoint(x: endDateAxisValue, y: minValue), - ChartPoint(x: startDateAxisValue, y: minValue) - ] - } +private extension DoubleRange { + func rangeWithMinimumIncremement(_ increment: Double) -> DoubleRange { + var minValue = self.minValue + var maxValue = self.maxValue + if (maxValue - minValue) < .ulpOfOne { + minValue -= increment + maxValue += increment + } + + return DoubleRange(minValue: minValue, maxValue: maxValue) + } } diff --git a/LoopUI/HUDView.xib b/LoopUI/HUDView.xib index 9bb1dcba95..919a91a921 100644 --- a/LoopUI/HUDView.xib +++ b/LoopUI/HUDView.xib @@ -1,11 +1,11 @@ - + - + @@ -26,7 +26,7 @@ -