Skip to content

Commit

Permalink
Onboarding Medication Page (#48)
Browse files Browse the repository at this point in the history
# Onboarding Medication Page

## ♻️ Current situation & Problem
Allows users to upload a picture of their medication which is stored in
Firebase.

## ⚙️ Release Notes 
Created Medication Page in the onboarding flow where user can take a
photo or upload a photo of their medication chart.

<img width="150" alt="Screenshot 2024-03-06 at 10 24 12 am"
src="https://github.com/CS342/2024-PICS/assets/137839789/129caebe-167f-4706-b93d-56efc2c0e5d7">



## 📚 Documentation
Used SourceImage Package


## ✅ Testing


## 📝 Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/CS342/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/CS342/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
czhang771 authored Mar 7, 2024
1 parent 8650e5c commit 77422af
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 1 deletion.
25 changes: 25 additions & 0 deletions PICS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
22365B782B902C9100C4528E /* Onboarding-Questionnaire.json in Resources */ = {isa = PBXBuildFile; fileRef = 22365B772B902C9100C4528E /* Onboarding-Questionnaire.json */; };
226C16F02B69DF3500FBA97D /* HeightKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226C16EF2B69DF3500FBA97D /* HeightKey.swift */; };
226C16F22B6C820C00FBA97D /* WeightKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 226C16F12B6C820B00FBA97D /* WeightKey.swift */; };
22C75CE12B978E33008986AF /* Medication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C75CE02B978E33008986AF /* Medication.swift */; };
22C75CF02B979D02008986AF /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C75CEF2B979D02008986AF /* ContentView.swift */; };
22C75CF72B979EA7008986AF /* ImageSource in Frameworks */ = {isa = PBXBuildFile; productRef = 22C75CF62B979EA7008986AF /* ImageSource */; };
27FA29902A388E9B009CAC45 /* ModalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27FA298F2A388E9B009CAC45 /* ModalView.swift */; };
2F1AC9DF2B4E840E00C24973 /* PICS.docc in Sources */ = {isa = PBXBuildFile; fileRef = 2F1AC9DE2B4E840E00C24973 /* PICS.docc */; };
2F3D4ABC2A4E7C290068FB2F /* SpeziScheduler in Frameworks */ = {isa = PBXBuildFile; productRef = 2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */; };
Expand Down Expand Up @@ -137,6 +140,8 @@
22365B772B902C9100C4528E /* Onboarding-Questionnaire.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Onboarding-Questionnaire.json"; sourceTree = "<group>"; };
226C16EF2B69DF3500FBA97D /* HeightKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeightKey.swift; sourceTree = "<group>"; };
226C16F12B6C820B00FBA97D /* WeightKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeightKey.swift; sourceTree = "<group>"; };
22C75CE02B978E33008986AF /* Medication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Medication.swift; sourceTree = "<group>"; };
22C75CEF2B979D02008986AF /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
27FA298F2A388E9B009CAC45 /* ModalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalView.swift; sourceTree = "<group>"; };
2F1AC9DE2B4E840E00C24973 /* PICS.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = PICS.docc; sourceTree = "<group>"; };
2F4E237D2989A2FE0013F3D9 /* LaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -219,6 +224,7 @@
2FE5DC6729EDD894004B9AB4 /* SpeziContact in Frameworks */,
2FE5DC8429EDD934004B9AB4 /* SpeziQuestionnaire in Frameworks */,
2FB099B32A875DF100B20952 /* FirebaseFirestoreSwift in Frameworks */,
22C75CF72B979EA7008986AF /* ImageSource in Frameworks */,
5661551D2AB8384200209B80 /* SwiftPackageList in Frameworks */,
2FB099B12A875DF100B20952 /* FirebaseFirestore in Frameworks */,
A9D83F962B083794000D0C78 /* SpeziFirebaseAccountStorage in Frameworks */,
Expand Down Expand Up @@ -304,6 +310,8 @@
2FE5DCAC29EE6107004B9AB4 /* AccountOnboarding.swift */,
2FE5DC2F29EDD7CA004B9AB4 /* Consent.swift */,
2FE5DC3029EDD7CA004B9AB4 /* HealthKitPermissions.swift */,
22C75CE02B978E33008986AF /* Medication.swift */,
22C75CEF2B979D02008986AF /* ContentView.swift */,
22306A292B7C4E8E000A8EC1 /* OnboardingQuestionnaire.swift */,
22306A402B8F20C4000A8EC1 /* AccountQuestionnaire.swift */,
);
Expand Down Expand Up @@ -535,6 +543,7 @@
9739A0C52AD7B5730084BEA5 /* FirebaseStorage */,
97D73D692AD860AD00B47FA0 /* SpeziFirebaseStorage */,
A9D83F952B083794000D0C78 /* SpeziFirebaseAccountStorage */,
22C75CF62B979EA7008986AF /* ImageSource */,
);
productName = PICS;
productReference = 653A254D283387FE005D4D48 /* PICS.app */;
Expand Down Expand Up @@ -629,6 +638,7 @@
2FE750CA2A87240100723EAE /* XCRemoteSwiftPackageReference "SpeziMockWebService" */,
2FB099B42A875E2B00B20952 /* XCRemoteSwiftPackageReference "HealthKitOnFHIR" */,
5661551B2AB8384200209B80 /* XCRemoteSwiftPackageReference "swift-package-list" */,
22C75CF52B979EA7008986AF /* XCRemoteSwiftPackageReference "ImageSource" */,
);
productRefGroup = 653A254E283387FE005D4D48 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -721,6 +731,7 @@
22306A2A2B7C4E8E000A8EC1 /* OnboardingQuestionnaire.swift in Sources */,
2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */,
2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */,
22C75CF02B979D02008986AF /* ContentView.swift in Sources */,
2FE5DC4529EDD7F2004B9AB4 /* Binding+Negate.swift in Sources */,
8644E67B2B6C75B1001218D0 /* MapView.swift in Sources */,
2FC975A82978F11A00BA99FE /* Home.swift in Sources */,
Expand All @@ -729,6 +740,7 @@
2FE5DC3729EDD7CA004B9AB4 /* OnboardingFlow.swift in Sources */,
2F1AC9DF2B4E840E00C24973 /* PICS.docc in Sources */,
86EB7FF72B8FB7A000D52EE2 /* NotificationPermissions.swift in Sources */,
22C75CE12B978E33008986AF /* Medication.swift in Sources */,
226C16F22B6C820C00FBA97D /* WeightKey.swift in Sources */,
A45993292B90544300A98C95 /* Assessments.swift in Sources */,
2FF53D8D2A8729D600042B76 /* PICSStandard.swift in Sources */,
Expand Down Expand Up @@ -1295,6 +1307,14 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
22C75CF52B979EA7008986AF /* XCRemoteSwiftPackageReference "ImageSource" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/StanfordBDHG/ImageSource";
requirement = {
branch = main;
kind = branch;
};
};
2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/StanfordSpezi/SpeziScheduler.git";
Expand Down Expand Up @@ -1426,6 +1446,11 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
22C75CF62B979EA7008986AF /* ImageSource */ = {
isa = XCSwiftPackageProductDependency;
package = 22C75CF52B979EA7008986AF /* XCRemoteSwiftPackageReference "ImageSource" */;
productName = ImageSource;
};
2F3D4ABB2A4E7C290068FB2F /* SpeziScheduler */ = {
isa = XCSwiftPackageProductDependency;
package = 2F3D4ABA2A4E7C290068FB2F /* XCRemoteSwiftPackageReference "SpeziScheduler" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,15 @@
"version" : "0.2.5"
}
},
{
"identity" : "imagesource",
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordBDHG/ImageSource",
"state" : {
"branch" : "main",
"revision" : "9f942f21a485f4d552cfcefffae2e4077c0e9635"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
Expand Down
53 changes: 53 additions & 0 deletions PICS/Onboarding/ContentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// This source file is part of the ImageSource open source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//
import Foundation
import ImageSource
import PDFKit
import SwiftUI


struct ContentView: View {
@State var image: UIImage?
@Environment(PICSStandard.self) private var standard

private var swiftUIImage: some View {
image.flatMap {
Image(uiImage: $0)
.accessibilityLabel(Text("Medication Plan"))
}
}

var body: some View {
ImageSource(image: $image)
.clipShape(RoundedRectangle(cornerRadius: 8))
.padding()
.onChange(of: image) {
uploadImage(image: image)
}
}
func uploadImage(image: UIImage?) {
if let img = image {
if let pdfPage = PDFPage(image: img) {
let pdfDocument = PDFDocument()
pdfDocument.insert(pdfPage, at: 0)
Task {
await standard.storeImage(image: pdfDocument)
}
} else {
print("Failed to create PDFPage from image")
}
}
}
}


struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
52 changes: 52 additions & 0 deletions PICS/Onboarding/Medication.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// This source file is part of the PICS based on the Stanford Spezi Template Application project
//
// SPDX-FileCopyrightText: 2023 Stanford University
//
// SPDX-License-Identifier: MIT
//
import Foundation
import SpeziHealthKit
import SpeziOnboarding
import SwiftUI


struct Medication: View {
@Environment(OnboardingNavigationPath.self) private var onboardingNavigationPath

var body: some View {
OnboardingView(
contentView: {
VStack {
OnboardingTitleView(
title: "MEDICATION_TITLE",
subtitle: "MEDICATION_SUBTITLE"
)
Spacer()
ContentView()
}
}, actionView: {
OnboardingActionsView(
"Upload Photo",
action: {
onboardingNavigationPath.nextStep()
}
)
}
)

// Small fix as otherwise "Login" or "Sign up" is still shown in the nav bar
.navigationTitle(Text(verbatim: ""))
}
}


#if DEBUG
#Preview {
OnboardingStack {
Medication()
}
.previewWith(standard: PICSStandard()) {
}
}
#endif
4 changes: 3 additions & 1 deletion PICS/Onboarding/OnboardingFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ struct OnboardingFlow: View {
OnboardingStack(onboardingFlowComplete: $completedOnboardingFlow) {
Welcome()
InterestingModules()

if !FeatureFlags.disableFirebase {
AccountOnboarding()
}

Medication()
AccountQuestionnaire()

#if !(targetEnvironment(simulator) && (arch(i386) || arch(x86_64)))
Consent()
#endif
Expand Down
31 changes: 31 additions & 0 deletions PICS/PICSStandard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,37 @@ actor PICSStandard: Standard, EnvironmentAccessible, HealthKitConstraint, Onboar
logger.error("Could not store consent form: \(error)")
}
}

func storeImage(image: PDFDocument) async {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd_HHmmss"
let dateString = formatter.string(from: Date())

guard !FeatureFlags.disableFirebase else {
guard let basePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
logger.error("Could not create path for storing medication plan.")
return
}

let filePath = basePath.appending(path: "medicationPlan_\(dateString).pdf")
image.write(to: filePath)

return
}

do {
guard let medicationData = image.dataRepresentation() else {
logger.error("Could not store medication plan.")
return
}

let metadata = StorageMetadata()
metadata.contentType = "application/pdf"
_ = try await userBucketReference.child("medicationPlan/\(dateString).pdf").putDataAsync(medicationData, metadata: metadata)
} catch {
logger.error("Could not store medication plan: \(error)")
}
}


func create(_ identifier: AdditionalRecordId, _ details: SignupDetails) async throws {
Expand Down
28 changes: 28 additions & 0 deletions PICS/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,31 @@
}
}
},
"Medication Plan" : {

},
"MEDICATION_SUBTITLE" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Please upload a photo of your medication chart. "
}
}
}
},
"MEDICATION_TITLE" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Medication Information"
}
}
}
},
"MiniNutritional_DESCRIPTION" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -1249,6 +1274,9 @@
}
}
}
},
"Upload Photo" : {

},
"Value" : {

Expand Down

0 comments on commit 77422af

Please sign in to comment.