diff --git a/nightguard Complication/nightguard_Complication.swift b/nightguard Complication/nightguard_Complication.swift index 37a9f71..1375a5e 100644 --- a/nightguard Complication/nightguard_Complication.swift +++ b/nightguard Complication/nightguard_Complication.swift @@ -10,6 +10,20 @@ import WidgetKit import SwiftUI import Intents +extension View { + + func widgetBackground(backgroundView: some View) -> some View { + if #available(watchOS 10.0, *) { + return containerBackground(for: .widget) { + backgroundView + } + } else { + return background(backgroundView) + } + } + +} + @main struct NightguardWidgetsBundle: WidgetBundle { var body: some Widget { @@ -70,21 +84,27 @@ struct nightguard_Complication_Extension_Previews: PreviewProvider { static var previews: some View { NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) + .previewDisplayName("Acc_Rect") NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryInline)) + .previewDisplayName("Acc_Inline") NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryCorner)) + .previewDisplayName("Acc_Corner") NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) + .previewDisplayName("Acc_Circ") NightguardGaugeEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryCorner)) + .previewDisplayName("Gauge_Acc_Corner") NightguardGaugeEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) + .previewDisplayName("Gauge_Acc_Circ") } } @@ -97,12 +117,15 @@ struct NightguardEntryView : View { switch widgetFamily { case .accessoryCorner: AccessoryCornerView(entry: entry) + .widgetBackground(backgroundView: background()) case .accessoryCircular: AccessoryCircularView(entry: entry) + .widgetBackground(backgroundView: background()) case .accessoryInline: AccessoryInlineView(entry: entry) case .accessoryRectangular: AccessoryRectangularView(entry: entry) + .widgetBackground(backgroundView: background()) @unknown default: //mandatory as there are more widget families as in lockscreen widgets etc Text(NSLocalizedString("Not an implemented widget yet", comment: "Gauge Widget Not Implemented Error Message")) @@ -119,8 +142,10 @@ struct NightguardGaugeEntryView : View { switch widgetFamily { case .accessoryCorner: AccessoryCornerGaugeView(entry: entry) + .widgetBackground(backgroundView: background()) case .accessoryCircular: AccessoryCircularGaugeView(entry: entry) + .widgetBackground(backgroundView: background()) default: //mandatory as there are more widget families as in lockscreen widgets etc Text(NSLocalizedString("No Gauge Support for this widget!", comment: "Gauge Widget Not Supported Error Message")) @@ -128,19 +153,19 @@ struct NightguardGaugeEntryView : View { } } -struct NightguardGaugePreviews: PreviewProvider { - static var previews: some View { - - NightguardEntryView(entry: NightscoutDataEntry.previewValues) - .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) - - NightguardEntryView(entry: NightscoutDataEntry.previewValues) - .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - - NightguardEntryView(entry: NightscoutDataEntry.previewValues) - .previewContext(WidgetPreviewContext(family: .accessoryCorner)) - - NightguardEntryView(entry: NightscoutDataEntry.previewValues) - .previewContext(WidgetPreviewContext(family: .accessoryInline)) - } -} +//struct NightguardGaugePreviews: PreviewProvider { +// static var previews: some View { +// +// NightguardEntryView(entry: NightscoutDataEntry.previewValues) +// .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) +// +// NightguardEntryView(entry: NightscoutDataEntry.previewValues) +// .previewContext(WidgetPreviewContext(family: .accessoryCircular)) +// +// NightguardEntryView(entry: NightscoutDataEntry.previewValues) +// .previewContext(WidgetPreviewContext(family: .accessoryCorner)) +// +// NightguardEntryView(entry: NightscoutDataEntry.previewValues) +// .previewContext(WidgetPreviewContext(family: .accessoryInline)) +// } +//} diff --git a/nightguard WatchKit App/ExtensionDelegate.swift b/nightguard WatchKit App/ExtensionDelegate.swift index d116148..2a6b68d 100644 --- a/nightguard WatchKit App/ExtensionDelegate.swift +++ b/nightguard WatchKit App/ExtensionDelegate.swift @@ -113,6 +113,11 @@ class ExtensionDelegate: NSObject, WKApplicationDelegate { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. AppState.isUIActive = true } + + func applicationWillEnterForeground() { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + NotificationCenter.default.post(name: .refreshDataOnAppBecameActive, object: nil) + } func applicationWillResignActive() { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. diff --git a/nightguard WatchKit App/NotificationExtension.swift b/nightguard WatchKit App/NotificationExtension.swift new file mode 100644 index 0000000..8c8da10 --- /dev/null +++ b/nightguard WatchKit App/NotificationExtension.swift @@ -0,0 +1,12 @@ +// +// NotificationExtension.swift +// nightguard WatchKit App +// +// Created by Philipp Pöml on 29.05.24. +// + +import Foundation + +extension Notification.Name { + static let refreshDataOnAppBecameActive = Notification.Name("Updates data on wrist raise") +} diff --git a/nightguard WatchKit App/views/MainView.swift b/nightguard WatchKit App/views/MainView.swift index 3d23603..c78dc4e 100644 --- a/nightguard WatchKit App/views/MainView.swift +++ b/nightguard WatchKit App/views/MainView.swift @@ -17,6 +17,7 @@ struct MainView: View { // update the ui every 15 seconds: let timer = Timer.publish(every: 15, on: .current, in: .common).autoconnect() + let refreshDataOnAppBecameActiveNotification = NotificationCenter.default.publisher(for: .refreshDataOnAppBecameActive) @ObservedObject var viewModel: MainViewModel @@ -201,6 +202,9 @@ struct MainView: View { .onReceive(timer) { _ in viewModel.refreshData(forceRefresh: false, moveToLatestValue: false) } + .onReceive(refreshDataOnAppBecameActiveNotification) { _ in + viewModel.refreshData(forceRefresh: false, moveToLatestValue: false) + } //} } diff --git a/nightguard Widget Extension/AccessoryCircularGaugeView.swift b/nightguard Widget Extension/AccessoryCircularGaugeView.swift index 76712c2..7ef773f 100644 --- a/nightguard Widget Extension/AccessoryCircularGaugeView.swift +++ b/nightguard Widget Extension/AccessoryCircularGaugeView.swift @@ -15,27 +15,29 @@ struct AccessoryCircularGaugeView : View { var entry: NightscoutDataEntry var body: some View { - - Gauge(value: Double( - calculateAgeInMinutes( - fromDouble: entry.lastBGValues.first?.timestamp ?? Date.now.timeIntervalSinceNow - 3600)) ?? 60, - in: 0...60) { - Text("\(entry.lastBGValues.first?.delta ?? "?")") - .foregroundColor( - Color(UIColorChanger.getDeltaLabelColor( - Float(entry.lastBGValues.first?.delta ?? "99") ?? 99))) - } currentValueLabel: { - Text(entry.lastBGValues.first?.value ?? "??") - .foregroundColor( - Color(UIColorChanger.getBgColor(entry.lastBGValues.first?.value ?? "999"))) + ZStack { + AccessoryWidgetBackground() + Gauge(value: Double( + calculateAgeInMinutes( + fromDouble: entry.lastBGValues.first?.timestamp ?? Date.now.timeIntervalSinceNow - 3600)) ?? 60, + in: 0...60) { + Text("\(entry.lastBGValues.first?.delta ?? "?")") + .foregroundColor( + Color(UIColorChanger.getDeltaLabelColor( + Float(entry.lastBGValues.first?.delta ?? "99") ?? 99))) + } currentValueLabel: { + Text(entry.lastBGValues.first?.value ?? "??") + .foregroundColor( + Color(UIColorChanger.getBgColor(entry.lastBGValues.first?.value ?? "999"))) + } + .tint( + Color(UIColorChanger.getTimeLabelColor( + fromDouble: entry.lastBGValues.first?.timestamp ?? Date().timeIntervalSinceNow - 3600))) + + .gaugeStyle(.accessoryCircular) + .widgetAccentable(true) + .unredacted() } - .tint( - Color(UIColorChanger.getTimeLabelColor( - fromDouble: entry.lastBGValues.first?.timestamp ?? Date().timeIntervalSinceNow - 3600))) - - .gaugeStyle(.accessoryCircular) - .widgetAccentable(true) - .unredacted() } } diff --git a/nightguard Widget Extension/AccessoryCircularView.swift b/nightguard Widget Extension/AccessoryCircularView.swift index 7ed0db7..0e52690 100644 --- a/nightguard Widget Extension/AccessoryCircularView.swift +++ b/nightguard Widget Extension/AccessoryCircularView.swift @@ -15,15 +15,20 @@ struct AccessoryCircularView : View { var entry: NightscoutDataEntry var body: some View { - Text("\(calculateAgeInMinutes(fromDouble: entry.lastBGValues.first?.timestamp ?? Date.now.timeIntervalSinceNow-3600))m") - Text("\(entry.lastBGValues.first?.value ?? "??")") - .foregroundColor( - Color(UIColorChanger.getBgColor(entry.lastBGValues.first?.value ?? "999"))) - Text("\(entry.lastBGValues.first?.delta ?? "?")") - .foregroundColor( - Color(UIColorChanger.getDeltaLabelColor(Float(entry.lastBGValues.first?.delta ?? "99") ?? 99.0))) - .widgetAccentable(true) - .unredacted() + ZStack { + AccessoryWidgetBackground() + VStack { + Text("\(calculateAgeInMinutes(fromDouble: entry.lastBGValues.first?.timestamp ?? Date.now.timeIntervalSinceNow-3600))m") + Text("\(entry.lastBGValues.first?.value ?? "??")") + .foregroundColor( + Color(UIColorChanger.getBgColor(entry.lastBGValues.first?.value ?? "999"))) + Text("\(entry.lastBGValues.first?.delta ?? "?")") + .foregroundColor( + Color(UIColorChanger.getDeltaLabelColor(Float(entry.lastBGValues.first?.delta ?? "99") ?? 99.0))) + .widgetAccentable(true) + .unredacted() + } + } } } diff --git a/nightguard Widget Extension/AccessoryInlineView.swift b/nightguard Widget Extension/AccessoryInlineView.swift index 1458468..5fe0ffb 100644 --- a/nightguard Widget Extension/AccessoryInlineView.swift +++ b/nightguard Widget Extension/AccessoryInlineView.swift @@ -15,6 +15,7 @@ struct AccessoryInlineView : View { var entry: NightscoutDataEntry var body: some View { + //AccessoryWidgetBackground() not supported in this Widget Family Text("| \(Date(timeIntervalSince1970:entry.lastBGValues.first?.timestamp ?? (Date.now.timeIntervalSinceNow - 3600) / 1000).toLocalTimeString()) " + "\(entry.lastBGValues.first?.value ?? "?")\(entry.lastBGValues.first?.delta ?? "?")") .widgetAccentable(true) .unredacted() diff --git a/nightguard Widget Extension/AccessoryRectangularView.swift b/nightguard Widget Extension/AccessoryRectangularView.swift index 698ab9b..d3afb0e 100644 --- a/nightguard Widget Extension/AccessoryRectangularView.swift +++ b/nightguard Widget Extension/AccessoryRectangularView.swift @@ -15,34 +15,58 @@ struct AccessoryRectangularView : View { var entry: NightscoutDataEntry var body: some View { - VStack { - HStack { - VStack { - ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in - Text("\(calculateAgeInMinutes(from:NSNumber(value: bgEntry.timestamp)))m") - .foregroundColor(Color(entry.sgvColor)) - .frame(maxWidth: .infinity, alignment: .trailing) - } - } - VStack { - ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in - Text("\(String(bgEntry.value)) \(bgEntry.delta)") - .foregroundColor(Color(entry.sgvColor)) - .frame(maxWidth: .infinity, alignment: .leading) + ZStack { + //No background on watch +#if os(iOS) + AccessoryWidgetBackground() + .clipShape(RoundedRectangle(cornerRadius: 10)) +#endif + VStack { + HStack { + VStack { + ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in + //Text("\(calculateAgeInMinutes(from:NSNumber(value: bgEntry.timestamp)))m") + if (entry.lastBGValues.first?.id == bgEntry.id) { + Text(Date.now.addingTimeInterval(-(Date.now.timeIntervalSince1970 - (bgEntry.timestamp / 1000))), style: .timer) + //iOS accessory widgets are b/w... +#if os(watchOS) + .foregroundColor(Color(entry.sgvColor)) +#endif + .frame(maxWidth: .infinity, alignment: .trailing) + .monospacedDigit() + .multilineTextAlignment(.trailing) + } else { + Text("+\(calculateAgeInMinutes(from:NSNumber(value: Date.now.timeIntervalSince1970 * 1000 + bgEntry.timestamp - (entry.lastBGValues.first?.timestamp ?? 0))))m") +#if os(watchOS) + .foregroundColor(Color(entry.sgvColor)) +#endif + .frame(maxWidth: .infinity, alignment: .trailing) + } + } } - } - if entry.lastBGValues.isEmpty { VStack { - Text("--- --- ---") + ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in + // Text("\(String(bgEntry.value)) \(bgEntry.delta)") + Text("\(String(bgEntry.value)) \(bgEntry.delta) \(bgEntry.arrow)") +#if os(watchOS) + .foregroundColor(Color(entry.sgvColor)) +#endif + .frame(maxWidth: .infinity, alignment: .leading) + } + } + if entry.lastBGValues.isEmpty { + VStack { + Text("--- --- ---") + } } } + if !entry.errorMessage.isEmpty { + Text("\(entry.errorMessage)") + .font(.system(size: 6)) + } + //Text(entry.entryDate, style: .time) + //Text("\(snoozedForMinutes(snoozeTimestamp: entry.snoozedUntilTimestamp))min Snoozed") } - if !entry.errorMessage.isEmpty { - Text("\(entry.errorMessage)") - .font(.system(size: 6)) - } - Text(entry.entryDate, style: .time) - //Text("\(snoozedForMinutes(snoozeTimestamp: entry.snoozedUntilTimestamp))min Snoozed") } .widgetAccentable(true) .unredacted() diff --git a/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Contents.json b/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Contents.json new file mode 100644 index 0000000..192829c --- /dev/null +++ b/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon-small-black@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Icon-small-black@3x.png b/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Icon-small-black@3x.png new file mode 100644 index 0000000..9a33424 Binary files /dev/null and b/nightguard Widget Extension/Assets.xcassets/WidgetImageBlack.imageset/Icon-small-black@3x.png differ diff --git a/nightguard Widget Extension/NightguardTimelineProvider.swift b/nightguard Widget Extension/NightguardTimelineProvider.swift index f95d839..790a74a 100644 --- a/nightguard Widget Extension/NightguardTimelineProvider.swift +++ b/nightguard Widget Extension/NightguardTimelineProvider.swift @@ -76,14 +76,14 @@ struct NightguardTimelineProvider: TimelineProvider { return BgEntry( value: UnitsConverter.mgdlToDisplayUnits(String(bgValue.value)), valueColor: UIColorChanger.getBgColor(String(bgValue.value)), - delta: "0", timestamp: bgValue.timestamp) + delta: "0", timestamp: bgValue.timestamp, arrow: bgValue.arrow) } } else if case .error(let error) = result { bgEntries = oldEntries.map() {bgValue in return BgEntry( value: UnitsConverter.mgdlToDisplayUnits(String(bgValue.value)), valueColor: UIColorChanger.getBgColor(String(bgValue.value)), - delta: "0", timestamp: bgValue.timestamp) + delta: "0", timestamp: bgValue.timestamp, arrow: bgValue.arrow) } errorMessage = error.localizedDescription } else { @@ -92,7 +92,7 @@ struct NightguardTimelineProvider: TimelineProvider { return BgEntry( value: UnitsConverter.mgdlToDisplayUnits(String(bgValue.value)), valueColor: UIColorChanger.getBgColor(String(bgValue.value)), - delta: "0", timestamp: bgValue.timestamp) + delta: "0", timestamp: bgValue.timestamp, arrow: bgValue.arrow) } } @@ -166,7 +166,7 @@ struct NightguardTimelineProvider: TimelineProvider { value: bgEntry.value, valueColor: UIColorChanger.getBgColor(bgEntry.value), delta: Float(v1AsFloat - v2AsFloat).cleanSignedValue, - timestamp: bgEntry.timestamp) + timestamp: bgEntry.timestamp, arrow: bgEntry.arrow) newEntries.append(newEntry) } preceedingEntry = bgEntry diff --git a/nightguard Widget Extension/NightscoutDataEntry.swift b/nightguard Widget Extension/NightscoutDataEntry.swift index 7631d38..225c178 100644 --- a/nightguard Widget Extension/NightscoutDataEntry.swift +++ b/nightguard Widget Extension/NightscoutDataEntry.swift @@ -78,9 +78,9 @@ struct NightscoutDataEntry: TimelineEntry { snoozedUntilTimestamp: 0, lastBGValues: [ - BgEntry(value: "100", valueColor: UIColor.nightguardGreen(), delta: "+2", timestamp: Date.now.timeIntervalSince1970 * 1000 - 120*1000), - BgEntry(value: "98", valueColor: UIColor.nightguardGreen(), delta: "-3", timestamp: (Date.now.timeIntervalSince1970 * 1000) - (60*5*1000)), - BgEntry(value: "101", valueColor: UIColor.nightguardGreen(), delta: "+2", timestamp: (Date.now.timeIntervalSince1970 * 1000) - (60*10*1000)) + BgEntry(value: "100", valueColor: UIColor.nightguardGreen(), delta: "+2", timestamp: Date.now.timeIntervalSince1970 * 1000 - 120*1000, arrow: "-"), + BgEntry(value: "98", valueColor: UIColor.nightguardGreen(), delta: "-3", timestamp: (Date.now.timeIntervalSince1970 * 1000) - (60*5*1000), arrow: "-"), + BgEntry(value: "101", valueColor: UIColor.nightguardGreen(), delta: "+2", timestamp: (Date.now.timeIntervalSince1970 * 1000) - (60*10*1000), arrow: "-") ], configuration: ConfigurationIntent()) } @@ -92,4 +92,5 @@ struct BgEntry : Identifiable, Hashable { let valueColor: UIColor let delta: String let timestamp: Double + let arrow: String } diff --git a/nightguard Widget Extension/SystemSmallView.swift b/nightguard Widget Extension/SystemSmallView.swift new file mode 100644 index 0000000..f439e26 --- /dev/null +++ b/nightguard Widget Extension/SystemSmallView.swift @@ -0,0 +1,73 @@ +// +// SystemSmallView.swift +// nightguard Widget Extension +// +// Created by Philipp Pöml on 26.05.24. +// + +import Foundation +import SwiftUI +import WidgetKit + +struct SystemSmallView : View { + + var entry: NightscoutDataEntry + + var body: some View { + VStack { + Image ("WidgetImageBlack") + .resizable() + .aspectRatio(contentMode: .fit) + HStack { + VStack { + ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in + //Text("\(calculateAgeInMinutes(from:NSNumber(value: bgEntry.timestamp)))m") + if (entry.lastBGValues.first?.id == bgEntry.id) { + Text(Date.now.addingTimeInterval(-(Date.now.timeIntervalSince1970 - (bgEntry.timestamp / 1000))), style: .timer) + .foregroundColor(Color(entry.sgvColor)) + .frame(maxWidth: .infinity, alignment: .trailing) + .monospacedDigit() + .multilineTextAlignment(.trailing) + } else { + Text("+\(calculateAgeInMinutes(from:NSNumber(value: Date.now.timeIntervalSince1970 * 1000 + bgEntry.timestamp - (entry.lastBGValues.first?.timestamp ?? 0))))m") + .foregroundColor(Color(entry.sgvColor)) + .frame(maxWidth: .infinity, alignment: .trailing) + } + } + } + .padding(.trailing, 20) + VStack { + ForEach(entry.lastBGValues, id: \.self.id) { bgEntry in + //Text("\(String(bgEntry.value)) \(bgEntry.delta)") + Text("\(String(bgEntry.value)) \(bgEntry.delta) \(bgEntry.arrow)") + .foregroundColor(Color(entry.sgvColor)) + .frame(maxWidth: .infinity, alignment: .leading) + } + .padding(.leading, -20) + } + if entry.lastBGValues.isEmpty { + VStack { + Text("--- --- ---") + } + } + } + if !entry.errorMessage.isEmpty { + Text("\(entry.errorMessage)") + .font(.system(size: 6)) + } + //Text(entry.entryDate, style: .time) + //Text("\(snoozedForMinutes(snoozeTimestamp: entry.snoozedUntilTimestamp))min Snoozed") + } + .widgetAccentable(true) + .unredacted() + } + + func snoozedForMinutes(snoozeTimestamp: TimeInterval) -> Int { + let currentTimestamp = Date().timeIntervalSince1970 + let snoozedMinutes = Int((snoozeTimestamp - currentTimestamp) / 60) + if snoozedMinutes < 0 { + return 0 + } + return snoozedMinutes + } +} diff --git a/nightguard Widget Extension/nightguard_Widget_Extension.swift b/nightguard Widget Extension/nightguard_Widget_Extension.swift index 1420126..0bd36d0 100644 --- a/nightguard Widget Extension/nightguard_Widget_Extension.swift +++ b/nightguard Widget Extension/nightguard_Widget_Extension.swift @@ -10,6 +10,19 @@ import WidgetKit import SwiftUI import Intents +extension View { + + func widgetBackground(backgroundView: some View) -> some View { + if #available(iOS 17.0, *) { + return containerBackground(for: .widget) { + backgroundView + } + } else { + return background(backgroundView) + } + } +} + @main struct NightguardWidgetsBundle: WidgetBundle { var body: some Widget { @@ -34,6 +47,7 @@ struct NightguardDefaultWidgets: Widget { NSLocalizedString("BG Values as Text", comment: "Widget Configuration Display Name")) .description(provider.displayName) .supportedFamilies([ + .systemSmall, .accessoryInline, .accessoryCircular, .accessoryRectangular, @@ -69,13 +83,17 @@ struct NightguardEntryView : View { var body: some View { switch widgetFamily { + case .systemSmall: + SystemSmallView(entry: entry) + .widgetBackground(backgroundView: Color.black) case .accessoryCircular: AccessoryCircularView(entry: entry) + .widgetBackground(backgroundView: background()) case .accessoryInline: AccessoryInlineView(entry: entry) case .accessoryRectangular: AccessoryRectangularView(entry: entry) - + .widgetBackground(backgroundView: EmptyView()) default: //mandatory as there are more widget families as in lockscreen widgets etc Text( @@ -93,7 +111,7 @@ struct NightguardGaugeEntryView : View { switch widgetFamily { case .accessoryCircular: AccessoryCircularGaugeView(entry: entry) - + .widgetBackground(backgroundView: background()) default: //mandatory as there are more widget families as in lockscreen widgets etc Text(NSLocalizedString("No Gauge Support for this widget!", comment: "Gauge Widget Not Supported Error Message")) @@ -104,6 +122,9 @@ struct NightguardGaugeEntryView : View { struct nightguard_Widget_Extension_Previews: PreviewProvider { static var previews: some View { + NightguardEntryView(entry: NightscoutDataEntry.previewValues) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + .previewDisplayName("SysSmall") NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryInline)) @@ -115,7 +136,7 @@ struct nightguard_Widget_Extension_Previews: PreviewProvider { NightguardGaugeEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) - .previewDisplayName("Circular") + .previewDisplayName("CircularGauge") NightguardEntryView(entry: NightscoutDataEntry.previewValues) .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) diff --git a/nightguard.xcodeproj/project.pbxproj b/nightguard.xcodeproj/project.pbxproj index 995bb8b..3a5567e 100644 --- a/nightguard.xcodeproj/project.pbxproj +++ b/nightguard.xcodeproj/project.pbxproj @@ -348,6 +348,8 @@ 43F1E11B1D076D9700C329A2 /* TimeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F1E11A1D076D9700C329A2 /* TimeService.swift */; }; 43FCE625208B80840080DA0A /* SnoozeAlarmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FCE624208B80840080DA0A /* SnoozeAlarmViewController.swift */; }; 4BD05B7C2B1E33F700A74E9B /* DateExtensionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD05B7B2B1E33F700A74E9B /* DateExtensionTest.swift */; }; + 7B4E31F42C2379C4005090CB /* NotificationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4E31F32C2379C4005090CB /* NotificationExtension.swift */; }; + 7B4E31F62C237F14005090CB /* SystemSmallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4E31F52C237F14005090CB /* SystemSmallView.swift */; }; 7FCFB7190EB96C437CD9908C /* Pods_nightguard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5F5A4E6048F7A6F26B9C31E /* Pods_nightguard.framework */; }; BD9486CCE1790AB9D245579D /* Pods_nightguard_Widget_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5AA741119F937A9FEA0FE16 /* Pods_nightguard_Widget_Extension.framework */; }; C21FEAA8173DC84337CC0E33 /* Pods_nightguard_WatchKit_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A960E5B86E46012C3B88556F /* Pods_nightguard_WatchKit_App.framework */; }; @@ -710,6 +712,8 @@ 4BD05B7B2B1E33F700A74E9B /* DateExtensionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtensionTest.swift; sourceTree = ""; }; 5560CB94CC76B8F0F7F5C440 /* Pods-nightguardTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightguardTests.release.xcconfig"; path = "Target Support Files/Pods-nightguardTests/Pods-nightguardTests.release.xcconfig"; sourceTree = ""; }; 77D200A6D5933D628408130C /* Pods_nightguardUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_nightguardUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7B4E31F32C2379C4005090CB /* NotificationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExtension.swift; sourceTree = ""; }; + 7B4E31F52C237F14005090CB /* SystemSmallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemSmallView.swift; sourceTree = ""; }; 89358A3E8C5372AE643A47B4 /* Pods-nightguard.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightguard.debug.xcconfig"; path = "Target Support Files/Pods-nightguard/Pods-nightguard.debug.xcconfig"; sourceTree = ""; }; A4F222974AF5F9228A291DD7 /* Pods-nightguard ComplicationExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightguard ComplicationExtension.debug.xcconfig"; path = "Target Support Files/Pods-nightguard ComplicationExtension/Pods-nightguard ComplicationExtension.debug.xcconfig"; sourceTree = ""; }; A960E5B86E46012C3B88556F /* Pods_nightguard_WatchKit_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_nightguard_WatchKit_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -991,6 +995,7 @@ 43647BF71BFF6435004389F9 /* Interface.storyboard */, 43647BFC1BFF6435004389F9 /* Info.plist */, 435DFF7029E1E858007A25EA /* ViewExtension.swift */, + 7B4E31F32C2379C4005090CB /* NotificationExtension.swift */, ); path = "nightguard WatchKit App"; sourceTree = ""; @@ -1008,6 +1013,7 @@ 439CBB2028EED0880036A0E8 /* nightguard_Widget_Extension.intentdefinition */, 438DAC8428D2356A00FBF520 /* Assets.xcassets */, 438DAC8628D2356A00FBF520 /* Info.plist */, + 7B4E31F52C237F14005090CB /* SystemSmallView.swift */, ); path = "nightguard Widget Extension"; sourceTree = ""; @@ -2101,6 +2107,7 @@ 43961F4A2533598400B1492B /* ActivateTemporaryTargetPopupView.swift in Sources */, 43794F421C2F435A00DB8B58 /* AppConstants.swift in Sources */, 439C39181C0E002F00D89872 /* ChartPainter.swift in Sources */, + 7B4E31F42C2379C4005090CB /* NotificationExtension.swift in Sources */, D13A4C212221E49200C71F08 /* NightSafeMessage.swift in Sources */, 43BB4B0824CF5DBA00DE96BB /* TemporaryTargetData.swift in Sources */, ); @@ -2136,6 +2143,7 @@ 4332FF5B2B164FF000DBF917 /* AlarmNotificationService.swift in Sources */, 43A40F222B17B38B0026E584 /* AlarmRule.swift in Sources */, 43BE674528D78C0B00285798 /* UserDefaultsRepository.swift in Sources */, + 7B4E31F62C237F14005090CB /* SystemSmallView.swift in Sources */, 435DFF6429E0A90A007A25EA /* AccessoryCornerView.swift in Sources */, 438DAC9128D253BC00FBF520 /* NightscoutData.swift in Sources */, 4332FF6D2B16596E00DBF917 /* Matrix.swift in Sources */, diff --git a/nightguard/BloodSugar.swift b/nightguard/BloodSugar.swift index 81bfcd6..416f28d 100644 --- a/nightguard/BloodSugar.swift +++ b/nightguard/BloodSugar.swift @@ -24,15 +24,17 @@ class BloodSugar : NSCoder, NSSecureCoding { let value : Float let timestamp : Double let isMeteredBloodGlucoseValue : Bool + let arrow : String var date: Date { return Date(timeIntervalSince1970: timestamp / 1000) } - required init(value : Float, timestamp : Double, isMeteredBloodGlucoseValue : Bool) { + required init(value : Float, timestamp : Double, isMeteredBloodGlucoseValue : Bool, arrow : String) { self.value = value self.timestamp = timestamp self.isMeteredBloodGlucoseValue = isMeteredBloodGlucoseValue + self.arrow = arrow } // when the noise is very strong, values are not computable... and we should exclude them from any logic & presentation @@ -68,14 +70,16 @@ class BloodSugar : NSCoder, NSSecureCoding { let value = decoder.decodeFloat(forKey: "value") let timestamp = decoder.decodeDouble(forKey: "timestamp") let isMeteredBloodGlucoseValue = decoder.decodeBool(forKey: "isMeteredBloodGlucoseValue") + let arrow = decoder.decodeObject(forKey: "arrow") as? String ?? "-" - self.init(value : value, timestamp : timestamp, isMeteredBloodGlucoseValue: isMeteredBloodGlucoseValue) + self.init(value : value, timestamp : timestamp, isMeteredBloodGlucoseValue: isMeteredBloodGlucoseValue, arrow : arrow) } @objc func encode(with coder: NSCoder) { coder.encode(self.value, forKey: "value") coder.encode(self.timestamp, forKey: "timestamp") coder.encode(self.isMeteredBloodGlucoseValue, forKey: "isMeteredBloodGlucoseValue") + coder.encode(self.arrow, forKey: "arrow") } func isOlderThanXMinutes(_ minutes : Int) -> Bool { diff --git a/nightguard/BloodSugarArrayExtension.swift b/nightguard/BloodSugarArrayExtension.swift index 00506a0..e7ea4c6 100644 --- a/nightguard/BloodSugarArrayExtension.swift +++ b/nightguard/BloodSugarArrayExtension.swift @@ -108,7 +108,7 @@ extension Array where Element: BloodSugar { if let sgvAsFloat = Float(nightscoutData.sgv) { self.append( - Element (value: sgvAsFloat, timestamp: nightscoutData.time.doubleValue, isMeteredBloodGlucoseValue: false) + Element (value: sgvAsFloat, timestamp: nightscoutData.time.doubleValue, isMeteredBloodGlucoseValue: false, arrow: nightscoutData.bgdeltaArrow) ) } } diff --git a/nightguard/StatsViewController.swift b/nightguard/StatsViewController.swift index 8ce88f3..94b9c87 100644 --- a/nightguard/StatsViewController.swift +++ b/nightguard/StatsViewController.swift @@ -107,7 +107,7 @@ class StatsViewController: UIViewController { normalizedBgValues.insert( BloodSugar.init(value: bgValue.value, timestamp: (normalizedTimeWithYear1971?.timeIntervalSince1970)! * 1000, - isMeteredBloodGlucoseValue: bgValue.isMeteredBloodGlucoseValue), at: 0) + isMeteredBloodGlucoseValue: bgValue.isMeteredBloodGlucoseValue, arrow: bgValue.arrow), at: 0) } return normalizedBgValues diff --git a/nightguard/external/NightscoutCacheService.swift b/nightguard/external/NightscoutCacheService.swift index 67fe787..b7b4f0a 100644 --- a/nightguard/external/NightscoutCacheService.swift +++ b/nightguard/external/NightscoutCacheService.swift @@ -283,7 +283,7 @@ class NightscoutCacheService: NSObject { fileprivate func transformToCurrentDay(yesterdaysValues : [BloodSugar]) -> [BloodSugar] { var transformedValues : [BloodSugar] = [] for yesterdaysValue in yesterdaysValues { - let transformedValue = BloodSugar.init(value: yesterdaysValue.value, timestamp: yesterdaysValue.timestamp + self.ONE_DAY_IN_MICROSECONDS, isMeteredBloodGlucoseValue: yesterdaysValue.isMeteredBloodGlucoseValue) + let transformedValue = BloodSugar.init(value: yesterdaysValue.value, timestamp: yesterdaysValue.timestamp + self.ONE_DAY_IN_MICROSECONDS, isMeteredBloodGlucoseValue: yesterdaysValue.isMeteredBloodGlucoseValue, arrow: yesterdaysValue.arrow) transformedValues.append(transformedValue) } diff --git a/nightguard/external/NightscoutService.swift b/nightguard/external/NightscoutService.swift index 6fb8de7..f458795 100644 --- a/nightguard/external/NightscoutService.swift +++ b/nightguard/external/NightscoutService.swift @@ -210,16 +210,38 @@ class NightscoutService { } var bloodSugarArray = [BloodSugar]() + var bloodValueArrowChar : String for singleBgValue in bgs { if let bgDict = singleBgValue as? Dictionary { if let bloodValue = bgDict["sgv"] as? Double { if let bloodValueTimestamp = bgDict["date"] as? Double { - let bloodSugar = BloodSugar( + if let bloodValueArrow = bgDict["direction"] as? String { + switch bloodValueArrow { + case "DoubleUp": + bloodValueArrowChar = "↑↑" + case "SingleUp": + bloodValueArrowChar = "↑" + case "FortyFiveUp": + bloodValueArrowChar = "↗" + case "Flat": + bloodValueArrowChar = "→" + case "FortyFiveDown": + bloodValueArrowChar = "↘" + case "SingleDown": + bloodValueArrowChar = "↓" + case "DoubleDown": + bloodValueArrowChar = "↓↓" + default: + bloodValueArrowChar = "-" + } + let bloodSugar = BloodSugar( value: Float(bloodValue), timestamp: bloodValueTimestamp, - isMeteredBloodGlucoseValue: false) - bloodSugarArray.insert(bloodSugar, at: 0) + isMeteredBloodGlucoseValue: false, + arrow: bloodValueArrowChar) + bloodSugarArray.insert(bloodSugar, at: 0) + } } } if let bloodValue = bgDict["mbg"] as? Double { @@ -227,7 +249,8 @@ class NightscoutService { let bloodSugar = BloodSugar( value: Float(bloodValue), timestamp: bloodValueTimestamp, - isMeteredBloodGlucoseValue: true) + isMeteredBloodGlucoseValue: true, + arrow: "-") bloodSugarArray.insert(bloodSugar, at: 0) } } diff --git a/nightguard/external/PredictionService.swift b/nightguard/external/PredictionService.swift index e97ada8..ab28c8c 100644 --- a/nightguard/external/PredictionService.swift +++ b/nightguard/external/PredictionService.swift @@ -154,7 +154,7 @@ class PredictionService { // cache the prediction... prediction = (0..