Ivan Valkou 5 سال پیش
والد
کامیت
ba01e4f850
25فایلهای تغییر یافته به همراه235 افزوده شده و 31 حذف شده
  1. 8 0
      FreeAPS/Resources/json/defaults/settings/basal_profile.json
  2. 14 0
      FreeAPS/Resources/json/defaults/settings/bg_targets.json
  3. 12 0
      FreeAPS/Resources/json/defaults/settings/carb_ratios.json
  4. 13 0
      FreeAPS/Resources/json/defaults/settings/insulin_sensitivities.json
  5. 1 0
      FreeAPS/Resources/json/defaults/settings/model.json
  6. 5 0
      FreeAPS/Resources/json/defaults/settings/settings.json
  7. 15 0
      FreeAPS/Resources/json/defaults/settings/temptargets.json
  8. 1 0
      FreeAPS/Sources/APS/APSManager.swift
  9. 5 0
      FreeAPS/Sources/APS/BaseAPSManager.swift
  10. 9 0
      FreeAPS/Sources/APS/OpenAPS/Constants.swift
  11. 48 2
      FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift
  12. 32 0
      FreeAPS/Sources/Helpers/Formatters.swift
  13. 6 4
      FreeAPS/Sources/Helpers/JSON.swift
  14. 15 2
      FreeAPS/Sources/Helpers/ViewModifiers.swift
  15. 1 1
      FreeAPS/Sources/Models/PumpHistoryEvent.swift
  16. 0 7
      FreeAPS/Sources/Modules/Base/BaseProvider.swift
  17. 1 1
      FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorProvider.swift
  18. 1 1
      FreeAPS/Sources/Modules/ConfigEditor/View/ConfigEditorRootView.swift
  19. 4 0
      FreeAPS/Sources/Modules/Home/HomeViewModel.swift
  20. 8 1
      FreeAPS/Sources/Modules/Home/View/HomeRootView.swift
  21. 1 0
      FreeAPS/Sources/Modules/Main/View/MainRootView.swift
  22. 1 2
      FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift
  23. 30 6
      FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift
  24. 2 2
      FreeAPS/Sources/Services/Storage/FileStorage.swift
  25. 2 2
      Templates/swift_pvvm/Code/View/RootView.swift.liquid

+ 8 - 0
FreeAPS/Resources/json/defaults/settings/basal_profile.json

@@ -0,0 +1,8 @@
+[
+    {
+        "i": 0,
+        "start": "00:00:00",
+        "minutes": 0,
+        "rate": 1.0
+    }
+]

+ 14 - 0
FreeAPS/Resources/json/defaults/settings/bg_targets.json

@@ -0,0 +1,14 @@
+{
+    "units": "mg/dL",
+    "user_preferred_units": "mmol/L",
+    "targets": [
+        {
+            "i": 0,
+            "high": 100.0,
+            "start": "00:00:00",
+            "low": 100.0,
+            "offset": 0,
+            "x": 0
+        }
+    ]
+}

+ 12 - 0
FreeAPS/Resources/json/defaults/settings/carb_ratios.json

@@ -0,0 +1,12 @@
+{
+    "units": "grams",
+    "schedule": [
+        {
+            "x": 0,
+            "i": 0,
+            "start": "00:00:00",
+            "offset": 0,
+            "ratio": 10
+        }
+    ]
+}

+ 13 - 0
FreeAPS/Resources/json/defaults/settings/insulin_sensitivities.json

@@ -0,0 +1,13 @@
+{
+    "units": "mg/dL",
+    "user_preferred_units": "mmol/L",
+    "sensitivities": [
+        {
+            "i": 0,
+            "x": 0,
+            "sensitivity": 72.0,
+            "offset": 0,
+            "start": "00:00:00"
+        }
+    ]
+}

+ 1 - 0
FreeAPS/Resources/json/defaults/settings/model.json

@@ -0,0 +1 @@
+"722"

+ 5 - 0
FreeAPS/Resources/json/defaults/settings/settings.json

@@ -0,0 +1,5 @@
+{
+    "insulin_action_curve": 5,
+    "maxBolus": 10,
+    "maxBasal": 2
+}

