Skip to content

Commit f05fc7a

Browse files
authored
Add remote sync option (#145)
1 parent 96de871 commit f05fc7a

File tree

2 files changed

+86
-4
lines changed

2 files changed

+86
-4
lines changed

CGMBLEKit/TransmitterManager.swift

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,29 @@ public struct TransmitterManagerState: RawRepresentable, Equatable {
1919
public var transmitterID: String
2020

2121
public var passiveModeEnabled: Bool = true
22+
23+
public var shouldSyncToRemoteService: Bool
2224

23-
public init(transmitterID: String) {
25+
public init(transmitterID: String, shouldSyncToRemoteService: Bool = false) {
2426
self.transmitterID = transmitterID
27+
self.shouldSyncToRemoteService = shouldSyncToRemoteService
2528
}
2629

2730
public init?(rawValue: RawValue) {
2831
guard let transmitterID = rawValue["transmitterID"] as? String
2932
else {
3033
return nil
3134
}
35+
36+
let shouldSyncToRemoteService = rawValue["shouldSyncToRemoteService"] as? Bool ?? false
3237

33-
self.init(transmitterID: transmitterID)
38+
self.init(transmitterID: transmitterID, shouldSyncToRemoteService: shouldSyncToRemoteService)
3439
}
3540

3641
public var rawValue: RawValue {
3742
return [
38-
"transmitterID": transmitterID
43+
"transmitterID": transmitterID,
44+
"shouldSyncToRemoteService": shouldSyncToRemoteService,
3945
]
4046
}
4147
}
@@ -50,14 +56,47 @@ public class TransmitterManager: TransmitterDelegate {
5056
private var state: TransmitterManagerState
5157

5258
private let observers = WeakSynchronizedSet<TransmitterManagerObserver>()
59+
60+
5361

5462
public required init(state: TransmitterManagerState) {
5563
self.state = state
5664
self.transmitter = Transmitter(id: state.transmitterID, passiveModeEnabled: state.passiveModeEnabled)
5765
self.shareManager = ShareClientManager()
5866

5967
self.transmitter.delegate = self
68+
69+
#if targetEnvironment(simulator)
70+
setupSimulatedSampleGenerator()
71+
#endif
72+
73+
}
74+
75+
76+
#if targetEnvironment(simulator)
77+
var simulatedSampleGeneratorTimer: DispatchSourceTimer?
78+
79+
private func setupSimulatedSampleGenerator() {
80+
81+
let timer = DispatchSource.makeTimerSource(queue: DispatchQueue(label: "com.loopkit.simulatedSampleGenerator"))
82+
timer.schedule(deadline: .now() + .seconds(10), repeating: .minutes(5))
83+
timer.setEventHandler(handler: { [weak self] in
84+
self?.generateSimulatedSample()
85+
})
86+
self.simulatedSampleGeneratorTimer = timer
87+
timer.resume()
88+
}
89+
90+
private func generateSimulatedSample() {
91+
let timestamp = Date()
92+
let syncIdentifier = "\(self.state.transmitterID) \(timestamp)"
93+
let period = TimeInterval(hours: 3)
94+
let glucoseValue = 100 + 20 * cos(Date().timeIntervalSinceReferenceDate.remainder(dividingBy: period) / period * Double.pi * 2)
95+
let quantity = HKQuantity(unit: .milligramsPerDeciliter, doubleValue: glucoseValue)
96+
let sample = NewGlucoseSample(date: timestamp, quantity: quantity, isDisplayOnly: false, syncIdentifier: syncIdentifier)
97+
self.updateDelegate(with: .newData([sample]))
6098
}
99+
#endif
61100

62101
required convenience public init?(rawState: CGMManager.RawStateValue) {
63102
guard let state = TransmitterManagerState(rawValue: rawState) else {
@@ -71,7 +110,15 @@ public class TransmitterManager: TransmitterDelegate {
71110
return state.rawValue
72111
}
73112

74-
public let shouldSyncToRemoteService = false
113+
public var shouldSyncToRemoteService: Bool {
114+
get {
115+
return state.shouldSyncToRemoteService
116+
}
117+
set {
118+
self.state.shouldSyncToRemoteService = newValue
119+
notifyDelegateOfStateChange()
120+
}
121+
}
75122

76123
public var cgmManagerDelegate: CGMManagerDelegate? {
77124
get {
@@ -193,6 +240,15 @@ public class TransmitterManager: TransmitterDelegate {
193240

194241
notifyObserversOfLatestReading()
195242
}
243+
244+
private func notifyDelegateOfStateChange() {
245+
if let manager = self as? CGMManager {
246+
shareManager.delegate.notify { (delegate) in
247+
delegate?.cgmManagerDidUpdateState(manager)
248+
}
249+
}
250+
}
251+
196252

197253
// MARK: - TransmitterDelegate
198254

CGMBLEKitUI/TransmitterSettingsViewController.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class TransmitterSettingsViewController: UITableViewController {
4545

4646
tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className)
4747
tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className)
48+
tableView.register(SwitchTableViewCell.self, forCellReuseIdentifier: SwitchTableViewCell.className)
4849
let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:)))
4950
self.navigationItem.setRightBarButton(button, animated: false)
5051
}
@@ -74,6 +75,7 @@ class TransmitterSettingsViewController: UITableViewController {
7475

7576
private enum Section: Int, CaseIterable {
7677
case transmitterID
78+
case remoteDataSync
7779
case latestReading
7880
case latestCalibration
7981
case latestConnection
@@ -116,6 +118,8 @@ class TransmitterSettingsViewController: UITableViewController {
116118
switch Section(rawValue: section)! {
117119
case .transmitterID:
118120
return 1
121+
case .remoteDataSync:
122+
return 1
119123
case .latestReading:
120124
return LatestReadingRow.allCases.count
121125
case .latestCalibration:
@@ -169,6 +173,16 @@ class TransmitterSettingsViewController: UITableViewController {
169173
cell.detailTextLabel?.text = cgmManager.transmitter.ID
170174

171175
return cell
176+
case .remoteDataSync:
177+
let switchCell = tableView.dequeueReusableCell(withIdentifier: SwitchTableViewCell.className, for: indexPath) as! SwitchTableViewCell
178+
179+
switchCell.selectionStyle = .none
180+
switchCell.switch?.isOn = cgmManager.shouldSyncToRemoteService
181+
switchCell.textLabel?.text = NSLocalizedString("Upload Readings", comment: "The title text for the upload glucose switch cell")
182+
183+
switchCell.switch?.addTarget(self, action: #selector(uploadEnabledChanged(_:)), for: .valueChanged)
184+
185+
return switchCell
172186
case .latestReading:
173187
let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath) as! SettingsTableViewCell
174188
let glucose = cgmManager.latestReading
@@ -283,6 +297,8 @@ class TransmitterSettingsViewController: UITableViewController {
283297
switch Section(rawValue: section)! {
284298
case .transmitterID:
285299
return nil
300+
case .remoteDataSync:
301+
return LocalizedString("Remote Data Synchronization", comment: "Section title for remote data synchronization")
286302
case .latestReading:
287303
return LocalizedString("Latest Reading", comment: "Section title for latest glucose reading")
288304
case .latestCalibration:
@@ -302,6 +318,8 @@ class TransmitterSettingsViewController: UITableViewController {
302318
switch Section(rawValue: indexPath.section)! {
303319
case .transmitterID:
304320
return false
321+
case .remoteDataSync:
322+
return false
305323
case .latestReading:
306324
return false
307325
case .latestCalibration:
@@ -329,6 +347,8 @@ class TransmitterSettingsViewController: UITableViewController {
329347
switch Section(rawValue: indexPath.section)! {
330348
case .transmitterID:
331349
break
350+
case .remoteDataSync:
351+
break
332352
case .latestReading:
333353
break
334354
case .latestCalibration:
@@ -373,6 +393,8 @@ class TransmitterSettingsViewController: UITableViewController {
373393
switch Section(rawValue: indexPath.section)! {
374394
case .transmitterID:
375395
break
396+
case .remoteDataSync:
397+
break
376398
case .latestReading:
377399
break
378400
case .latestCalibration:
@@ -394,6 +416,10 @@ class TransmitterSettingsViewController: UITableViewController {
394416

395417
return indexPath
396418
}
419+
420+
@objc private func uploadEnabledChanged(_ sender: UISwitch) {
421+
cgmManager.shouldSyncToRemoteService = sender.isOn
422+
}
397423
}
398424

399425

0 commit comments

Comments
 (0)