V3.1.0 Changes

This commit is contained in:
dirk 2020-10-07 06:39:50 +02:00
parent f296b1caca
commit 43942d776e
26 changed files with 419 additions and 184 deletions

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="17156" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="zZT-1m-QPq">
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="17156" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
<device id="watch44"/>
<dependencies>
<deployment identifier="watchOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="17034"/>
</dependencies>
@ -11,7 +12,18 @@
<objects>
<hostingController id="zZT-1m-QPq" customClass="HostingController" customModule="nightguard"/>
</objects>
<point key="canvasLocation" x="-70" y="-321"/>
<point key="canvasLocation" x="-129" y="-607"/>
</scene>
<!--Action Button Controller-->
<scene sceneID="bxz-Z6-DaQ">
<objects>
<controller id="ymg-17-TBh" customClass="ActionButtonController" customModule="nightguard">
<connections>
<segue destination="wky-cb-ykJ" kind="relationship" relationship="nextPage" id="oPp-bk-zxe"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="102" y="-321"/>
</scene>
<!--Interface Controller-->
<scene sceneID="aou-V4-d1y">
@ -203,7 +215,7 @@
</connections>
</controller>
</objects>
<point key="canvasLocation" x="-70" y="-44.5"/>
<point key="canvasLocation" x="-129" y="-321"/>
</scene>
<!--InfoInterfaceController-->
<scene sceneID="uNG-cf-2tk">
@ -266,7 +278,7 @@
</connections>
</controller>
</objects>
<point key="canvasLocation" x="166.51282051282053" y="-44.025641025641029"/>
<point key="canvasLocation" x="339" y="-321"/>
</scene>
<!--SnoozeInterfaceController-->
<scene sceneID="Wo6-eU-PUk">
@ -350,7 +362,7 @@
</connections>
</controller>
</objects>
<point key="canvasLocation" x="409" y="-44"/>
<point key="canvasLocation" x="-392" y="-321"/>
</scene>
<!--Static Notification Interface Controller-->
<scene sceneID="AEw-b0-oYE">
@ -366,14 +378,14 @@
</connections>
</notificationController>
</objects>
<point key="canvasLocation" x="-70" y="281"/>
<point key="canvasLocation" x="-129" y="102"/>
</scene>
<!--Notification Controller-->
<scene sceneID="ZPc-GJ-vnh">
<objects>
<controller id="4sK-HA-Art" customClass="NotificationController" customModule="nightguard" customModuleProvider="target"/>
</objects>
<point key="canvasLocation" x="167" y="281"/>
<point key="canvasLocation" x="110" y="102"/>
</scene>
</scenes>
<resources>

View File

@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<string>614</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>

View File

