Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Stanford360.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
C15624902D6D6E6E00298CEB /* InfiniteDayTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C156248F2D6D6E6E00298CEB /* InfiniteDayTimelineView.swift */; };
C15C64082D75CF8500979C62 /* LogWeightSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15C64072D75CF8500979C62 /* LogWeightSheet.swift */; };
C15C640A2D75CFF700979C62 /* LogWeightView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15C64092D75CFF700979C62 /* LogWeightView.swift */; };
C18772D72D82A57D004967EC /* TPPDF in Frameworks */ = {isa = PBXBuildFile; productRef = C18772D62D82A57D004967EC /* TPPDF */; };
C1CF13CF2D6D72C40057BC77 /* DailyScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF13CE2D6D72C40057BC77 /* DailyScheduleView.swift */; };
C1CF13DA2D6D76BE0057BC77 /* ScheduleTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF13D92D6D76BE0057BC77 /* ScheduleTask.swift */; };
C1CF13E72D6D7CF20057BC77 /* TaskStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CF13E62D6D7CF20057BC77 /* TaskStore.swift */; };
Expand Down Expand Up @@ -195,6 +196,7 @@
2FB099B62A875E2B00B20952 /* HealthKitOnFHIR in Frameworks */,
56E7083B2BB06F6F00B08F0A /* SwiftPackageList in Frameworks */,
56E708352BB06B7100B08F0A /* SpeziLicense in Frameworks */,
C18772D72D82A57D004967EC /* TPPDF in Frameworks */,
2FE5DC8A29EDD972004B9AB4 /* SpeziLocalStorage in Frameworks */,
4D2965DE2D7A8084000664B4 /* SpeziLLMLocalDownload in Frameworks */,
2FE5DC8C29EDD972004B9AB4 /* SpeziSecureStorage in Frameworks */,
Expand Down Expand Up @@ -469,6 +471,7 @@
4D2965DB2D7A8084000664B4 /* SpeziLLMLocal */,
4D2965DD2D7A8084000664B4 /* SpeziLLMLocalDownload */,
4D2965DF2D7A8084000664B4 /* SpeziLLMOpenAI */,
C18772D62D82A57D004967EC /* TPPDF */,
);
productName = Stanford360;
productReference = 653A254D283387FE005D4D48 /* Stanford360.app */;
Expand Down Expand Up @@ -577,6 +580,7 @@
A94DDFFB2CBD1190004930BD /* XCRemoteSwiftPackageReference "SpeziNotifications" */,
4DD4BE2A2D79C04F00B5FFC0 /* XCRemoteSwiftPackageReference "llama.cpp" */,
4D2965D62D7A8084000664B4 /* XCRemoteSwiftPackageReference "SpeziLLM" */,
C18772D22D82A401004967EC /* XCRemoteSwiftPackageReference "TPPDF" */,
);
productRefGroup = 653A254E283387FE005D4D48 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -1360,6 +1364,14 @@
minimumVersion = 1.0.2;
};
};
C18772D22D82A401004967EC /* XCRemoteSwiftPackageReference "TPPDF" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/techprimate/TPPDF";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.6.1;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand Down Expand Up @@ -1557,6 +1569,11 @@
package = 2F66D20D2BB723180010D555 /* XCRemoteSwiftPackageReference "SwiftLint" */;
productName = "plugin:SwiftLintBuildToolPlugin";
};
C18772D62D82A57D004967EC /* TPPDF */ = {
isa = XCSwiftPackageProductDependency;
package = C18772D22D82A401004967EC /* XCRemoteSwiftPackageReference "TPPDF" */;
productName = TPPDF;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 653A2545283387FE005D4D48 /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

120 changes: 56 additions & 64 deletions Stanford360/Dashboard/Views/DashboardChart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,82 +20,72 @@ struct DashboardChart: View {

var timeFrame: TimeFrame

private var filteredActivities: [Date] {
private var dates: [Date] {
let (startDate, endDate) = timeFrame.dateRange()
return Array(activityManager.activitiesByDate.keys)
.filter { date in
date >= startDate && date <= endDate
}
.sorted()
}

private var filteredHydration: [Date] {
let (startDate, endDate) = timeFrame.dateRange()
return Array(hydrationManager.hydrationByDate.keys)
.filter { date in
date >= startDate && date <= endDate
}
.sorted()
}

private var filteredMeals: [Date] {
let (startDate, endDate) = timeFrame.dateRange()
return Array(proteinManager.mealsByDate.keys)
.filter { date in
date >= startDate && date <= endDate
}
.sorted()
var dates: [Date] = []
let calendar = Calendar.current
var currentDate = calendar.startOfDay(for: startDate)

while currentDate <= endDate {
dates.append(currentDate)
currentDate = calendar.date(byAdding: .day, value: 1, to: currentDate) ?? Date()
}

return dates
}

var body: some View {
Chart {
ForEach(filteredActivities, id: \.self) { date in
if let activities = activityManager.activitiesByDate[date] {
LineMark(
x: .value("Week", date),
y: .value("Activity Minutes", activityManager.getTotalActivityMinutes(activities)),
series: .value("Metric", "Activity")
)
.applyChartStyle(color: Color.activityColor)
}
}

ForEach(filteredHydration, id: \.self) { date in
if let hydration = hydrationManager.hydrationByDate[date] {
LineMark(
x: .value("Week", date),
y: .value("Hydration Ounces", hydrationManager.getTotalHydrationOunces(hydration)),
series: .value("Metric", "Hydration")
)
.applyChartStyle(color: Color.hydrationColor)
}
}

ForEach(filteredMeals, id: \.self) { date in
if let meals = proteinManager.mealsByDate[date] {
LineMark(
x: .value("Week", date),
y: .value("Protein Grams", proteinManager.getTotalProteinGrams(meals)),
series: .value("Metric", "Protein")
)
.applyChartStyle(color: Color.proteinColor)
}
ForEach(dates, id: \.self) { date in
let activities = getActivities(from: date)
LineMark(
x: .value("Week", date),
y: .value("Activity Minutes", activityManager.getTotalActivityMinutes(activities)),
series: .value("Metric", "Activity")
)
.applyChartStyle(color: Color.activityColor)

let hydration = getHydration(from: date)
LineMark(
x: .value("Week", date),
y: .value("Hydration Ounces", hydrationManager.getTotalHydrationOunces(hydration)),
series: .value("Metric", "Hydration")
)
.applyChartStyle(color: Color.hydrationColor)

let meals = getMeals(from: date)
LineMark(
x: .value("Week", date),
y: .value("Protein Grams", proteinManager.getTotalProteinGrams(meals)),
series: .value("Metric", "Protein")
)
.applyChartStyle(color: Color.proteinColor)
}

goalLine()
}
.frame(height: 300)
.padding()
.padding(.leading, 40)
.padding(.trailing, 10)
.chartXAxis {
AxisMarks(values: .automatic) { value in
AxisMarks(values: .stride(by: .day)) { value in
if let date = value.as(Date.self) {
AxisValueLabel {
Text(date, format: .dateTime.month().day())
}
AxisValueLabel(date.formatted(.dateTime.weekday(.abbreviated)))
}
}
}
.chartXScale(domain: timeFrame.dateRange().start...timeFrame.dateRange().end)
}

private func getActivities(from date: Date) -> [Activity] {
activityManager.activitiesByDate[date] ?? []
}

private func getHydration(from date: Date) -> [HydrationLog] {
hydrationManager.hydrationByDate[date] ?? []
}

private func getMeals(from date: Date) -> [Meal] {
proteinManager.mealsByDate[date] ?? []
}
}

Expand All @@ -106,16 +96,18 @@ extension LineMark {
.symbol {
Circle()
.fill(color)
.frame(width: 8, height: 8)
.frame(width: 5, height: 5)
}
}
}

#Preview {
@Previewable @State var activityManager = ActivityManager()
@Previewable @State var activityManager = ActivityManager(activities: activitiesData)
@Previewable @State var hydrationManager = HydrationManager(hydration: hydrationData)
@Previewable @State var proteinManager = ProteinManager(meals: mealsData)

DashboardChart(timeFrame: .month)
DashboardChart(timeFrame: .week)
.environment(activityManager)
.environment(hydrationManager)
.environment(proteinManager)
}
31 changes: 31 additions & 0 deletions Stanford360/Dashboard/Views/DashboardPDFView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// DashboardPDFView.swift
// Stanford360
//
// Created by Kelly Bonilla Guzmán on 3/13/25.
//
// SPDX-FileCopyrightText: 2025 Stanford University
//
// SPDX-License-Identifier: MIT
//

import PDFKit
import SwiftUI
import TPPDF

struct DashboardPDFView: UIViewRepresentable {
var image: UIImage

func makeUIView(context: Context) -> PDFView {
let url = PDFDocument.generatePDF(image: image)
let pdfView = PDFView()
pdfView.document = PDFKit.PDFDocument(url: url)
return pdfView
}

func updateUIView(_ uiView: PDFView, context: Context) { }
}

#Preview {
DashboardPDFView(image: UIImage(systemName: "chart.xyaxis.line") ?? UIImage())
}
4 changes: 2 additions & 2 deletions Stanford360/Dashboard/Views/DashboardTimeFrameView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ struct DashboardTimeFrameView: View {
.tag(TimeFrame.today)
DashboardWeeklyView()
.tag(TimeFrame.week)
DashboardMonthlyView()
.tag(TimeFrame.month)
// DashboardMonthlyView()
// .tag(TimeFrame.month)
}
.tabViewStyle(PageTabViewStyle())
}
Expand Down
3 changes: 3 additions & 0 deletions Stanford360/Dashboard/Views/DashboardTodayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ struct DashboardTodayView: View {
ProgressCard(
title: "Activity",
progress: CGFloat(activityManager.getTodayTotalMinutes()),
unit: "min",
color: .activityColor,
streak: activityManager.streak
)

ProgressCard(
title: "Hydration",
progress: CGFloat(hydrationManager.getTodayTotalOunces()),
unit: "oz",
color: .hydrationColor,
streak: hydrationManager.streak
)

ProgressCard(
title: "Protein",
progress: CGFloat(proteinManager.getTodayTotalGrams()),
unit: "g",
color: .proteinColor,
streak: proteinManager.streak
)
Expand Down
16 changes: 15 additions & 1 deletion Stanford360/Dashboard/Views/DashboardWeeklyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,22 @@
import SwiftUI

struct DashboardWeeklyView: View {
@State var showPDFExportSheet: Bool = false
@State var size: CGSize?

var body: some View {
DashboardChartView(timeFrame: .week)
VStack {
HStack {
Spacer()
ExportPDFButton(showingSheet: $showPDFExportSheet)
.padding(.trailing, 20)
}

DashboardChartView(timeFrame: .week)
}
.sheet(isPresented: $showPDFExportSheet) {
ExportPDFSheet()
}
}
}

Expand Down
29 changes: 29 additions & 0 deletions Stanford360/Dashboard/Views/ExportPDFButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// ExportPDFButton.swift
// Stanford360
//
// Created by Kelly Bonilla Guzmán on 3/12/25.
//
// SPDX-FileCopyrightText: 2025 Stanford University
//
// SPDX-License-Identifier: MIT
//

import SwiftUI

struct ExportPDFButton: View {
@Binding var showingSheet: Bool

var body: some View {
Button(action: { showingSheet = true }) {
Text("View as PDF")
Image(systemName: "eye")
.accessibilityLabel(Text("View as PDF Button"))
}
}
}

#Preview {
@Previewable @State var showingSheet: Bool = false
ExportPDFButton(showingSheet: $showingSheet)
}
Loading
Loading