Skip to content

Commit

Permalink
Glucose chart panning
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanDegraeve committed Nov 24, 2019
1 parent 687e03c commit 1f697eb
Show file tree
Hide file tree
Showing 9 changed files with 619 additions and 200 deletions.
12 changes: 12 additions & 0 deletions xdrip/Constants/ConstantsGlucoseChart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,17 @@ enum ConstantsGlucoseChart {

/// diameter of the circle for blood glucose readings
static let glucoseCircleDiameter: CGFloat = 5

/// when user pans the chart, when ending the gesture, deceleration is done. At regular intervals the chart needs to be redrawn. This is the interval in seconds
static let decelerationTimerValueInSeconds = 0.02

/// deceleration rate to use when ending pan gesture on chart
static let decelerationRate = UIScrollView.DecelerationRate.normal.rawValue

/// maximum amount of elements in the glucoseChartPoints array, this will be limited for performance reasons
static let maximumElementsInGlucoseChartPointsArray:Int = 1000

/// dateformat for minutesAgo label when user is panning the chart back in time. The label will show the timestamp of the latest shown value in the chart
static let dateFormatLatestChartPointWhenPanning = "E d MMM HH:mm"

}
18 changes: 11 additions & 7 deletions xdrip/Core Data/accessors/BgReadingsAccessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ class BgReadingsAccessor {
/// - if ignoreCalculatedValue = true, then value of calculatedValue will be ignored
/// - returns: an array with readings, can be empty array.
/// Order by timestamp, descending meaning the reading at index 0 is the youngest
func getLatestBgReadings(limit:Int?, howOld maximumDays:Int?, forSensor sensor:Sensor?, ignoreRawData:Bool, ignoreCalculatedValue:Bool) -> [BgReading] {
func getLatestBgReadings(limit:Int?, howOld:Int?, forSensor sensor:Sensor?, ignoreRawData:Bool, ignoreCalculatedValue:Bool) -> [BgReading] {

// if maximum age specified then create fromdate
var fromDate:Date?
if let maximumDays = maximumDays, maximumDays >= 0 {
fromDate = Date(timeIntervalSinceNow: Double(-maximumDays * 60 * 60 * 24))
if let howOld = howOld, howOld >= 0 {
fromDate = Date(timeIntervalSinceNow: Double(-howOld * 60 * 60 * 24))
}

return getLatestBgReadings(limit: limit, fromDate: fromDate, forSensor: sensor, ignoreRawData: ignoreRawData, ignoreCalculatedValue: ignoreCalculatedValue)
Expand Down Expand Up @@ -106,13 +106,15 @@ class BgReadingsAccessor {
}

/// gets readings on a managedObjectContact that is created with concurrencyType: .privateQueueConcurrencyType
/// - returns:
/// readings sorted by timestamp, ascending (ie first is oldest)
/// - parameters:
/// - to : if specified, only return readings with timestamp smaller than fromDate
/// - from : if specified, only return readings with timestamp greater than fromDate
func getBgReadingOnPrivateManagedObjectContext(from: Date?, to: Date?) -> [BgReading] {
/// - to : if specified, only return readings with timestamp smaller than fromDate (not equal to)
/// - from : if specified, only return readings with timestamp greater than fromDate (not equal to)
func getBgReadingsOnPrivateManagedObjectContext(from: Date?, to: Date?) -> [BgReading] {

let fetchRequest: NSFetchRequest<BgReading> = BgReading.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(BgReading.timeStamp), ascending: false)]
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(BgReading.timeStamp), ascending: true)]

// create predicate
if let from = from, to == nil {
Expand Down Expand Up @@ -148,6 +150,8 @@ class BgReadingsAccessor {
/// - parameters:
/// - limit: maximum amount of readings to fetch, if 0 then no limit
/// - fromDate : if specified, only return readings with timestamp > fromDate
/// - returns:
/// List of readings, descending, ie first is youngest
private func fetchBgReadings(limit:Int?, fromDate:Date?) -> [BgReading] {
let fetchRequest: NSFetchRequest<BgReading> = BgReading.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(BgReading.timeStamp), ascending: false)]
Expand Down
1 change: 1 addition & 0 deletions xdrip/Extensions/ChartPoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SwiftCharts

extension ChartPoint {

// if bgReading.calculatedValue == 0 then return nil
convenience init?(bgReading: BgReading, formatter: DateFormatter, unitIsMgDl: Bool) {

if bgReading.calculatedValue > 0 {
Expand Down
463 changes: 381 additions & 82 deletions xdrip/Managers/Charts/GlucoseChartManager.swift

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions xdrip/Managers/NightScout/NightScoutUploadManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class NightScoutUploadManager:NSObject {
private let nightScoutAuthTestPath = "/api/v1/experiments/test"

/// for logging
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryNightScoutUploadManager)
private var oslog = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryNightScoutUploadManager)

/// BgReadingsAccessor instance
private let bgReadingsAccessor:BgReadingsAccessor
Expand Down Expand Up @@ -82,7 +82,7 @@ public class NightScoutUploadManager:NSObject {
if success {
self.upload()
} else {
trace("in observeValue, NightScout credential check failed", log: self.log, type: .info)
trace("in observeValue, NightScout credential check failed", log: self.oslog, type: .info)
}
}
})
Expand All @@ -104,7 +104,7 @@ public class NightScoutUploadManager:NSObject {
if success {
self.upload()
} else {
trace("in observeValue, NightScout credential check failed", log: self.log, type: .info)
trace("in observeValue, NightScout credential check failed", log: self.oslog, type: .info)
}
}
})
Expand All @@ -123,7 +123,7 @@ public class NightScoutUploadManager:NSObject {

private func uploadBgReadingsToNightScout(siteURL:String, apiKey:String) {

trace("in uploadBgReadingsToNightScout", log: self.log, type: .info)
trace("in uploadBgReadingsToNightScout", log: self.oslog, type: .info)

// get readings to upload, limit to x days, x = ConstantsNightScout.maxDaysToUpload
var timeStamp = Date(timeIntervalSinceNow: TimeInterval(-ConstantsNightScout.maxDaysToUpload*24*60*60))
Expand All @@ -137,7 +137,7 @@ public class NightScoutUploadManager:NSObject {
let bgReadingsToUpload = bgReadingsAccessor.getLatestBgReadings(limit: nil, fromDate: timeStamp, forSensor: nil, ignoreRawData: true, ignoreCalculatedValue: false)

if bgReadingsToUpload.count > 0 {
trace(" number of readings to upload : %{public}@", log: self.log, type: .info, bgReadingsToUpload.count.description)
trace(" number of readings to upload : %{public}@", log: self.oslog, type: .info, bgReadingsToUpload.count.description)

// map readings to dictionaryRepresentation
let bgReadingsDictionaryRepresentation = bgReadingsToUpload.map({$0.dictionaryRepresentationForNightScoutUpload})
Expand All @@ -164,54 +164,54 @@ public class NightScoutUploadManager:NSObject {
// Create upload Task
let dataTask = sharedSession.uploadTask(with: request, from: sendData, completionHandler: { (data, response, error) -> Void in

trace("in uploadTask completionHandler", log: self.log, type: .info)
trace("in uploadTask completionHandler", log: self.oslog, type: .info)

// if ends without success then log the data
var success = false
defer {
if !success {
if let data = data {
if let dataAsString = String(bytes: data, encoding: .utf8) {
trace(" data = %{public}@", log: self.log, type: .error, dataAsString)
trace(" data = %{public}@", log: self.oslog, type: .error, dataAsString)
}
}
}
}

// error cases
if let error = error {
trace(" failed to upload, error = %{public}@", log: self.log, type: .error, error.localizedDescription)
trace(" failed to upload, error = %{public}@", log: self.oslog, type: .error, error.localizedDescription)
return
}

// check that response is HTTPURLResponse and error code between 200 and 299
if let response = response as? HTTPURLResponse {
guard (200...299).contains(response.statusCode) else {
trace(" failed to upload, statuscode = %{public}@", log: self.log, type: .error, response.statusCode.description)
trace(" failed to upload, statuscode = %{public}@", log: self.oslog, type: .error, response.statusCode.description)
return
}
} else {
trace(" response is not HTTPURLResponse", log: self.log, type: .error)
trace(" response is not HTTPURLResponse", log: self.oslog, type: .error)
}

// successful cases,
success = true

// change timeStampLatestNightScoutUploadedBgReading
if let lastReading = bgReadingsToUpload.first {
trace(" upload succeeded, setting timeStampLatestNightScoutUploadedBgReading to %{public}@", log: self.log, type: .info, lastReading.timeStamp.description(with: .current))
trace(" upload succeeded, setting timeStampLatestNightScoutUploadedBgReading to %{public}@", log: self.oslog, type: .info, lastReading.timeStamp.description(with: .current))
UserDefaults.standard.timeStampLatestNightScoutUploadedBgReading = lastReading.timeStamp
}

})
dataTask.resume()
}
} catch let error {
trace(" %{public}@", log: self.log, type: .info, error.localizedDescription)
trace(" %{public}@", log: self.oslog, type: .info, error.localizedDescription)
}

} else {
trace(" no readings to upload", log: self.log, type: .info)
trace(" no readings to upload", log: self.oslog, type: .info)
}

}
Expand Down
19 changes: 18 additions & 1 deletion xdrip/Storyboards/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0nE-AX-r0w" customClass="BloodGlucoseChartView" customModule="xdrip" customModuleProvider="target">
<rect key="frame" x="5" y="225" width="310" height="289"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<gestureRecognizers/>
<connections>
<outletCollection property="gestureRecognizers" destination="Fi5-iu-Usk" appends="YES" id="Rkv-hK-sLH"/>
<outletCollection property="gestureRecognizers" destination="axt-dD-sCA" appends="YES" id="Bxm-Qp-L3P"/>
</connections>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
Expand Down Expand Up @@ -95,7 +100,9 @@
</tabBarItem>
<connections>
<outlet property="calibrateButtonOutlet" destination="mSJ-jy-nHJ" id="XSS-W3-gbX"/>
<outlet property="chartLongPressGestureRecognizerOutlet" destination="axt-dD-sCA" id="mUZ-cu-720"/>
<outlet property="chartOutlet" destination="0nE-AX-r0w" id="ivs-se-S3b"/>
<outlet property="chartPanGestureRecognizerOutlet" destination="Fi5-iu-Usk" id="zn5-wp-DKt"/>
<outlet property="diffLabelOutlet" destination="7Wo-wd-80o" id="nnn-w9-1sX"/>
<outlet property="minutesLabelOutlet" destination="uyn-2k-K74" id="XXm-rq-Suy"/>
<outlet property="preSnoozeButtonOutlet" destination="fSY-nc-amN" id="T25-Z1-3Ad"/>
Expand All @@ -106,7 +113,17 @@
<placeholder placeholderIdentifier="IBFirstResponder" id="W5J-7L-Pyd" sceneMemberID="firstResponder"/>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.90000000000000002" id="tYH-fG-Lky">
<connections>
<action selector="valueLabelLongPressedAction:" destination="9pv-A4-QxB" id="NlL-kQ-dpZ"/>
<action selector="valueLabelLongPressGestureRecognizerAction:" destination="9pv-A4-QxB" id="NlL-kQ-dpZ"/>
</connections>
</pongPressGestureRecognizer>
<panGestureRecognizer minimumNumberOfTouches="1" id="Fi5-iu-Usk">
<connections>
<action selector="chartPanGestureRecognizerAction:" destination="9pv-A4-QxB" id="NUY-gV-rdx"/>
</connections>
</panGestureRecognizer>
<pongPressGestureRecognizer allowableMovement="10" minimumPressDuration="0.5" id="axt-dD-sCA">
<connections>
<action selector="chartLongPressGestureRecognizerAction:" destination="9pv-A4-QxB" id="6qG-44-Nd4"/>
</connections>
</pongPressGestureRecognizer>
</objects>
Expand Down
1 change: 0 additions & 1 deletion xdrip/Utilities/Trace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fileprivate var log:OSLog = {
return log
}()


/// will only be used during development
func debuglogging(_ logtext:String) {
os_log("%{public}@", log: log, type: .debug, logtext)
Expand Down
Loading

0 comments on commit 1f697eb

Please sign in to comment.