+ 15 - 0
FreeAPS/Resources/json/defaults/settings/temptargets.json

@@ -0,0 +1,15 @@
+[
+    {
+        "_id": "601bf716211b34b896be0e24",
+        "eventType": "Temporary Target",
+        "entededBy": "Automagic",
+        "reason": "Manual",
+        "targetTop": 126,
+        "targetBottom": 126,
+        "duration": 300,
+        "created_at": "2021-02-04T13:31:02.076Z",
+        "utcOffset": 0,
+        "carbs": null,
+        "insulin": null
+    }
+]

+ 1 - 0
FreeAPS/Sources/APS/APSManager.swift

@@ -3,6 +3,7 @@ import LoopKitUI
 
 protocol APSManager {
     func runTest()
+    func makeProfiles()
     var pumpManager: PumpManagerUI? { get set }
     var pumpDisplayState: CurrentValueSubject<PumpDisplayState?, Never> { get }
 }

+ 5 - 0
FreeAPS/Sources/APS/BaseAPSManager.swift

@@ -27,4 +27,9 @@ final class BaseAPSManager: APSManager, Injectable {
     func runTest() {
         openAPS.test()
     }
+
+    func makeProfiles() {
+        openAPS.makeProfile(autotuned: false)
+        openAPS.makeProfile(autotuned: true)
+    }
 }

+ 9 - 0
FreeAPS/Sources/APS/OpenAPS/Constants.swift

@@ -25,6 +25,15 @@ extension OpenAPS {
         static let preferences = "preferences.json"
         static let autotune = "settings/autotune.json"
         static let autosense = "settings/autosense.json"
+        static let profile = "settings/profile.json"
+        static let pumpProfile = "settings/pumpprofile.json"
+        static let settings = "settings/settings.json"
+        static let bgTargets = "settings/bg_targets.json"
+        static let insulinSensitivities = "settings/insulin_sensitivities.json"
+        static let basalProfile = "settings/basal_profile.json"
+        static let carbRatios = "settings/carb_ratios.json"
+        static let tempTargets = "settings/temptargets.json"
+        static let model = "settings/model.json"
     }
 
     enum Monitor {

+ 48 - 2
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -35,7 +35,7 @@ final class OpenAPS {
                 carbs: carbs,
                 glucose: glucose,
                 basalprofile: basalProfile,
-                temptargets: "null"
+                temptargets: RawJSON.null
             )
             print("AUTOSENS: \(autosensResult)")
             try? self.storage.save(autosensResult, as: Settings.autosense)
@@ -45,7 +45,7 @@ final class OpenAPS {
                 profile: profile,
                 clock: clock,
                 autosens: autosensResult,
-                pumphistory24: "null"
+                pumphistory24: RawJSON.null
             )
             print("IOB: \(iobResult)")
 
@@ -103,6 +103,41 @@ final class OpenAPS {
         }
     }
 
