add user-defined TIR back but in a better way
to avoid adding extra menu lines, use an enum to track the TIR type chosen and allow the user to just chose directly, or cycle through by double-tapping the statistics view
This commit is contained in:
parent
d96f2e2e66
commit
bd6ce1c184
|
@ -37,6 +37,7 @@
|
|||
47ADD2E127FB05EB0025E2F4 /* ChartPointsScatterDownTrianglesWithDropdownLineLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47ADD2E027FB05EB0025E2F4 /* ChartPointsScatterDownTrianglesWithDropdownLineLayer.swift */; };
|
||||
47B60F3726F389E2003198D3 /* LandscapeChartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B60F3626F389E2003198D3 /* LandscapeChartViewController.swift */; };
|
||||
47B7FC722B00CF4B004C872B /* FollowerBackgroundKeepAliveType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47B7FC712B00CF4B004C872B /* FollowerBackgroundKeepAliveType.swift */; };
|
||||
47CF18B22B37689A00FA6160 /* TimeInRangeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CF18B12B37689A00FA6160 /* TimeInRangeType.swift */; };
|
||||
47D2DB3B2B14F6D000C8EE6B /* ScreenLockDimmingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D2DB3A2B14F6D000C8EE6B /* ScreenLockDimmingType.swift */; };
|
||||
47D9BC952A78498500AB85B2 /* BgReadingsDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47D9BC942A78498500AB85B2 /* BgReadingsDetailView.swift */; };
|
||||
47DB06C22A6FC02200267BE3 /* SettingsViewDataSourceSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47DB06C12A6FC02200267BE3 /* SettingsViewDataSourceSettingsViewModel.swift */; };
|
||||
|
@ -742,6 +743,7 @@
|
|||
47ADD2E027FB05EB0025E2F4 /* ChartPointsScatterDownTrianglesWithDropdownLineLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartPointsScatterDownTrianglesWithDropdownLineLayer.swift; sourceTree = "<group>"; };
|
||||
47B60F3626F389E2003198D3 /* LandscapeChartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandscapeChartViewController.swift; sourceTree = "<group>"; };
|
||||
47B7FC712B00CF4B004C872B /* FollowerBackgroundKeepAliveType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowerBackgroundKeepAliveType.swift; sourceTree = "<group>"; };
|
||||
47CF18B12B37689A00FA6160 /* TimeInRangeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInRangeType.swift; sourceTree = "<group>"; };
|
||||
47D2DB3A2B14F6D000C8EE6B /* ScreenLockDimmingType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockDimmingType.swift; sourceTree = "<group>"; };
|
||||
47D9BC942A78498500AB85B2 /* BgReadingsDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BgReadingsDetailView.swift; sourceTree = "<group>"; };
|
||||
47DB06C02A6FB3CC00267BE3 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/BgReadings.strings; sourceTree = "<group>"; };
|
||||
|
@ -1670,6 +1672,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
47FB28072636B04200042FFB /* StatisticsManager.swift */,
|
||||
47CF18B12B37689A00FA6160 /* TimeInRangeType.swift */,
|
||||
);
|
||||
path = Statistics;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3862,6 +3865,7 @@
|
|||
F8F9722D23A5915900C3F17D /* M5StackBluetoothTransmitter.swift in Sources */,
|
||||
F808D2C8240323CA0084B5DB /* BubbleBluetoothPeripheralViewModel.swift in Sources */,
|
||||
F8E6C79024CEC22A007C1199 /* TextsSnooze.swift in Sources */,
|
||||
47CF18B22B37689A00FA6160 /* TimeInRangeType.swift in Sources */,
|
||||
F8F9722C23A5915900C3F17D /* GlucoseData.swift in Sources */,
|
||||
F8A389E7232ECE7E0010F405 /* SettingsViewUtilities.swift in Sources */,
|
||||
F8A2BC3125DB0D6D001D1E78 /* BluetoothPeripheralManager+M5StackBluetoothTransmitterDelegate.swift in Sources */,
|
||||
|
|
|
@ -125,6 +125,8 @@ extension UserDefaults {
|
|||
case daysToUseStatistics = "daysToUseStatistics"
|
||||
/// use IFCC way to show A1C?
|
||||
case useIFCCA1C = "useIFCCA1C"
|
||||
/// which type of TIR calculation is selected?
|
||||
case timeInRangeType = "timeInRangeType"
|
||||
/// no longer used, but will leave it here to prevent compiler coredata warnings
|
||||
case useStandardStatisticsRange = "useStandardStatisticsRange"
|
||||
/// use the newer TITR of 70-140mg/dL to calculate the statistics? If false, we will use the conventional TIR of 70-180mg/dL
|
||||
|
@ -1171,25 +1173,15 @@ extension UserDefaults {
|
|||
}
|
||||
}
|
||||
|
||||
/// no longer used, but will leave it here to prevent compiler coredata warnings
|
||||
@objc dynamic var useStandardStatisticsRange: Bool {
|
||||
// default value for bool in userdefaults is false, by default we want the statistics view to calculate using the older-style, standardised TIR values (false)
|
||||
/// holds the enum integer of the time in range calculation type
|
||||
/// it will default to 0 which is standard
|
||||
var timeInRangeType: TimeInRangeType {
|
||||
get {
|
||||
return bool(forKey: Key.useTITRStatisticsRange.rawValue)
|
||||
let timeInRangeTypeAsInt = integer(forKey: Key.timeInRangeType.rawValue)
|
||||
return TimeInRangeType(rawValue: timeInRangeTypeAsInt) ?? .standardRange
|
||||
}
|
||||
set {
|
||||
set(newValue, forKey: Key.useTITRStatisticsRange.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// use the newer TITR range of 70-140mg/dL to calculate the statistics? If false, we will use the conventional TIR range of 70-180mg/dL
|
||||
@objc dynamic var useTITRStatisticsRange: Bool {
|
||||
// default value for bool in userdefaults is false, by default we want the statistics view to calculate using the older-style, standardised TIR values (false)
|
||||
get {
|
||||
return bool(forKey: Key.useTITRStatisticsRange.rawValue)
|
||||
}
|
||||
set {
|
||||
set(newValue, forKey: Key.useTITRStatisticsRange.rawValue)
|
||||
set(newValue.rawValue, forKey: Key.timeInRangeType.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ public final class StatisticsManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// let's set up the which values will be used to calculate TIR. It can be either the standardised "Time in Range" values or the newer "Time in Tight Range" values.
|
||||
let useTITR: Bool = UserDefaults.standard.useTITRStatisticsRange
|
||||
|
||||
|
@ -132,6 +132,9 @@ public final class StatisticsManager {
|
|||
lowLimitForTIR = useTITR ? ConstantsStatistics.standardisedLowValueForTITRInMmol : ConstantsStatistics.standardisedLowValueForTIRInMmol
|
||||
highLimitForTIR = useTITR ? ConstantsStatistics.standardisedHighValueForTITRInMmol : ConstantsStatistics.standardisedHighValueForTIRInMmol
|
||||
}
|
||||
*/
|
||||
lowLimitForTIR = UserDefaults.standard.timeInRangeType.lowerLimit
|
||||
highLimitForTIR = UserDefaults.standard.timeInRangeType.higherLimit
|
||||
|
||||
// make sure that there exist elements in the glucoseValue array before trying to process statistics calculations or we could get a fatal divide by zero error/crash
|
||||
if glucoseValues.count > 0 {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// TimeInRangeType.swift
|
||||
// xdrip
|
||||
//
|
||||
// Created by Paul Plant on 23/12/23.
|
||||
// Copyright © 2023 Johan Degraeve. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
/// types of background keep-alive
|
||||
public enum TimeInRangeType: Int, CaseIterable {
|
||||
|
||||
// when adding to TimeInRangeType, add new cases at the end (ie 3, ...)
|
||||
// if this is done in the middle then a database migration would be required, because the rawvalue is stored as Int16 in the coredata
|
||||
// the order of the returned enum can be defined in allCases below
|
||||
|
||||
case standardRange = 0
|
||||
case tightRange = 1
|
||||
case userDefinedRange = 2
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .standardRange:
|
||||
return Texts_SettingsView.timeInRangeTypeStandardRange
|
||||
case .tightRange:
|
||||
return Texts_SettingsView.timeInRangeTypeTightRange
|
||||
case .userDefinedRange:
|
||||
return Texts_SettingsView.timeInRangeTypeUserDefinedRange
|
||||
}
|
||||
}
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .standardRange:
|
||||
return Texts_Common.inRangeStatistics
|
||||
case .tightRange:
|
||||
return Texts_Common.inTightRangeStatistics
|
||||
case .userDefinedRange:
|
||||
return Texts_Common.userRangeStatistics
|
||||
}
|
||||
}
|
||||
|
||||
var lowerLimit: Double {
|
||||
|
||||
let isMgDl = UserDefaults.standard.bloodGlucoseUnitIsMgDl
|
||||
|
||||
switch self {
|
||||
case .standardRange:
|
||||
return isMgDl ? ConstantsStatistics.standardisedLowValueForTIRInMgDl : ConstantsStatistics.standardisedLowValueForTIRInMmol
|
||||
case .tightRange:
|
||||
return isMgDl ? ConstantsStatistics.standardisedLowValueForTITRInMgDl : ConstantsStatistics.standardisedLowValueForTITRInMmol
|
||||
case .userDefinedRange:
|
||||
return UserDefaults.standard.lowMarkValueInUserChosenUnit
|
||||
}
|
||||
}
|
||||
|
||||
var higherLimit: Double {
|
||||
|
||||
let isMgDl = UserDefaults.standard.bloodGlucoseUnitIsMgDl
|
||||
|
||||
switch self {
|
||||
case .standardRange:
|
||||
return isMgDl ? ConstantsStatistics.standardisedHighValueForTIRInMgDl : ConstantsStatistics.standardisedHighValueForTIRInMmol
|
||||
case .tightRange:
|
||||
return isMgDl ? ConstantsStatistics.standardisedHighValueForTITRInMgDl : ConstantsStatistics.standardisedHighValueForTITRInMmol
|
||||
case .userDefinedRange:
|
||||
return UserDefaults.standard.highMarkValueInUserChosenUnit
|
||||
}
|
||||
}
|
||||
|
||||
func rangeString() -> String {
|
||||
|
||||
let isMgDl = UserDefaults.standard.bloodGlucoseUnitIsMgDl
|
||||
|
||||
return " (" + self.lowerLimit.bgValuetoString(mgdl: isMgDl) + "-" + self.higherLimit.bgValuetoString(mgdl: isMgDl) + ")"
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -30,7 +30,6 @@
|
|||
"settingsviews_showStatistics" = "Show Statistics";
|
||||
"settingsviews_daysToUseStatisticsTitle" = "Days to Calculate";
|
||||
"settingsviews_daysToUseStatisticsMessage" = "Maximum days we should try to use to calculate the statistics?\n\n(Enter 0 to calculate today since midnight)";
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
"settingsviews_sectiontitletransmitter" = "Transmitter";
|
||||
"settingsviews_transmittertype" = "Transmitter Type";
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"common_statistics_low" = "Low";
|
||||
"common_statistics_inRange" = "In Range";
|
||||
"common_statistics_inTightRange" = "Tight Range";
|
||||
"common_statistics_userRange" = "User Range";
|
||||
"common_statistics_high" = "High";
|
||||
"common_statistics_average" = "Average";
|
||||
"common_statistics_a1c" = "HbA1c";
|
||||
|
|
|
@ -60,7 +60,10 @@
|
|||
"settingsviews_showStatistics" = "Show Statistics";
|
||||
"settingsviews_daysToUseStatisticsTitle" = "Days to Calculate";
|
||||
"settingsviews_daysToUseStatisticsMessage" = "Maximum days we should try to use to calculate the statistics?\n\n(Enter 0 to calculate today since midnight)";
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
"settingsviews_labelTimeInRangeType" = "Time In Range Type";
|
||||
"settingsviews_timeInRangeTypeStandardRange" = "Standard Range";
|
||||
"settingsviews_timeInRangeTypeTightRange" = "Tight Range";
|
||||
"settingsviews_timeInRangeTypeUserDefinedRange" = "User Range";
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
"settingsviews_sectiontitletransmitter" = "Transmitter";
|
||||
"settingsviews_transmittertype" = "Transmitter Type";
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
"common_statistics_low" = "Baja";
|
||||
"common_statistics_inRange" = "En Rango";
|
||||
"common_statistics_inTightRange" = "Estrecho";
|
||||
"common_statistics_userRange" = "Usuario";
|
||||
"common_statistics_high" = "Alta";
|
||||
"common_statistics_average" = "Promedio";
|
||||
"common_statistics_a1c" = "HbA1c";
|
||||
|
|
|
@ -55,7 +55,10 @@
|
|||
"settingsviews_showStatistics" = "Mostrar Estadísticas";
|
||||
"settingsviews_daysToUseStatisticsTitle" = "Días a Calcular";
|
||||
"settingsviews_daysToUseStatisticsMessage" = "Máximos días a intentar usar para calcular las estadísticas?\n\n(Entrar 0 para calcular el día de hoy desde las 00:00hrs)";
|
||||
"settingsviews_useTITRStatisticsRange" = "Usar Tiempo en Rango Estrecho";
|
||||
"settingsviews_labelTimeInRangeType" = "Tipo de Tiempo en Rango";
|
||||
"settingsviews_timeInRangeTypeStandardRange" = "Rango Estándar";
|
||||
"settingsviews_timeInRangeTypeTightRange" = "Rango Estrecho";
|
||||
"settingsviews_timeInRangeTypeUserDefinedRange" = "Rango Usuario";
|
||||
"settingsviews_useIFCCA1C" = "Ver HbA1c en mmols/mol";
|
||||
"settingsviews_sectiontitletransmitter" = "Transmisor";
|
||||
"settingsviews_transmittertype" = "Tipo de Transmisor";
|
||||
|
|
|
@ -307,9 +307,6 @@
|
|||
/// statistics settings, section title
|
||||
"settingsviews_sectiontitlestatistics" = "Statistics";
|
||||
|
||||
/// statistics settings, use standard range?
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
|
||||
/// statistics settings, use IFCC method for HbA1c?
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
|
||||
|
|
|
@ -307,9 +307,6 @@
|
|||
/// statistics settings, section title
|
||||
"settingsviews_sectiontitlestatistics" = "Statistics";
|
||||
|
||||
/// statistics settings, use standard range?
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
|
||||
/// statistics settings, use IFCC method for HbA1c?
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
|
||||
|
|
|
@ -307,9 +307,6 @@
|
|||
/// statistics settings, section title
|
||||
"settingsviews_sectiontitlestatistics" = "Statistics";
|
||||
|
||||
/// statistics settings, use standard range?
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
|
||||
/// statistics settings, use IFCC method for HbA1c?
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
|
||||
|
|
|
@ -270,9 +270,6 @@
|
|||
/// transmitter settings, this is for the button, when clicked then user will be requested to give transmitter id. The only difference with settingsviews_transmitterid is that ':' is not added
|
||||
"settingsviews_transmitterid_text_for_button" = "Transmitter ID";
|
||||
|
||||
/// statistics settings, use standard range?
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
|
||||
/// dexcom share settings, where user can select if readings should be uploaded to dexcom share yes or no
|
||||
"settingsviews_uploadReadingstoDexcomShare" = "Upload to Dexcom Share";
|
||||
|
||||
|
|
|
@ -231,9 +231,6 @@
|
|||
/// statistics settings, section title
|
||||
"settingsviews_sectiontitlestatistics" = "Statistics";
|
||||
|
||||
/// statistics settings, use standard range?
|
||||
"settingsviews_useTITRStatisticsRange" = "Use Time in Tight Range";
|
||||
|
||||
/// statistics settings, use IFCC method for HbA1c?
|
||||
"settingsviews_useIFCCA1C" = "Show HbA1c in mmols/mol";
|
||||
|
||||
|
|
|
@ -190,6 +190,10 @@ class Texts_Common {
|
|||
return NSLocalizedString("common_statistics_inTightRange", tableName: filename, bundle: Bundle.main, value: "Tight Range", comment: "the words in tight range")
|
||||
}()
|
||||
|
||||
static let userRangeStatistics = {
|
||||
return NSLocalizedString("common_statistics_userRange", tableName: filename, bundle: Bundle.main, value: "User Range", comment: "the words in user range")
|
||||
}()
|
||||
|
||||
static let highStatistics = {
|
||||
return NSLocalizedString("common_statistics_high", tableName: filename, bundle: Bundle.main, value: "High", comment: "the word high")
|
||||
}()
|
||||
|
|
|
@ -272,8 +272,20 @@ class Texts_SettingsView {
|
|||
return NSLocalizedString("settingsviews_daysToUseStatisticsMessage", tableName: filename, bundle: Bundle.main, value: "How many days should we use to calculate the statistics? (Enter 0 to calculate today since midnight)", comment: "statistics settings, how many days to use for calculations")
|
||||
}()
|
||||
|
||||
static let labelUseTITRStatisticsRange: String = {
|
||||
return NSLocalizedString("settingsviews_useTITRStatisticsRange", tableName: filename, bundle: Bundle.main, value: "Use Time in Tight Range", comment: "statistics settings, prefer time in tight range")
|
||||
static let labelTimeInRangeType: String = {
|
||||
return NSLocalizedString("settingsviews_labelTimeInRangeType", tableName: filename, bundle: Bundle.main, value: "Time In Range Type", comment: "statistics settings, the type of time in range selected")
|
||||
}()
|
||||
|
||||
static let timeInRangeTypeStandardRange: String = {
|
||||
return NSLocalizedString("settingsviews_timeInRangeTypeStandardRange", tableName: filename, bundle: Bundle.main, value: "Standard Range", comment: "statistics settings, prefer standard time in range")
|
||||
}()
|
||||
|
||||
static let timeInRangeTypeTightRange: String = {
|
||||
return NSLocalizedString("settingsviews_timeInRangeTypeTightRange", tableName: filename, bundle: Bundle.main, value: "Tight Range", comment: "statistics settings, prefer time in tight range")
|
||||
}()
|
||||
|
||||
static let timeInRangeTypeUserDefinedRange: String = {
|
||||
return NSLocalizedString("settingsviews_timeInRangeTypeUserDefinedRange", tableName: filename, bundle: Bundle.main, value: "User Range", comment: "statistics settings, prefer user-defined range")
|
||||
}()
|
||||
|
||||
static let labelUseIFFCA1C: String = {
|
||||
|
|
|
@ -375,47 +375,61 @@ final class RootViewController: UIViewController, ObservableObject {
|
|||
|
||||
@IBOutlet var miniChartDoubleTapGestureRecognizer: UITapGestureRecognizer!
|
||||
|
||||
/// can be used as a shortcut to switch between TIR and TITR calculation methods. The user will be notified of the change via UI transitions to show what has changed in the calculation limits
|
||||
/// can be used as a shortcut to switch between different TIR calculation methods. The user will be notified of the change via UI transitions to show what has changed in the calculation limits
|
||||
@IBAction func statisticsViewDoubleTapGestureRecognizer(_ sender: UITapGestureRecognizer) {
|
||||
|
||||
// the userdefault will be changed due to the double tap
|
||||
let useTITR = !UserDefaults.standard.useTITRStatisticsRange
|
||||
let previousTimeInRangeType = UserDefaults.standard.timeInRangeType
|
||||
|
||||
UserDefaults.standard.useTITRStatisticsRange = useTITR
|
||||
var newTimeInRangeType: TimeInRangeType = previousTimeInRangeType
|
||||
|
||||
// if we're at the last index in the enum, then go to the first one
|
||||
// otherwise, just set to the next index
|
||||
if previousTimeInRangeType == TimeInRangeType.allCases.last {
|
||||
|
||||
newTimeInRangeType = .standardRange
|
||||
|
||||
} else {
|
||||
|
||||
newTimeInRangeType = TimeInRangeType(rawValue: previousTimeInRangeType.rawValue + 1) ?? .tightRange
|
||||
|
||||
}
|
||||
|
||||
// write the new index back to userdefaults (this will also trigger the observers to update the UI)
|
||||
UserDefaults.standard.timeInRangeType = newTimeInRangeType
|
||||
|
||||
updateStatistics(animate: false)
|
||||
|
||||
let normalTitleColor: UIColor = lowTitleLabelOutlet.textColor
|
||||
let normalLimitValueColor: UIColor = lowLabelOutlet.textColor
|
||||
|
||||
inRangeTitleLabelOutlet.textColor = ConstantsStatistics.highlightColorTitles
|
||||
|
||||
if ConstantsStatistics.standardisedLowValueForTIRInMgDl != ConstantsStatistics.standardisedLowValueForTITRInMgDl {
|
||||
if previousTimeInRangeType.lowerLimit != newTimeInRangeType.lowerLimit {
|
||||
|
||||
self.lowLabelOutlet.textColor = ConstantsStatistics.labelLowColor
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ConstantsStatistics.standardisedHighValueForTIRInMgDl != ConstantsStatistics.standardisedHighValueForTITRInMgDl {
|
||||
if previousTimeInRangeType.higherLimit != newTimeInRangeType.higherLimit {
|
||||
|
||||
self.highLabelOutlet.textColor = ConstantsStatistics.labelHighColor
|
||||
|
||||
}
|
||||
|
||||
// wait a short while and then fade the labels back out
|
||||
// even if the label colours weren't changed, it's easier to just fade them all every time.
|
||||
// even if some of the label colours weren't changed, it's easier to just fade them all every time.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
|
||||
|
||||
UIView.transition(with: self.inRangeTitleLabelOutlet, duration: 2, options: .transitionCrossDissolve, animations: {
|
||||
UIView.transition(with: self.inRangeTitleLabelOutlet, duration: 1, options: .transitionCrossDissolve, animations: {
|
||||
self.inRangeTitleLabelOutlet.textColor = normalTitleColor
|
||||
})
|
||||
|
||||
UIView.transition(with: self.lowLabelOutlet, duration: 2, options: .transitionCrossDissolve, animations: {
|
||||
self.lowLabelOutlet.textColor = normalLimitValueColor
|
||||
UIView.transition(with: self.lowLabelOutlet, duration: 1, options: .transitionCrossDissolve, animations: {
|
||||
self.lowLabelOutlet.textColor = .lightGray
|
||||
})
|
||||
|
||||
UIView.transition(with: self.highLabelOutlet, duration: 2, options: .transitionCrossDissolve, animations: {
|
||||
self.highLabelOutlet.textColor = normalLimitValueColor
|
||||
UIView.transition(with: self.highLabelOutlet, duration: 1, options: .transitionCrossDissolve, animations: {
|
||||
self.highLabelOutlet.textColor = .lightGray
|
||||
})
|
||||
|
||||
}
|
||||
|
@ -2609,7 +2623,7 @@ final class RootViewController: UIViewController, ObservableObject {
|
|||
|
||||
// set the title labels to their correct localization
|
||||
self.lowTitleLabelOutlet.text = Texts_Common.lowStatistics
|
||||
self.inRangeTitleLabelOutlet.text = UserDefaults.standard.useTITRStatisticsRange ? Texts_Common.inTightRangeStatistics : Texts_Common.inRangeStatistics
|
||||
self.inRangeTitleLabelOutlet.text = UserDefaults.standard.timeInRangeType.title
|
||||
self.highTitleLabelOutlet.text = Texts_Common.highStatistics
|
||||
self.averageTitleLabelOutlet.text = Texts_Common.averageStatistics
|
||||
self.a1cTitleLabelOutlet.text = Texts_Common.a1cStatistics
|
||||
|
|
|
@ -15,8 +15,8 @@ fileprivate enum Setting:Int, CaseIterable {
|
|||
//show the statistics on the home screen?
|
||||
case showStatistics = 0
|
||||
|
||||
//should we use the standard range for TIR, or the newer Time in Tighter Range values?
|
||||
case useTITRStatisticsRange = 1
|
||||
//which TIR type should be used?
|
||||
case timeInRangeType = 1
|
||||
|
||||
//urgent low value
|
||||
case useIFCCA1C = 2
|
||||
|
@ -24,7 +24,15 @@ fileprivate enum Setting:Int, CaseIterable {
|
|||
}
|
||||
|
||||
/// conforms to SettingsViewModelProtocol for all general settings in the first sections screen
|
||||
struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
||||
class SettingsViewStatisticsSettingsViewModel: NSObject, SettingsViewModelProtocol {
|
||||
|
||||
override init() {
|
||||
|
||||
super.init()
|
||||
|
||||
addObservers()
|
||||
|
||||
}
|
||||
|
||||
func uiView(index: Int) -> UIView? {
|
||||
|
||||
|
@ -35,8 +43,8 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
case .showStatistics:
|
||||
return UISwitch(isOn: UserDefaults.standard.showStatistics, action: {(isOn:Bool) in UserDefaults.standard.showStatistics = isOn})
|
||||
|
||||
case .useTITRStatisticsRange :
|
||||
return UISwitch(isOn: UserDefaults.standard.useTITRStatisticsRange, action: {(isOn:Bool) in UserDefaults.standard.useTITRStatisticsRange = isOn})
|
||||
case .timeInRangeType:
|
||||
return nil
|
||||
|
||||
case .useIFCCA1C :
|
||||
return UISwitch(isOn: UserDefaults.standard.useIFCCA1C, action: {(isOn:Bool) in UserDefaults.standard.useIFCCA1C = isOn})
|
||||
|
@ -45,12 +53,21 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
}
|
||||
|
||||
func completeSettingsViewRefreshNeeded(index: Int) -> Bool {
|
||||
|
||||
// changing follower to master or master to follower requires changing ui for nightscout settings and transmitter type settings
|
||||
if (index == Setting.timeInRangeType.rawValue) {return true}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var sectionReloadClosure: (() -> Void)?
|
||||
|
||||
func storeRowReloadClosure(rowReloadClosure: ((Int) -> Void)) {}
|
||||
|
||||
func storeSectionReloadClosure(sectionReloadClosure: @escaping (() -> Void)) {
|
||||
self.sectionReloadClosure = sectionReloadClosure
|
||||
}
|
||||
|
||||
func storeUIViewController(uIViewController: UIViewController) {}
|
||||
|
||||
func storeMessageHandler(messageHandler: ((String, String) -> Void)) {
|
||||
|
@ -65,34 +82,59 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
guard let setting = Setting(rawValue: index) else { fatalError("Unexpected Section") }
|
||||
|
||||
switch setting {
|
||||
|
||||
case .showStatistics:
|
||||
return SettingsSelectedRowAction.callFunction(function: {
|
||||
if UserDefaults.standard.showStatistics {
|
||||
UserDefaults.standard.showStatistics = false
|
||||
} else {
|
||||
UserDefaults.standard.showStatistics = true
|
||||
}
|
||||
})
|
||||
|
||||
case .timeInRangeType:
|
||||
|
||||
// data to be displayed in list from which user needs to pick a screen dimming type
|
||||
var data = [String]()
|
||||
|
||||
var selectedRow: Int?
|
||||
|
||||
var index = 0
|
||||
|
||||
let currentTimeInRangeType = UserDefaults.standard.timeInRangeType
|
||||
|
||||
// get all data source types and add the description to data. Search for the type that matches the ScreenLockDimmingType that is currently stored in userdefaults.
|
||||
for timeInRangeType in TimeInRangeType.allCases {
|
||||
|
||||
case .showStatistics:
|
||||
return SettingsSelectedRowAction.callFunction(function: {
|
||||
if UserDefaults.standard.showStatistics {
|
||||
UserDefaults.standard.showStatistics = false
|
||||
} else {
|
||||
UserDefaults.standard.showStatistics = true
|
||||
}
|
||||
})
|
||||
data.append(timeInRangeType.description + timeInRangeType.rangeString())
|
||||
|
||||
if timeInRangeType == currentTimeInRangeType {
|
||||
selectedRow = index
|
||||
}
|
||||
|
||||
index += 1
|
||||
|
||||
}
|
||||
|
||||
return SettingsSelectedRowAction.selectFromList(title: Texts_SettingsView.labelTimeInRangeType, data: data, selectedRow: selectedRow, actionTitle: nil, cancelTitle: nil, actionHandler: {(index:Int) in
|
||||
|
||||
if index != selectedRow {
|
||||
|
||||
case .useTITRStatisticsRange:
|
||||
return SettingsSelectedRowAction.callFunction(function: {
|
||||
if UserDefaults.standard.useTITRStatisticsRange {
|
||||
UserDefaults.standard.useTITRStatisticsRange = false
|
||||
} else {
|
||||
UserDefaults.standard.useTITRStatisticsRange = true
|
||||
}
|
||||
})
|
||||
|
||||
case .useIFCCA1C:
|
||||
return SettingsSelectedRowAction.callFunction(function: {
|
||||
if UserDefaults.standard.useIFCCA1C {
|
||||
UserDefaults.standard.useIFCCA1C = false
|
||||
} else {
|
||||
UserDefaults.standard.useIFCCA1C = true
|
||||
}
|
||||
})
|
||||
UserDefaults.standard.timeInRangeType = TimeInRangeType(rawValue: index) ?? .standardRange
|
||||
|
||||
}
|
||||
|
||||
}, cancelHandler: nil, didSelectRowHandler: nil)
|
||||
|
||||
case .useIFCCA1C:
|
||||
return SettingsSelectedRowAction.callFunction(function: {
|
||||
if UserDefaults.standard.useIFCCA1C {
|
||||
UserDefaults.standard.useIFCCA1C = false
|
||||
} else {
|
||||
UserDefaults.standard.useIFCCA1C = true
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,8 +160,8 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
case .showStatistics:
|
||||
return Texts_SettingsView.labelShowStatistics
|
||||
|
||||
case .useTITRStatisticsRange:
|
||||
return Texts_SettingsView.labelUseTITRStatisticsRange
|
||||
case .timeInRangeType:
|
||||
return Texts_SettingsView.labelTimeInRangeType
|
||||
|
||||
case .useIFCCA1C:
|
||||
return Texts_SettingsView.labelUseIFFCA1C
|
||||
|
@ -132,9 +174,12 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
|
||||
switch setting {
|
||||
|
||||
case .showStatistics, .useTITRStatisticsRange, .useIFCCA1C:
|
||||
case .showStatistics, .useIFCCA1C:
|
||||
return UITableViewCell.AccessoryType.none
|
||||
|
||||
case .timeInRangeType:
|
||||
return UITableViewCell.AccessoryType.disclosureIndicator
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,9 +188,42 @@ struct SettingsViewStatisticsSettingsViewModel:SettingsViewModelProtocol {
|
|||
|
||||
switch setting {
|
||||
|
||||
case .showStatistics, .useTITRStatisticsRange, .useIFCCA1C:
|
||||
case .showStatistics, .useIFCCA1C:
|
||||
return nil
|
||||
|
||||
case .timeInRangeType:
|
||||
return UserDefaults.standard.timeInRangeType.description
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - observe functions
|
||||
|
||||
private func addObservers() {
|
||||
|
||||
// Listen for changes in the timeInRangeType to trigger the UI to be updated
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.timeInRangeType.rawValue, options: .new, context: nil)
|
||||
|
||||
}
|
||||
|
||||
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
|
||||
guard let keyPath = keyPath,
|
||||
let keyPathEnum = UserDefaults.Key(rawValue: keyPath)
|
||||
else { return }
|
||||
|
||||
switch keyPathEnum {
|
||||
case UserDefaults.Key.timeInRangeType:
|
||||
|
||||
// we have to run this in the main thread to avoid access errors
|
||||
DispatchQueue.main.async {
|
||||
self.sectionReloadClosure?()
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue