diff --git a/Config.xcconfig b/Config.xcconfig index 7753c8d5..866f3234 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -6,4 +6,4 @@ unique_id = ${DEVELOPMENT_TEAM} //Version (DEFAULT) -LOOP_FOLLOW_MARKETING_VERSION = 2.1.2 +LOOP_FOLLOW_MARKETING_VERSION = 2.1.3 diff --git a/LoopFollow/Controllers/Nightscout/CAge.swift b/LoopFollow/Controllers/Nightscout/CAge.swift index c51f77e9..c56abf03 100644 --- a/LoopFollow/Controllers/Nightscout/CAge.swift +++ b/LoopFollow/Controllers/Nightscout/CAge.swift @@ -10,7 +10,7 @@ import Foundation extension MainViewController { // NS Cage Web Call func webLoadNSCage() { - let currentTimeString = dateTimeUtils.getCurrentDateTimeString() + let currentTimeString = dateTimeUtils.getDateTimeString() let parameters: [String: String] = [ "find[eventType]": NightscoutUtils.EventType.cage.rawValue, diff --git a/LoopFollow/Controllers/Nightscout/SAge.swift b/LoopFollow/Controllers/Nightscout/SAge.swift index fc014184..eb7743e2 100644 --- a/LoopFollow/Controllers/Nightscout/SAge.swift +++ b/LoopFollow/Controllers/Nightscout/SAge.swift @@ -10,8 +10,8 @@ import Foundation extension MainViewController { // NS Sage Web Call func webLoadNSSage() { - let lastDateString = dateTimeUtils.nowMinus60DaysTimeInterval() - let currentTimeString = dateTimeUtils.getCurrentDateTimeString() + let lastDateString = dateTimeUtils.getDateTimeString(addingDays: -60) + let currentTimeString = dateTimeUtils.getDateTimeString() let parameters: [String: String] = [ "find[eventType]": NightscoutUtils.EventType.sage.rawValue, diff --git a/LoopFollow/Controllers/Nightscout/Treatments.swift b/LoopFollow/Controllers/Nightscout/Treatments.swift index 03f874e3..4305d8f6 100644 --- a/LoopFollow/Controllers/Nightscout/Treatments.swift +++ b/LoopFollow/Controllers/Nightscout/Treatments.swift @@ -14,9 +14,8 @@ extension MainViewController { if UserDefaultsRepository.debugLog.value { self.writeDebugLog(value: "Download: Treatments") } if !UserDefaultsRepository.downloadTreatments.value { return } - let graphHours = 24 * UserDefaultsRepository.downloadDays.value - let startTimeString = dateTimeUtils.nowMinusNHoursTimeInterval(N: graphHours) - let currentTimeString = dateTimeUtils.getCurrentDateTimeString() + let startTimeString = dateTimeUtils.getDateTimeString(addingDays: -1 * UserDefaultsRepository.downloadDays.value) + let currentTimeString = dateTimeUtils.getDateTimeString(addingHours: 6) let parameters: [String: String] = [ "find[created_at][$gte]": startTimeString, "find[created_at][$lte]": currentTimeString diff --git a/LoopFollow/Controllers/Nightscout/Treatments/Carbs.swift b/LoopFollow/Controllers/Nightscout/Treatments/Carbs.swift index 36217f10..8f276ba6 100644 --- a/LoopFollow/Controllers/Nightscout/Treatments/Carbs.swift +++ b/LoopFollow/Controllers/Nightscout/Treatments/Carbs.swift @@ -43,7 +43,7 @@ extension MainViewController { offset = bolusTime.offset ? 70 : 20 } - if dateTimeStamp < (dateTimeUtils.getNowTimeIntervalUTC() + (60 * 60)) { + if dateTimeStamp < (dateTimeUtils.getNowTimeIntervalUTC() + (3600 * UserDefaultsRepository.predictionToLoad.value)) { // Make the dot let dot = carbGraphStruct(value: Double(carbs), date: Double(dateTimeStamp), sgv: Int(sgv.sgv + Double(offset)), absorptionTime: absorptionTime) carbData.append(dot) diff --git a/LoopFollow/ViewControllers/SettingsViewController.swift b/LoopFollow/ViewControllers/SettingsViewController.swift index 9694d3ee..74eef9e5 100644 --- a/LoopFollow/ViewControllers/SettingsViewController.swift +++ b/LoopFollow/ViewControllers/SettingsViewController.swift @@ -78,6 +78,7 @@ class SettingsViewController: FormViewController { row.hidden = "$showNS == false" }.cellSetup { (cell, row) in cell.textField.autocorrectionType = .no + cell.textField.autocapitalizationType = .none }.onChange { row in guard let value = row.value else { UserDefaultsRepository.url.value = "" @@ -104,6 +105,8 @@ class SettingsViewController: FormViewController { row.hidden = "$showNS == false" }.cellSetup { (cell, row) in cell.textField.autocorrectionType = .no + cell.textField.autocapitalizationType = .none + cell.textField.textContentType = .password }.onChange { row in if row.value == nil { UserDefaultsRepository.token.value = "" @@ -144,6 +147,7 @@ class SettingsViewController: FormViewController { row.hidden = "$showDex == false" }.cellSetup { (cell, row) in cell.textField.autocorrectionType = .no + cell.textField.autocapitalizationType = .none }.onChange { row in if row.value == nil { UserDefaultsRepository.shareUserName.value = "" @@ -159,6 +163,7 @@ class SettingsViewController: FormViewController { }.cellSetup { (cell, row) in cell.textField.autocorrectionType = .no cell.textField.isSecureTextEntry = true + cell.textField.autocapitalizationType = .none }.onChange { row in if row.value == nil { UserDefaultsRepository.sharePassword.value = "" diff --git a/LoopFollow/helpers/DateTime.swift b/LoopFollow/helpers/DateTime.swift index 03f3030a..1b8f7cca 100644 --- a/LoopFollow/helpers/DateTime.swift +++ b/LoopFollow/helpers/DateTime.swift @@ -57,42 +57,26 @@ class dateTimeUtils { return utcTime } - static func getCurrentDateTimeString() -> String { - let currentTimeInterval = getNowTimeIntervalUTC() + static func getDateTimeString(addingHours hours: Int? = nil, addingDays days: Int? = nil) -> String { + let currentDate = Date() + var date = currentDate - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" - dateFormatter.locale = Locale(identifier: "en_US") - dateFormatter.timeZone = TimeZone.init(secondsFromGMT: 0) + if let hoursToAdd = hours { + date = Calendar.current.date(byAdding: .hour, value: hoursToAdd, to: currentDate)! + } - let currentDate = Date(timeIntervalSince1970: currentTimeInterval) - let currentTimeString = dateFormatter.string(from: currentDate) + if let daysToAdd = days { + date = Calendar.current.date(byAdding: .day, value: daysToAdd, to: currentDate)! + } - return currentTimeString - } - - static func nowMinusNHoursTimeInterval(N: Int) -> String { - let today = Date() - let nHoursAgo = Calendar.current.date(byAdding: .hour, value: -N, to: today)! let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" dateFormatter.locale = Locale(identifier: "en_US") - dateFormatter.timeZone = TimeZone.init(secondsFromGMT: 0) - let nHoursAgoString = dateFormatter.string(from: nHoursAgo) - return nHoursAgoString - } - - static func nowMinus60DaysTimeInterval() -> String { - let today = Date() - let oldDate = Calendar.current.date(byAdding: .day, value: -10, to: today)! - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd" - dateFormatter.locale = Locale(identifier: "en_US") - dateFormatter.timeZone = TimeZone.init(secondsFromGMT: 0) - let dayString = dateFormatter.string(from: oldDate) - return dayString + dateFormatter.timeZone = TimeZone(secondsFromGMT: 0) + + return dateFormatter.string(from: date) } - + static func printNow() -> String { let date = Date() let formatter = DateFormatter() diff --git a/README.md b/README.md index 6492b957..cd67ef67 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,10 @@ The _display_name_ is found in a single file. Summary instructions by build method: * Browser Build: + * Fork and setup the repository for each Loop Follow instance you want to use: + * https://github.com/loopandlearn/LoopFollow + * https://github.com/loopandlearn/LoopFollow_Second + * https://github.com/loopandlearn/LoopFollow_Third * Commit the desired _display_name_ in the LoopFollowDisplayNameConfig.xcconfig file of your forked repository for LoopFollow, LoopFollow_Second or LoopFollow_Third * Mac-Xcode Build * First build with script, you will be prompted to enter the desired _display_name_ @@ -73,58 +77,56 @@ When modifications and versions are updated, there might be a slight delay for g Please review the list on [Loop and Learn: Loop Follow](https://www.loopandlearn.org/loop-follow/) which may be updated more frequently than this README.md file. -- scrollable/scalable graph display with BG, basal, bolus, and carb details plus Loop status, Loop Prediction, and the General NS Care portal info. -- Override DND and system volume for all alerts. -- snoozes per alert, presnooze, edit existing snooze, and snooze all alert settings. -- the standard Low/High, Urgent Low/High, and missed reading alerts with additonal option to select persistence; for example, alert when high for x minutes. -- fast drop/rise alerts with BG limits; for example, alert for fast drop only when glucose is below specific value. -- sage/cage reminder alerts for x hours before change. -- Not Looping with glucose limits alert: you can configure the alert if under or over a glucose range. -- Missed Bolus alert. -- calendar entries to use watch complication with BG, arrow, delta, cob, iob and minutes ago (if old reading). -- background silent audio to keep iOS from killing the app. This is why it can’t go in the App Store for just a simple download. +Each time a release is made, the features added or bugs fixed are found at [Loop Follow Releases](https://github.com/loopandlearn/LoopFollow/releases). + +Each of the features below is selectable - you decide whether to use them.  Additionally, many features are adjustable because YDMV (your diabetes may vary). + +1. Scrollable/scalable graph display with BG, IOB, COB, Basal, Bolus, and the General Nightscout Care portal info + * Supports Glucose display when Dexcom is available but Nightscout is not + * Supports Loop and iAPS when Nightscout URL is provided and Download Loop/iAPS data is enabled (show Nightscout Settings to see the enable slider) + * Loop: Loop status, Loop Prediction + * iAPS: iAPS status, iAPS Prediction lines, Autosens +2. Tap on Alarms on Toolbar to configure. + * Override DND (Do Not Disturb) and system volume for all alerts with a Snooze All Until and a Mute All Until + * List of Alarms covers the standard high/low/rise/fall/urgent glucose but also include alerts for missed glucose readings, if below configured glucose, IOB, COB, Not Looping, Overrides, Pump, Missed Bolus, SAGE, CAGE and Battery + * Each Alarm has configurable settings including Sound selection, PreSnooze (set to be quiet At Night, During Day or Never) and Snooze Until +3. Calendar entries (displayed on watch and/or carplay at 5 minute intervals) pre-formatted with two lines that the user can modify: + * BG, arrow, delta,  MINAGO (minutes ago for reading) + * COB, IOB, Basal (U/hr) +4. Background silent audio is played to keep iOS from killing the app; this trick is why it can’t go into the App Store for a simple download and why Loop Follow puts an extra load on the phone battery +5. Badge displays the current BG value on the app icon +6. Information Display Settings allows user to configure the items selected and their order for the right panel when Nightscout URL is provided + * IOB, COB, Basal, Override, Battery, Pump, SAGE, CAGE, (Recommended) Rec. Bolus, (Glucose Eventually) Pred., Carbs today (Loop and iAPS) + * Autosens (iAPS only) +7. Pull down on the glucose value to force a refresh from Nightscout (iPhone only - does not work on Mac) +8. When adding a Nightscout site, NS Status says "Checking", "Site Not Found", "Token Required", "Invalid Token", or "OK" +9. New with v2.1.2: Multiple Loopers (up to 3) are easily supported with either Browser Build or Mac-Xcode build +10. New with v2.1.2: The app name (displayed on phone) can be customized when building + * If enabled, that custom name will be displayed on the main Loop Follow display ### Open Source DIY - This is a DIY open source project that may or may not function as you expect. You take full responsibility for building and running this app and do so at your own risk. -## For Developers - -> * If you are interested in assisting with this app and want to work on new features and improvements for Loop, iAPS and Nightscout functionality, please reach out. -> * Issues and Pull Requests in GitHub are monitored and will get a response. -> * Please always direct your PR to the dev branch. +## Versions -### Versions - -We added version numbers that are incremented with each pull request (or group of pull requests) merged. - -New PR are directed to the dev branch. If you direct one to main, we will move it to point to dev. So always start with your code aligned with dev. +We added version numbers to Loop Follow. Typically the main branch and dev branch are at the same version, but when work is underway, the dev branch may have different code, which we try to indicate with a different version number. The versioning is: * major.minor.micro * For example our first version is 2.0.0 -After a PR is merged to dev, the repository maintainers will bump up the verion number before merging to main - please do not modify the version in your branch. +For the most part, the deveopers keep main and dev branches at the same level. But sometimes we want to combine several PR or keep a modification in dev for additional testing. -For the most part, the deveopers keep main and dev branches at the same level. But sometimes we want modification to remain in dev for additional testing. +## For Developers -#### Version Example +> * If you are interested in assisting with this app and want to work on new features and improvements for Loop, iAPS and Nightscout functionality, please reach out. +> * Issues and Pull Requests in GitHub are monitored and will get a response. -Starting with version 2.1.0 +New PR are directed to the dev branch. If you direct one to main, we will move it to point to dev. So always start with your code aligned with dev. -* PR with Feature A gets merged to dev - * Maintainers, bump dev to 2.1.0 -* Maintainers merge dev into main - * both main and dev are at 2.1.0 -* PR with Feature B gets merged to dev - * Maintainers, bump dev to 2.1.1 - * main is still at 2.1.0 -* PR with Feature C gets merged to dev - * Maintainers, bump dev to 2.1.2 - * main is still at 2.1.0 -* Maintainers merge dev into main - * both main and dev are at 2.1.2 +After a PR is merged to dev, the repository maintainers will bump up the verion number before merging to main - please do not modify the version in your branch. #### Version Updates -Modify the LOOP_FOLLOW_MARKETING_VERSION in Config.xcconfig file to change the version reported by Loop Follow. \ No newline at end of file +Only the maintainers for Loop Follow will update version numbers. This is done by incrementing the LOOP_FOLLOW_MARKETING_VERSION in Config.xcconfig file.