From b008b70afc2618bd658963dcad46100befa548c7 Mon Sep 17 00:00:00 2001 From: syoung-smallwisdom Date: Mon, 4 Mar 2019 10:23:23 -0800 Subject: [PATCH] Update copy, fix unit test, change to using frequency --- .../MotorControlTests/NavigationTests.swift | 7 +- Research/Research.xcodeproj/project.pbxproj | 10 +++ Research/Research/RSDFrequencyType.swift | 66 +++++++++++++++++++ Research/Research/RSDStudyConfiguration.swift | 30 +++++---- 4 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 Research/Research/RSDFrequencyType.swift diff --git a/MotorControl/MotorControlTests/NavigationTests.swift b/MotorControl/MotorControlTests/NavigationTests.swift index 54ad20ca3..c5b608e0a 100644 --- a/MotorControl/MotorControlTests/NavigationTests.swift +++ b/MotorControl/MotorControlTests/NavigationTests.swift @@ -72,9 +72,13 @@ class NavigationTests: XCTestCase { var taskController : TestTaskController! var steps : [RSDStep]! var handSelection : [String]! - + var previousFrequency : RSDFrequencyType! override func setUp() { + + previousFrequency = RSDStudyConfiguration.shared.fullInstructionsFrequency + RSDStudyConfiguration.shared.fullInstructionsFrequency = .standard(.monthly) + self.steps = [] let firstSteps : [RSDStep] = TestStep.steps(from: ["overview", "instruction"]) self.steps.append(contentsOf: firstSteps) @@ -101,6 +105,7 @@ class NavigationTests: XCTestCase { override func tearDown() { self.taskController = nil self.steps = nil + RSDStudyConfiguration.shared.fullInstructionsFrequency = previousFrequency super.tearDown() } diff --git a/Research/Research.xcodeproj/project.pbxproj b/Research/Research.xcodeproj/project.pbxproj index efa2e20b3..ae71f6180 100644 --- a/Research/Research.xcodeproj/project.pbxproj +++ b/Research/Research.xcodeproj/project.pbxproj @@ -562,6 +562,10 @@ F8FCB9882229E9620011F27F /* RSDStudyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB9862229E9620011F27F /* RSDStudyConfiguration.swift */; }; F8FCB9892229E9620011F27F /* RSDStudyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB9862229E9620011F27F /* RSDStudyConfiguration.swift */; }; F8FCB98A2229E9620011F27F /* RSDStudyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB9862229E9620011F27F /* RSDStudyConfiguration.swift */; }; + F8FCB98E222D9F510011F27F /* RSDFrequencyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */; }; + F8FCB98F222D9F510011F27F /* RSDFrequencyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */; }; + F8FCB990222D9F510011F27F /* RSDFrequencyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */; }; + F8FCB991222D9F510011F27F /* RSDFrequencyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */; }; F8FCE05F203F46EC00616CE8 /* ScheduleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FCE05E203F46EC00616CE8 /* ScheduleTests.swift */; }; F8FD56352141BD5100BA2FA6 /* RSDTaskMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FD56342141BD5100BA2FA6 /* RSDTaskMetadata.swift */; }; F8FD56362141BD5100BA2FA6 /* RSDTaskMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FD56342141BD5100BA2FA6 /* RSDTaskMetadata.swift */; }; @@ -1015,6 +1019,7 @@ F8F9544120239E8F00347940 /* RSDDateRangeObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDDateRangeObject.swift; sourceTree = ""; }; F8F9544520239ED400347940 /* RSDNumberRangeObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDNumberRangeObject.swift; sourceTree = ""; }; F8FCB9862229E9620011F27F /* RSDStudyConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDStudyConfiguration.swift; sourceTree = ""; }; + F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDFrequencyType.swift; sourceTree = ""; }; F8FCE05E203F46EC00616CE8 /* ScheduleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleTests.swift; sourceTree = ""; }; F8FD56342141BD5100BA2FA6 /* RSDTaskMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDTaskMetadata.swift; sourceTree = ""; }; F8FD56392141BDE000BA2FA6 /* RSDFileManifest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSDFileManifest.swift; sourceTree = ""; }; @@ -1844,6 +1849,7 @@ F8C7D394209155A9007490BC /* RSDUIActionType.swift */, F8C0A8CB20FB045C00EC758A /* RSDUITransitionStyle.swift */, F8BE10C02135E19B000AAB1E /* RSDValidationError.swift */, + F8FCB98D222D9F510011F27F /* RSDFrequencyType.swift */, ); name = Types; sourceTree = ""; @@ -2266,6 +2272,7 @@ F8BE12C421371B21000AAB1E /* RSDDateCoderObject.swift in Sources */, F8BE12B221371A41000AAB1E /* RSDUIActionObjectType.swift in Sources */, F8BE12EB21371B56000AAB1E /* RSDTaskObject.swift in Sources */, + F8FCB991222D9F510011F27F /* RSDFrequencyType.swift in Sources */, F8BE1280213719EC000AAB1E /* RSDComparable.swift in Sources */, F8BE12D121371B33000AAB1E /* RSDAnswerResultType+Codable.swift in Sources */, F8BE129D21371A1C000AAB1E /* RSDPickerDataSource.swift in Sources */, @@ -2588,6 +2595,7 @@ F8BE113D2136081E000AAB1E /* RSDViewThemeElement.swift in Sources */, F82D11132125EA9F00EA1A33 /* RSDFileResult.swift in Sources */, F8BE1129213602DB000AAB1E /* RSDActiveUIStep.swift in Sources */, + F8FCB98E222D9F510011F27F /* RSDFrequencyType.swift in Sources */, FF8B53F61FCE6C86006B6937 /* RSDDateCoderObject.swift in Sources */, FF8B53A41FCE6C7A006B6937 /* RSDDateCoder.swift in Sources */, F8FD563A2141BDE000BA2FA6 /* RSDFileManifest.swift in Sources */, @@ -2813,6 +2821,7 @@ F8BF1350213F97B0009505E5 /* RSDPathComponent.swift in Sources */, F8864AD82163F96500DF57CF /* RSDResultSummaryStep.swift in Sources */, FF8B54161FCE6C99006B6937 /* RSDResultObject.swift in Sources */, + F8FCB98F222D9F510011F27F /* RSDFrequencyType.swift in Sources */, FF8B53FC1FCE6C87006B6937 /* RSDRegExValidatorObject.swift in Sources */, FF8B53CB1FCE6C7B006B6937 /* RSDThemedUIStep.swift in Sources */, FF8B54C21FCE6D0A006B6937 /* NumberFormatter+Codable.swift in Sources */, @@ -2912,6 +2921,7 @@ F8BE11172135FF45000AAB1E /* RSDNavigationUIAction.swift in Sources */, FF8B53DB1FCE6C7B006B6937 /* RSDTaskInfoStep.swift in Sources */, F8864AD92163F96500DF57CF /* RSDResultSummaryStep.swift in Sources */, + F8FCB990222D9F510011F27F /* RSDFrequencyType.swift in Sources */, FF8B54881FCE6CDC006B6937 /* RSDStepController.swift in Sources */, FF8B54AC1FCE6CF8006B6937 /* RSDInputFieldError.swift in Sources */, F8F367E7215B404A00A49F89 /* RSDTaskState.swift in Sources */, diff --git a/Research/Research/RSDFrequencyType.swift b/Research/Research/RSDFrequencyType.swift new file mode 100644 index 000000000..577a9b546 --- /dev/null +++ b/Research/Research/RSDFrequencyType.swift @@ -0,0 +1,66 @@ +// +// RSDFrequencyType.swift +// Research +// +// Created by Shannon Young on 3/4/19. +// Copyright © 2019 Sage Bionetworks. All rights reserved. +// + +import Foundation + +/// The frequency type can be used to indicate the frequency with which to do something within the app. +public enum RSDFrequencyType { + + case standard(Standard) + + /// Standard set of frequencies defined within this framework. + public enum Standard : String, CaseIterable { + case always + case daily + case weekly + case monthly + case quarterly + case biannual + case annual + } + + /// A custom frequency. Must be handled by the app. + case custom(String) + + /// The string for the custom action (if applicable). + public var customAction: String? { + if case .custom(let str) = self { + return str + } else { + return nil + } + } +} + +extension RSDFrequencyType: RawRepresentable, Codable, Hashable { + + public init(rawValue: String) { + if let subtype = Standard(rawValue: rawValue) { + self = .standard(subtype) + } + else { + self = .custom(rawValue) + } + } + + public var rawValue: String { + switch (self) { + case .standard(let value): + return value.rawValue + + case .custom(let value): + return value + } + } +} + +extension RSDFrequencyType : ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + self.init(rawValue: value) + } +} diff --git a/Research/Research/RSDStudyConfiguration.swift b/Research/Research/RSDStudyConfiguration.swift index beef5d45f..aa26be811 100644 --- a/Research/Research/RSDStudyConfiguration.swift +++ b/Research/Research/RSDStudyConfiguration.swift @@ -34,24 +34,32 @@ import Foundation /// The study configuration is intended as a shared singleton that contains any information that should be -/// applied to the entire study which may effect the presentation of a given module. +/// applied to the entire study that may effect the presentation of a given module. open class RSDStudyConfiguration { /// Singleton for the study configuration for a given app. public static var shared: RSDStudyConfiguration = RSDStudyConfiguration() - /// Should each run of the app display full instructions or can the instructions be abbreviated for - /// subsequent runs. + /// How often should a given task be displayed to the user with the full instructions? + /// (Default = `always`) /// - /// Setting this flag to `true` will result in modules that use this flag showing the full instruction - /// sequence for every run. This can be used both to test the instruction flow as well as for a case - /// where a study uses the same mobile device for multiple participants. + /// Setting this flag to `always` will result in modules that use this flag showing the full instruction + /// sequence for every run. This can be used both to test the instruction flow as well as where a study + /// uses the same mobile device for multiple participants and needs to display the instructions every + /// time. /// - /// Setting this flag to `false` will result in modules that use this flag showing an abbreviated set of - /// instructions for subsequent runs so that complicated and/or lengthy instructions can be limited to - /// only being displayed sometimes (first run, on demand, etc.) rather than every time the *same* user - /// runs the module. + /// Setting this flag to another value will result in modules that use this flag showing an abbreviated + /// set of instructions for subsequent runs so that complicated and/or lengthy instructions can be + /// limited to only being displayed sometimes (first run, on demand, etc.) rather than every time the + /// *same* user runs the module. For this case, the frequency with which the app shows the full + /// instructions is determined by the frequency type. For example, if set to `monthly` then the user is + /// shown the full instructions once per month. /// - public var alwaysShowFullInstructions : Bool = true + public var fullInstructionsFrequency : RSDFrequencyType = .standard(.always) + + /// - seealso: `fullInstructionsFrequency` + public var alwaysShowFullInstructions : Bool { + return self.fullInstructionsFrequency == .standard(.always) + } }