Implemented treatment, with persistence and uploading to nightscout.

This commit is contained in:
eduardopietre 2021-12-26 21:44:12 -03:00 committed by Johan Degraeve
parent 689dc5ab1e
commit 956c23b29d
37 changed files with 1441 additions and 52 deletions

View File

@ -1,6 +1,6 @@
PODS:
- ActionClosurable (2.0.0)
- CryptoSwift (1.4.0)
- CryptoSwift (1.4.2)
- PieCharts (0.0.7)
- SwiftCharts (0.6.5)
@ -27,7 +27,7 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
ActionClosurable: 92729a0f0bb4b38d2744319ea8282a3ce8fb1e0a
CryptoSwift: 7cc902df1784de3b389a387756c7d710f197730c
CryptoSwift: a532e74ed010f8c95f611d00b8bbae42e9fe7c17
PieCharts: 30e50dfa7dc19e5b84e9878d32089673ef5d0453
SwiftCharts: 2e755ea292f0b87d3e4b2c1eb5afc080a20cdc15

View File

@ -26,10 +26,17 @@
47F8E95A2710255D00B8B02B /* ConstantsWatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47F8E9592710255C00B8B02B /* ConstantsWatchApp.swift */; };
47FB28082636B04200042FFB /* StatisticsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47FB28072636B04200042FFB /* StatisticsManager.swift */; };
533272967B05B378D81F6529 /* Pods_xdrip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DB0736D7B1553FC8350324C /* Pods_xdrip.framework */; };
666E283A26F7E54C00ACE4DF /* xDrip.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 666E283826F7E54C00ACE4DF /* xDrip.xcconfig */; };
666E283B26F7E54C00ACE4DF /* Version.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 666E283926F7E54C00ACE4DF /* Version.xcconfig */; };
CE1B2FE025D0264B00F642F5 /* LaunchScreen.strings in Resources */ = {isa = PBXBuildFile; fileRef = CE1B2FD125D0264900F642F5 /* LaunchScreen.strings */; };
CE1B2FE125D0264B00F642F5 /* Main.strings in Resources */ = {isa = PBXBuildFile; fileRef = CE1B2FD425D0264900F642F5 /* Main.strings */; };
D400F8032778BD8000B57648 /* TextsTreatmentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D400F8022778BD8000B57648 /* TextsTreatmentsView.swift */; };
D4028CC02774A50600341476 /* TreatmentsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4028CBF2774A50600341476 /* TreatmentsViewController.swift */; };
D40C3DA4277542C400111B73 /* TreatmentEntry+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40C3DA3277542C400111B73 /* TreatmentEntry+CoreDataClass.swift */; };
D40C3DA62775438F00111B73 /* TreatmentEntry+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = D40C3DA52775438F00111B73 /* TreatmentEntry+CoreDataProperties.swift */; };
D482BD942776153F003C4FB2 /* TreatmentsNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D482BD932776153F003C4FB2 /* TreatmentsNavigationController.swift */; };
D484BC292774F783008490E9 /* TreatmentsInsertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D484BC282774F783008490E9 /* TreatmentsInsertViewController.swift */; };
D4AC54502778C82C0097FF10 /* Treatments.strings in Resources */ = {isa = PBXBuildFile; fileRef = D4AC54412778C82B0097FF10 /* Treatments.strings */; };
D4BAF37627769B38009D3465 /* TreatmentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4BAF37527769B38009D3465 /* TreatmentTableViewCell.swift */; };
D4FD899727772F9100689788 /* TreatmentEntryAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FD899627772F9100689788 /* TreatmentEntryAccessor.swift */; };
F51B9F7D24B216CD00FC0643 /* Libre1NonFixedSlopeCalibrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F51B9F7C24B216CD00FC0643 /* Libre1NonFixedSlopeCalibrator.swift */; };
F8025C0A21D94FD700ECF0C0 /* CBManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */; };
F8025C1321DA683400ECF0C0 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C1221DA683400ECF0C0 /* Data.swift */; };
@ -703,6 +710,30 @@
CE1B2FDE25D0264B00F642F5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Snooze.strings; sourceTree = "<group>"; };
CE1B2FDF25D0264B00F642F5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/BluetoothPeripheralView.strings; sourceTree = "<group>"; };
CE1B2FE425D026B400F642F5 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Common.strings; sourceTree = "<group>"; };
D400F8022778BD8000B57648 /* TextsTreatmentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextsTreatmentsView.swift; sourceTree = "<group>"; };
D4028CBF2774A50600341476 /* TreatmentsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentsViewController.swift; sourceTree = "<group>"; };
D40C3DA3277542C400111B73 /* TreatmentEntry+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TreatmentEntry+CoreDataClass.swift"; sourceTree = "<group>"; };
D40C3DA52775438F00111B73 /* TreatmentEntry+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TreatmentEntry+CoreDataProperties.swift"; sourceTree = "<group>"; };
D482BD932776153F003C4FB2 /* TreatmentsNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentsNavigationController.swift; sourceTree = "<group>"; };
D484BC282774F783008490E9 /* TreatmentsInsertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentsInsertViewController.swift; sourceTree = "<group>"; };
D4A2661D2773EB8300B60F2A /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
D4A2661F2773EB8300B60F2A /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
D4AC54422778C82B0097FF10 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54432778C82B0097FF10 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54442778C82B0097FF10 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54452778C82B0097FF10 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54462778C82B0097FF10 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54472778C82B0097FF10 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC54482778C82B0097FF10 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/Treatments.strings"; sourceTree = "<group>"; };
D4AC54492778C82B0097FF10 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544A2778C82B0097FF10 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544B2778C82B0097FF10 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544C2778C82B0097FF10 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544D2778C82C0097FF10 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544E2778C82C0097FF10 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Treatments.strings; sourceTree = "<group>"; };
D4AC544F2778C82C0097FF10 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Treatments.strings; sourceTree = "<group>"; };
D4BAF37527769B38009D3465 /* TreatmentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentTableViewCell.swift; sourceTree = "<group>"; };
D4FD899627772F9100689788 /* TreatmentEntryAccessor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreatmentEntryAccessor.swift; sourceTree = "<group>"; };
F51B9F7C24B216CD00FC0643 /* Libre1NonFixedSlopeCalibrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Libre1NonFixedSlopeCalibrator.swift; sourceTree = "<group>"; };
F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBManagerState.swift; sourceTree = "<group>"; };
F8025C1221DA683400ECF0C0 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
@ -1533,6 +1564,17 @@
path = Pods;
sourceTree = "<group>";
};
D4028CBE2774A4B900341476 /* Treatments */ = {
isa = PBXGroup;
children = (
D4028CBF2774A50600341476 /* TreatmentsViewController.swift */,
D484BC282774F783008490E9 /* TreatmentsInsertViewController.swift */,
D482BD932776153F003C4FB2 /* TreatmentsNavigationController.swift */,
D4BAF37527769B38009D3465 /* TreatmentTableViewCell.swift */,
);
path = Treatments;
sourceTree = "<group>";
};
F8025C0B21D9513400ECF0C0 /* Extensions */ = {
isa = PBXGroup;
children = (
@ -1930,6 +1972,7 @@
F85DC2F921D2CCC000B9F74A /* Storyboards */ = {
isa = PBXGroup;
children = (
D4AC54412778C82B0097FF10 /* Treatments.strings */,
F8B3A7B3226A0A71004BA588 /* Alerts.strings */,
F8B3A80B227A3E97004BA588 /* AlertTypesSettingsView.strings */,
470CE1FE246802EB00D5CB74 /* BluetoothPeripheralsView.strings */,
@ -1960,6 +2003,7 @@
F85DC2FA21D2CD3000B9F74A /* View Controllers */ = {
isa = PBXGroup;
children = (
D4028CBE2774A4B900341476 /* Treatments */,
F8297F47238DCAD800D74D66 /* BluetoothPeripheralsNavigationController */,
F8B3A806227A28F9004BA588 /* Helpers */,
F8025E5921F7861200ECF0C0 /* Root View Controller */,
@ -2302,6 +2346,7 @@
F8B3A814227DEA69004BA588 /* accessors */ = {
isa = PBXGroup;
children = (
D4FD899627772F9100689788 /* TreatmentEntryAccessor.swift */,
F8B3A816227DEC91004BA588 /* AlertEntriesAccessor.swift */,
F8B3A81A227DEC92004BA588 /* AlertTypesAccessor.swift */,
F8B3A818227DEC92004BA588 /* BgReadingsAccessor.swift */,
@ -2433,6 +2478,7 @@
F82436FB24BE014000BED341 /* TextsLibreStates.swift */,
F8E6C78F24CEC22A007C1199 /* TextsSnooze.swift */,
F8A5EEB7257CF2940085E660 /* TextsLibreNFC.swift */,
D400F8022778BD8000B57648 /* TextsTreatmentsView.swift */,
);
path = Texts;
sourceTree = "<group>";
@ -2625,6 +2671,8 @@
F85FF3CC252F9FD7004E6FF1 /* SnoozeParameters+CoreDataProperties.swift */,
F830991A23C2909E005741DF /* Watlaa+CoreDataClass.swift */,
F830991B23C2909E005741DF /* Watlaa+CoreDataProperties.swift */,
D40C3DA3277542C400111B73 /* TreatmentEntry+CoreDataClass.swift */,
D40C3DA52775438F00111B73 /* TreatmentEntry+CoreDataProperties.swift */,
);
path = classes;
sourceTree = "<group>";
@ -3069,9 +3117,9 @@
F8AC425221ADEBD60078C348 /* Project object */ = {
isa = PBXProject;
attributes = {
DefaultBuildSystemTypeForWorkspace = Latest;
LastSwiftUpdateCheck = 1300;
LastUpgradeCheck = 1200;
DefaultBuildSystemTypeForWorkspace = Original;
LastSwiftUpdateCheck = 1310;
LastUpgradeCheck = 1310;
ORGANIZATIONNAME = "Johan Degraeve";
TargetAttributes = {
470B6185270C448000561E56 = {
@ -3237,7 +3285,6 @@
F824379624CB7A9900BED341 /* Oringz.caf in Resources */,
F824377D24CB7A9800BED341 /* Open_Your_Eyes_And_See.caf in Resources */,
F82437A624CB7A9900BED341 /* Siri_Glucose_Rising_Fast.caf in Resources */,
666E283A26F7E54C00ACE4DF /* xDrip.xcconfig in Resources */,
F81F370825C1584A00520946 /* LibreStates.strings in Resources */,
F82437B724CB7A9900BED341 /* Cartoon_Tip_Toe_Sneaky_Walk.caf in Resources */,
F824379A24CB7A9900BED341 /* Siri_Alert_Device_Muted.caf in Resources */,
@ -3285,9 +3332,9 @@
F82437C824CB7A9900BED341 /* Siri_Alert_Missed_Readings.caf in Resources */,
F821CF7D22A46CDD005C1E43 /* 1-millisecond-of-silence.mp3 in Resources */,
F824377A24CB7A9800BED341 /* Sci-Fi_Spaceship_Message.caf in Resources */,
D4AC54502778C82C0097FF10 /* Treatments.strings in Resources */,
F824377124CB7A9800BED341 /* Indeed.caf in Resources */,
F8B3A7CE226CC0B7004BA588 /* shorthigh2.mp3 in Resources */,
666E283B26F7E54C00ACE4DF /* Version.xcconfig in Resources */,
F82437D224CB7A9900BED341 /* Remembers_Me_Of_Asia.caf in Resources */,
F824378F24CB7A9900BED341 /* Siri_Alert_Glucose_Rising_Fast.caf in Resources */,
F824378A24CB7A9900BED341 /* Two_Turtle_Doves.caf in Resources */,
@ -3401,6 +3448,7 @@
F8F1670A2727317D001AA3D8 /* DexcomTransmitterTimeRxMessage.swift in Sources */,
F8EA6C8221B723BC0082976B /* Date.swift in Sources */,
F8E3A2A523D78FBD00E5E98A /* SettingsViewAppleWatchSettingsViewModel.swift in Sources */,
D400F8032778BD8000B57648 /* TextsTreatmentsView.swift in Sources */,
F81FA006228E09D40028C70F /* TextsCalibration.swift in Sources */,
F816E0F724367137009EE65B /* GNSEntry+CoreDataClass.swift in Sources */,
F8F9721923A5915900C3F17D /* CGMGNSEntryTransmitter.swift in Sources */,
@ -3481,6 +3529,8 @@
F80859292364D61B00F3829D /* UserDefaults+charts.swift in Sources */,
F8B955B7258D5E2000C06016 /* ConstantsHealthKit.swift in Sources */,
F8B3A7B2226A0878004BA588 /* TextsAlerts.swift in Sources */,
D4BAF37627769B38009D3465 /* TreatmentTableViewCell.swift in Sources */,
D40C3DA62775438F00111B73 /* TreatmentEntry+CoreDataProperties.swift in Sources */,
F80D917024F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift in Sources */,
F8F9721423A5915900C3F17D /* AuthChallengeRxMessage.swift in Sources */,
47B60F3726F389E2003198D3 /* LandscapeChartViewController.swift in Sources */,
@ -3499,6 +3549,7 @@
4752B4062635878E0081D551 /* SettingsViewStatisticsSettingsViewModel.swift in Sources */,
F897AAF92200F2D200CDDD10 /* CBPeripheralState.swift in Sources */,
F858CCED25AE4CD100786B91 /* LibreOOPWebError.swift in Sources */,
D4FD899727772F9100689788 /* TreatmentEntryAccessor.swift in Sources */,
F8F971B623A5914D00C3F17D /* M5Stack+BluetoothPeripheral.swift in Sources */,
F830992323C291EE005741DF /* Watlaa+BluetoothPeripheral.swift in Sources */,
F821CF57229BF43A005C1E43 /* SnoozeParameters.swift in Sources */,
@ -3525,6 +3576,7 @@
F8A1587322EDC893007F5B5D /* ConstantsDexcomShare.swift in Sources */,
F8A1586F22EDC7EE007F5B5D /* ConstantsSuspensionPrevention.swift in Sources */,
F8B3A82D227F07D6004BA588 /* SettingsNavigationController.swift in Sources */,
D482BD942776153F003C4FB2 /* TreatmentsNavigationController.swift in Sources */,
F80ED2EC236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift in Sources */,
F8BECB05235CE5D80060DAE1 /* GlucoseChartManager.swift in Sources */,
F8C97850242A9FD500A09483 /* MiaoMiaoBluetoothPeripheralViewModel.swift in Sources */,
@ -3605,6 +3657,7 @@
F80ED2ED236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift in Sources */,
F816E10A2437E7B8009EE65B /* CGMBlueReaderTransmitterDelegate.swift in Sources */,
F8B3A850227F26F8004BA588 /* AlertTypesSettingsViewController.swift in Sources */,
D484BC292774F783008490E9 /* TreatmentsInsertViewController.swift in Sources */,
F816E0FE24367338009EE65B /* GNSEntry+BluetoothPeripheral.swift in Sources */,
F8B3A808227A2933004BA588 /* SettingsSelectedRowAction.swift in Sources */,
F8A5EEB2257CEC290085E660 /* LibreNFC.swift in Sources */,
@ -3627,6 +3680,7 @@
F8CB59C6273ECFE500BA199E /* DexcomG6GlucoseDataRxMessage.swift in Sources */,
F81F9FFC2288C7530028C70F /* NewAlertSettingsViewController.swift in Sources */,
F80D916524F5B3DE006840B5 /* Libre2+CoreDataClass.swift in Sources */,
D4028CC02774A50600341476 /* TreatmentsViewController.swift in Sources */,
F898EDF2234A8A0500BFB79B /* UInt8.swift in Sources */,
F8DF766423E781C100063910 /* BLEPeripheralAccessor.swift in Sources */,
F8F1671727288B24001AA3D8 /* DexcomSessionStopRxMessage.swift in Sources */,
@ -3647,6 +3701,7 @@
F821CF5F229BF43A005C1E43 /* ApplicationManager.swift in Sources */,
F8B3A834227F08AC004BA588 /* PickerViewData.swift in Sources */,
F8177025248ED4DE00AA3600 /* Libre1DerivedAlgorithmParameters.swift in Sources */,
D40C3DA4277542C400111B73 /* TreatmentEntry+CoreDataClass.swift in Sources */,
F808592D23677D6A00F3829D /* ChartPoint.swift in Sources */,
F8A2BC0425DB093B001D1E78 /* Atom+CoreDataClass.swift in Sources */,
F8F9722823A5915900C3F17D /* BluconUtilities.swift in Sources */,
@ -3855,6 +3910,27 @@
name = Main.strings;
sourceTree = "<group>";
};
D4AC54412778C82B0097FF10 /* Treatments.strings */ = {
isa = PBXVariantGroup;
children = (
D4AC54422778C82B0097FF10 /* en */,
D4AC54432778C82B0097FF10 /* sl */,
D4AC54442778C82B0097FF10 /* de */,
D4AC54452778C82B0097FF10 /* sv */,
D4AC54462778C82B0097FF10 /* es */,
D4AC54472778C82B0097FF10 /* pt */,
D4AC54482778C82B0097FF10 /* pl-PL */,
D4AC54492778C82B0097FF10 /* ru */,
D4AC544A2778C82B0097FF10 /* nl */,
D4AC544B2778C82B0097FF10 /* fr */,
D4AC544C2778C82B0097FF10 /* fi */,
D4AC544D2778C82C0097FF10 /* zh */,
D4AC544E2778C82C0097FF10 /* it */,
D4AC544F2778C82C0097FF10 /* ar */,
);
name = Treatments.strings;
sourceTree = "<group>";
};
F81F370525C1583400520946 /* WatlaaView.strings */ = {
isa = PBXVariantGroup;
children = (
@ -4509,12 +4585,13 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
@ -4567,7 +4644,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@ -4581,7 +4658,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = FB1D964808BD308C74247D66 /* Pods-xdrip.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APP_GROUP_IDENTIFIER = "group.com.${DEVELOPMENT_TEAM}.loopkit.LoopGroup";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@ -4610,7 +4686,6 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 170A1629CB2C62ADD901F4A6 /* Pods-xdrip.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
APP_GROUP_IDENTIFIER = "group.com.${DEVELOPMENT_TEAM}.loopkit.LoopGroup";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;

View File

@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1310"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
@ -55,8 +55,10 @@
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "32">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/(null)">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
@ -64,7 +66,7 @@
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</RemoteRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@ -73,8 +75,10 @@
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "32">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/(null)">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
@ -82,7 +86,16 @@
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
BuildableName = "xDrip4iO5.app"
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -54,8 +54,10 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/(null)">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
@ -63,7 +65,7 @@
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</RemoteRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@ -71,8 +73,10 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.Carousel"
RemotePath = "/(null)">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
@ -80,7 +84,16 @@
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "470B6185270C448000561E56"
BuildableName = "xDrip4iO5.app"
BlueprintName = "Watch App"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1310"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
@ -74,7 +74,6 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4A2661B2773EB8300B60F2A"
BuildableName = "xDripMultiWidgetExtension.appex"
BlueprintName = "xDripMultiWidgetExtension"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F8AC425921ADEBD60078C348"
BuildableName = "xdrip.app"
BlueprintName = "xdrip"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<RemoteRunnable
runnableDebuggingMode = "2"
BundleIdentifier = "com.apple.springboard">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D4A2661B2773EB8300B60F2A"
BuildableName = "xDripMultiWidgetExtension.appex"
BlueprintName = "xDripMultiWidgetExtension"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F8AC425921ADEBD60078C348"
BuildableName = "xdrip.app"
BlueprintName = "xdrip"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<EnvironmentVariables>
<EnvironmentVariable
key = "_XCWidgetKind"
value = ""
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetDefaultView"
value = "timeline"
isEnabled = "NO">
</EnvironmentVariable>
<EnvironmentVariable
key = "_XCWidgetFamily"
value = "medium"
isEnabled = "NO">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F8AC425921ADEBD60078C348"
BuildableName = "xdrip.app"
BlueprintName = "xdrip"
ReferencedContainer = "container:xdrip.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1250"
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -51,6 +51,9 @@ enum ConstantsLog {
/// application data bgreadings
static let categoryApplicationDataBgReadings = "ApplicationDataBgReadings "
/// application data Treatments
static let categoryApplicationDataTreatments = "ApplicationDataTreatments "
/// application data calibrations
static let categoryApplicationDataCalibrations = "ApplicationDataCalibrations "

View File

@ -0,0 +1,206 @@
//
// TreatmentEntryAccessor.swift
// xdrip
//
// Created by Eduardo Pietre on 24/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
import CoreData
import os
class TreatmentEntryAccessor {
// MARK: - Properties
/// for logging
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryApplicationDataTreatments)
/// CoreDataManager to use
private let coreDataManager:CoreDataManager
// MARK: - initializer
init(coreDataManager:CoreDataManager) {
self.coreDataManager = coreDataManager
}
// MARK: - public functions
/// Gives the 50 latest treatments
///
/// - returns: an array with treatments, can be empty array.
/// Order by timestamp, descending meaning the treatment at index 0 is the youngest
func getLatestTreatments() -> [TreatmentEntry] {
return getLatestTreatments(limit:50)
}
/// Returns the treatments among the 50 latest
/// that have not yet been uploaded
///
/// - returns: an array with treatments not uploaded, can be empty array.
/// Order by timestamp, descending meaning the treatment at index 0 is the youngest
func getRequireUploadTreatments() -> [TreatmentEntry] {
// filter by not uploaded
return getLatestTreatments().filter { treatment in
return !treatment.uploaded
}
}
/// Gives latest treatments
///
/// - parameters:
/// - limit : maximum amount of treatments to return, if nil then no limit in amount
/// - returns: an array with treatments, can be empty array.
/// Order by timestamp, descending meaning the treatment at index 0 is the youngest
func getLatestTreatments(limit:Int) -> [TreatmentEntry] {
return getLatestTreatments(limit:limit, howOld:nil)
}
/// Gives treatments with maximumDays old
///
/// - parameters:
/// - limit : maximum amount of treatments to return, if nil then no limit in amount
/// - howOld : maximum age in days, it will calculate exacte (24 hours) * howOld, if nil then no limit in age
/// - returns: an array with treatments, can be empty array.
/// Order by timestamp, descending meaning the treatment at index 0 is the youngest
func getLatestTreatments(limit:Int?, howOld:Int?) -> [TreatmentEntry] {
// if maximum age specified then create fromdate
var fromDate:Date?
if let howOld = howOld, howOld >= 0 {
fromDate = Date(timeIntervalSinceNow: Double(-howOld * 60 * 60 * 24))
}
return getLatestTreatments(limit: limit, fromDate: fromDate)
}
/// Gives treatments with timestamp higher than fromDate
///
/// - parameters:
/// - limit : maximum amount of treatments to return, if nil then no limit in amount
/// - fromDate : treatment must have date > fromDate
/// - returns: an array with treatments, can be empty array.
/// Order by timestamp, descending meaning the treatment at index 0 is the youngest
func getLatestTreatments(limit:Int?, fromDate:Date?) -> [TreatmentEntry] {
var returnValue:[TreatmentEntry] = []
let treatments = fetchTreatments(limit: limit, fromDate: fromDate)
loop: for (_, treatment) in treatments.enumerated() {
returnValue.append(treatment)
}
return returnValue
}
/// gets last treatment
func last() -> TreatmentEntry? {
let treatments = getLatestTreatments(limit: 1, howOld: nil)
if treatments.count > 0 {
return treatments.last
} else {
return nil
}
}
/// gets treatments, synchronously, in the managedObjectContext's thread
/// - returns:
/// treatments sorted by timestamp, ascending (ie first is oldest)
/// - parameters:
/// - to : if specified, only return treatments with timestamp smaller than fromDate (not equal to)
/// - from : if specified, only return treatments with timestamp greater than fromDate (not equal to)
/// - managedObjectContext : the ManagedObjectContext to use
func getTreatments(from: Date?, to: Date?, on managedObjectContext: NSManagedObjectContext) -> [TreatmentEntry] {
let fetchRequest: NSFetchRequest<TreatmentEntry> = TreatmentEntry.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(TreatmentEntry.date), ascending: true)]
// create predicate
if let from = from, to == nil {
let predicate = NSPredicate(format: "date > %@", from as NSDate)
fetchRequest.predicate = predicate
} else if let to = to, from == nil {
let predicate = NSPredicate(format: "date < %@", to as NSDate)
fetchRequest.predicate = predicate
} else if let to = to, let from = from {
let predicate = NSPredicate(format: "date < %@ AND date > %@", to as CVarArg, from as NSDate)
fetchRequest.predicate = predicate
}
var treatments: [TreatmentEntry] = []
managedObjectContext.performAndWait {
do {
// Execute Fetch Request
treatments = try fetchRequest.execute()
} catch {
let fetchError = error as NSError
trace("in getTreatments, Unable to Execute BgReading Fetch Request : %{public}@", log: self.log, category: ConstantsLog.categoryApplicationDataTreatments, type: .error, fetchError.localizedDescription)
}
}
return treatments
}
/// deletes treatmentEntry, synchronously, in the managedObjectContext's thread
/// - treatmentEntry : treatmentEntry to delete
/// - managedObjectContext : the ManagedObjectContext to use
func delete(treatmentEntry: TreatmentEntry, on managedObjectContext: NSManagedObjectContext) {
managedObjectContext.performAndWait {
managedObjectContext.delete(treatmentEntry)
// save changes to coredata
do {
try managedObjectContext.save()
} catch {
trace("in delete bgReading, Unable to Save Changes, error.localizedDescription = %{public}@", log: self.log, category: ConstantsLog.categoryApplicationDataTreatments, type: .error, error.localizedDescription)
}
}
}
// MARK: - private helper functions
/// returnvalue can be empty array
/// - parameters:
/// - limit: maximum amount of treatments to fetch, if 0 then no limit
/// - fromDate : if specified, only return readings with timestamp > fromDate
/// - returns:
/// List of treatments, descending, ie first is youngest
private func fetchTreatments(limit:Int?, fromDate:Date?) -> [TreatmentEntry] {
let fetchRequest: NSFetchRequest<TreatmentEntry> = TreatmentEntry.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(TreatmentEntry.date), ascending: false)]
// if fromDate specified then create predicate
if let fromDate = fromDate {
let predicate = NSPredicate(format: "date > %@", fromDate as NSDate)
fetchRequest.predicate = predicate
}
// set fetchLimit
if let limit = limit, limit >= 0 {
fetchRequest.fetchLimit = limit
}
var treatments: [TreatmentEntry] = []
coreDataManager.mainManagedObjectContext.performAndWait {
do {
// Execute Fetch Request
treatments = try fetchRequest.execute()
} catch {
let fetchError = error as NSError
trace("in fetchTreatments, Unable to Execute BgReading Fetch Request : %{public}@", log: self.log, category: ConstantsLog.categoryApplicationDataTreatments, type: .error, fetchError.localizedDescription)
}
}
return treatments
}
}

View File

@ -0,0 +1,96 @@
//
// TreatmentEntry+CoreDataClass.swift
// xdrip
//
// Created by Eduardo Pietre on 23/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
import CoreData
// @objc and Int16 allows enums to work with CoreData
@objc public enum TreatmentType: Int16 {
case Insulin
case Carbs
case Exercise
public func asString() -> String {
switch self {
case .Insulin:
return "Insulin"
case .Carbs:
return "Carbs"
case .Exercise:
return "Exercise"
default:
return "Unknown"
}
}
public func unit() -> String {
switch self {
case .Insulin:
return "u"
case .Carbs:
return "g"
case .Exercise:
return "min"
default:
return ""
}
}
}
public class TreatmentEntry: NSManagedObject {
init(date: Date, value: Double, treatmentType: TreatmentType, nsManagedObjectContext:NSManagedObjectContext) {
let entity = NSEntityDescription.entity(forEntityName: "TreatmentEntry", in: nsManagedObjectContext)!
super.init(entity: entity, insertInto: nsManagedObjectContext)
self.date = date
self.value = value
self.treatmentType = treatmentType
self.uploaded = false // tracks upload to nightscout
}
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
public func displayValue() -> String {
var string = String(self.value)
// Checks prevents .0 from being displayed
if string.suffix(2) == ".0" {
string = String(string.dropLast(2))
}
return string + " " + self.treatmentType.unit()
}
public func dictionaryRepresentationForNightScoutUpload() -> [String: Any] {
var dict: [String: Any] = [
"enteredBy": "xDrip4iOS",
"eventTime": self.date.ISOStringFromDate(),
]
switch self.treatmentType {
case .Insulin:
dict["eventType"] = "Correction Bolus"
dict["insulin"] = self.value
case .Carbs:
dict["eventType"] = "Meal Bolus"
dict["carbs"] = self.value
case .Exercise:
dict["eventType"] = "Exercise"
dict["duration"] = self.value
default:
break
}
return dict
}
}

View File

@ -0,0 +1,27 @@
//
// TreatmentEntry+CoreDataProperties.swift
// xdrip
//
// Created by Eduardo Pietre on 23/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
import CoreData
extension TreatmentEntry {
@nonobjc public class func fetchRequest() -> NSFetchRequest<TreatmentEntry> {
return NSFetchRequest<TreatmentEntry>(entityName: "TreatmentEntry")
}
@NSManaged public var date: Date
@NSManaged public var value: Double
@NSManaged public var treatmentType: TreatmentType
@NSManaged public var uploaded: Bool
}

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="19461" systemVersion="20G95" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="19461" systemVersion="21A559" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AlertEntry" representedClassName=".AlertEntry" syncable="YES">
<attribute name="alertkind" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="start" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
@ -153,6 +153,12 @@
<attribute name="snoozePeriodInMinutes" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snoozeTimeStamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
</entity>
<entity name="TreatmentEntry" representedClassName=".TreatmentEntry" syncable="YES">
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="treatmentType" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="uploaded" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="value" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
</entity>
<entity name="Watlaa" representedClassName=".Watlaa" syncable="YES">
<attribute name="firmware" optional="YES" attributeType="String"/>
<attribute name="hardware" optional="YES" attributeType="String"/>
@ -177,6 +183,7 @@
<element name="MiaoMiao" positionX="-657" positionY="189" width="128" height="88"/>
<element name="Sensor" positionX="-603.0859375" positionY="482.2890625" width="128" height="133"/>
<element name="SnoozeParameters" positionX="-648" positionY="198" width="128" height="28"/>
<element name="TreatmentEntry" positionX="-657" positionY="189" width="128" height="89"/>
<element name="Watlaa" positionX="-639" positionY="207" width="128" height="88"/>
</elements>
</model>

View File

@ -8,6 +8,7 @@
import Foundation
public class LoopManager:NSObject {
// MARK: - private properties
@ -88,7 +89,6 @@ public class LoopManager:NSObject {
UserDefaults.standard.timeStampLatestLoopSharedBgReading = lastReadings.first!.timeStamp
UserDefaults.standard.readingsStoredInSharedUserDefaultsAsDictionary = dictionary
}
}

View File

@ -29,6 +29,9 @@ public class NightScoutUploadManager:NSObject {
/// CalibrationsAccessor instance
private let calibrationsAccessor: CalibrationsAccessor
/// TreatmentEntryAccessor
private let treatmentEntryAccessor: TreatmentEntryAccessor
/// reference to coreDataManager
private let coreDataManager: CoreDataManager
@ -60,6 +63,7 @@ public class NightScoutUploadManager:NSObject {
self.calibrationsAccessor = CalibrationsAccessor(coreDataManager: coreDataManager)
self.messageHandler = messageHandler
self.sensorsAccessor = SensorsAccessor(coreDataManager: coreDataManager)
self.treatmentEntryAccessor = TreatmentEntryAccessor(coreDataManager: coreDataManager)
super.init()
@ -108,6 +112,9 @@ public class NightScoutUploadManager:NSObject {
// upload calibrations
uploadCalibrationsToNightScout()
// upload treatments
uploadTreatmentsToNightScout()
// upload activeSensor if needed
if UserDefaults.standard.uploadSensorStartTimeToNS, let activeSensor = sensorsAccessor.fetchActiveSensor() {
@ -348,6 +355,40 @@ public class NightScoutUploadManager:NSObject {
}
}
/// upload treatments to nightscout
/// Only checks recents ones
public func uploadTreatmentsToNightScout() {
trace("in uploadTreatmentsToNightScout", log: self.oslog, category: ConstantsLog.categoryNightScoutUploadManager, type: .info)
// get the latest treatments from the last maxDaysToUpload days
// filter by those that have not been uploaded
let treatments = treatmentEntryAccessor.getRequireUploadTreatments()
guard treatments.count > 0 else {
trace(" no treatments to upload", log: self.oslog, category: ConstantsLog.categoryNightScoutUploadManager, type: .info)
return
}
trace(" number of treatments to upload : %{public}@", log: self.oslog, category: ConstantsLog.categoryNightScoutUploadManager, type: .info, treatments.count.description)
// map treatments to dictionaryRepresentation
let treatmentsDictionaryRepresentation = treatments.map({$0.dictionaryRepresentationForNightScoutUpload()})
uploadData(dataToUpload: treatmentsDictionaryRepresentation, traceString: "uploadTreatmentsToNightScout", path: nightScoutTreatmentPath, completionHandler: {
// Be sure to use the correct thread.
// Running in the completionHandler thread will
// result in issues.
self.coreDataManager.mainManagedObjectContext.performAndWait {
for treatment in treatments {
treatment.uploaded = true
}
self.coreDataManager.saveChanges()
}
})
}
/// upload latest calibrations to nightscout
/// - parameters:

View File

@ -152,7 +152,125 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="KZT-Nh-dNE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-246" y="-891"/>
<point key="canvasLocation" x="-566" y="-891"/>
</scene>
<!--Treatments Scene-->
<scene sceneID="9ri-2S-eW8">
<objects>
<viewController title="Treatments Scene" interfaceStyle="dark" id="01q-Jv-AjA" customClass="TreatmentsViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="os0-CD-Pjv">
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" estimatedSectionHeaderHeight="-1" sectionFooterHeight="28" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="XPB-uN-uCA">
<rect key="frame" x="0.0" y="88" width="390" height="673"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="blue" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="TreatmentsCell" id="Gwu-WR-xta" customClass="TreatmentTableViewCell" customModule="xdrip" customModuleProvider="target">
<rect key="frame" x="0.0" y="44.666666030883789" width="390" height="45"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Gwu-WR-xta" id="DBW-d4-0o5">
<rect key="frame" x="0.0" y="0.0" width="390" height="45"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="3X4-8k-4dp">
<rect key="frame" x="30" y="10" width="330" height="25"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00:00" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JuE-mg-S0t">
<rect key="frame" x="0.0" y="1.6666666666666661" width="110" height="21.666666666666671"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</label>
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Insulin" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U6e-jp-cms">
<rect key="frame" x="110" y="1.6666666666666661" width="110" height="21.666666666666671"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="8u" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0na-qZ-kDB">
<rect key="frame" x="220" y="1.6666666666666661" width="110" height="21.666666666666671"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="highlightedColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="height" constant="25" id="hTe-PH-KmG"/>
</constraints>
</stackView>
</subviews>
<constraints>
<constraint firstItem="3X4-8k-4dp" firstAttribute="top" secondItem="DBW-d4-0o5" secondAttribute="top" constant="10" id="7vl-wW-HHy"/>
<constraint firstItem="3X4-8k-4dp" firstAttribute="leading" secondItem="DBW-d4-0o5" secondAttribute="leading" constant="30" id="Jqk-mh-mGZ"/>
<constraint firstAttribute="bottom" secondItem="3X4-8k-4dp" secondAttribute="bottom" constant="10" id="hTk-XK-vN6"/>
<constraint firstAttribute="trailing" secondItem="3X4-8k-4dp" secondAttribute="trailing" constant="30" id="m5c-aQ-ZYB"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" white="0.17999999999999999" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="dateLabel" destination="JuE-mg-S0t" id="03N-y2-Umh"/>
<outlet property="typeLabel" destination="U6e-jp-cms" id="uqQ-L0-k60"/>
<outlet property="valueLabel" destination="0na-qZ-kDB" id="DRt-MD-law"/>
</connections>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="01q-Jv-AjA" id="ZgA-8s-GVa"/>
<outlet property="delegate" destination="01q-Jv-AjA" id="zLD-2f-MIF"/>
</connections>
</tableView>
</subviews>
<viewLayoutGuide key="safeArea" id="l6g-XB-W8K"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="XPB-uN-uCA" firstAttribute="trailing" secondItem="l6g-XB-W8K" secondAttribute="trailing" id="4II-Lt-Jac"/>
<constraint firstItem="XPB-uN-uCA" firstAttribute="leading" secondItem="l6g-XB-W8K" secondAttribute="leading" id="55U-5F-TZa"/>
<constraint firstItem="XPB-uN-uCA" firstAttribute="centerX" secondItem="os0-CD-Pjv" secondAttribute="centerX" id="THx-wK-P5b"/>
<constraint firstItem="XPB-uN-uCA" firstAttribute="bottom" secondItem="l6g-XB-W8K" secondAttribute="bottom" id="ktr-HH-FqK"/>
<constraint firstItem="XPB-uN-uCA" firstAttribute="top" secondItem="l6g-XB-W8K" secondAttribute="top" id="vph-fE-Ppx"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Treatments" image="Home" id="EM7-TR-8Pt"/>
<navigationItem key="navigationItem" title="Treatments" id="fUA-gv-91n">
<barButtonItem key="leftBarButtonItem" image="arrow.clockwise.icloud" catalog="system" id="eLq-m9-bla">
<color key="tintColor" red="0.96848052740000001" green="0.89723356880000005" blue="0.24125458929999999" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
<connections>
<action selector="syncButtonTapped:" destination="01q-Jv-AjA" id="EeF-H4-ZK3"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="add" id="iA1-b8-F3J">
<color key="tintColor" systemColor="systemYellowColor"/>
<connections>
<segue destination="QgE-Gq-57r" kind="show" identifier="TreatmentsToNewTreatmentsSegue" id="iy5-gk-yrr"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="tableView" destination="XPB-uN-uCA" id="fV3-OR-Exz"/>
<outlet property="titleNavigation" destination="fUA-gv-91n" id="b1y-Qh-HjD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="IwV-Pn-lau" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1536.9230769230769" y="-1614.4549763033174"/>
</scene>
<!--Treatments-->
<scene sceneID="WDM-MY-6pS">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="IdU-mY-C1M" customClass="TreatmentsNavigationController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Treatments" image="pencil" catalog="system" id="Jgh-Nb-wg6"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Z4f-sX-pvq">
<rect key="frame" x="0.0" y="44" width="390" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="01q-Jv-AjA" kind="relationship" relationship="rootViewController" id="TU7-Ve-5LG"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="KjZ-T8-3hn" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="745" y="-1614"/>
</scene>
<!--Home-->
<scene sceneID="hNz-n2-bh7">
@ -177,6 +295,7 @@
<segue destination="NvR-Zh-2Zn" kind="show" identifier="RootViewToSnoozeView" id="VtQ-ZG-btn"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="8MU-0O-ujy"/>
<barButtonItem style="plain" systemItem="flexibleSpace" id="uM8-jT-s3T"/>
<barButtonItem title="Sensor" image="ellipsis.circle" catalog="system" id="ZIM-Wf-bUy">
<connections>
@ -190,17 +309,12 @@
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="SlH-A4-F18"/>
<barButtonItem style="plain" systemItem="flexibleSpace" id="Bnf-FN-LqX"/>
<barButtonItem title="Lock" image="lock" catalog="system" id="wfX-50-2w6">
<connections>
<action selector="screenLockToolbarButtonAction:" destination="9pv-A4-QxB" id="L14-hJ-4a9"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="a6G-aW-JeE"/>
<barButtonItem title="Help" image="questionmark.circle" catalog="system" id="DuN-xR-xYB">
<connections>
<action selector="helpToolbarButtonAction:" destination="9pv-A4-QxB" id="DGg-9c-TqQ"/>
</connections>
</barButtonItem>
</items>
</toolbar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="C16-NQ-F1Y">
@ -603,7 +717,6 @@
<outlet property="clockView" destination="ETk-QH-u1x" id="XuQ-dY-93L"/>
<outlet property="cvTitleLabelOutlet" destination="PZI-Ln-kfh" id="IKV-zy-dNM"/>
<outlet property="diffLabelOutlet" destination="7Wo-wd-80o" id="nnn-w9-1sX"/>
<outlet property="helpToolbarButtonOutlet" destination="DuN-xR-xYB" id="TdW-5k-hgZ"/>
<outlet property="highLabelOutlet" destination="Xlz-6g-zzD" id="DyX-x0-PwZ"/>
<outlet property="highStatisticLabelOutlet" destination="EbR-T4-LIg" id="VZk-1K-BCq"/>
<outlet property="highTitleLabelOutlet" destination="bUK-pC-4bd" id="R8q-Q6-q9d"/>
@ -625,7 +738,6 @@
<outlet property="sensorToolbarButtonOutlet" destination="ZIM-Wf-bUy" id="kjL-rX-6ZV"/>
<outlet property="statisticsView" destination="MtJ-rx-OB9" id="u5w-qN-5Tq"/>
<outlet property="timePeriodLabelOutlet" destination="On3-dy-RgB" id="hAe-Kx-vnM"/>
<outlet property="toolbarOutlet" destination="tVG-ML-9xd" id="p1N-b3-pnD"/>
<outlet property="valueLabelOutlet" destination="We3-bN-ffR" id="wtY-sZ-mev"/>
</connections>
</viewController>
@ -721,7 +833,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lDU-f7-mwF" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1753.8461538461538" y="-887.20379146919424"/>
<point key="canvasLocation" x="1537" y="-891"/>
</scene>
<!--Picker View Controller-->
<scene sceneID="6RW-Ef-2Hm">
@ -803,7 +915,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HPe-YM-BbI" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-566" y="1268"/>
<point key="canvasLocation" x="-566" y="1500"/>
</scene>
<!--Date Picker View Controller-->
<scene sceneID="OeI-t1-GDw">
@ -885,7 +997,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="y9l-yM-uDB" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="183" y="1268"/>
<point key="canvasLocation" x="403" y="1501"/>
</scene>
<!--Settings View Controller-->
<scene sceneID="wg7-f3-ORb">
@ -1569,13 +1681,14 @@
</userDefinedRuntimeAttributes>
<connections>
<segue destination="9pv-A4-QxB" kind="relationship" relationship="viewControllers" id="u7Y-xg-7CH"/>
<segue destination="FwD-2z-GTm" kind="relationship" relationship="viewControllers" id="aWk-QN-f3h"/>
<segue destination="dyf-bd-1WE" kind="relationship" relationship="viewControllers" id="lzU-1b-eKA"/>
<segue destination="IdU-mY-C1M" kind="relationship" relationship="viewControllers" id="zLS-NW-E1a"/>
<segue destination="FwD-2z-GTm" kind="relationship" relationship="viewControllers" id="jP9-BP-Xv0"/>
<segue destination="dyf-bd-1WE" kind="relationship" relationship="viewControllers" id="xge-N9-aEh"/>
</connections>
</tabBarController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HuB-VB-40B" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-621" y="155"/>
<point key="canvasLocation" x="-566" y="153"/>
</scene>
<!--Settings-->
<scene sceneID="jbr-kK-p6W">
@ -1712,17 +1825,149 @@
</objects>
<point key="canvasLocation" x="3973" y="581"/>
</scene>
<!--Treatments Insert Scene-->
<scene sceneID="xQI-ZW-z6P">
<objects>
<viewController title="Treatments Insert Scene" id="QgE-Gq-57r" customClass="TreatmentsInsertViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="u0y-ki-EPd">
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="40" translatesAutoresizingMaskIntoConstraints="NO" id="Ltu-UO-Ypa">
<rect key="frame" x="35" y="219" width="320" height="406"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="24" translatesAutoresizingMaskIntoConstraints="NO" id="lph-Ca-ZpH">
<rect key="frame" x="36" y="0.0" width="248" height="150"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="ZDj-72-yiq" userLabel="Carbs Stack">
<rect key="frame" x="0.0" y="0.0" width="248" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Carbs (g):" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fvP-G8-Gxk">
<rect key="frame" x="0.0" y="5.6666666666666572" width="140" height="23"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="140" id="XcQ-AC-RqE"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="19"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Amount" textAlignment="center" minimumFontSize="16" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="saY-fP-EEW">
<rect key="frame" x="148" y="0.0" width="100" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="o92-Cd-7bP"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="numberPad" smartInsertDeleteType="no" smartQuotesType="no"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="4G8-c0-IhJ" userLabel="Insulin Stack">
<rect key="frame" x="0.0" y="58" width="248" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Insulin (U):" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="agq-m8-HZ9">
<rect key="frame" x="0.0" y="0.0" width="140" height="34"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="140" id="PIM-iN-dt1"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="19"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Amount" textAlignment="center" minimumFontSize="16" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="ggq-1D-Pj6">
<rect key="frame" x="148" y="0.0" width="100" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="KId-Tf-1aj"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="numberPad" smartInsertDeleteType="no" smartQuotesType="no"/>
</textField>
</subviews>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="OJv-t7-QLZ" userLabel="Exercise Stack">
<rect key="frame" x="0.0" y="116" width="248" height="34"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Exercise (min):" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9tx-02-GXf">
<rect key="frame" x="0.0" y="0.0" width="140" height="34"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="140" id="c4f-TH-tJq"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="19"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Amount" textAlignment="center" minimumFontSize="16" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="kl9-iM-MlH">
<rect key="frame" x="148" y="0.0" width="100" height="34"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="1kf-sW-mbf"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="20"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="numberPad" smartInsertDeleteType="no" smartQuotesType="no"/>
</textField>
</subviews>
</stackView>
</subviews>
</stackView>
<datePicker contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" datePickerMode="dateAndTime" minuteInterval="1" style="wheels" translatesAutoresizingMaskIntoConstraints="NO" id="M5l-qV-xjH">
<rect key="frame" x="0.0" y="190" width="320" height="216"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
<color key="value" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="boolean" keyPath="highlightsToday" value="NO"/>
</userDefinedRuntimeAttributes>
</datePicker>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="mwU-Tw-d7Q"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Ltu-UO-Ypa" firstAttribute="centerX" secondItem="u0y-ki-EPd" secondAttribute="centerX" id="0AB-vn-joB"/>
<constraint firstItem="Ltu-UO-Ypa" firstAttribute="centerY" secondItem="u0y-ki-EPd" secondAttribute="centerY" id="aQT-9v-5xe"/>
</constraints>
</view>
<tabBarItem key="tabBarItem" title="Treatments" image="Home" id="ucH-hI-fdv"/>
<toolbarItems/>
<navigationItem key="navigationItem" title="New Entry" id="nDn-qs-kKp">
<barButtonItem key="rightBarButtonItem" systemItem="done" id="6Fh-ms-ugk">
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<action selector="doneButtonTapped:" destination="QgE-Gq-57r" id="pG7-65-6ae"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="carbsLabel" destination="fvP-G8-Gxk" id="d2b-CN-IK4"/>
<outlet property="carbsStackView" destination="ZDj-72-yiq" id="HEu-wA-BlI"/>
<outlet property="carbsTextField" destination="saY-fP-EEW" id="4DV-cC-8cz"/>
<outlet property="datePicker" destination="M5l-qV-xjH" id="itP-VQ-w6m"/>
<outlet property="doneButton" destination="6Fh-ms-ugk" id="RiQ-MN-r0W"/>
<outlet property="exerciseLabel" destination="9tx-02-GXf" id="GH5-oA-TX3"/>
<outlet property="exerciseStackView" destination="OJv-t7-QLZ" id="kuw-Ef-fXa"/>
<outlet property="exerciseTextField" destination="kl9-iM-MlH" id="hcJ-8j-9xT"/>
<outlet property="insulinLabel" destination="agq-m8-HZ9" id="rx7-pv-7Yo"/>
<outlet property="insulinStackView" destination="4G8-c0-IhJ" id="tao-kP-Rbv"/>
<outlet property="insulinTextField" destination="ggq-1D-Pj6" id="eDP-Dz-C8Z"/>
<outlet property="titleNavigation" destination="nDn-qs-kKp" id="OLC-l6-yUz"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vCD-5v-swn" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2342" y="-1614"/>
</scene>
</scenes>
<resources>
<image name="Bluetooth" width="30" height="30"/>
<image name="Home" width="30" height="30"/>
<image name="Settings" width="30" height="30"/>
<image name="arrow.clockwise.icloud" catalog="system" width="128" height="88"/>
<image name="chevron.backward" catalog="system" width="96" height="128"/>
<image name="chevron.forward" catalog="system" width="96" height="128"/>
<image name="ellipsis.circle" catalog="system" width="128" height="121"/>
<image name="lock" catalog="system" width="128" height="128"/>
<image name="moon.zzz" catalog="system" width="115" height="128"/>
<image name="questionmark.circle" catalog="system" width="128" height="121"/>
<image name="pencil" catalog="system" width="128" height="113"/>
<image name="scope" catalog="system" width="128" height="122"/>
<image name="sensor14_14_alt" width="390" height="14"/>
<systemColor name="systemGrayColor">

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,6 @@
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -0,0 +1,10 @@
/////////////////////////////////////////////////////////////////////////////////////////////
///// Translation needed - remove this header after translation /////
/////////////////////////////////////////////////////////////////////////////////////////////
"treatments_title" = "Treatments";
"treatments_new_button" = "New";
"treatments_new_entry" = "New Entry";
"treatments_carbs_with_unit" = "Carbs (g):";
"treatments_insulin_with_unit" = "Insulin (U):";
"treatments_exercise_with_unit" = "Exercise (min):";

View File

@ -38,7 +38,10 @@
<key>NFCReaderUsageDescription</key>
<string>xDrip4iO5 uses NFC to scan Libre sensors.</string>
<key>NSAppTransportSecurity</key>
<dict/>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Connect to CGM Transmitter and M5Stack</string>
<key>NSBluetoothPeripheralUsageDescription</key>

View File

@ -0,0 +1,31 @@
import Foundation
/// all texts related to treatmentss (2 views)
enum Texts_TreatmentsView {
static private let filename = "Treatments"
static let treatmentsTitle:String = {
return NSLocalizedString("treatments_title", tableName: filename, bundle: Bundle.main, value: "Treatments", comment: "Title of treatments view.")
}()
static let newButton:String = {
return NSLocalizedString("treatments_new_button", tableName: filename, bundle: Bundle.main, value: "New", comment: "New button text.")
}()
static let newEntryTitle:String = {
return NSLocalizedString("treatments_new_entry", tableName: filename, bundle: Bundle.main, value: "New Entry", comment: "New entry view title.")
}()
static let carbsWithUnit:String = {
return NSLocalizedString("treatments_carbs_with_unit", tableName: filename, bundle: Bundle.main, value: "Carbs (g):", comment: "Carbs with unit.")
}()
static let insulinWithUnit:String = {
return NSLocalizedString("treatments_insulin_with_unit", tableName: filename, bundle: Bundle.main, value: "Insulin (U):", comment: "Insulin with unit.")
}()
static let exerciseWithUnit:String = {
return NSLocalizedString("treatments_exercise_with_unit", tableName: filename, bundle: Bundle.main, value: "Exercise (min):", comment: "Exercise with unit.")
}()
}

View File

@ -312,6 +312,9 @@ final class RootViewController: UIViewController {
/// CalibrationsAccessor instance
private var calibrationsAccessor:CalibrationsAccessor?
/// TreatmentEntryAccessor instance
private var treatmentEntryAccessor:TreatmentEntryAccessor?
/// NightScoutUploadManager instance
private var nightScoutUploadManager:NightScoutUploadManager?
@ -784,6 +787,8 @@ final class RootViewController: UIViewController {
guard let bgReadingsAccessor = bgReadingsAccessor else {
fatalError("In setupApplicationData, failed to initialize bgReadings")
}
treatmentEntryAccessor = TreatmentEntryAccessor(coreDataManager: coreDataManager)
// instantiate calibrations
calibrationsAccessor = CalibrationsAccessor(coreDataManager: coreDataManager)
@ -2922,7 +2927,9 @@ extension RootViewController: UITabBarControllerDelegate {
navigationController.configure(coreDataManager: coreDataManager, bluetoothPeripheralManager: bluetoothPeripheralManager)
}
} else if let navigationController = viewController as? TreatmentsNavigationController, let coreDataManager = coreDataManager, let nightScoutUploadManager = nightScoutUploadManager, let treatmentEntryAccessor = treatmentEntryAccessor {
navigationController.configure(coreDataManager: coreDataManager, nightScoutUploadManager: nightScoutUploadManager, treatmentEntryAccessor: treatmentEntryAccessor)
}
}
}

View File

@ -0,0 +1,25 @@
//
// TreatmentTableViewCell.swift
// xdrip
//
// Created by Eduardo Pietre on 24/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
class TreatmentTableViewCell: UITableViewCell {
@IBOutlet weak var typeLabel: UILabel!
@IBOutlet weak var valueLabel: UILabel!
@IBOutlet weak var dateLabel: UILabel!
public func setupWithTreatment(_ treatment: TreatmentEntry) {
self.typeLabel.text = treatment.treatmentType.asString()
self.valueLabel.text = treatment.displayValue()
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM HH:mm"
self.dateLabel.text = formatter.string(from: treatment.date)
}
}

View File

@ -0,0 +1,132 @@
//
// TreatmentsInsertViewController.swift
// xdrip
//
// Created by Eduardo Pietre on 23/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
class TreatmentsInsertViewController : UIViewController {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var carbsLabel: UILabel!
@IBOutlet weak var insulinLabel: UILabel!
@IBOutlet weak var exerciseLabel: UILabel!
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var okButton: UIButton!
@IBOutlet weak var datePicker: UIDatePicker!
@IBOutlet weak var carbsTextField: UITextField!
@IBOutlet weak var insulinTextField: UITextField!
@IBOutlet weak var exerciseTextField: UITextField!
// MARK: - private properties
/// reference to coreDataManager
private var coreDataManager:CoreDataManager?
// handler to executed when user clicks actionButton
private var entryHandler:((_ entries: [TreatmentEntry]) -> Void)?
/// handler to execute when user clicks cancelHandler
private var cancelHandler:(() -> Void)?
// MARK: - overrides
// set the status bar content colour to light to match new darker theme
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Title
self.titleLabel.text = Texts_TreatmentsView.newEntryTitle
// Labels for each TextField
self.carbsLabel.text = Texts_TreatmentsView.carbsWithUnit
self.insulinLabel.text = Texts_TreatmentsView.insulinWithUnit
self.exerciseLabel.text = Texts_TreatmentsView.exerciseWithUnit
// Buttons
self.cancelButton.setTitle(Texts_Common.Cancel, for: .normal)
self.okButton.setTitle(Texts_Common.Ok, for: .normal)
self.addDoneButtonOnNumpad(textField: self.carbsTextField)
self.addDoneButtonOnNumpad(textField: self.insulinTextField)
self.addDoneButtonOnNumpad(textField: self.exerciseTextField)
self.setDismissKeyboard()
}
// MARK: - buttons actions
@IBAction func okButtonTapped(_ sender: UIButton) {
guard let coreDataManager = coreDataManager, let entryHandler = entryHandler else {
return
}
var treatments: [TreatmentEntry] = []
let date = datePicker.date
if let carbsText = carbsTextField.text, let carbs = Double(carbsText) {
let treatment = TreatmentEntry(date: date, value: carbs, treatmentType: .Carbs, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
treatments.append(treatment)
}
if let insulinText = insulinTextField.text, let insulin = Double(insulinText) {
let treatment = TreatmentEntry(date: date, value: insulin, treatmentType: .Insulin, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
treatments.append(treatment)
}
if let exerciseText = exerciseTextField.text, let exercise = Double(exerciseText) {
let treatment = TreatmentEntry(date: date, value: exercise, treatmentType: .Exercise, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
treatments.append(treatment)
}
entryHandler(treatments)
}
@IBAction func cancelButtonTapped(_ sender: UIButton) {
if let cancelHandler = cancelHandler {
cancelHandler()
}
}
// MARK: - public functions
public func configure(coreDataManager: CoreDataManager?, entryHandler: ((_ entries: [TreatmentEntry]) -> Void)?, cancelHandler:(() -> Void)?) {
// initalize private properties
self.coreDataManager = coreDataManager
self.entryHandler = entryHandler
self.cancelHandler = cancelHandler
}
// MARK: - private functions
private func addDoneButtonOnNumpad(textField: UITextField) {
let keypadToolbar: UIToolbar = UIToolbar()
// add a done button to the numberpad
keypadToolbar.items = [
UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil),
UIBarButtonItem(title: Texts_Common.Ok, style: UIBarButtonItem.Style.done, target: textField, action: #selector(UITextField.resignFirstResponder))
]
keypadToolbar.sizeToFit()
// add a toolbar with a done button above the number pad
textField.inputAccessoryView = keypadToolbar
} //addDoneToKeyPad
func setDismissKeyboard() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboardTouchOutside))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc private func dismissKeyboardTouchOutside() {
view.endEditing(true)
}
}

View File

@ -0,0 +1,73 @@
//
// TreatmentsNavigationController.swift
// xdrip
//
// Created by Eduardo Pietre on 24/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import UIKit
final class TreatmentsNavigationController: UINavigationController {
// set the status bar content colour to light to match new darker theme
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
// MARK: - private properties
/// reference to coreDataManager
private var coreDataManager:CoreDataManager?
/// reference to nightScoutUploadManager
private var nightScoutUploadManager: NightScoutUploadManager?
/// reference to treatmentEntryAccessor
private var treatmentEntryAccessor: TreatmentEntryAccessor?
// MARK: - public functions
/// configure
public func configure(coreDataManager: CoreDataManager, nightScoutUploadManager: NightScoutUploadManager, treatmentEntryAccessor: TreatmentEntryAccessor) {
// initalize private properties
self.coreDataManager = coreDataManager
self.nightScoutUploadManager = nightScoutUploadManager
self.treatmentEntryAccessor = treatmentEntryAccessor
}
// MARK: - overrides
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
override func viewDidAppear(_ animated: Bool) {
// remove titles from tabbar items
self.tabBarController?.cleanTitles()
}
override func viewWillAppear(_ animated: Bool) {
// restrict rotation of this Navigation Controller to just portrait
(UIApplication.shared.delegate as! AppDelegate).restrictRotation = .portrait
}
}
extension TreatmentsNavigationController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if let coreDataManager = coreDataManager, let nightScoutUploadManager = nightScoutUploadManager, let treatmentEntryAccessor = treatmentEntryAccessor, let treatmentsViewController = viewController as? TreatmentsViewController {
treatmentsViewController.configure(coreDataManager: coreDataManager, nightScoutUploadManager: nightScoutUploadManager, treatmentEntryAccessor: treatmentEntryAccessor)
}
}
}

View File

@ -0,0 +1,134 @@
//
// TreatmentsViewController.swift
// xdrip
//
// Created by Eduardo Pietre on 23/12/21.
// Copyright © 2021 Johan Degraeve. All rights reserved.
//
import Foundation
import UIKit
class TreatmentsViewController : UIViewController {
// MARK: - private properties
// Will store the recent treatments to be displayed
private var treatments: [TreatmentEntry] = []
/// reference to coreDataManager
private var coreDataManager: CoreDataManager?
/// reference to nightScoutUploadManager
private var nightScoutUploadManager: NightScoutUploadManager?
/// reference to treatmentEntryAccessor
private var treatmentEntryAccessor: TreatmentEntryAccessor?
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var newButton: UIButton!
@IBOutlet weak var tableView: UITableView!
@IBAction func newButtonTapped(_ sender: UIButton) {
self.presentTreatmentsInsert()
}
@IBAction func uploadButtonTapped(_ sender: UIButton) {
nightScoutUploadManager?.uploadTreatmentsToNightScout()
let alert = UIAlertController(title: Texts_Common.Ok, message: Texts_Common.Ok, actionHandler: nil)
self.present(alert, animated: true, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.titleLabel.text = Texts_TreatmentsView.treatmentsTitle
self.newButton.setTitle(Texts_TreatmentsView.newButton, for: .normal)
}
// MARK: - public functions
public func configure(coreDataManager: CoreDataManager, nightScoutUploadManager: NightScoutUploadManager, treatmentEntryAccessor: TreatmentEntryAccessor) {
// initalize private properties
self.coreDataManager = coreDataManager
self.nightScoutUploadManager = nightScoutUploadManager
self.treatmentEntryAccessor = treatmentEntryAccessor
self.reloadTreatments()
self.tableView.reloadData()
}
// MARK: - private functions
private func reloadTreatments() {
guard let treatmentEntryAccessor = treatmentEntryAccessor else { return }
self.treatments = treatmentEntryAccessor.getLatestTreatments()
}
private func presentTreatmentsInsert() {
let insertViewController = UIStoryboard.main.instantiateViewController(withIdentifier: "TreatmentsInsertViewController") as! TreatmentsInsertViewController
insertViewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
let entryHandler = { (entries : [TreatmentEntry]) in
self.coreDataManager?.saveChanges()
insertViewController.dismiss(animated: true, completion: nil)
self.reloadTreatments()
self.tableView.reloadData()
}
let cancelHandler = {
insertViewController.dismiss(animated: true, completion: nil)
}
//configure insertViewController
insertViewController.configure(coreDataManager: coreDataManager, entryHandler: entryHandler, cancelHandler: cancelHandler)
// present it
self.present(insertViewController, animated: true)
}
}
// MARK: - UITableView related
extension TreatmentsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.treatments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TreatmentsCell", for: indexPath) as? TreatmentTableViewCell else {
fatalError("Unexpected Table View Cell")
}
let treatment = self.treatments[indexPath.row]
cell.setupWithTreatment(treatment)
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
guard let treatmentEntryAccessor = treatmentEntryAccessor, let coreDataManager = coreDataManager else {
return
}
let treatment = treatments[indexPath.row]
treatmentEntryAccessor.delete(treatmentEntry: treatment, on: coreDataManager.mainManagedObjectContext)
treatments.remove(at: indexPath.row)
self.reloadTreatments()
self.tableView.reloadData()
}
}
}