Przeglądaj źródła

Merge pull request #370 from nightscout/contact-image-glucose-coloring

Fix Therapy Rate Hour Parsing; Fix Contact Image Glucose Color for mmol/L
Daniel Snällfot 1 rok temu
rodzic
commit
003130b8be

+ 4 - 4
Trio.xcodeproj/project.pbxproj

@@ -304,7 +304,6 @@
 		BD249D9D2D42FCF500412DEB /* MealStatsSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D9C2D42FCF300412DEB /* MealStatsSetup.swift */; };
 		BD249D9F2D42FD0600412DEB /* StackedChartSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D9E2D42FD0200412DEB /* StackedChartSetup.swift */; };
 		BD249DA12D42FD1200412DEB /* TDDSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249DA02D42FD1000412DEB /* TDDSetup.swift */; };
-		BD249DA52D42FD9700412DEB /* CustomDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249DA42D42FD9500412DEB /* CustomDatePicker.swift */; };
 		BD249DA72D42FE4600412DEB /* Calendar+GlucoseStatsChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249DA62D42FE3800412DEB /* Calendar+GlucoseStatsChart.swift */; };
 		BD2B464E0745FBE7B79913F4 /* NightscoutConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */; };
 		BD2FF1A02AE29D43005D1C5D /* CheckboxToggleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD2FF19F2AE29D43005D1C5D /* CheckboxToggleStyle.swift */; };
@@ -540,6 +539,7 @@
 		DDAA29852D2D1D9E006546A1 /* AdjustmentsRootView+TempTargets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAA29842D2D1D98006546A1 /* AdjustmentsRootView+TempTargets.swift */; };
 		DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC42D05048F00D99BF4 /* ContactImageStorage.swift */; };
 		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
+		DDCAE8332D78D4A800B1BB51 /* TherapySettingsUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCAE8322D78D49C00B1BB51 /* TherapySettingsUtil.swift */; };
 		DDCE790F2D6F97FC000A4D7A /* SubmodulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE790E2D6F97F7000A4D7A /* SubmodulesView.swift */; };
 		DDCEBF5B2CC1B76400DF4C36 /* LiveActivity+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */; };
 		DDD163122C4C689900CD525A /* AdjustmentsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163112C4C689900CD525A /* AdjustmentsStateModel.swift */; };