+    func makeProfile(autotuned: Bool) {
+        processQueue.async {
+            print("MAKE PROFILE autotuned \(autotuned)")
+            let preferences = self.loadFileFromStorage(name: Settings.preferences)
+            let pumpSettings = self.loadFileFromStorage(name: Settings.settings)
+            let bgTargets = self.loadFileFromStorage(name: Settings.bgTargets)
+            let basalProfile = self.loadFileFromStorage(name: Settings.basalProfile)
+            let isf = self.loadFileFromStorage(name: Settings.insulinSensitivities)
+            let cr = self.loadFileFromStorage(name: Settings.carbRatios)
+            let tempTargets = self.loadFileFromStorage(name: Settings.tempTargets)
+            let model = self.loadFileFromStorage(name: Settings.model)
+            let autotune = self.loadFileFromStorage(name: Settings.autotune)
+
+            let profile = self.makeProfile(
+                preferences: preferences,
+                pumpSettings: pumpSettings,
+                bgTargets: bgTargets,
+                basalProfile: basalProfile,
+                isf: isf,
+                carbRatio: cr,
+                tempTargets: tempTargets,
+                model: model,
+                autotune: autotuned ? autotune : .null
+            )
+
+            print("PROFILE RESULT \n\(profile)")
+
+            if autotuned {
+                try? self.storage.save(profile, as: Settings.profile)
+            } else {
+                try? self.storage.save(profile, as: Settings.pumpProfile)
+            }
+        }
+    }
+
     private func iob(pumphistory: JSON, profile: JSON, clock: JSON, autosens: JSON, pumphistory24: JSON) -> RawJSON {
         dispatchPrecondition(condition: .onQueue(processQueue))
         return jsWorker.inCommonContext { worker in
@@ -289,4 +324,15 @@ final class OpenAPS {
     private func loadJSON(name: String) -> String {
         try! String(contentsOf: Foundation.Bundle.main.url(forResource: "json/\(name)", withExtension: "json")!)
     }
+
+    private func loadFileFromStorage(name: String) -> RawJSON {
+        (try? storage.retrieve(name, as: RawJSON.self)) ?? OpenAPS.defaults(for: name)
+    }
+
+    static func defaults(for file: String) -> RawJSON {
+        guard let url = Foundation.Bundle.main.url(forResource: "json/defaults/\(file)", withExtension: "") else {
+            return ""
+        }
+        return (try? String(contentsOf: url)) ?? ""
+    }
 }

+ 32 - 0
FreeAPS/Sources/Helpers/Formatters.swift

@@ -15,3 +15,35 @@ enum Formatters {
         return formater.string(from: TimeInterval(minutes * 60))!
     }
 }
+
+extension Formatter {
+    static let iso8601withFractionalSeconds: ISO8601DateFormatter = {
+        let formatter = ISO8601DateFormatter()
+        formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
+        return formatter
+    }()
+
+    static let iso8601: ISO8601DateFormatter = {
+        let formatter = ISO8601DateFormatter()
+        formatter.formatOptions = [.withInternetDateTime]
+        return formatter
+    }()
+}
+
+extension JSONDecoder.DateDecodingStrategy {
+    static let customISO8601 = custom {
+        let container = try $0.singleValueContainer()
+        let string = try container.decode(String.self)
+        if let date = Formatter.iso8601withFractionalSeconds.date(from: string) ?? Formatter.iso8601.date(from: string) {
+            return date
+        }
+        throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
+    }
+}
+
+extension JSONEncoder.DateEncodingStrategy {
+    static let customISO8601 = custom {
+        var container = $1.singleValueContainer()
+        try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
+    }
+}

+ 6 - 4
FreeAPS/Sources/Helpers/JSON.swift

@@ -40,13 +40,11 @@ extension Decimal: JSON {}
 
 extension Date: JSON {
     var rawJSON: String {
-        let formatter = ISO8601DateFormatter()
-        return formatter.string(from: self)
+        Formatter.iso8601withFractionalSeconds.string(from: self)
     }
 
     init?(from: String) {
-        let dateFormatter = ISO8601DateFormatter()
-        dateFormatter.formatOptions.insert(.withFractionalSeconds)
+        let dateFormatter = Formatter.iso8601withFractionalSeconds
         let string = from.replacingOccurrences(of: "\"", with: "")
         if let date = dateFormatter.date(from: string) {
             self = date
@@ -58,5 +56,9 @@ extension Date: JSON {
 
 typealias RawJSON = String
 
+extension RawJSON {
+    static let null = "null"
+}
+
 extension Array: JSON where Element: JSON {}
 extension Dictionary: JSON where Key: JSON, Value: JSON {}

+ 15 - 2
FreeAPS/Sources/Helpers/ViewModifiers.swift

@@ -83,8 +83,7 @@ struct AdaptsToSoftwareKeyboard: ViewModifier {
     }
 }
 
-struct ClearButton: ViewModifier
-{
+struct ClearButton: ViewModifier {
     @Binding var text: String
     func body(content: Content) -> some View {
         HStack {
@@ -100,6 +99,16 @@ struct ClearButton: ViewModifier
     }
 }
 
+struct ChevronCell: ViewModifier {
+    func body(content: Content) -> some View {
+        HStack {
+            content
+            Spacer()
+            Image(systemName: "chevron.forward").foregroundColor(.secondary)
+        }.contentShape(Rectangle())
+    }
+}
+
 extension View {
     func roundedBackground() -> some View {
         modifier(RoundedBackground())
@@ -124,4 +133,8 @@ extension View {
     }
 
     func asAny() -> AnyView { .init(self) }
+
+    func chevronCell() -> some View {
+        modifier(ChevronCell())
+    }
 }

+ 1 - 1
FreeAPS/Sources/Models/PumpHistoryEvent.swift

@@ -32,7 +32,7 @@ enum PumpHistoryTempType: String, JSON {
 
 extension PumpHistoryEvent {
     private enum CodingKeys: String, CodingKey {
-        case id = "_id"
+        case id
         case type = "_type"
         case timestamp
         case amount

+ 0 - 7
FreeAPS/Sources/Modules/Base/BaseProvider.swift

@@ -29,13 +29,6 @@ class BaseProvider: Provider, Injectable {
             .store(in: &lifetime)
     }
 
-    func defaults(for file: String) -> RawJSON {
-        guard let url = Foundation.Bundle.main.url(forResource: "json/defaults/\(file)", withExtension: "") else {
-            return ""
-        }
-        return (try? String(contentsOf: url)) ?? ""
-    }
-
     func type(for file: String) -> JSON.Type {
         switch file {
         case OpenAPS.Monitor.pumpHistory:

+ 1 - 1
FreeAPS/Sources/Modules/ConfigEditor/ConfigEditorProvider.swift

@@ -10,7 +10,7 @@ extension ConfigEditor {
             } else if let value = try? storage.retrieve(file, as: [PumpHistoryEvent].self) {
                 return value.rawJSON
             }
-            return defaults(for: file)
+            return OpenAPS.defaults(for: file)
         }
 
         func urlFor(file: String) -> URL? {

+ 1 - 1
FreeAPS/Sources/Modules/ConfigEditor/View/ConfigEditorRootView.swift

@@ -19,7 +19,6 @@ extension ConfigEditor {
                             Image(systemName: "square.and.arrow.up")
                         }
                     }
-                    ToolbarItem(placement: .principal) { Text(viewModel.file) }
                 }
                 .navigationBarItems(
                     leading: Button("Close", action: viewModel.hideModal),
@@ -28,6 +27,7 @@ extension ConfigEditor {
                 .sheet(isPresented: $showShareSheet) {
                     ShareSheet(activityItems: [viewModel.provider.urlFor(file: viewModel.file)!])
                 }
+                .navigationTitle(viewModel.file)
                 .navigationBarTitleDisplayMode(.inline)
                 .padding()
         }

+ 4 - 0
FreeAPS/Sources/Modules/Home/HomeViewModel.swift

@@ -7,5 +7,9 @@ extension Home {
         func runOpenAPS() {
             apsManager.runTest()
         }
+
+        func makeProfiles() {
+            apsManager.makeProfiles()
+        }
     }
 }

+ 8 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -13,10 +13,17 @@ extension Home {
                         .foregroundColor(.white)
                         .buttonBackground()
                 }
+                Button(action: viewModel.makeProfiles) {
+                    Text("Make profiles")
+                        .frame(maxWidth: .infinity)
+                        .foregroundColor(.white)
+                        .buttonBackground()
+                }
                 Spacer()
             }
             .padding()
-            .toolbar { ToolbarItem(placement: .principal) { Text("Home") } }
+            .navigationTitle("Home")
+            .navigationBarTitleDisplayMode(.automatic)
         }
     }
 }

+ 1 - 0
FreeAPS/Sources/Modules/Main/View/MainRootView.swift

@@ -8,6 +8,7 @@ extension Main {
             viewModel.view(for: viewModel.scene.screen)
                 .sheet(isPresented: $viewModel.isModalPresented) {
                     NavigationView { self.viewModel.modal!.view }
+                        .navigationViewStyle(StackNavigationViewStyle())
                 }
         }
     }

+ 1 - 2
FreeAPS/Sources/Modules/NightscoutConfig/View/NightscoutConfigRootView.swift

@@ -35,9 +35,8 @@ extension NightscoutConfig {
                     Button("Delete") { viewModel.delete() }.foregroundColor(.red).disabled(viewModel.connecting)
                 }
             }
-            .toolbar { ToolbarItem(placement: .principal) { Text("Nightscout Config") } }
+            .navigationBarTitle("Nightscout Config", displayMode: .automatic)
             .navigationBarItems(leading: Button("Close", action: viewModel.hideModal))
-            .navigationBarTitleDisplayMode(.inline)
         }
     }
 }

+ 30 - 6
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -6,13 +6,37 @@ extension Settings {
 
         var body: some View {
             Form {
-                Text("Preferences").modal(for: .configEditor(file: OpenAPS.Settings.preferences), from: self)
-                Text("Autosense").modal(for: .configEditor(file: OpenAPS.Settings.autosense), from: self)
-                Text("Pump History").modal(for: .configEditor(file: OpenAPS.Monitor.pumpHistory), from: self)
-                Text("Nightscout").modal(for: .nighscoutConfig, from: self)
-                Text("Pump").modal(for: .pumpConfig, from: self)
+                Section(header: Text("Config files")) {
+                    Group {
+                        Text("Preferences").chevronCell()
+                            .modal(for: .configEditor(file: OpenAPS.Settings.preferences), from: self)
+                        Text("Settings").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.settings), from: self)
+                        Text("Autosense").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.autosense), from: self)
+                        Text("Pump History").chevronCell()
+                            .modal(for: .configEditor(file: OpenAPS.Monitor.pumpHistory), from: self)
+                        Text("Basal profile").chevronCell()
+                            .modal(for: .configEditor(file: OpenAPS.Settings.basalProfile), from: self)
+                        Text("BG targets").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.bgTargets), from: self)
+                        Text("Carb ratios").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.carbRatios), from: self)
+                        Text("Insulin sensitivities").chevronCell()
+                            .modal(for: .configEditor(file: OpenAPS.Settings.carbRatios), from: self)
+                    }
+
+                    Text("Temp targets").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.tempTargets), from: self)
+                    Text("Pump profile").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.pumpProfile), from: self)
+                    Text("Profile").chevronCell().modal(for: .configEditor(file: OpenAPS.Settings.profile), from: self)
+                }
+
+                Section(header: Text("Services")) {
+                    Text("Nightscout").chevronCell().modal(for: .nighscoutConfig, from: self)
+                }
+
+                Section(header: Text("Devices")) {
+                    Text("Pump").chevronCell().modal(for: .pumpConfig, from: self)
+                }
             }