@ -0,0 +1,23 @@
//
// ActionController.swift
// nightguard WatchKit Extension
//
// Created by Dirk Hermanns on 05.10.20.
// Copyright © 2020 private. All rights reserved.
//
import WatchKit
import Foundation
import SwiftUI
class ActionButtonController: WKHostingController<ActionButtonView> {
override var body: ActionButtonView {
return ActionButtonView()
}
}
struct ActionButtonController_Previews: PreviewProvider {
static var previews: some View {
/*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
}
}

View File

@ -0,0 +1,44 @@
//
// ContentView.swift
// nightguard WatchKit Extension
//
// Created by Dirk Hermanns on 08.09.20.
// Copyright © 2020 private. All rights reserved.
//
import SwiftUI
import SpriteKit
import Combine
struct ActionButtonView: View {
@State private var snoozeModalIsPresented = false
init() {}
var body: some View {
VStack() {
HStack(spacing: 5, content: {
if #available(watchOSApplicationExtension 7.0, *) {
Button("Snooze", action: {
self.snoozeModalIsPresented.toggle()
}).fullScreenCover(isPresented: self.$snoozeModalIsPresented, content: {
SnoozeModalView(isPresented: self.$snoozeModalIsPresented)
})
}
Button("Aktualisieren", action: {
print("Button")
})
})
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.bottom)
.focusable(false)
}
}
struct ActionButtonView_Previews: PreviewProvider {
static var previews: some View {
ContentView(mainViewModel: MainViewModel())
}
}

View File

@ -50,7 +50,7 @@ class ComplicationController: NSObject, CLKComplicationDataSource {
modTemplate.line1TextProvider = CLKSimpleTextProvider(text: "\(currentNightscoutData.hourAndMinutes)")
modTemplate.line1TextProvider.tintColor = UIColorChanger.getBgColor(
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv))
modTemplate.line2TextProvider = CLKSimpleTextProvider(text: "\(UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv))\(UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.bgdeltaString))\(currentNightscoutData.bgdeltaArrow)")
modTemplate.line2TextProvider = CLKSimpleTextProvider(text: "\(UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv))\(UnitsConverter.mgdlToDisplayUnitsWithSign(currentNightscoutData.bgdeltaString))\(currentNightscoutData.bgdeltaArrow)")
}
template = modTemplate
case .modularLarge:
@ -176,7 +176,7 @@ class ComplicationController: NSObject, CLKComplicationDataSource {
// Display 11:24 113+2
func getOneBigLine(_ data : NightscoutData) -> String {
return "\(data.hourAndMinutes) \(UnitsConverter.mgdlToDisplayUnits(data.sgv))\(UnitsConverter.mgdlToDisplayUnits(data.bgdeltaString))\(data.bgdeltaArrow)"
return "\(data.hourAndMinutes) \(UnitsConverter.mgdlToDisplayUnits(data.sgv))\(UnitsConverter.mgdlToDisplayUnitsWithSign(data.bgdeltaString))\(data.bgdeltaArrow)"
}
// Display 11:24
@ -186,12 +186,12 @@ class ComplicationController: NSObject, CLKComplicationDataSource {
// Displays 113 +2
func getOneLine(_ data : NightscoutData) -> String {
return "\(getSgvAndArrow(data, " "))\t\(UnitsConverter.mgdlToDisplayUnits(data.bgdeltaString))"
return "\(getSgvAndArrow(data, " "))\t\(UnitsConverter.mgdlToDisplayUnitsWithSign(data.bgdeltaString))"
}
// Displays 113+2
func getOneShortLine(_ data : NightscoutData) -> String {
return "\(getSgvAndArrow(data, ""))\(UnitsConverter.mgdlToDisplayUnits(data.bgdeltaString))"
return "\(getSgvAndArrow(data, ""))\(UnitsConverter.mgdlToDisplayUnitsWithSign(data.bgdeltaString))"
}
func getSgvAndArrow(_ data: NightscoutData, _ separator: String) -> String {

View File

@ -8,13 +8,13 @@
import SwiftUI
import SpriteKit
import Combine
struct ContentView: View {
@State var crownValue = 0.1
@ObservedObject var viewModel: MainViewModel
let chartScene: SKScene
init(mainViewModel: MainViewModel) {
self.viewModel = mainViewModel
@ -31,21 +31,18 @@ struct ContentView: View {
// Apple Watch 42mm
sceneHeight = 145.0
}
chartScene = ChartScene(size: CGSize(width: screenBounds.width, height: sceneHeight),
newCanvasWidth: screenBounds.width * 6, useContrastfulColors: false)
}
}
var body: some View {
VStack() {
HStack(spacing: 5, content: {
Text(UnitsConverter.toDisplayUnits(
Text(UnitsConverter.mgdlToDisplayUnits(
viewModel.nightscoutData?.sgv ?? "---"))
.foregroundColor(viewModel.sgvColor)
.font(.system(size: 45))
.font(.system(size: 40))
.frame(alignment: .topLeading)
VStack() {
Text(UnitsConverter.toDisplayDeltaUnits(
Text(UnitsConverter.mgdlToDisplayUnits(
viewModel.nightscoutData?.bgdeltaString ?? "?"))
.foregroundColor(viewModel.sgvDeltaColor)
.font(.system(size: 12))
@ -103,7 +100,11 @@ struct ContentView: View {
}.frame(minWidth: 0,
maxWidth: .infinity)
VStack() {
SpriteView(scene: chartScene)
if #available(watchOSApplicationExtension 7.0, *) {
SpriteView(scene: viewModel.skScene!)
} else {
// Fallback on earlier versions
}
}.frame(minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
@ -111,6 +112,13 @@ struct ContentView: View {
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.edgesIgnoringSafeArea(.bottom)
.focusable(false)
.digitalCrownRotation($crownValue, from: 0.1, through: 5.0, sensitivity: .low, isContinuous: false, isHapticFeedbackEnabled: true)
.onAppear() {
}.onReceive(Just(crownValue)) { output in
print(output) // Here is the answer.
}
}
}

View File

@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<string>614</string>
<key>CLKComplicationPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
<key>CLKComplicationSupportedFamilies</key>

View File

@ -368,7 +368,7 @@ class InterfaceController: WKInterfaceController, WKCrownDelegate {
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv)))
self.deltaLabel.setText(
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.bgdeltaString))
UnitsConverter.mgdlToDisplayUnitsWithSign(currentNightscoutData.bgdeltaString))
self.deltaArrowLabel.setText(currentNightscoutData.bgdeltaArrow)
self.deltaLabel.setTextColor(UIColorChanger.getDeltaLabelColor(
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.bgdelta)))
@ -485,7 +485,8 @@ class InterfaceController: WKInterfaceController, WKCrownDelegate {
let temporaryTargetData = NightscoutCacheService.singleton.getTemporaryTargetData()
if temporaryTargetData.activeUntilDate.remainingMinutes() > 0 {
self.temporaryTargetLabel.setText("TT \(UnitsConverter.toDisplayUnits(temporaryTargetData.targetTop)) \(temporaryTargetData.activeUntilDate.remainingMinutes())m")
self.temporaryTargetLabel.setText(
"TT \(UnitsConverter.mgdlToDisplayUnits(String(describing: temporaryTargetData.targetTop))) \(temporaryTargetData.activeUntilDate.remainingMinutes())m")
} else {
self.temporaryTargetLabel.setText("TT --")
}

View File

@ -8,6 +8,7 @@
import Foundation
import SwiftUI
import SpriteKit
class MainViewModel: ObservableObject, Identifiable {
@ -30,10 +31,65 @@ class MainViewModel: ObservableObject, Identifiable {
@Published var error: Error?
@Published var active: Bool = false
@Published var skScene: ChartScene?
// Old values that have been read before
@Published var cachedTodaysBgValues : [BloodSugar] = []
@Published var cachedYesterdaysBgValues : [BloodSugar] = []
init() {
loadCurrentBgData(forceRefresh: false)
loadCareData()
loadDeviceStatusData()
loadChartData(forceRepaint: false)
}
fileprivate func paintChartData(todaysData : [BloodSugar], yesterdaysData : [BloodSugar], moveToLatestValue : Bool) {
let device = WKInterfaceDevice.current()
let bounds = device.screenBounds
let todaysDataWithPrediction = todaysData + PredictionService.singleton.nextHourGapped
let chartSceneHeight = determineSceneHeightFromCurrentWatchType(interfaceBounds: bounds)
skScene = ChartScene(size: CGSize(width: bounds.width, height: chartSceneHeight), newCanvasWidth: bounds.width * 6, useContrastfulColors: false)
skScene!.paintChart(
[todaysDataWithPrediction, yesterdaysData],
newCanvasWidth: bounds.width * 6,
maxYDisplayValue: CGFloat(UserDefaultsRepository.maximumBloodGlucoseDisplayed.value),
moveToLatestValue: moveToLatestValue,
displayDaysLegend: false,
useConstrastfulColors: false,
infoLabel: determineInfoLabel())
}
func determineInfoLabel() -> String {
if !AlarmRule.isSnoozed() {
if let alarmReason = AlarmRule.getAlarmActivationReason() {
return alarmReason
} else {
return ""
}
}
return String(format: NSLocalizedString("Snoozed %dmin", comment: "Snoozed duration on watch"), AlarmRule.getRemainingSnoozeMinutes())
}
fileprivate func determineSceneHeightFromCurrentWatchType(interfaceBounds : CGRect) -> CGFloat {
if (interfaceBounds.height >= 224.0) {
// Apple Watch 44mm
return 165.0
}
if (interfaceBounds.height >= 195.0) {
// Apple Watch 42mm
return 145.0
}
// interfaceBounds.height == 170.0
// Apple Watch 38mm
return 125.0
}
func loadCurrentBgData(forceRefresh: Bool) {
@ -70,11 +126,12 @@ class MainViewModel: ObservableObject, Identifiable {
fileprivate func calculateColors(nightscoutData: NightscoutData) {
self.sgvColor = Color(UIColorChanger.getBgColor(UnitsConverter.toDisplayUnits(nightscoutData.sgv)))
self.sgvColor = Color(UIColorChanger.getBgColor(UnitsConverter.mgdlToDisplayUnits(nightscoutData.sgv)))
self.sgvDeltaColor = Color(UIColorChanger.getDeltaLabelColor(
UnitsConverter.toDisplayUnits(nightscoutData.bgdelta)))
UnitsConverter.mgdlToDisplayUnits(nightscoutData.bgdelta)))
self.arrowColor = Color(
UIColorChanger.getDeltaLabelColor(nightscoutData.bgdelta))
UIColorChanger.getDeltaLabelColor(
UnitsConverter.mgdlToDisplayUnits(nightscoutData.bgdelta)))
self.timeColor = Color(UIColorChanger.getTimeLabelColor(nightscoutData.time))
}
@ -109,9 +166,58 @@ class MainViewModel: ObservableObject, Identifiable {
let temporaryTargetData = NightscoutCacheService.singleton.getTemporaryTargetData()
if temporaryTargetData.activeUntilDate.remainingMinutes() > 0 {
self.temporaryTarget = "TT \(UnitsConverter.toDisplayUnits(temporaryTargetData.targetTop)) \(temporaryTargetData.activeUntilDate.remainingMinutes())m"
self.temporaryTarget = "TT \(UnitsConverter.mgdlToDisplayUnits(String(describing: temporaryTargetData.targetTop))) \(temporaryTargetData.activeUntilDate.remainingMinutes())m"
} else {
self.temporaryTarget = "TT --"
}
}
func loadChartData(forceRepaint : Bool) {
// show a message if the today & yesterday data is missing, we're gonna load them now (will show on first install and when URI changes)
if UserDefaultsRepository.baseUri.exists && NightscoutCacheService.singleton.isEmpty && NightscoutDataRepository.singleton.isEmpty {
//TODO
//showMessage("Loading BG data...")
}
let newCachedTodaysBgValues: [BloodSugar]
if NightscoutCacheService.singleton.hasTodaysBgDataPendingRequests {
newCachedTodaysBgValues = NightscoutDataRepository.singleton.loadTodaysBgData()
} else {
newCachedTodaysBgValues = NightscoutCacheService.singleton.loadTodaysData { [unowned self] result in
guard let result = result else { return }
dispatchOnMain { [unowned self] in
guard active else { return }
if case .data(let newTodaysData) = result {
self.cachedTodaysBgValues = newTodaysData
paintChartData(todaysData : cachedTodaysBgValues, yesterdaysData : cachedYesterdaysBgValues, moveToLatestValue : true)
}
}
}
}
cachedTodaysBgValues = newCachedTodaysBgValues
let newCachedYesterdaysBgValues: [BloodSugar]
if NightscoutCacheService.singleton.hasYesterdaysBgDataPendingRequests {
newCachedYesterdaysBgValues = NightscoutDataRepository.singleton.loadYesterdaysBgData()
} else {
newCachedYesterdaysBgValues = NightscoutCacheService.singleton.loadYesterdaysData { [unowned self] result in
guard let result = result else { return }
dispatchOnMain { [unowned self] in
guard active else { return }
if case .data(let newYesterdaysData) = result {
self.cachedYesterdaysBgValues = newYesterdaysData
paintChartData(todaysData : cachedTodaysBgValues, yesterdaysData : cachedYesterdaysBgValues, moveToLatestValue : true)
}
}
}
}
cachedYesterdaysBgValues = newCachedYesterdaysBgValues
paintChartData(todaysData : cachedTodaysBgValues, yesterdaysData : cachedYesterdaysBgValues, moveToLatestValue : true)
}
}

View File

@ -0,0 +1,71 @@
//
// SnoozePopupView.swift
// nightguard WatchKit Extension
//
// Created by Dirk Hermanns on 06.10.20.
// Copyright © 2020 private. All rights reserved.
//
import SwiftUI
import SpriteKit
import Combine
struct SnoozeModalView: View {
@Environment(\.presentationMode) var presentationMode
@Binding var isPresented: Bool
var body: some View {
ScrollView {
VStack {
Button("Stop Snoozing", action: {
self.isPresented.toggle()
})
.background(Color.white)
.foregroundColor(Color.black)
HStack {
Button("5min", action: {
})
Button("10min", action: {
})
}
HStack {
Button("15min", action: {
})
Button("20min", action: {
})
}
Button("30min", action: {
})
Button("45min", action: {
})
Button("1h", action: {
})
Button("2h", action: {
})
Button("3h", action: {
})
Button("6h", action: {
})
Button("1d", action: {
})
}
.focusable()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
presentationMode.wrappedValue.dismiss()
}
}}
}

View File

@ -137,6 +137,9 @@
437EEDC41FB7180000694EAD /* NightscoutDataRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43794F451C303E4200DB8B58 /* NightscoutDataRepository.swift */; };
437EEDC51FB7185500694EAD /* UserDefaultsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43794F4E1C343B9800DB8B58 /* UserDefaultsRepository.swift */; };
438066FE1D21C2350021B618 /* AppMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438066FD1D21C2350021B618 /* AppMessageService.swift */; };
43989365252BB91C007A252F /* ActionButtonController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43989364252BB91C007A252F /* ActionButtonController.swift */; };
4398937D252BBFE5007A252F /* ActionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4398937C252BBFE5007A252F /* ActionButtonView.swift */; };
43989389252CEB15007A252F /* SnoozeModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43989388252CEB15007A252F /* SnoozeModalView.swift */; };
439BADF81C24C315006BEADB /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 439BADF71C24C315006BEADB /* Media.xcassets */; };
439C39181C0E002F00D89872 /* ChartPainter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439C39171C0E002F00D89872 /* ChartPainter.swift */; };
439C39191C0E28DD00D89872 /* ChartPainter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 439C39171C0E002F00D89872 /* ChartPainter.swift */; };
@ -425,6 +428,9 @@
437C8A9124C9E54A005CF5B3 /* UILabelExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILabelExtension.swift; sourceTree = "<group>"; };
438066FD1D21C2350021B618 /* AppMessageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppMessageService.swift; sourceTree = "<group>"; };
438591D91C14DC4D00F9CEE2 /* scoutwatch WatchKit Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "scoutwatch WatchKit Extension.entitlements"; sourceTree = "<group>"; };
43989364252BB91C007A252F /* ActionButtonController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonController.swift; sourceTree = "<group>"; };
4398937C252BBFE5007A252F /* ActionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonView.swift; sourceTree = "<group>"; };
43989388252CEB15007A252F /* SnoozeModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnoozeModalView.swift; sourceTree = "<group>"; };
439BADF71C24C315006BEADB /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
439C39171C0E002F00D89872 /* ChartPainter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChartPainter.swift; path = "nightguard WatchKit Extension/ChartPainter.swift"; sourceTree = SOURCE_ROOT; };
439C391A1C0E295C00D89872 /* ChartPainterTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartPainterTest.swift; sourceTree = "<group>"; };
@ -722,18 +728,13 @@
43647C051BFF6435004389F9 /* nightguard WatchKit Extension */ = {
isa = PBXGroup;
children = (
4398937A252BBF88007A252F /* controllers */,
4398937B252BBFB0007A252F /* views */,
4368A100252279D80013E425 /* viewmodel */,
432E62E51D11288100DD7978 /* app */,
438066FC1D21C1ED0021B618 /* external */,
43647C061BFF6435004389F9 /* Supporting Files */,
43A0476924D202030040D853 /* helper */,
43CE59AB250813D700D71B77 /* HostingController.swift */,
43CE59A925080D6A00D71B77 /* ContentView.swift */,
43647C081BFF6435004389F9 /* InterfaceController.swift */,
43794F4C1C34248500DB8B58 /* InfoInterfaceController.swift */,
43C87AF7202F21F10000F5F6 /* SnoozeInterfaceController.swift */,
43647C0C1BFF6435004389F9 /* NotificationController.swift */,
43647C0E1BFF6435004389F9 /* ComplicationController.swift */,
43647C0A1BFF6435004389F9 /* ExtensionDelegate.swift */,
43794F411C2F435A00DB8B58 /* AppConstants.swift */,
43D213631C2214D60046C52D /* Assets.xcassets */,
@ -777,6 +778,30 @@
name = external;
sourceTree = "<group>";
};
4398937A252BBF88007A252F /* controllers */ = {
isa = PBXGroup;
children = (
43CE59AB250813D700D71B77 /* HostingController.swift */,
43989364252BB91C007A252F /* ActionButtonController.swift */,
43647C081BFF6435004389F9 /* InterfaceController.swift */,
43794F4C1C34248500DB8B58 /* InfoInterfaceController.swift */,
43C87AF7202F21F10000F5F6 /* SnoozeInterfaceController.swift */,
43647C0C1BFF6435004389F9 /* NotificationController.swift */,
43647C0E1BFF6435004389F9 /* ComplicationController.swift */,
);
name = controllers;
sourceTree = "<group>";
};
4398937B252BBFB0007A252F /* views */ = {
isa = PBXGroup;
children = (
43CE59A925080D6A00D71B77 /* ContentView.swift */,
4398937C252BBFE5007A252F /* ActionButtonView.swift */,
43989388252CEB15007A252F /* SnoozeModalView.swift */,
);
name = views;
sourceTree = "<group>";
};
43A0476924D202030040D853 /* helper */ = {
isa = PBXGroup;
children = (
@ -1630,8 +1655,10 @@
43647C0F1BFF6435004389F9 /* ComplicationController.swift in Sources */,
D1D1623F221AB253006F990A /* WatchSyncRequestMessage.swift in Sources */,
D133079321C85FAE00DC6879 /* RegressionHelper.swift in Sources */,
43989389252CEB15007A252F /* SnoozeModalView.swift in Sources */,
43C87AF8202F21F10000F5F6 /* SnoozeInterfaceController.swift in Sources */,
D133078B21C85DA800DC6879 /* ArrayExtension.swift in Sources */,
4398937D252BBFE5007A252F /* ActionButtonView.swift in Sources */,
D133079721C85FAE00DC6879 /* Matrix+Description.swift in Sources */,
D15055AD2200CD6500F31C1F /* UserDefaultsValueGroups.swift in Sources */,
4368A0FA252279CA0013E425 /* MainViewModel.swift in Sources */,
@ -1650,6 +1677,7 @@
D18C5D8C22293C230099D96E /* BasicStats.swift in Sources */,
43288A681D1B359D00EE3999 /* StringExtension.swift in Sources */,
43BB4B0324CF42C400DE96BB /* DoubleExtension.swift in Sources */,
43989365252BB91C007A252F /* ActionButtonController.swift in Sources */,
438066FE1D21C2350021B618 /* AppMessageService.swift in Sources */,
437EEDC51FB7185500694EAD /* UserDefaultsRepository.swift in Sources */,
D1BD14E5205BB9E200B93389 /* BackgroundRefreshScheduler.swift in Sources */,
@ -1910,7 +1938,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEVELOPMENT_TEAM = BSAVUVP8PV;
INFOPLIST_FILE = "nightguard WatchKit Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
@ -1928,7 +1956,7 @@
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
WATCHOS_DEPLOYMENT_TARGET = 6.2;
};
name = Debug;
};
@ -1941,7 +1969,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEVELOPMENT_TEAM = BSAVUVP8PV;
INFOPLIST_FILE = "nightguard WatchKit Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
@ -1959,7 +1987,7 @@
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
WATCHOS_DEPLOYMENT_TARGET = 6.2;
};
name = Release;
};
@ -1973,7 +2001,7 @@
CODE_SIGN_ENTITLEMENTS = "nightguard WatchKit App/nightguard.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = BSAVUVP8PV;
IBSC_MODULE = scoutwatch_WatchKit_Extension;
@ -1992,7 +2020,7 @@
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
WATCHOS_DEPLOYMENT_TARGET = 6.2;
};
name = Debug;
};
@ -2006,7 +2034,7 @@
CODE_SIGN_ENTITLEMENTS = "nightguard WatchKit App/nightguard.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = BSAVUVP8PV;
IBSC_MODULE = scoutwatch_WatchKit_Extension;
@ -2024,7 +2052,7 @@
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 7.0;
WATCHOS_DEPLOYMENT_TARGET = 6.2;
};
name = Release;
};
@ -2036,7 +2064,7 @@
CODE_SIGN_ENTITLEMENTS = nightguard/scoutwatch.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = BSAVUVP8PV;
ENABLE_BITCODE = YES;
@ -2064,7 +2092,7 @@
CODE_SIGN_ENTITLEMENTS = nightguard/scoutwatch.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 604;
CURRENT_PROJECT_VERSION = 614;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = BSAVUVP8PV;
ENABLE_BITCODE = YES;

