Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add consent document viewer to profile screen #26

Merged
merged 3 commits into from
Jun 30, 2024
Merged
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
16 changes: 10 additions & 6 deletions LifeSpace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -61,6 +61,7 @@
63497B732BBF855E001F8419 /* OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63497B722BBF855E001F8419 /* OptionsPanel.swift */; };
634FFF672C169F40005E8217 /* LifeSpaceConsent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634FFF662C169F40005E8217 /* LifeSpaceConsent.swift */; };
634FFF6D2C16B81A005E8217 /* HIPAAAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634FFF6C2C16B81A005E8217 /* HIPAAAuthorization.swift */; };
639B69DB2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639B69DA2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift */; };
63A28D312C0580310025A1E0 /* RefreshIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63A28D302C0580310025A1E0 /* RefreshIcon.swift */; };
63A28D332C062E2E0025A1E0 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 63A28D322C062E2E0025A1E0 /* GoogleService-Info.plist */; };
63A8DB292C1FE81200939757 /* AppIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 63A8DB282C1FE81200939757 /* AppIcon.png */; };
@@ -139,6 +140,7 @@
63497B722BBF855E001F8419 /* OptionsPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionsPanel.swift; sourceTree = "<group>"; };
634FFF662C169F40005E8217 /* LifeSpaceConsent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LifeSpaceConsent.swift; sourceTree = "<group>"; };
634FFF6C2C16B81A005E8217 /* HIPAAAuthorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HIPAAAuthorization.swift; sourceTree = "<group>"; };
639B69DA2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConsentPDFVIewer.swift; sourceTree = "<group>"; };
63A28D302C0580310025A1E0 /* RefreshIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshIcon.swift; sourceTree = "<group>"; };
63A28D322C062E2E0025A1E0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
63A8DB282C1FE81200939757 /* AppIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = AppIcon.png; sourceTree = "<group>"; };
@@ -404,6 +406,7 @@
A9FE7ACF2AA39BAB0077B045 /* AccountSheet.swift */,
A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */,
A9DFE8A82ABE551400428242 /* AccountButton.swift */,
639B69DA2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift */,
);
path = Account;
sourceTree = "<group>";
@@ -622,6 +625,7 @@
2FE5DC3829EDD7CA004B9AB4 /* InterestingModules.swift in Sources */,
2FE5DC3529EDD7CA004B9AB4 /* Consent.swift in Sources */,
63EA5F8C2BC78F8400A48590 /* DailySurveyResponse.swift in Sources */,
639B69DB2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift in Sources */,
2FE5DC4529EDD7F2004B9AB4 /* Binding+Negate.swift in Sources */,
63497B732BBF855E001F8419 /* OptionsPanel.swift in Sources */,
2FC975A82978F11A00BA99FE /* Home.swift in Sources */,
@@ -768,7 +772,7 @@
CODE_SIGN_ENTITLEMENTS = "LifeSpace/Supporting Files/LifeSpace.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
@@ -832,7 +836,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 637867499T;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.odden.strokecoguitests;
@@ -972,7 +976,7 @@
CODE_SIGN_ENTITLEMENTS = "LifeSpace/Supporting Files/LifeSpace.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
@@ -1019,7 +1023,7 @@
CODE_SIGN_ENTITLEMENTS = "LifeSpace/Supporting Files/LifeSpace.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
@@ -1102,7 +1106,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 637867499T;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.odden.strokecoguitests;
@@ -1120,7 +1124,7 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 637867499T;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.odden.strokecoguitests;
Original file line number Diff line number Diff line change
@@ -24,8 +24,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "076b241a625e25eac22f8849be256dfb960fcdfe",
"version" : "10.19.1"
"revision" : "3b62f154d00019ae29a71e9738800bb6f18b236d",
"version" : "10.19.2"
}
},
{
@@ -42,17 +42,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk.git",
"state" : {
"revision" : "8bcaf973b1d84e119b7c7c119abad72ed460979f",
"version" : "10.27.0"
"revision" : "e57841b296d04370ea23580f908881b0ccab17b9",
"version" : "10.28.1"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "70df02431e216bed98dd461e0c4665889245ba70",
"version" : "10.27.0"
"revision" : "fe727587518729046fc1465625b9afd80b5ab361",
"version" : "10.28.0"
}
},
{
@@ -123,17 +123,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/mapbox-common-ios.git",
"state" : {
"revision" : "9c04997ed32c5b2506eb704f9f7a16367b5dcc64",
"version" : "24.4.0"
"revision" : "8e3259433704add95894a3e7823f5658a17bd43b",
"version" : "24.5.0-rc.1"
}
},
{
"identity" : "mapbox-core-maps-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mapbox/mapbox-core-maps-ios.git",
"state" : {
"revision" : "c7897628028afb2c008d50c5d5d4054768c99340",
"version" : "11.4.0"
"revision" : "20d05d13d66371c46d486ce6d79d0e463df20fb9",
"version" : "11.5.0-rc.1"
}
},
{
@@ -142,7 +142,7 @@
"location" : "https://github.com/mapbox/mapbox-maps-ios.git",
"state" : {
"branch" : "main",
"revision" : "88a52b28b59e2bf89b149b6cfa221b7db039b977"
"revision" : "a4fb127d3a48ce84fbff0aa922218766d27000e0"
}
},
{
@@ -213,17 +213,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordSpezi/SpeziFirebase.git",
"state" : {
"revision" : "f05c859f75d317dca9b378b7f8a7cfa8e135df04",
"version" : "1.1.1"
"revision" : "00ff0db12bf72ba39354e263d8f916ae8392368b",
"version" : "1.1.2"
}
},
{
"identity" : "spezifoundation",
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordSpezi/SpeziFoundation",
"state" : {
"revision" : "01af5b91a54f30ddd121258e81aff2ddc2a99ff9",
"version" : "1.0.4"
"revision" : "656f7659895dd4f182306963c2def75c16608472",
"version" : "1.1.1"
}
},
{
@@ -285,8 +285,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/StanfordSpezi/SpeziViews.git",
"state" : {
"revision" : "4d2a724d97c8f19ac7de7aa2c046b1cb3ef7b279",
"version" : "1.3.1"
"revision" : "0899c34c4b05e85b19e2dd2395783686aef81652",
"version" : "1.4.0"
}
},
{
51 changes: 51 additions & 0 deletions LifeSpace/Account/AccountSheet.swift
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
// SPDX-License-Identifier: MIT
//

import PDFKit
import SpeziAccount
import SwiftUI

@@ -19,12 +20,14 @@ struct AccountSheet: View {
@State var isInSetup = false
@State var overviewIsEditing = false

@AppStorage(StorageKeys.studyID) var studyID = "unknownStudyID"

var body: some View {
NavigationStack {
ZStack {
if account.signedIn && !isInSetup {
AccountOverview(isEditing: $overviewIsEditing) {
optionsList
}
.onDisappear {
overviewIsEditing = false
@@ -53,6 +56,44 @@ struct AccountSheet: View {
}
}
}

var optionsList: some View {
List {
Section(header: Text("STUDYID_SECTION")) {
Text(studyID)
}
Section(header: Text("DOCUMENTS_SECTION")) {
NavigationLink(destination: {
if let url = getDocumentURL(for: "consent") {
ConsentPDFViewer(url: url)
} else {
Text("DOCUMENT_NOT_FOUND_MESSAGE")
}
}) {
Text("VIEW_CONSENT_DOCUMENT")
}
NavigationLink(destination: {
if let url = getDocumentURL(for: "hipaaAuthorization") {
ConsentPDFViewer(url: url)
} else {
Text("DOCUMENT_NOT_FOUND_MESSAGE")
}
}) {
Text("VIEW_HIPAA_AUTHORIZATION")
}
NavigationLink(destination: EmptyView()) {
Button(action: {
if let url = URL(string: "https://michelleodden.com/cardinal-lifespace-privacy-policy/") {
UIApplication.shared.open(url)
}
}) {
Text("VIEW_PRIVACY_POLICY")
}
.buttonStyle(PlainButtonStyle())
}
}
}
}

var closeButton: some ToolbarContent {
ToolbarItem(placement: .cancellationAction) {
@@ -61,6 +102,16 @@ struct AccountSheet: View {
}
}
}


func getDocumentURL(for fileName: String) -> URL? {
guard let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return nil
}

let filenameWithStudyID = "\(studyID)_\(fileName).pdf"
return documentsURL.appendingPathComponent(filenameWithStudyID)
}
}


22 changes: 22 additions & 0 deletions LifeSpace/Account/ConsentPDFVIewer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// ConsentPDFViewer.swift
// LifeSpace
//
// Created by Vishnu Ravi on 6/26/24.
//

import PDFKit
import SwiftUI

struct ConsentPDFViewer: UIViewRepresentable {
let url: URL

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

func updateUIView(_ uiView: PDFView, context: Context) {}
}
18 changes: 13 additions & 5 deletions LifeSpace/LifeSpaceStandard.swift
Original file line number Diff line number Diff line change
@@ -61,6 +61,10 @@ actor LifeSpaceStandard: Standard, EnvironmentAccessible, HealthKitConstraint, O
}
}

var studyID: String {
UserDefaults.standard.string(forKey: StorageKeys.studyID) ?? "unknownStudyID"
}


init() {
if !FeatureFlags.disableFirebase {
@@ -214,8 +218,6 @@ actor LifeSpaceStandard: Standard, EnvironmentAccessible, HealthKitConstraint, O
///
/// - Parameter consent: The consent form's data to be stored as a `PDFDocument`.
func store(consent: PDFDocument) async {
let studyID = UserDefaults.standard.string(forKey: StorageKeys.studyID) ?? "unknownStudyID"

guard !FeatureFlags.disableFirebase else {
guard let basePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
logger.error("Could not create path for writing consent form to user document directory.")
@@ -248,7 +250,6 @@ actor LifeSpaceStandard: Standard, EnvironmentAccessible, HealthKitConstraint, O
/// - Parameter name: The name of the consent document.
func store(consentData: Data, name: String) async {
/// Adds the study ID to the file name
let studyID = UserDefaults.standard.string(forKey: StorageKeys.studyID) ?? "unknownStudyID"
let filename = "\(studyID)_\(name).pdf"

guard let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
@@ -271,8 +272,15 @@ actor LifeSpaceStandard: Standard, EnvironmentAccessible, HealthKitConstraint, O

func isConsentFormUploaded(name: String) async -> Bool {
do {
let studyID = UserDefaults.standard.string(forKey: StorageKeys.studyID) ?? "unknownStudyID"
_ = try await userBucketReference.child("ls_consent/\(studyID)_\(name).pdf").getMetadata()
let maxSize: Int64 = 10 * 1024 * 1024
let data = try await userBucketReference.child("ls_consent/\(studyID)_\(name).pdf").data(maxSize: maxSize)

if let docURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let filename = "\(studyID)_\(name).pdf"
let url = docURL.appendingPathComponent(filename)
try? data.write(to: url)
}

return true
} catch {
return false
62 changes: 61 additions & 1 deletion LifeSpace/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -163,6 +163,19 @@
}
}
},
"DOCUMENT_NOT_FOUND_MESSAGE" : {

},
"DOCUMENTS_SECTION" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Documents"
}
}
}
},
"ERROR" : {
"localizations" : {
"en" : {
@@ -457,7 +470,14 @@
}
},
"PREVIOUS_DAY_SURVEY_LABEL" : {

"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Yesterday's Survey"
}
}
}
},
"PREVIOUS_DAY_SURVEY_NOTICE" : {
"localizations" : {
@@ -531,6 +551,16 @@
}
}
},
"STUDYID_SECTION" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Study ID"
}
}
}
},
"STUDYID_SUBTITLE" : {
"localizations" : {
"en" : {
@@ -651,6 +681,36 @@
}
}
},
"VIEW_CONSENT_DOCUMENT" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "View Consent Document"
}
}
}
},
"VIEW_HIPAA_AUTHORIZATION" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "View HIPAA Authorization"
}
}
}
},
"VIEW_PRIVACY_POLICY" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "View Privacy Policy"
}
}
}
},
"WELCOME_AREA1_DESCRIPTION" : {
"localizations" : {
"en" : {
33 changes: 33 additions & 0 deletions LifeSpace/Resources/studyIDs.csv
Original file line number Diff line number Diff line change
@@ -5,3 +5,36 @@
333333
444444
555555
123803
173060
201938
208495
208914
211142
224547
292795
422555
440309
457982
491854
513003
606647
612922
628002
683401
703611
712567
761295
764367
853261
865802
900779
907218
913939
947160
958806
966990
976512
481434
689724
391194