-            .toolbar { ToolbarItem(placement: .principal) { Text("Settings") } }
+            .navigationTitle("Settings")
+            .navigationBarTitleDisplayMode(.automatic)
         }
     }
 }

+ 2 - 2
FreeAPS/Sources/Services/Storage/FileStorage.swift

@@ -21,13 +21,13 @@ final class BaseFileStorage: FileStorage {
     private var encoder: JSONEncoder {
         let encoder = JSONEncoder()
         encoder.outputFormatting = .prettyPrinted
-        encoder.dateEncodingStrategy = .iso8601
+        encoder.dateEncodingStrategy = .customISO8601
         return encoder
     }
 
     private var decoder: JSONDecoder {
         let decoder = JSONDecoder()
-        decoder.dateDecodingStrategy = .iso8601
+        decoder.dateDecodingStrategy = .customISO8601
         return decoder
     }
 

+ 2 - 2
Templates/swift_pvvm/Code/View/RootView.swift.liquid

@@ -6,9 +6,9 @@ extension {{ module_info.name }} {
 
         var body: some View {
             Text("{{ module_info.name }} screen")
-            	.toolbar { ToolbarItem(placement: .principal) { Text("{{ module_info.name }}") } }
+            	.navigationTitle("{{ module_info.name }}")
+            	.navigationBarTitleDisplayMode(.automatic)
                 .navigationBarItems(leading: Button("Close", action: viewModel.hideModal))
-                .navigationBarTitleDisplayMode(.inline)
         }
     }
 }