View File

@ -74,10 +74,16 @@ class AlarmNotificationService {
let nightscoutData = NightscoutCacheService.singleton.getCurrentNightscoutData()
let units = UserDefaultsRepository.units.value.description
content.title = "\(nightscoutData.sgv) \(nightscoutData.bgdeltaArrow)\t\(nightscoutData.bgdeltaString) \(units)"
content.body = "\(alarmActivationReason) alert"
if let sgv = Float(nightscoutData.sgv) {
content.badge = NSNumber(value: sgv)
content.title =
"\(UnitsConverter.mgdlToDisplayUnits(nightscoutData.sgv)) " +
"\(nightscoutData.bgdeltaArrow)\t\(UnitsConverter.mgdlToDisplayUnitsWithSign(nightscoutData.bgdeltaString)) " +
"\(units)"
content.body = "\(alarmActivationReason)"
if let sgv = Float(UnitsConverter.mgdlToDisplayUnits(nightscoutData.sgv)) {
// display the current sgv on appbadge only if the user actived it:
if UserDefaultsRepository.showBGOnAppBadge.value {
content.badge = NSNumber(value: sgv)
}
}
if #available(iOS 12.0, *) {
content.sound = UNNotificationSound.criticalSoundNamed(convertToUNNotificationSoundName("alarm-notification.m4a"), withAudioVolume: 0.6)

View File

@ -44,7 +44,10 @@ class AlarmViewController: CustomFormViewController {
maximumValue: UnitsConverter.mgdlToDisplayUnits(MAX_ALERT_ABOVE_VALUE))
aboveSliderRow.cell.slider.addTarget(self, action: #selector(onSliderValueChanged(slider:event:)), for: .valueChanged)
belowSliderRow = SliderRow.glucoseLevelSlider(initialValue: AlarmRule.alertIfBelowValue.value, minimumValue: MIN_ALERT_BELOW_VALUE, maximumValue: MAX_ALERT_BELOW_VALUE)
belowSliderRow = SliderRow.glucoseLevelSlider(
initialValue: UnitsConverter.mgdlToDisplayUnits(AlarmRule.alertIfBelowValue.value),
minimumValue: UnitsConverter.mgdlToDisplayUnits(MIN_ALERT_BELOW_VALUE),
maximumValue: UnitsConverter.mgdlToDisplayUnits(MAX_ALERT_BELOW_VALUE))
belowSliderRow.cell.slider.addTarget(self, action: #selector(onSliderValueChanged(slider:event:)), for: .valueChanged)
form
@ -213,7 +216,7 @@ class AlarmViewController: CustomFormViewController {
}
}
}
@objc func onSliderValueChanged(slider: UISlider, event: UIEvent) {
guard let touchEvent = event.allTouches?.first else { return }

View File

@ -260,6 +260,6 @@ extension BasicStats {
private func formattedUnits(_ value: Float) -> String? {
return value.isNaN ? nil :
UnitsConverter.toDisplayUnits("\(value)") + " \(UserDefaultsRepository.units.value.description)"
UnitsConverter.mgdlToDisplayUnits("\(value)") + " \(UserDefaultsRepository.units.value.description)"
}
}

View File

@ -100,13 +100,14 @@ class BedsideViewController: UIViewController {
return
}
self.bgLabel.text = UnitsConverter.toDisplayUnits(currentNightscoutData.sgv)
self.bgLabel.text = UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv)
self.bgLabel.textColor = UIColorChanger.getBgColor(
UnitsConverter.toDisplayUnits(currentNightscoutData.sgv))
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv))
self.deltaLabel.text = UnitsConverter.toDisplayDeltaUnits(currentNightscoutData.bgdeltaString)
if let displayDelta = Float(UnitsConverter.toDisplayDeltaUnits(currentNightscoutData.bgdeltaString)) {
self.deltaLabel.textColor = UIColorChanger.getDeltaLabelColor(displayDelta)
self.deltaLabel.text = UnitsConverter.mgdlToDisplayUnitsWithSign(currentNightscoutData.bgdeltaString)
if let displayDelta = Float(UnitsConverter.mgdlToDisplayUnitsWithSign(currentNightscoutData.bgdeltaString)) {
self.deltaLabel.textColor = UIColorChanger.getDeltaLabelColor(
UnitsConverter.mgdlToDisplayUnits(displayDelta))
} else {
self.deltaLabel.textColor = UIColor.white
}

View File

@ -96,7 +96,7 @@ class CareViewController: CustomFormViewController {
row.value = UserDefaultsRepository.temporaryTarget.value
row.displayValueFor = { value in
guard let value = value else { return nil }
return UnitsConverter.toDisplayUnits(value)
return UnitsConverter.mgdlToDisplayUnits(String(describing: value))
}
}.onChange { row in
UserDefaultsRepository.temporaryTarget.value = row.value!

View File

@ -250,11 +250,9 @@ extension SliderRow {
class func glucoseLevelSlider(initialValue: Float, minimumValue: Float, maximumValue: Float, snapIncrementForMgDl: Float = 10.0) -> SliderRow {
return SliderRow() { row in
row.value = initialValue
row.value = initialValue
}.cellSetup { cell, row in
let minimumValue = Float(UnitsConverter.mgdlToDisplayUnits("\(minimumValue)"))!
let maximumValue = Float(UnitsConverter.mgdlToDisplayUnits("\(maximumValue)"))!
let snapIncrement = (UserDefaultsRepository.units.value == .mgdl) ? snapIncrementForMgDl : 0.1
let steps = (maximumValue - minimumValue) / snapIncrement
@ -264,6 +262,18 @@ extension SliderRow {
row.displayValueFor = { value in
guard let value = value else { return "" }
let units = UserDefaultsRepository.units.value.description
// Play haptic sound
if value.truncatingRemainder(dividingBy: snapIncrement) == 0 {
if let lastAssignedValue = row.lastSelectedValue {
if Int(lastAssignedValue * 10) != Int(value * 10) {
let uiImpactFeedbackGenerator = UIImpactFeedbackGenerator(style: .medium)
uiImpactFeedbackGenerator.impactOccurred()
}
}
}
row.lastSelectedValue = value
return String("\(value.cleanValue) \(units)")
}

View File

@ -48,7 +48,7 @@ class FastRiseDropViewController: CustomFormViewController {
}
}.cellSetup { cell, row in
row.value = Double(UnitsConverter.toDisplayUnits("\(AlarmRule.deltaAmount.value)"))!
row.value = Double(UnitsConverter.mgdlToDisplayUnits("\(AlarmRule.deltaAmount.value)"))!
let mmolUnits = (UserDefaultsRepository.units.value == .mmol)
cell.stepper.stepValue = mmolUnits ? 0.1 : 1

View File

@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<string>614</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>

View File

@ -466,7 +466,7 @@ class MainViewController: UIViewController, SlideToSnoozeDelegate {
self.bgLabel.textColor = UIColorChanger.getBgColor(
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.sgv))
self.deltaLabel.text = UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.bgdeltaString)
self.deltaLabel.text = UnitsConverter.mgdlToDisplayUnitsWithSign(currentNightscoutData.bgdeltaString)
self.deltaArrowsLabel.text = currentNightscoutData.bgdeltaArrow
self.deltaLabel.textColor = UIColorChanger.getDeltaLabelColor(
UnitsConverter.mgdlToDisplayUnits(currentNightscoutData.bgdelta))

View File

@ -586,7 +586,7 @@ class NightscoutService {
raw = scale * (unfiltered - intercept) / slope / ratio
}
return "\(Int(UnitsConverter.toDisplayUnits(raw.rounded())))"
return "\(Int(UnitsConverter.mgdlToDisplayUnits(raw.rounded())))"
}
/* Reads the treatment record for the last cannula change, sensor change and battery age */

View File

@ -17,7 +17,7 @@ extension UIApplication {
func setCurrentBGValueOnAppBadge() {
let nightscoutData = NightscoutCacheService.singleton.getCurrentNightscoutData()
guard let sgvAsDouble = Double(UnitsConverter.toDisplayUnits(nightscoutData.sgv)) else {
guard let sgvAsDouble = Double(UnitsConverter.mgdlToDisplayUnits(nightscoutData.sgv)) else {
return
}
let sgvAsInt = Int(sgvAsDouble.rounded())

View File

@ -22,7 +22,13 @@ class UnitsConverter {
return value
}
let units = UserDefaultsRepository.units.value
// if the UI is locked, looks like we are not allowed to access the userdefaults
// so do this on main Thread only:
var units = Units.mmol
dispatchOnMain {
units = UserDefaultsRepository.units.value
}
if units == Units.mgdl {
// nothing to do here - just remove decimals
if value.contains(".") {
@ -34,41 +40,37 @@ class UnitsConverter {
return toMmol(value)
}
// Converts uncertain value to the wished unit
// Unit to be used.
static func toDisplayUnits(_ value : String) -> String {
static func mgdlToDisplayUnitsWithSign(_ value : String) -> String {
if value == "---" {
return value
let valueInDisplayUnits = mgdlToDisplayUnits(value)
if valueInDisplayUnits == "---" {
return valueInDisplayUnits
}
let units = UserDefaultsRepository.units.value
if units == Units.mgdl {
return toMgdl(value)
// add a sign
guard let floatValue = Float(valueInDisplayUnits) else {
return valueInDisplayUnits
}
return toMmol(value)
}
static func toDisplayDeltaUnits(_ value : String) -> String {
if value == "---" {
return value
if floatValue >= 0 {
// remove .0 decimals and add a sign
return "\(floatValue.cleanSignedValue)"
}
let units = UserDefaultsRepository.units.value
if units == Units.mgdl {
return toMgdlDelta(value)
}
return toMmolDelta(value)
return valueInDisplayUnits
}
// Converts the internally mg/dL to mmol if thats the defined
// Unit to be used.
static func mgdlToDisplayUnits(_ value : Float) -> Float {
let units = UserDefaultsRepository.units.value
// if the UI is locked, looks like we are not allowed to access the userdefaults
// so do this on main Thread only:
var units = Units.mmol
dispatchOnMain {
units = UserDefaultsRepository.units.value
}
if units == Units.mgdl {
return removeDecimals(value)
}
@ -77,60 +79,6 @@ class UnitsConverter {
return value * 0.0555
}
static func toDisplayUnits(_ value : Float) -> Float {
let units = UserDefaultsRepository.units.value
if units == Units.mgdl {
return removeDecimals(value)
}
// convert mg/dL to mmol/l
return value * 0.0555
}
static func toDisplayUnits(_ value : Int) -> String {
let units = UserDefaultsRepository.units.value
if units == Units.mgdl {
return String(describing: value)
}
// convert mg/dL to mmol/l
let floatValue : Float = Float(value) * 0.0555
return String(floatValue.cleanValue)
}
static func toDisplayUnits(_ value : CGFloat) -> CGFloat {
return CGFloat(toDisplayUnits(Float(value)))
}
static func toDisplayUnits(_ mgValues : [BloodSugar]) -> [BloodSugar] {
let units = UserDefaultsRepository.units.value
if units == Units.mgdl {
return mgValues
}
var mmolValues : [BloodSugar] = []
for value in mgValues {
mmolValues.append(toMmol(value))
}
return mmolValues
}
static func toDisplayUnits(_ days : [[BloodSugar]]) -> [[BloodSugar]] {
var newDays : [[BloodSugar]] = []
for day in days {
newDays.append(toDisplayUnits(day))
}
return newDays
}
static func toMmol(_ bloodSugar : BloodSugar) -> BloodSugar {
return BloodSugar.init(value: toMmol(bloodSugar.value), timestamp: bloodSugar.timestamp)
@ -140,31 +88,12 @@ class UnitsConverter {
return Float(mmolValue * 0.0555).round(to: 1)
}
static func toMmol(_ uncertainValue : String) -> String {
static func toMmol(_ mgdlValue : String) -> String {
// determine whether mmol is already contained
var doubleValue : Double = Double(uncertainValue)!
if uncertainValue.contains(".") {
// the value seems to be already mmol -> nothing to do
return uncertainValue.cleanFloatValue
guard let mmolValue = Float(mgdlValue) else {
return "??"
}
// looks like mgdl is contained
// convert mg/dL to mmol/l
doubleValue = doubleValue * 0.0555
return doubleValue.cleanValue
}
static func toMmolDelta(_ uncertainValue : String) -> String {
var floatValue : Float = Float(uncertainValue)!
// Looks like we have a mg/dl delta value. Convert to mmol:
if floatValue < 1 && floatValue > -1 {
// seems to be already a mmol delta
return String(floatValue.cleanSignedValue)
}
floatValue = floatValue * 0.0555
return floatValue.cleanSignedValue
return (mmolValue * 0.0555).cleanValue
}
// Converts the value in Display Units to Mg/dL.
@ -195,21 +124,6 @@ class UnitsConverter {
return String(floatValue.cleanValue)
}
static func toMgdlDelta(_ uncertainValue : String) -> String {
var floatValue : Float = Float(uncertainValue)!
if (floatValue >= 1 || floatValue <= -1) {
// the value seems to be already mgdl -> nothing to do
return floatValue.rounded().cleanSignedValue
}
// looks like mmol is contained
// convert mmol to mg/dl
floatValue = floatValue * (1 / 0.0555)
return floatValue.rounded().cleanSignedValue
}
// if a "." is contained, simply takes the left part of the string only
static fileprivate func removeDecimals(_ value : String) -> String {
if !value.contains(".") {

View File

@ -0,0 +1,8 @@
{
"Simulator Target Bundle": "de.my-wan.dhe.nightguard",
"aps": {
"alert": "Push Notifications Test",
"sound": "default",
"badge": 1
}
}

View File

@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>602</string>
<string>614</string>
</dict>
</plist>

View File

@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>602</string>
<string>614</string>
</dict>
</plist>