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 Timed Walk Test & Improve Rendering Possibilities for the QuestionnaireView #16

Merged
merged 32 commits into from Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f9bd2d0
initial commit
dguo8412 Oct 3, 2023
cb2423d
feat: implement functionality for timedWalk
dguo8412 Oct 4, 2023
7e872d5
feat: refactor to add dual functionality for QuestionnaireView and Fi…
dguo8412 Oct 5, 2023
bf8d5b9
fix: refactor code to account for ORKFileResult from FitnessCheck
dguo8412 Oct 5, 2023
3858189
test version
dguo8412 Oct 7, 2023
62cffc0
prints out data
dguo8412 Oct 10, 2023
b34770e
rough draft of manually coded walk test
dguo8412 Oct 11, 2023
53ac208
removed unnecessary location permissions
dguo8412 Oct 11, 2023
3dcbef0
enhanced UI and added timer functionality
dguo8412 Oct 17, 2023
49b6f66
fixed all functionality
dguo8412 Oct 18, 2023
12abf3a
refactor permissions
dguo8412 Oct 20, 2023
1666e5c
deleted TimedWalkView and refactored WalkTestDataSource, WalkTestCons…
dguo8412 Oct 23, 2023
e7b58a1
feat: added button enabling/disabling
dguo8412 Oct 23, 2023
c60424d
feat: added restart feature, reverted changes to questionnaire target…
dguo8412 Oct 27, 2023
ff3e916
Merge branch 'main' into daniel/timed-walk
dguo8412 Oct 30, 2023
802161d
extract walkTest to separate target + implement internal presentation…
dguo8412 Nov 2, 2023
696eb7e
added WalkTestError, refactored test app to support both WalkTest and…
dguo8412 Nov 2, 2023
28ee1d4
added WalkTestReponse extension to observation, added licenses.
dguo8412 Nov 3, 2023
3597d7a
refactored code with viewModel
dguo8412 Nov 7, 2023
2cd8300
edited bugs and added UITest for SpeziWalkTest
dguo8412 Nov 7, 2023
f5061ef
changed development team back
dguo8412 Nov 7, 2023
b87b084
edits to variable names and UI test comments
dguo8412 Nov 7, 2023
ae72798
create dummy pedometer results for UITests
dguo8412 Nov 8, 2023
92c39fa
edit UI and Response
dguo8412 Dec 1, 2023
34db5e0
Merge branch 'main' into daniel/timed-walk
PSchmiedmayer Mar 4, 2024
fe831b8
Update Walk Test
PSchmiedmayer Mar 4, 2024
480455f
Update Test
PSchmiedmayer Mar 4, 2024
cd0fbae
Update ResearchKit
PSchmiedmayer Mar 9, 2024
f352051
Remodel Results
PSchmiedmayer Mar 9, 2024
ecb86af
Improve Stability
PSchmiedmayer Mar 10, 2024
fc88f66
Update Documentation
PSchmiedmayer Mar 10, 2024
9be97d8
Add Documentation
PSchmiedmayer Mar 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 10 additions & 10 deletions Sources/SpeziQuestionnaire/ORKOrderedTaskView.swift
Expand Up @@ -16,12 +16,12 @@ import UIKit
struct ORKOrderedTaskView: UIViewControllerRepresentable {
class Coordinator: NSObject, ORKTaskViewControllerDelegate, ObservableObject {
private let isPresented: Binding<Bool>
private let questionnaireResponse: @MainActor (QuestionnaireResponse) async -> Void
private let timedWalkResponse: @MainActor (ORKTimedWalkResult) async -> Void


init(isPresented: Binding<Bool>, questionnaireResponse: @escaping @MainActor (QuestionnaireResponse) async -> Void) {
init(isPresented: Binding<Bool>, timedWalkResponse: @escaping @MainActor (ORKTimedWalkResult) async -> Void) {
self.isPresented = isPresented
self.questionnaireResponse = questionnaireResponse
self.timedWalkResponse = timedWalkResponse
}


Expand All @@ -35,10 +35,10 @@ struct ORKOrderedTaskView: UIViewControllerRepresentable {

switch reason {
case .completed:
let fhirResponse = taskViewController.result.fhirResponse
fhirResponse.subject = Reference(reference: FHIRPrimitive(FHIRString("My Patient")))
let response = taskViewController.result

await questionnaireResponse(fhirResponse)
// what is this doing down here?
await timedWalkResponse(response)
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
default:
break
}
Expand All @@ -49,7 +49,7 @@ struct ORKOrderedTaskView: UIViewControllerRepresentable {

private let tasks: ORKOrderedTask
private let tintColor: Color
private let questionnaireResponse: @MainActor (QuestionnaireResponse) async -> Void
private let timedWalkResponse: @MainActor (ORKTimedWalkResult) async -> Void

@Binding private var isPresented: Bool

Expand All @@ -60,18 +60,18 @@ struct ORKOrderedTaskView: UIViewControllerRepresentable {
init(
tasks: ORKOrderedTask,
isPresented: Binding<Bool>,
questionnaireResponse: @escaping @MainActor (QuestionnaireResponse) async -> Void,
timedWalkResponse: @escaping @MainActor (ORKTimedWalkResult) async -> Void,
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
tintColor: Color = Color(UIColor(named: "AccentColor") ?? .systemBlue)
) {
self.tasks = tasks
self._isPresented = isPresented
self.tintColor = tintColor
self.questionnaireResponse = questionnaireResponse
self.timedWalkResponse = timedWalkResponse
}


func makeCoordinator() -> Coordinator {
Coordinator(isPresented: $isPresented, questionnaireResponse: questionnaireResponse)
Coordinator(isPresented: $isPresented, timedWalkResponse: timedWalkResponse)
}

func updateUIViewController(_ uiViewController: ORKTaskViewController, context: Context) {
Expand Down
91 changes: 91 additions & 0 deletions Sources/SpeziQuestionnaire/TimedWalkView.swift
@@ -0,0 +1,91 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import FHIRQuestionnaires
import ModelsR4
import ResearchKit
import ResearchKitOnFHIR
import SwiftUI


/// Renders a FHIR `Questionnaire`.
public struct TimedWalkView: View {
@EnvironmentObject private var questionnaireDataSource: QuestionnaireDataSource

@Binding private var isPresented: Bool

private let identifier: String?
private let distanceInMeters: Double?
private let timeLimit: TimeInterval?
private let turnAroundTimeLimit: TimeInterval?
private let timedWalkResponse: ((ORKTimedWalkResult) async -> Void)?


public var body: some View {
if let task = createTask() {
ORKOrderedTaskView(
tasks: task,
isPresented: $isPresented,
timedWalkResponse: { response in
await timedWalkResponse?(response)
await questionnaireDataSource.add(response)
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
},
tintColor: .accentColor
)
.ignoresSafeArea(.container, edges: .bottom)
.ignoresSafeArea(.keyboard, edges: .bottom)
} else {
Text("QUESTIONNAIRE_LOADING_ERROR_MESSAGE")
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
}
}


/// - Parameters:
/// - questionnaire: The `Questionnaire` that should be displayed.
/// - isPresented: Indication from the questionnaire view if should be presented (not "Done" pressed or cancelled).
/// - completionStepMessage: Optional completion message that can be appended at the end of the questionnaire.
/// - questionnaireResponse: Optional response closure that can be used to manually obtain the `QuestionnaireResponse`.
public init(
identifier: String?,
distanceInMeters: Double?,
timeLimit: TimeInterval?,
turnAroundTimeLimit: TimeInterval?,
isPresented: Binding<Bool> = .constant(true),
timedWalkResponse: (@MainActor (ORKTimedWalkResult) async -> Void)? = nil
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
) {
self.identifier = identifier
self.distanceInMeters = distanceInMeters
self.timeLimit = timeLimit
self.turnAroundTimeLimit = turnAroundTimeLimit
self._isPresented = isPresented
self.timedWalkResponse = timedWalkResponse
}


/// Creates a ResearchKit navigable task from a questionnaire
/// - Parameter questionnaire: a questionnaire
/// - Returns: a ResearchKit ordered task
private func createTask() -> ORKOrderedTask? {
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
// Create a navigable task from the Questionnaire
do {
return try timedWalk(withIdentifier: identifier, intendedUseDescription: "", distanceInMeters: distanceInMeters, timeLimit: timeLimit, turnAroundTimeLimit: turnAroundTimeLimit, includeAssistiveDeviceForm: false, options: ORKPredefinedTaskOption(rawValue: 0))

Check failure on line 76 in Sources/SpeziQuestionnaire/TimedWalkView.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Line Length Violation: Line should be 150 characters or less; currently it has 270 characters (line_length)
dguo8412 marked this conversation as resolved.
Show resolved Hide resolved
} catch {
print("Error creating task: \(error)")
return nil
}
}
}


#if DEBUG
struct TimedWalkView_Previews: PreviewProvider {
static var previews: some View {
QuestionnaireView(questionnaire: Questionnaire.dateTimeExample, isPresented: .constant(false))
}
}
#endif
6 changes: 3 additions & 3 deletions Tests/UITests/UITests.xcodeproj/project.pbxproj
Expand Up @@ -388,7 +388,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = 64FJ2MWNP4;
DEVELOPMENT_TEAM = 4DR2J9J8WP;
PSchmiedmayer marked this conversation as resolved.
Show resolved Hide resolved
ENABLE_PREVIEWS = YES;
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -419,7 +419,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = 64FJ2MWNP4;
DEVELOPMENT_TEAM = 4DR2J9J8WP;
ENABLE_PREVIEWS = YES;
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -548,7 +548,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = 64FJ2MWNP4;
DEVELOPMENT_TEAM = 4DR2J9J8WP;
ENABLE_PREVIEWS = YES;
ENABLE_TESTING_SEARCH_PATHS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand Down