Skip to content

Commit

Permalink
Updates docs, tracks HealthKit transmissions
Browse files Browse the repository at this point in the history
  • Loading branch information
vishnuravi committed Dec 28, 2024
1 parent a93a7ee commit 8eebce2
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 27 deletions.
8 changes: 4 additions & 4 deletions LifeSpace.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@
CODE_SIGN_ENTITLEMENTS = "LifeSpace/Supporting Files/LifeSpace.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
Expand Down Expand Up @@ -1026,7 +1026,7 @@
CODE_SIGN_ENTITLEMENTS = "LifeSpace/Supporting Files/LifeSpace.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
Expand Down Expand Up @@ -1074,7 +1074,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 3;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = "";
Expand Down Expand Up @@ -1104,7 +1104,7 @@
PRODUCT_BUNDLE_IDENTIFIER = edu.stanford.lifespace;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Cardinal LifeSpace";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
Expand Down
9 changes: 7 additions & 2 deletions LifeSpace/Account/AccountSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ struct AccountSheet: View {

@AppStorage(StorageKeys.studyID) var studyID = "unknownStudyID"
@AppStorage(StorageKeys.trackingPreference) private var trackingOn = true
@AppStorage(StorageKeys.lastSurveyTransmissionDate) private var lastSurveyTransmissionDate = "Not set"
@AppStorage(StorageKeys.lastLocationTransmissionDate) private var lastLocationTransmissionDate = "Not set"

@AppStorage(StorageKeys.lastSurveyTransmissionDate) private var lastSurveyTransmissionDate = "None"
@AppStorage(StorageKeys.lastLocationTransmissionDate) private var lastLocationTransmissionDate = "None"
@AppStorage(StorageKeys.lastHealthKitTransmissionDate) private var lastHealthKitTransmissionDate = "None"

var body: some View {
NavigationStack {
Expand Down Expand Up @@ -116,6 +118,9 @@ struct AccountSheet: View {
Section(header: Text("LAST_LOCATION_TRANSMISSION_SECTION")) {
Text(lastLocationTransmissionDate)
}
Section(header: Text("LAST_HEALTHKIT_TRANSMISSION_SECTION")) {
Text(lastHealthKitTransmissionDate)
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions LifeSpace/Location/LocationStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@ internal actor LocationStorage {
self.allLocations.append(coordinate)
}

func getLastSaved() -> (location: CLLocationCoordinate2D, date: Date)? {
lastSaved
}

func updateLastSaved(location: CLLocationCoordinate2D, date: Date) {
self.lastSaved = (location: location, date: date)
}

func getAllLocations() -> [CLLocationCoordinate2D] {
allLocations
}

func clearLocations() {
allLocations.removeAll()
}
}
25 changes: 12 additions & 13 deletions LifeSpace/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,22 @@
}
}
},
"LAST_HEALTHKIT_TRANSMISSION_SECTION" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Last HealthKit Transmission"
}
}
}
},
"LAST_LOCATION_TRANSMISSION_SECTION" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Last Successful Location Data Transmission"
"value" : "Last Location Transmission"
}
}
}
Expand All @@ -340,7 +350,7 @@
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Last Successful Survey Transmission"
"value" : "Last Survey Transmission"
}
}
}
Expand Down Expand Up @@ -465,17 +475,6 @@
}
}
},
"LOGS" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Logs"
}
}
}
},
"LOGS_SHARE_PREVIEW_TITLE" : {

},
Expand Down
3 changes: 3 additions & 0 deletions LifeSpace/SharedContext/StorageKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ enum StorageKeys {
static let lastSurveyTransmissionDate = "lastSurveyTransmissionDate"
/// `Date`s containing the timestamp of the last successful transmission for location data.
static let lastLocationTransmissionDate = "lastLocationTransmissionDate"
/// `Date`s containing the timestamp of the last successful transmission for HealthKit data.
static let lastHealthKitTransmissionDate = "lastHealthKitTransmissionDate"

Check failure on line 31 in LifeSpace/SharedContext/StorageKeys.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint

Vertical Whitespace before Closing Braces Violation: Don't include vertical whitespace (empty line) before closing braces (vertical_whitespace_closing_braces)
}
44 changes: 36 additions & 8 deletions LifeSpaceStandard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ actor LifeSpaceStandard: Standard,
}
}


/// Saves a HealthKit sample to Firestore
/// - Parameter sample: an `HKSample` from HealthKit
func add(sample: HKSample) async {
guard let userId = Auth.auth().currentUser?.uid else {
logger.error("User is not logged in.")
Expand All @@ -72,6 +75,9 @@ actor LifeSpaceStandard: Standard,
dataDict["studyID"] = studyID

try await healthKitDocument(id: sample.id).setData(dataDict)

// Store the timestamp of this transmission for debugging purposes
storeCurrentTimestamp(forKey: StorageKeys.lastHealthKitTransmissionDate)
} catch {
logger.error("Could not store HealthKit sample: \(error) Sample: \(sample.sampleType)")
}
Expand All @@ -85,6 +91,9 @@ actor LifeSpaceStandard: Standard,
}
}


