Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Loop/Managers/CGM/CGMManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ protocol CGMManager: CustomDebugStringConvertible {
/// Whether the device is capable of waking the app
var providesBLEHeartbeat: Bool { get }

/// The length of time to keep samples in HealthKit before removal. Return nil to never remove samples.
var managedDataInterval: TimeInterval? { get }

var sensorState: SensorDisplayable? { get }

/// The representation of the device for use in HealthKit
Expand Down
21 changes: 20 additions & 1 deletion Loop/Managers/CGM/DexCGMManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class DexCGMManager: CGMManager {
return shareManager?.sensorState
}

var managedDataInterval: TimeInterval? {
return shareManager?.managedDataInterval
}

fileprivate var shareManager: ShareClientManager? = ShareClientManager()

var device: HKDevice? {
Expand All @@ -53,12 +57,14 @@ class DexCGMManager: CGMManager {
final class ShareClientManager: CGMManager {
weak var delegate: CGMManagerDelegate?

var providesBLEHeartbeat = false
let providesBLEHeartbeat = false

var sensorState: SensorDisplayable? {
return latestBackfill
}

let managedDataInterval: TimeInterval? = nil

private var latestBackfill: ShareGlucose?

func fetchNewDataIfNeeded(with deviceManager: DeviceDataManager, _ completion: @escaping (CGMResult) -> Void) {
Expand Down Expand Up @@ -129,6 +135,14 @@ final class G5CGMManager: DexCGMManager, TransmitterDelegate {
return latestReading ?? super.sensorState
}

override var managedDataInterval: TimeInterval? {
if let transmitter = transmitter, transmitter.passiveModeEnabled {
return .hours(3)
}

return super.managedDataInterval
}

private var latestReading: Glucose? {
didSet {
// Once we have our first reading, disable backfill
Expand Down Expand Up @@ -202,6 +216,11 @@ final class G4CGMManager: DexCGMManager, ReceiverDelegate {
return latestReading ?? super.sensorState
}


override var managedDataInterval: TimeInterval? {
return .hours(3)
}

private var latestReading: GlucoseG4? {
didSet {
// Once we have our first reading, disable backfill
Expand Down
4 changes: 3 additions & 1 deletion Loop/Managers/CGM/EnliteCGMManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import MinimedKit


final class EnliteCGMManager: CGMManager {
var providesBLEHeartbeat = false
let providesBLEHeartbeat = false

weak var delegate: CGMManagerDelegate?

var sensorState: SensorDisplayable?

let managedDataInterval: TimeInterval? = nil

func fetchNewDataIfNeeded(with deviceManager: DeviceDataManager, _ completion: @escaping (CGMResult) -> Void) {
guard let device = deviceManager.rileyLinkManager.firstConnectedDevice?.ops
else {
Expand Down
1 change: 1 addition & 0 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ final class DeviceDataManager {
private func setupCGM() {
cgmManager = cgm?.createManager()
cgmManager?.delegate = self
loopManager.glucoseStore.managedDataInterval = cgmManager?.managedDataInterval

/// Controls the management of the RileyLink timer tick, which is a reliably-changing BLE
/// characteristic which can cause the app to wake. For most users, the G5 Transmitter and
Expand Down
107 changes: 74 additions & 33 deletions Loop/View Controllers/SettingsTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
case enlite = 0
case g4
case g5
case dexcomShare // only displayed if g4 or g5 switched on
case g5TransmitterID // only displayed if g5 switched on
}

Expand All @@ -120,8 +121,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
}

fileprivate enum ServiceRow: Int, CaseCountable {
case share = 0
case nightscout
case nightscout = 0
case mLab
case loggly
case amplitude
Expand Down Expand Up @@ -151,10 +151,12 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
return PumpRow.count
case .cgm:
switch dataManager.cgm {
case .g4?:
return CGMRow.count - 1 // No Transmitter ID cell
case .g5?:
return CGMRow.count
default:
return CGMRow.count - 1
return CGMRow.count - 2 // No Share or Transmitter ID cell
}
case .configuration:
return ConfigurationRow.count
Expand All @@ -166,8 +168,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell

switch Section(rawValue: indexPath.section)! {
case .loop:
switch LoopRow(rawValue: indexPath.row)! {
Expand Down Expand Up @@ -205,20 +205,28 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
configCell.textLabel?.text = NSLocalizedString("Pump Battery Type", comment: "The title text for the battery type value")
configCell.detailTextLabel?.text = String(describing: dataManager.batteryChemistry)
}
cell = configCell
return configCell
case .cgm:
let row = CGMRow(rawValue: indexPath.row)!
switch row {
case .dexcomShare:
let configCell = tableView.dequeueReusableCell(withIdentifier: ConfigCellIdentifier, for: indexPath)
let shareService = dataManager.remoteDataManager.shareService

configCell.textLabel?.text = shareService.title
configCell.detailTextLabel?.text = shareService.username ?? TapToSetString

return configCell
case .g5TransmitterID:
let configCell = tableView.dequeueReusableCell(withIdentifier: ConfigCellIdentifier, for: indexPath)

configCell.textLabel?.text = NSLocalizedString("G5 Transmitter ID", comment: "The title text for the Dexcom G5 transmitter ID config value")
configCell.textLabel?.text = NSLocalizedString("Transmitter ID", comment: "The title text for the Dexcom G5 transmitter ID config value")

if case .g5(let transmitterID)? = dataManager.cgm {
configCell.detailTextLabel?.text = transmitterID ?? TapToSetString
}

cell = configCell
return configCell
default:
let switchCell = tableView.dequeueReusableCell(withIdentifier: SwitchTableViewCell.className, for: indexPath) as! SwitchTableViewCell

Expand All @@ -240,11 +248,11 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu

switchCell.titleLabel.text = NSLocalizedString("G5 Transmitter", comment: "The title text for the G5 Transmitter switch cell")
switchCell.switch?.addTarget(self, action: #selector(g5Changed(_:)), for: .valueChanged)
case .g5TransmitterID:
case .dexcomShare, .g5TransmitterID:
assertionFailure()
}

cell = switchCell
return switchCell
}
case .configuration:
let configCell = tableView.dequeueReusableCell(withIdentifier: ConfigCellIdentifier, for: indexPath)
Expand Down Expand Up @@ -318,7 +326,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
configCell.detailTextLabel?.text = TapToSetString
}
case .maxBasal:
configCell.textLabel?.text = NSLocalizedString("Maximum Basal Rate", comment: "The title text for the maximum basal rate value")
configCell.textLabel?.text = NSLocalizedString("Maximum Basal Rate", comment: "The title text for the maximum basal rate value")

if let maxBasal = dataManager.loopManager.settings.maximumBasalRatePerHour {
configCell.detailTextLabel?.text = "\(valueNumberFormatter.string(from: NSNumber(value: maxBasal))!) U/hour"
Expand All @@ -335,7 +343,7 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
}
}

cell = configCell
return configCell
case .devices:
let deviceCell = tableView.dequeueReusableCell(withIdentifier: RileyLinkDeviceTableViewCell.className) as! RileyLinkDeviceTableViewCell
let device = dataManager.rileyLinkManager.devices[indexPath.row]
Expand All @@ -347,16 +355,11 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu

deviceCell.connectSwitch.addTarget(self, action: #selector(deviceConnectionChanged(_:)), for: .valueChanged)

cell = deviceCell
return deviceCell
case .services:
let configCell = tableView.dequeueReusableCell(withIdentifier: ConfigCellIdentifier, for: indexPath)

switch ServiceRow(rawValue: indexPath.row)! {
case .share:
let shareService = dataManager.remoteDataManager.shareService

configCell.textLabel?.text = shareService.title
configCell.detailTextLabel?.text = shareService.username ?? TapToSetString
case .nightscout:
let nightscoutService = dataManager.remoteDataManager.nightscoutService

Expand All @@ -381,7 +384,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu

return configCell
}
return cell
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
Expand All @@ -403,6 +405,22 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu

// MARK: - UITableViewDelegate

override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int {
switch Section(rawValue: indexPath.section)! {
case .cgm:
switch CGMRow(rawValue: indexPath.row)! {
case .dexcomShare, .g5TransmitterID:
return 1
default:
break
}
default:
break
}

return 0
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let sender = tableView.cellForRow(at: indexPath)

Expand Down Expand Up @@ -432,6 +450,16 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
}
case .cgm:
switch CGMRow(rawValue: indexPath.row)! {
case .dexcomShare:
let service = dataManager.remoteDataManager.shareService
let vc = AuthenticationViewController(authentication: service)
vc.authenticationObserver = { [unowned self] (service) in
self.dataManager.remoteDataManager.shareService = service

self.tableView.reloadRows(at: [indexPath], with: .none)
}

show(vc, sender: sender)
case .g5TransmitterID:
let vc: TextFieldTableViewController
var value: String?
Expand Down Expand Up @@ -591,16 +619,6 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
}
case .services:
switch ServiceRow(rawValue: indexPath.row)! {
case .share:
let service = dataManager.remoteDataManager.shareService
let vc = AuthenticationViewController(authentication: service)
vc.authenticationObserver = { [unowned self] (service) in
self.dataManager.remoteDataManager.shareService = service

self.tableView.reloadRows(at: [indexPath], with: .none)
}

show(vc, sender: sender)
case .nightscout:
let service = dataManager.remoteDataManager.nightscoutService
let vc = AuthenticationViewController(authentication: service)
Expand Down Expand Up @@ -687,10 +705,17 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
if sender.isOn {
setG4SwitchOff()
setEnliteSwitchOff()
let shareRowExists = tableView.numberOfRows(inSection: Section.cgm.rawValue) > CGMRow.dexcomShare.rawValue
dataManager.cgm = .g5(transmitterID: g5TransmitterID)

tableView.insertRows(at: [IndexPath(row: CGMRow.g5TransmitterID.rawValue, section:Section.cgm.rawValue)], with: .top)
var indexPaths = [IndexPath(row: CGMRow.g5TransmitterID.rawValue, section:Section.cgm.rawValue)]
if !shareRowExists {
indexPaths.insert(IndexPath(row: CGMRow.dexcomShare.rawValue, section:Section.cgm.rawValue), at: 0)
}

tableView.insertRows(at: indexPaths, with: .top)
} else {
removeDexcomShareRow()
removeG5TransmitterIDRow()
dataManager.cgm = nil
}
Expand All @@ -702,8 +727,15 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
if sender.isOn {
setG5SwitchOff()
setEnliteSwitchOff()
removeG5TransmitterIDRow()
let shareRowExists = tableView.numberOfRows(inSection: Section.cgm.rawValue) > CGMRow.dexcomShare.rawValue
dataManager.cgm = .g4

if !shareRowExists {
tableView.insertRows(at: [IndexPath(row: CGMRow.dexcomShare.rawValue, section:Section.cgm.rawValue)], with: .top)
}
} else {
removeDexcomShareRow()
dataManager.cgm = nil
}
tableView.endUpdates()
Expand All @@ -714,6 +746,8 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu
if sender.isOn {
setG5SwitchOff()
setG4SwitchOff()
removeDexcomShareRow()
removeG5TransmitterIDRow()
dataManager.cgm = .enlite
} else {
dataManager.cgm = nil
Expand All @@ -723,18 +757,25 @@ final class SettingsTableViewController: UITableViewController, DailyValueSchedu

// MARK: Views

private func removeDexcomShareRow() {
switch dataManager.cgm {
case .g4?, .g5?:
tableView.deleteRows(at: [IndexPath(row: CGMRow.dexcomShare.rawValue, section: Section.cgm.rawValue)], with: .top)
default:
break;
}
}

private func removeG5TransmitterIDRow() {
if case .g5(let transmitterID)? = dataManager.cgm {
g5TransmitterID = transmitterID
tableView.deleteRows(at: [IndexPath(row: CGMRow.g5TransmitterID.rawValue, section:Section.cgm.rawValue)], with: .top)
tableView.deleteRows(at: [IndexPath(row: CGMRow.g5TransmitterID.rawValue, section: Section.cgm.rawValue)], with: .top)
}
}

private func setG5SwitchOff() {
let switchCell = tableView.cellForRow(at: IndexPath(row: CGMRow.g5.rawValue, section: Section.cgm.rawValue)) as! SwitchTableViewCell
switchCell.switch?.setOn(false, animated: true)

removeG5TransmitterIDRow()
}

private func setG4SwitchOff() {
Expand Down
1 change: 1 addition & 0 deletions Loop/Views/AuthenticationTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ final class AuthenticationTableViewCell: UITableViewCell, NibLoadable {
super.prepareForReuse()

textField.delegate = nil
credentialOptionPicker = nil
}

var credentialOptionPicker: CredentialOptionPicker? {
Expand Down