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
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
16 changes: 10 additions & 6 deletions LifeSpace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -404,6 +406,7 @@
A9FE7ACF2AA39BAB0077B045 /* AccountSheet.swift */,
A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */,
A9DFE8A82ABE551400428242 /* AccountButton.swift */,
639B69DA2C2BCD6A00C0FF4A /* ConsentPDFVIewer.swift */,
);
path = Account;
sourceTree = "<group>";
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
},
{
Expand All @@ -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"
}
},
{
Expand Down Expand Up @@ -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"
}
},
{
Expand All @@ -142,7 +142,7 @@
"location" : "https://github.com/mapbox/mapbox-maps-ios.git",
"state" : {
"branch" : "main",
"revision" : "88a52b28b59e2bf89b149b6cfa221b7db039b977"
"revision" : "a4fb127d3a48ce84fbff0aa922218766d27000e0"
}
},
{
Expand Down Expand Up @@ -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"
}
},
{
Expand Down Expand Up @@ -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"
}
},
{
Expand Down
51 changes: 51 additions & 0 deletions LifeSpace/Account/AccountSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// SPDX-License-Identifier: MIT
//

import PDFKit
import SpeziAccount
import SwiftUI

Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}
}


Expand Down
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
Expand Up @@ -61,6 +61,10 @@ actor LifeSpaceStandard: Standard, EnvironmentAccessible, HealthKitConstraint, O
}
}

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


init() {
if !FeatureFlags.disableFirebase {
Expand Down Expand Up @@ -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.")
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
Loading
Loading