I'm trying to display a users weekly steps from HealthKit (broken down into daily eg Monday - 1200, Tuesday - 800), I've made a View model that gets all the data, if I do not add a delay on the data in my view, it wont print, but now my chart is not displaying at all? Any help would be appreciated
//View
import SwiftUI
import Charts
struct DashboardView: View {
var body: some View {
@ObservedObject var healthKitManager = HealthKitManager()
@State var stepsData = healthKitManager.weeklySteps
@State var showChart = false
VStack {
VStack {
HStack{
Text("Hello")
.foregroundColor(Color.black)
.font(.largeTitle)
Text("Leander ")
.foregroundColor(Color.black)
.font(.largeTitle)
.fontDesign(.serif)
.fontWeight(.bold)
}
.padding(10)
VStack{
Text("WANT TO SEE YOUR NEARBY USERS?")
.padding(.leading, 70)
.font(.subheadline)
.foregroundColor(Color("purple"))
Divider()
.frame(minHeight: 1)
.overlay(Color("Green"))
.padding(.leading, 70)
Text("WANT TO SEE CONNETIONS MADE?")
.font(.subheadline)
.padding(.leading, 70)
.foregroundColor(Color("Green"))
}
.padding(.vertical, 3)
VStack {
Text("Connections made:")
Spacer()
.frame(height: 20)
Chart {
ForEach(stepsData, id: \.day) { item in
LineMark(
x: .value("date", item.day),
y: .value("connections", item.steps)
)
}
}
.frame(maxHeight: 150)
Spacer()
Text("Distance walked:")
.padding(.bottom, 5)
}
.padding(20)
}
.frame(maxWidth: .infinity, maxHeight: 900, alignment: .top)
.padding(20)
.background(Color.white)
// .cornerRadius(radius: 170.0, corners: [.topLeft])
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
.background(Color("Green"))
.onAppear{
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0){
print("HERE: \(healthKitManager.weeklySteps)")
stepsData = healthKitManager.weeklySteps
showChart = true
}
}
}
}
struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
DashboardView()
}
}
// View Model
import Foundation
import HealthKit
class HealthKitManager: ObservableObject {
let healthStore: HKHealthStore = HKHealthStore()
let steps = HKQuantityType(.stepCount)
//Steps tesster
var thisWeekSteps: [Int: Int] = [1: 0, 2: 0, 3: 0,
4: 0, 5: 0, 6: 0, 7: 0]
var weeklySteps: [StepsModel] = []
init(){
if(HKHealthStore.isHealthDataAvailable()){
let heartBeat = HKQuantityType(.heartRate)
let healtTyoes: Set = [steps, heartBeat]
Task{
do{
try await healthStore.requestAuthorization(toShare: [], read: healtTyoes)
fetchSteps()
}catch{
print("Error retrieving data")
}
}
}
}
func fetchSteps() {
guard let stepCountType = HKQuantityType.quantityType(forIdentifier: .stepCount) else {
return
}
let today = Date()
let startOfWeek = Calendar.firstWeekday
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
guard let endOfWeek = Calendar.current.date(byAdding: .day, value: 6, to: startOfWeek) else {
print("Failed to calculate the end date of the week.")
return
}
let predicate = HKQuery.predicateForSamples(
withStart: startOfWeek,
end: endOfWeek,
options: .strictStartDate
)
let query = HKStatisticsCollectionQuery(
quantityType: stepCountType,
quantitySamplePredicate: predicate,
options: .cumulativeSum,
anchorDate: startOfWeek,
intervalComponents: DateComponents(day: 1)
)
query.initialResultsHandler = { _, result, error in
guard let result = result, error == nil else {
print("Error getting steps \(error?.localizedDescription ?? "")")
return
}
result.enumerateStatistics(from: startOfWeek, to: today) { statistics, _ in
if let quantity = statistics.sumQuantity() {
let steps = Int(quantity.doubleValue(for: HKUnit.count()))
let date = statistics.startDate
let dayOfWeek = dateFormatter.string(from: date)
self.weeklySteps.append(StepsModel(day: dayOfWeek, steps: steps))
print("\(dayOfWeek) - \(steps)")
}
}
//
// result.enumerateStatistics(from: startOfWeek, to: endOfWeek) { statistics, _ in
// if let quantity = statistics.sumQuantity() {
// let steps = Int(quantity.doubleValue(for: HKUnit.count()))
// let day = calendar.component(.weekday, from: statistics.startDate)
// self.thisWeekSteps[day] = steps
// print("day: \(day) - steps: \(steps)")
// }
// }
}
healthStore.execute(query)
}
func readStepCountThisWeek() {
guard let stepCountType = HKQuantityType.quantityType(forIdentifier: .stepCount) else {
return
}
let calendar = Calendar.current
let today = calendar.startOfDay(for: Date())
// let startOfWeek = Calendar.firstWeekday
// Find the start date (Monday) of the current week
guard let startOfWeek = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: today)) else {
print("Failed to calculate the start date of the week.")
return
}
// Find the end date (Sunday) of the current week
guard let endOfWeek = calendar.date(byAdding: .day, value: 6, to: startOfWeek) else {
print("Failed to calculate the end date of the week.")
return
}
let predicate = HKQuery.predicateForSamples(
withStart: startOfWeek,
end: today,
options: .strictStartDate
)
let query = HKStatisticsCollectionQuery(
quantityType: stepCountType,
quantitySamplePredicate: predicate,
options: .cumulativeSum, // fetch the sum of steps for each day
anchorDate: startOfWeek,
intervalComponents: DateComponents(day: 1) // interval to make sure the sum is per 1 day
)
query.initialResultsHandler = { _, result, error in
guard let result = result else {
if let error = error {
print("An error occurred while retrieving step count: \(error.localizedDescription)")
}
return
}
result.enumerateStatistics(from: startOfWeek, to: endOfWeek) { statistics, _ in
if let quantity = statistics.sumQuantity() {
let steps = Int(quantity.doubleValue(for: HKUnit.count()))
let day = calendar.component(.weekday, from: statistics.startDate)
self.thisWeekSteps[day] = steps
print("day: \(day) - steps: \(steps)")
}
}
}
healthStore.execute(query)
}
}
extension Calendar {
static var firstWeekday: Date {
let calendar = Calendar.current
let now = Date()
let beginningOfWeek = calendar.dateInterval(of: .weekOfYear, for: now)?.start
return beginningOfWeek ?? now
}
}
// Data Model
import Foundation
struct StepsModel: Identifiable, Codable, Equatable {
var id = UUID()
var day: String
var steps: Int
}