/// Saves a FHIR QuestionnaireResponse to Firestore
/// - Parameter response: A FHIR R4 `QuestionnaireResponse`
func add(response: ModelsR4.QuestionnaireResponse) async {
let id = response.identifier?.value?.value?.string ?? UUID().uuidString

Expand All @@ -98,6 +107,9 @@ actor LifeSpaceStandard: Standard,
}
}


/// Saves a location data point to Firestore, appending a timestamp, study ID, and user ID.
/// - Parameter location: A `CLLocationCoordinate2D` containing the latitude and longitude of a location.
func add(location: CLLocationCoordinate2D) async throws {
guard let userId = Auth.auth().currentUser?.uid else {
throw LifeSpaceStandardError.userNotAuthenticatedYet
Expand Down Expand Up @@ -127,9 +139,7 @@ actor LifeSpaceStandard: Standard,
.setData(from: dataPoint)

// Store a timestamp of this transmission for debugging purposes
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
UserDefaults.standard.set(formatter.string(from: Date.now), forKey: StorageKeys.lastLocationTransmissionDate)
storeCurrentTimestamp(forKey: StorageKeys.lastLocationTransmissionDate)
}

func fetchLocations(on date: Date = Date()) async throws -> [CLLocationCoordinate2D] {
Expand Down Expand Up @@ -165,6 +175,9 @@ actor LifeSpaceStandard: Standard,
}



Check failure on line 178 in LifeSpaceStandard.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint

Vertical Whitespace Violation: Limit vertical whitespace to maximum 2 empty lines; currently 3 (vertical_whitespace)
/// Saves a LifeSpace daily survey response to Firestore
/// - Parameter response: A `DailySurveyResponse`
func add(response: DailySurveyResponse) async throws {
guard let userId = Auth.auth().currentUser?.uid else {
throw LifeSpaceStandardError.userNotAuthenticatedYet
Expand All @@ -190,11 +203,12 @@ actor LifeSpaceStandard: Standard,
)

// Store a timestamp of this transmission for debugging purposes
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
UserDefaults.standard.set(formatter.string(from: Date.now), forKey: StorageKeys.lastSurveyTransmissionDate)
storeCurrentTimestamp(forKey: StorageKeys.lastSurveyTransmissionDate)
}


/// Gets the date of the latest completed survey from the user document in Firestore, saves it to `UserDefaults` and returns it.
/// - Returns: The latest survey date as a `String`
func getLatestSurveyDate() async -> String {
let document = try? await configuration.userDocumentReference.getDocument()

Expand All @@ -209,6 +223,10 @@ actor LifeSpaceStandard: Standard,
}



Check failure on line 226 in LifeSpaceStandard.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint

Vertical Whitespace Violation: Limit vertical whitespace to maximum 2 empty lines; currently 3 (vertical_whitespace)
/// Returns a reference to a given HealthKit document
/// - Parameter uuid: The document's unique identifier as a `UUID`.
/// - Returns: A reference to the document as a `DocumentReference`.
private func healthKitDocument(id uuid: UUID) async throws -> DocumentReference {
try await configuration.userDocumentReference
.collection(Constants.healthKitCollectionName)
Expand All @@ -225,7 +243,6 @@ actor LifeSpaceStandard: Standard,
}

/// Stores the given consent form in the user's document directory with a unique timestamped filename.
///
/// - Parameter consent: The consent form's data to be stored as a `PDFDocument`.
func store(consent: PDFDocument) async {
guard !FeatureFlags.disableFirebase else {
Expand Down Expand Up @@ -257,7 +274,6 @@ actor LifeSpaceStandard: Standard,
}

/// Stores the given consent form in the user's document directory and in the consent bucket in Firebase
///
/// - Parameter consentData: The consent form's data to be stored.
/// - Parameter name: The name of the consent document.
func store(consentData: Data, name: String) async {
Expand All @@ -284,6 +300,10 @@ actor LifeSpaceStandard: Standard,
}
}


/// Check if a consent form with a given name exists in Cloud Storage
/// - Parameter name: A `String` containing the name of the file to check for existence
/// - Returns: A `Bool` representing the existence of the file
func isConsentFormUploaded(name: String) async -> Bool {
do {
let maxSize: Int64 = 10 * 1024 * 1024
Expand Down Expand Up @@ -316,4 +336,12 @@ actor LifeSpaceStandard: Standard,
logger.error("Unable to set Study ID: \(error)")
}
}

/// A helper function to store a current timestamp to `UserDefaults` for a given key.
/// Used to keep track of the last transmission's timestamp for debugging purposes.
func storeCurrentTimestamp(forKey key: String) {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
UserDefaults.standard.set(formatter.string(from: Date.now), forKey: key)
}
}

0 comments on commit 8eebce2

Please sign in to comment.