@@ -1028,7 +1028,6 @@
 		BD249D9C2D42FCF300412DEB /* MealStatsSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealStatsSetup.swift; sourceTree = "<group>"; };
 		BD249D9E2D42FD0200412DEB /* StackedChartSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackedChartSetup.swift; sourceTree = "<group>"; };
 		BD249DA02D42FD1000412DEB /* TDDSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDDSetup.swift; sourceTree = "<group>"; };
-		BD249DA42D42FD9500412DEB /* CustomDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomDatePicker.swift; sourceTree = "<group>"; };
 		BD249DA62D42FE3800412DEB /* Calendar+GlucoseStatsChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+GlucoseStatsChart.swift"; sourceTree = "<group>"; };
 		BD2FF19F2AE29D43005D1C5D /* CheckboxToggleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxToggleStyle.swift; sourceTree = "<group>"; };
 		BD3CC0712B0B89D50013189E /* MainChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainChartView.swift; sourceTree = "<group>"; };
@@ -1267,6 +1266,7 @@
 		DDB37CC32D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		DDB37CC42D05048F00D99BF4 /* ContactImageStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImageStorage.swift; sourceTree = "<group>"; };
 		DDB37CC62D05127500D99BF4 /* FontExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontExtensions.swift; sourceTree = "<group>"; };
+		DDCAE8322D78D49C00B1BB51 /* TherapySettingsUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettingsUtil.swift; sourceTree = "<group>"; };
 		DDCE790E2D6F97F7000A4D7A /* SubmodulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmodulesView.swift; sourceTree = "<group>"; };
 		DDCEBF5A2CC1B76400DF4C36 /* LiveActivity+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LiveActivity+Helper.swift"; sourceTree = "<group>"; };
 		DDD163112C4C689900CD525A /* AdjustmentsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjustmentsStateModel.swift; sourceTree = "<group>"; };
@@ -2154,8 +2154,8 @@
 		388E5A5A25B6F05F0019842D /* Helpers */ = {
 			isa = PBXGroup;
 			children = (
+				DDCAE8322D78D49C00B1BB51 /* TherapySettingsUtil.swift */,
 				BD249DA62D42FE3800412DEB /* Calendar+GlucoseStatsChart.swift */,
-				BD249DA42D42FD9500412DEB /* CustomDatePicker.swift */,
 				DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */,
 				CEF1ED6A2D58FB4600FAF41E /* CGMOptions.swift */,
 				C2A0A42E2CE0312C003B98E8 /* ConstantValues.swift */,
@@ -3708,7 +3708,6 @@
 				38AEE75225F022080013F05B /* SettingsManager.swift in Sources */,
 				3894873A2614928B004DF424 /* DispatchTimer.swift in Sources */,
 				3895E4C625B9E00D00214B37 /* Preferences.swift in Sources */,
-				BD249DA52D42FD9700412DEB /* CustomDatePicker.swift in Sources */,
 				CE94598429E9E3E60047C9C6 /* WatchConfigStateModel.swift in Sources */,
 				DD6B7CB92C7BAC6900B75029 /* NightscoutImportResultView.swift in Sources */,
 				38DF1786276A73D400B3528F /* TagCloudView.swift in Sources */,
@@ -4002,6 +4001,7 @@
 				DD9ECB712CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift in Sources */,
 				63E890B4D951EAA91C071D5C /* BasalProfileEditorStateModel.swift in Sources */,
 				38FEF3FA2737E42000574A46 /* BaseStateModel.swift in Sources */,
+				DDCAE8332D78D4A800B1BB51 /* TherapySettingsUtil.swift in Sources */,
 				BDA25EFD2D261C0000035F34 /* WatchState.swift in Sources */,
 				CC6C406E2ACDD69E009B8058 /* RawFetchedProfile.swift in Sources */,
 				385CEA8225F23DFD002D6D5B /* NightscoutStatus.swift in Sources */,

+ 0 - 56
Trio/Sources/Helpers/CustomDatePicker.swift

@@ -1,56 +0,0 @@
-import SwiftUI
-
-struct CustomDatePicker: UIViewRepresentable {
-    @Binding var selection: Date
-
-    // Coordinator to handle date changes
-    class Coordinator: NSObject {
-        var parent: CustomDatePicker
-
-        init(_ parent: CustomDatePicker) {
-            self.parent = parent
-        }
-
-        @objc func dateChanged(_ sender: UIDatePicker) {
-            let calendar = Calendar.current
-            // Set the time of the selected date to 23:59:59 for any selected date
-            if let adjustedDate = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: sender.date) {
-                parent.selection = adjustedDate
-            } else {
-                parent.selection = sender.date // Fallback in case something goes wrong
-            }
-        }
-    }
-
-    func makeUIView(context: Context) -> UIDatePicker {
-        let datePicker = UIDatePicker()
-        datePicker.datePickerMode = .date
-
-        // Calculate yesterday's date at 23:59:59
-        let today = Date()
-        let calendar = Calendar.current
-        if let yesterday = calendar.date(byAdding: .day, value: -1, to: today),
-           let adjustedYesterday = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: yesterday)
-        {
-            datePicker.maximumDate = adjustedYesterday // Set maximum date to yesterday at 23:59:59
-            datePicker.date = adjustedYesterday // Set default date to yesterday at 23:59:59
-        }
-
-        // Set up the date change action
-        datePicker.addTarget(context.coordinator, action: #selector(Coordinator.dateChanged(_:)), for: .valueChanged)
-
-        return datePicker
-    }
-
-    func updateUIView(_ uiView: UIDatePicker, context _: Context) {
-        // Ensure the displayed date is also adjusted to 23:59:59
-        let calendar = Calendar.current
-        if let adjustedDate = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: selection) {
-            uiView.date = adjustedDate
-        }
-    }
-
-    func makeCoordinator() -> Coordinator {
-        Coordinator(self)
-    }
-}

