Skip to content

Commit 457dd18

Browse files
authored
Fix rendering of target ranges in chart complication (#870)
1 parent ab1157a commit 457dd18

File tree

3 files changed

+55
-31
lines changed

3 files changed

+55
-31
lines changed

WatchApp Extension/ComplicationController.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ final class ComplicationController: NSObject, CLKComplicationDataSource {
6262
// c.f. https://developer.apple.com/design/human-interface-guidelines/watchos/icons-and-images/complication-images/
6363
let size: CGSize = {
6464
switch WKInterfaceDevice.current().screenBounds.width {
65-
case 162: // 40mm
66-
return CGSize(width: 150.0, height: 47.0)
67-
default /* case 184 */: // 44mm
65+
case let x where x > 180: // 44mm
6866
return CGSize(width: 171.0, height: 54.0)
67+
default: // 40mm
68+
return CGSize(width: 150.0, height: 47.0)
6969
}
7070
}()
7171

WatchApp Extension/Managers/ComplicationChartManager.swift

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,37 @@ import HealthKit
1212
import WatchKit
1313

1414
private let textInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
15-
private let glucoseSize = CGSize(width: 2, height: 2)
16-
private let glucoseLabelAttributes: [NSAttributedString.Key: Any] = [
17-
.font: UIFont(name: "HelveticaNeue", size: 10)!,
18-
.foregroundColor: UIColor.chartLabel
19-
]
20-
private let predictionDashPhase: CGFloat = 11
21-
private let predictionDashLengths: [CGFloat] = [5, 3]
2215

23-
private enum GlucoseLabelPosition {
24-
case high
25-
case low
16+
extension CGSize {
17+
fileprivate static let glucosePoint = CGSize(width: 2, height: 2)
18+
}
19+
20+
extension NSAttributedString {
21+
fileprivate class func forGlucoseLabel(string: String) -> NSAttributedString {
22+
return NSAttributedString(string: string, attributes: [
23+
.font: UIFont(name: "HelveticaNeue", size: 10)!,
24+
.foregroundColor: UIColor.chartLabel
25+
])
26+
}
2627
}
2728

29+
extension CGFloat {
30+
fileprivate static let predictionDashPhase: CGFloat = 11
31+
}
32+
33+
private let predictionDashLengths: [CGFloat] = [5, 3]
34+
35+
2836
final class ComplicationChartManager {
37+
private enum GlucoseLabelPosition {
38+
case high
39+
case low
40+
}
41+
2942
var data: GlucoseChartData?
30-
var lastRenderDate: Date?
31-
var renderedChartImage: UIImage?
32-
var visibleInterval: TimeInterval = .hours(4)
43+
private var lastRenderDate: Date?
44+
private var renderedChartImage: UIImage?
45+
private var visibleInterval: TimeInterval = .hours(4)
3346

3447
private var unit: HKUnit {
3548
return data?.unit ?? .milligramsPerDeciliter
@@ -44,7 +57,10 @@ final class ComplicationChartManager {
4457
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
4558
defer { UIGraphicsEndImageContext() }
4659

47-
let context = UIGraphicsGetCurrentContext()!
60+
guard let context = UIGraphicsGetCurrentContext() else {
61+
return nil
62+
}
63+
4864
drawChart(in: context, data: data, size: size)
4965

5066
guard let cgImage = context.makeImage() else {
@@ -75,9 +91,9 @@ final class ComplicationChartManager {
7591
}
7692

7793
private func drawGlucoseLabelText(_ text: String, position: GlucoseLabelPosition, scaler: GlucoseChartScaler) {
78-
let attributedText = NSAttributedString(string: text, attributes: glucoseLabelAttributes)
94+
let attributedText = NSAttributedString.forGlucoseLabel(string: text)
7995
let size = attributedText.size()
80-
let x = scaler.xCoordinate(for: scaler.dates.end) - size.width - textInsets.right
96+
let x = scaler.xCoordinate(for: scaler.dates.end) - size.width - textInsets.right
8197
let y: CGFloat = {
8298
switch position {
8399
case .high:
@@ -111,12 +127,12 @@ final class ComplicationChartManager {
111127

112128
private func drawHistoricalGlucose(in context: CGContext, using scaler: GlucoseChartScaler) {
113129
context.setFillColor(UIColor.glucose.cgColor)
114-
data?.historicalGlucose?.lazy
115-
.filter { scaler.dates.contains($0.startDate) }
116-
.forEach { glucose in
117-
let origin = scaler.point(for: glucose, unit: unit)
118-
let glucoseRect = CGRect(origin: origin, size: glucoseSize).alignedToScreenScale(WKInterfaceDevice.current().screenScale)
119-
context.fill(glucoseRect)
130+
data?.historicalGlucose?.lazy.filter {
131+
scaler.dates.contains($0.startDate)
132+
}.forEach { glucose in
133+
let origin = scaler.point(for: glucose, unit: unit)
134+
let glucoseRect = CGRect(origin: origin, size: .glucosePoint).alignedToScreenScale(WKInterfaceDevice.current().screenScale)
135+
context.fill(glucoseRect)
120136
}
121137
}
122138

@@ -127,7 +143,7 @@ final class ComplicationChartManager {
127143
let predictedPath = CGMutablePath()
128144
let glucosePoints = predictedGlucose.map { scaler.point(for: $0, unit: unit) }
129145
predictedPath.addLines(between: glucosePoints)
130-
let dashedPath = predictedPath.copy(dashingWithPhase: predictionDashPhase, lengths: predictionDashLengths)
146+
let dashedPath = predictedPath.copy(dashingWithPhase: .predictionDashPhase, lengths: predictionDashLengths)
131147
context.setStrokeColor(UIColor.white.cgColor)
132148
context.addPath(dashedPath)
133149
context.strokePath()

WatchApp Extension/Models/GlucoseChartScaler.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,18 @@ struct GlucoseChartScaler {
7070
maxY = range.max
7171
}
7272

73-
let bottomLeft = point(max(dates.start, range.start), minY)
74-
let topRight = point(min(dates.end, range.end), maxY)
75-
let size = CGSize(width: topRight.x - bottomLeft.x, height: max(topRight.y - bottomLeft.y, minHeight))
76-
return CGRect(origin: bottomLeft, size: size).alignedToScreenScale(screenScale)
73+
switch coordinateSystem {
74+
case .standard:
75+
let topLeft = point(max(dates.start, range.start), maxY)
76+
let bottomRight = point(min(dates.end, range.end), minY)
77+
let size = CGSize(width: bottomRight.x - topLeft.x, height: max(bottomRight.y - topLeft.y, minHeight))
78+
return CGRect(origin: topLeft, size: size).alignedToScreenScale(screenScale)
79+
case .inverted:
80+
let bottomLeft = point(max(dates.start, range.start), minY)
81+
let topRight = point(min(dates.end, range.end), maxY)
82+
let size = CGSize(width: topRight.x - bottomLeft.x, height: max(topRight.y - bottomLeft.y, minHeight))
83+
return CGRect(origin: bottomLeft, size: size).alignedToScreenScale(screenScale)
84+
}
7785
}
7886
}
7987

@@ -89,7 +97,7 @@ extension GlucoseChartScaler {
8997
}
9098

9199
extension Range where Bound == HKQuantity {
92-
func span(with unit: HKUnit) -> Double {
100+
fileprivate func span(with unit: HKUnit) -> Double {
93101
return upperBound.doubleValue(for: unit) - lowerBound.doubleValue(for: unit)
94102
}
95103
}

0 commit comments

Comments
 (0)