Skip to content

Commit

Permalink
Finish HealthChart as public-facing api
Browse files Browse the repository at this point in the history
  • Loading branch information
nriedman committed Nov 6, 2024
1 parent cbbc335 commit 4f5ff38
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 98 deletions.

This file was deleted.

37 changes: 20 additions & 17 deletions Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,34 @@
// SPDX-License-Identifier: MIT
//


import SwiftUI
import HealthKit

// TODO: Next steps:
// Verify data flow / implement data input infrastructure.
// Mock text in `HealthChart` just shows the current values of all inputs.
// See how they change with picker, modifiers, etc.

public struct HealthChart: View {
@State private var range: ChartRange
@State private var rangeBinding: Binding<ChartRange>?
@State private var measurements: [HKQuantitySample] = []
@State private var privateRange: ChartRange
private var privateRangeBinding: Binding<ChartRange>?

var range: Binding<ChartRange> {
Binding(
get: {
privateRangeBinding?.wrappedValue ?? privateRange
}, set: { newValue in
if let privateRangeBinding {
privateRangeBinding.wrappedValue = newValue
} else {
privateRange = newValue
}
}
)
}

Check warning on line 29 in Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift#L17-L29

Added lines #L17 - L29 were not covered by tests

private let quantityType: HKQuantityType
private let dataProvider: any DataProvider


public var body: some View {
Text("here is the metric chart.")
.onChange(of: range) { _, newRange in
Task { @MainActor in
measurements = try await dataProvider.fetchData(for: quantityType, in: newRange)
}
}
InternalHealthChart(quantityType, range: range, provider: dataProvider)
}

Check warning on line 37 in Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift#L35-L37

Added lines #L35 - L37 were not covered by tests


Expand All @@ -40,7 +43,7 @@ public struct HealthChart: View {
provider: any DataProvider = HealthKitDataProvider()
) {
self.quantityType = type
self.range = initialRange
self.privateRange = initialRange
self.dataProvider = provider
}

Check warning on line 48 in Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift#L44-L48

Added lines #L44 - L48 were not covered by tests

Expand All @@ -49,8 +52,8 @@ public struct HealthChart: View {
range: Binding<ChartRange>,
provider: any DataProvider = HealthKitDataProvider()
) {
self.range = range.wrappedValue
self.rangeBinding = range
self.privateRange = range.wrappedValue
self.privateRangeBinding = range
self.quantityType = type
self.dataProvider = provider
}

Check warning on line 59 in Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/HealthChart.swift#L54-L59

Added lines #L54 - L59 were not covered by tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import HealthKit
import SwiftUI


struct InternalHealthChart: View {
@Binding private var range: ChartRange
@State private var measurements: [Int] = [1]

Check warning on line 15 in Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift#L15

Added line #L15 was not covered by tests


@Environment(\.disabledChartInteractions) private var disabledInteractions
@Environment(\.healthChartStyle) private var chartStyle


private let quantityType: HKQuantityType
private let dataProvider: any DataProvider


var body: some View {
List {
HStack {
Text("Quantity Type:")
.bold()
Spacer(minLength: 5)
Text(quantityType.identifier)
}
HStack {
Text("Chart Range (Binding):")
.bold()
Spacer(minLength: 5)
Text(range.interval.description)
}
HStack {
Text("Chart Style (Modifier):")
.bold()
Spacer(minLength: 5)
Text("\(chartStyle.frameSize)")
}
HStack {
Text("Disabled Interactions (Modifier):")
.bold()
Spacer(minLength: 5)
Text(String(disabledInteractions.rawValue, radix: 2))
}
Section("Measurements") {
ForEach(measurements, id: \.self) { measurement in
Text("\(measurement)")
}
}
}
.onChange(of: range) { _, _ in
measurements.append(measurements.reduce(0, +))
}
}

Check warning on line 61 in Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift#L26-L61

Added lines #L26 - L61 were not covered by tests


init(
_ type: HKQuantityType,
range: Binding<ChartRange>,
provider: any DataProvider = HealthKitDataProvider()
) {
self._range = range
self.quantityType = type
self.dataProvider = provider
}

Check warning on line 72 in Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/ChartViews/InternalHealthChart.swift#L68-L72

Added lines #L68 - L72 were not covered by tests
}
10 changes: 5 additions & 5 deletions Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import Foundation


/// A `ChartRange` is the date domain of the x-axis of a `HealthChart`.
public struct ChartRange: Sendable, Equatable {
var start: Date
var end: Date
var granularity: Calendar.Component
public struct ChartRange: Sendable, Equatable, Hashable {
public var start: Date

Check failure on line 14 in Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Type Contents Order Violation: An 'instance_property' should not be placed amongst the type content(s) 'type_property' (type_contents_order)
public var end: Date

Check failure on line 15 in Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Type Contents Order Violation: An 'instance_property' should not be placed amongst the type content(s) 'type_property' (type_contents_order)
public var granularity: Calendar.Component

Check failure on line 16 in Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Type Contents Order Violation: An 'instance_property' should not be placed amongst the type content(s) 'type_property' (type_contents_order)


var interval: DateInterval {
public var interval: DateInterval {

Check failure on line 19 in Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Type Contents Order Violation: An 'instance_property' should not be placed amongst the type content(s) 'type_property' (type_contents_order)
DateInterval(start: start, end: end)
}

Check warning on line 21 in Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/Models/ChartRange.swift#L19-L21

Added lines #L19 - L21 were not covered by tests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public struct HealthChartInteractions: OptionSet, Sendable {
}

Check warning on line 16 in Sources/SpeziHealthCharts/MetricChart/Models/HealthChartInteractions.swift

View check run for this annotation

Codecov / codecov/patch

Sources/SpeziHealthCharts/MetricChart/Models/HealthChartInteractions.swift#L14-L16

Added lines #L14 - L16 were not covered by tests


static let swipe: HealthChartInteractions = HealthChartInteractions(rawValue: 1 << 0)
static let tap: HealthChartInteractions = HealthChartInteractions(rawValue: 1 << 1)
public static let swipe: HealthChartInteractions = HealthChartInteractions(rawValue: 1 << 0)

Check failure on line 19 in Sources/SpeziHealthCharts/MetricChart/Models/HealthChartInteractions.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Redundant Type Annotation Violation: Variables should not have redundant type annotation (redundant_type_annotation)
public static let tap: HealthChartInteractions = HealthChartInteractions(rawValue: 1 << 1)

Check failure on line 20 in Sources/SpeziHealthCharts/MetricChart/Models/HealthChartInteractions.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Redundant Type Annotation Violation: Variables should not have redundant type annotation (redundant_type_annotation)

static let all: HealthChartInteractions = [.tap, .swipe]
public static let all: HealthChartInteractions = [.tap, .swipe]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import Foundation


public struct HealthChartStyle: Sendable {
public let frameSize: CGFloat = 200.0
let frameSize: CGFloat


public init(idealHeight: CGFloat = 200.0) {
frameSize = idealHeight
}


public static let `default` = HealthChartStyle()
Expand Down
25 changes: 25 additions & 0 deletions Tests/UITests/TestApp/HealthKitTestsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ struct HealthKitTestsView: View {
@Environment(HealthKit.self) var healthKitModule
@Environment(HealthKitStore.self) var healthKitStore

@State private var showHealthChartBinding = false
@State private var showHealthChart = false

@State private var chartRange: ChartRange = .month


var body: some View {
List {
Expand All @@ -40,7 +45,27 @@ struct HealthKitTestsView: View {
}
}
}
Button("Show HealthChart with binding") { showHealthChartBinding.toggle() }
Button("Show HealthChart without binding") { showHealthChart.toggle() }
}
.sheet(isPresented: $showHealthChartBinding) {
VStack {
Picker("Chart Range", selection: $chartRange) {
Text("Daily").tag(ChartRange.day)
Text("Weekly").tag(ChartRange.week)
Text("Monthly").tag(ChartRange.month)
Text("Six Months").tag(ChartRange.sixMonths)
Text("Yearly").tag(ChartRange.year)
}
Text("Parent's Range: \(chartRange.interval.description)")
HealthChart(HKQuantityType(.bodyMass), range: $chartRange)
.style(HealthChartStyle(idealHeight: 150))
}
}
.sheet(isPresented: $showHealthChart) {
HealthChart(HKQuantityType(.bodyMass))
.disable(interactions: .swipe)
}
}
}

Expand Down

0 comments on commit 4f5ff38

Please sign in to comment.