+ 21 - 0
Trio/Sources/Helpers/TherapySettingsUtil.swift

@@ -0,0 +1,21 @@
+import Foundation
+
+enum TherapySettingsUtil {
+    /// Parses a time string of therapy setting entry into a `Date` object using either "HH:mm:ss" or "HH:mm" formats.
+    /// This function ensures compatibility with time strings that may include or exclude seconds.
+    ///
+    /// - Parameter timeString: A string representing the time in "HH:mm:ss" or "HH:mm" format.
+    /// - Returns: A `Date` object set to today’s date with the extracted time, or `nil` if parsing fails.
+    static func parseTime(_ timeString: String) -> Date? {
+        let formats = ["HH:mm:ss", "HH:mm"]
+        for format in formats {
+            let formatter = DateFormatter()
+            formatter.dateFormat = format
+            formatter.timeZone = TimeZone.current
+            if let date = formatter.date(from: timeString) {
+                return date
+            }
+        }
+        return nil
+    }
+}

+ 1 - 1
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -171518,7 +171518,7 @@
         }
       }
     },
-    "This feature cannot be enabled unless Autosens Max > 100%." : {
+    "This feature cannot be enabled unless Algorithm Settings > Autosens > Autosens Max is set higher than 100%." : {
 
     },
     "This feature ensures more accurate insulin adjustments when carb entries are missing or incorrect." : {

+ 3 - 6
Trio/Sources/Modules/Home/HomeStateModel.swift

@@ -558,15 +558,12 @@ extension Home {
         private func getCurrentGlucoseTarget() async {
             let now = Date()
             let calendar = Calendar.current
-            let dateFormatter = DateFormatter()
-            dateFormatter.dateFormat = "HH:mm"
-            dateFormatter.timeZone = TimeZone.current
 
             let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
 
             for (index, entry) in entries.enumerated() {
-                guard let entryTime = dateFormatter.date(from: entry.start) else {
-                    print("Invalid entry start time: \(entry.start)")
+                guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                    debug(.default, "Invalid entry start time: \(entry.start)")
                     continue
                 }
 
@@ -580,7 +577,7 @@ extension Home {
 
                 let entryEndTime: Date
                 if index < entries.count - 1,
-                   let nextEntryTime = dateFormatter.date(from: entries[index + 1].start)
+                   let nextEntryTime = TherapySettingsUtil.parseTime(entries[index + 1].start)
                 {
                     let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                     entryEndTime = calendar.date(

+ 3 - 22
Trio/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -286,11 +286,6 @@ extension Treatments {
         private func getCurrentSettingValue(for type: SettingType) async {
             let now = Date()
             let calendar = Calendar.current
-            let dateFormatter = DateFormatter()
-            dateFormatter.timeZone = TimeZone.current
-
-            let regexWithSeconds = #"^\d{2}:\d{2}:\d{2}$"#
-
             let entries: [(start: String, value: Decimal)]
 
             switch type {
@@ -309,15 +304,8 @@ extension Treatments {
             }
 
             for (index, entry) in entries.enumerated() {
-                // Dynamically set the format based on whether it matches the regex
-                if entry.start.range(of: regexWithSeconds, options: .regularExpression) != nil {
-                    dateFormatter.dateFormat = "HH:mm:ss"
-                } else {
-                    dateFormatter.dateFormat = "HH:mm"
-                }
-
-                guard let entryTime = dateFormatter.date(from: entry.start) else {
-                    print("Invalid entry start time: \(entry.start)")
+                guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                    debug(.default, "Invalid entry start time: \(entry.start)")
                     continue
                 }
 
@@ -331,14 +319,7 @@ extension Treatments {
 
                 let entryEndTime: Date
                 if index < entries.count - 1 {
-                    // Dynamically set the format again for the next element
-                    if entries[index + 1].start.range(of: regexWithSeconds, options: .regularExpression) != nil {
-                        dateFormatter.dateFormat = "HH:mm:ss"
-                    } else {
-                        dateFormatter.dateFormat = "HH:mm"
-                    }
-
-                    if let nextEntryTime = dateFormatter.date(from: entries[index + 1].start) {
+                    if let nextEntryTime = TherapySettingsUtil.parseTime(entries[index + 1].start) {
                         let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                         entryEndTime = calendar.date(
                             bySettingHour: nextEntryComponents.hour!,

+ 3 - 22
Trio/Sources/Services/BolusCalculator/BolusCalculationManager.swift

@@ -71,11 +71,6 @@ final class BaseBolusCalculationManager: BolusCalculationManager, Injectable {
     private func getCurrentSettingValue(for type: SettingType) async -> Decimal {
         let now = Date()
         let calendar = Calendar.current
-        let dateFormatter = DateFormatter()
-        dateFormatter.timeZone = TimeZone.current
-
-        let regexWithSeconds = #"^\d{2}:\d{2}:\d{2}$"#
-
         let entries: [(start: String, value: Decimal)]
 
         switch type {
@@ -94,15 +89,8 @@ final class BaseBolusCalculationManager: BolusCalculationManager, Injectable {
         }
 
         for (index, entry) in entries.enumerated() {
-            // Dynamically set the format based on whether it matches the regex
-            if entry.start.range(of: regexWithSeconds, options: .regularExpression) != nil {
-                dateFormatter.dateFormat = "HH:mm:ss"
-            } else {
-                dateFormatter.dateFormat = "HH:mm"
-            }
-
-            guard let entryTime = dateFormatter.date(from: entry.start) else {
-                print("Invalid entry start time: \(entry.start)")
+            guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                debug(.default, "Invalid entry start time: \(entry.start)")
                 continue
             }
 
@@ -116,14 +104,7 @@ final class BaseBolusCalculationManager: BolusCalculationManager, Injectable {
 
             let entryEndTime: Date
             if index < entries.count - 1 {
-                // Dynamically set the format again for the next element
-                if entries[index + 1].start.range(of: regexWithSeconds, options: .regularExpression) != nil {
-                    dateFormatter.dateFormat = "HH:mm:ss"
-                } else {
-                    dateFormatter.dateFormat = "HH:mm"
-                }
-
-                if let nextEntryTime = dateFormatter.date(from: entries[index + 1].start) {
+                if let nextEntryTime = TherapySettingsUtil.parseTime(entries[index + 1].start) {
                     let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                     entryEndTime = calendar.date(
                         bySettingHour: nextEntryComponents.hour!,

+ 9 - 14
Trio/Sources/Services/ContactImage/ContactImageManager.swift

@@ -129,33 +129,29 @@ final class BaseContactImageManager: NSObject, ContactImageManager, Injectable {
     private func getCurrentGlucoseTarget() async -> Decimal? {
         let now = Date()
         let calendar = Calendar.current
-        let dateFormatter = DateFormatter()
-        dateFormatter.dateFormat = "HH:mm"
-        dateFormatter.timeZone = TimeZone.current
 
         let bgTargets = await fileStorage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
             ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
             ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
-        let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
+        let entries: [(start: String, value: Decimal)] = bgTargets.targets
+            .map { ($0.start.trimmingCharacters(in: .whitespacesAndNewlines), $0.low) }
 
         for (index, entry) in entries.enumerated() {
-            guard let entryTime = dateFormatter.date(from: entry.start) else {
-                print("Invalid entry start time: \(entry.start)")
+            guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                debug(.default, "Invalid entry start time: \(entry.start)")
                 continue
             }
 
             let entryComponents = calendar.dateComponents([.hour, .minute, .second], from: entryTime)
-            let entryStartTime = calendar.date(
+            guard let entryStartTime = calendar.date(
                 bySettingHour: entryComponents.hour!,
                 minute: entryComponents.minute!,
                 second: entryComponents.second!,
                 of: now
-            )!
+            ) else { continue }
 
             let entryEndTime: Date
-            if index < entries.count - 1,
-               let nextEntryTime = dateFormatter.date(from: entries[index + 1].start)
-            {
+            if index < entries.count - 1, let nextEntryTime = TherapySettingsUtil.parseTime(entries[index + 1].start) {
                 let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                 entryEndTime = calendar.date(
                     bySettingHour: nextEntryComponents.hour!,
@@ -239,12 +235,11 @@ final class BaseContactImageManager: NSObject, ContactImageManager, Injectable {
             let isDynamicColorScheme = settingsManager.settings.glucoseColorScheme == .dynamicColor
             let highGlucoseColorValue = isDynamicColorScheme ? hardCodedHigh : settingsManager.settings.highGlucose
             let lowGlucoseColorValue = isDynamicColorScheme ? hardCodedLow : settingsManager.settings.lowGlucose
+            let fetchedTarget = await getCurrentGlucoseTarget() // ⚠️ this value is mg/dL
 
             state.highGlucoseColorValue = units == .mgdL ? highGlucoseColorValue : highGlucoseColorValue.asMmolL
             state.lowGlucoseColorValue = units == .mgdL ? lowGlucoseColorValue : lowGlucoseColorValue.asMmolL
-            state
-                .targetGlucose = await getCurrentGlucoseTarget() ??
-                (settingsManager.settings.units == .mgdL ? Decimal(100) : 100.asMmolL)
+            state.targetGlucose = units == .mgdL ? fetchedTarget ?? Decimal(100) : fetchedTarget?.asMmolL ?? 100.asMmolL
             state.glucoseColorScheme = settingsManager.settings.glucoseColorScheme
 
             // Notify delegate about state update on main thread

+ 3 - 6
Trio/Sources/Services/Network/TidepoolManager.swift

@@ -540,9 +540,6 @@ extension BaseTidepoolManager {
     private func getCurrentBasalRate() -> BasalProfileEntry? {
         let now = Date()
         let calendar = Calendar.current
-        let dateFormatter = DateFormatter()
-        dateFormatter.dateFormat = "HH:mm"
-        dateFormatter.timeZone = TimeZone.current
 
         let basalEntries = storage.retrieve(OpenAPS.Settings.basalProfile, as: [BasalProfileEntry].self)
             ?? [BasalProfileEntry](from: OpenAPS.defaults(for: OpenAPS.Settings.basalProfile))
@@ -551,8 +548,8 @@ extension BaseTidepoolManager {
         var currentRate: BasalProfileEntry = basalEntries[0]
 
         for (index, entry) in basalEntries.enumerated() {
-            guard let entryTime = dateFormatter.date(from: entry.start) else {
-                print("Invalid entry start time: \(entry.start)")
+            guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                debug(.default, "Invalid entry start time: \(entry.start)")
                 continue
             }
 
@@ -566,7 +563,7 @@ extension BaseTidepoolManager {
 
             let entryEndTime: Date
             if index < basalEntries.count - 1,
-               let nextEntryTime = dateFormatter.date(from: basalEntries[index + 1].start)
+               let nextEntryTime = TherapySettingsUtil.parseTime(basalEntries[index + 1].start)
             {
                 let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                 entryEndTime = calendar.date(

+ 3 - 6
Trio/Sources/Services/WatchManager/AppleWatchManager.swift

@@ -1043,9 +1043,6 @@ extension BaseWatchManager {
     private func getCurrentGlucoseTarget() async -> Decimal? {
         let now = Date()
         let calendar = Calendar.current
-        let dateFormatter = DateFormatter()
-        dateFormatter.dateFormat = "HH:mm"
-        dateFormatter.timeZone = TimeZone.current
 
         let bgTargets = await fileStorage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
             ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
@@ -1053,8 +1050,8 @@ extension BaseWatchManager {
         let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
 
         for (index, entry) in entries.enumerated() {
-            guard let entryTime = dateFormatter.date(from: entry.start) else {
-                print("Invalid entry start time: \(entry.start)")
+            guard let entryTime = TherapySettingsUtil.parseTime(entry.start) else {
+                debug(.default, "Invalid entry start time: \(entry.start)")
                 continue
             }
 
@@ -1068,7 +1065,7 @@ extension BaseWatchManager {
 
             let entryEndTime: Date
             if index < entries.count - 1,
-               let nextEntryTime = dateFormatter.date(from: entries[index + 1].start)
+               let nextEntryTime = TherapySettingsUtil.parseTime(entries[index + 1].start)
             {
                 let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime)
                 entryEndTime = calendar.date(