Apple Health Frameworks

Nov 29 2022 · Swift 5, iOS 15, Xcode 13

Part 2: Dive Into More Details

08. Create a CheckIn Task

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 07. Add a Vaccination Task Next episode: 09. Work With StoreManager

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 08. Create a CheckIn Task

Part 2, Episode 09, Create CheckIn task

In this episode, I want to show you how to make a daily Symptom & Measurement Tracker. You should be familiar with the flow by now. So let’s begin.

From the project navigator inside the ViewModels folder, open TaskManager, and after // Make CheckIn - CareKitTask make a CheckIn task.

  static func makeCheckin() -> OCKTask {
    let schedule = OCKSchedule.dailyAtTime(
      hour: 8,
      minutes: 0,
      start: Date(),
      end: nil,
      text: nil
    )
    let task = OCKTask(
      id: TaskModel.checkIn.rawValue,
      title: "Check In",
      carePlanUUID: nil,
      schedule: schedule
    )
    return task
  }

Here you just made a daily schedule for the CheckIn task to tell the OCKDailyPageViewController to show a task inside the calendar every day at 8 until the user gets the vaccination done.

Next, you have to add it to the OCKStoreManager, so open the SceneDelegate from the project navigator, and inside of the taskList array right after // Add CheckIn Task to the StoreManager comment, add the task that you just made:

    let taskList = [TaskManager.makeOnboarding(),
                    TaskManager.makeVaccinationCheck(),
                    TaskManager.makeCheckin()]

The next step is to make the survey, from project navigator inside the ViewModels folder, open SurveyManager, and at the bottom of the class right after // Prepare CheckIn Survey - ResearchTask comment, add a function:

  private static var musclePainItem: ORKFormItem {
    let musclePainAnswerFormat = ORKAnswerFormat.scale(
      withMaximumValue: 10,
      minimumValue: 1,
      defaultValue: 5,
      step: 1,
      vertical: false,
      maximumValueDescription: "Very painful",
      minimumValueDescription: "No pain")
    let musclePainItem = ORKFormItem(
      identifier: IdentifierModel.checkinMuscle.rawValue,
      text: "How would you rate your muscle pain?",
      answerFormat: musclePainAnswerFormat)
    musclePainItem.isOptional = false
    return musclePainItem
  }

Here you made an ORKFormItem for the muscle pain to get the scale of pain from the user, and you set vertical to false to have a horizontal scaling from 1 to 5. Next item in the form is headache item, let’s create it:

  private static var headacheItem: ORKFormItem {
    let headacheAnswerFormat = ORKAnswerFormat.scale(
      withMaximumValue: 10,
      minimumValue: 1,
      defaultValue: 5,
      step: 1,
      vertical: false,
      maximumValueDescription: "Very painful",
      minimumValueDescription: "No pain")
    let headacheItem = ORKFormItem(
      identifier: IdentifierModel.checkinHeadache.rawValue,
      text: "How would you rate your headache?",
      answerFormat: headacheAnswerFormat)
    headacheItem.isOptional = false
    return headacheItem
  }

Here you made an ORKFormItem for the headache to get the scale of pain from the user, and you set vertical to false to have a horizontal scaling from 1 to 5. Next step is a tiredness item:

  private static var tirednessItem: ORKFormItem {
    let tirednessAnswerFormat = ORKAnswerFormat.scale(
      withMaximumValue: 10,
      minimumValue: 0,
      defaultValue: 5,
      step: 1,
      vertical: false,
      maximumValueDescription: nil,
      minimumValueDescription: nil)
    let tirednessItem = ORKFormItem(
      identifier: IdentifierModel.checkinTiredness.rawValue,
      text: "How would you rate your tiredness?",
      answerFormat: tirednessAnswerFormat)
    tirednessItem.isOptional = false
    return tirednessItem
  }

Here is the same as before, you made an ORKFormItem for the tiredness to get the scale from the user, and you set vertical to false to have a horizontal scaling from 0 to 10. Next is fever level:

  private static var feverItem: ORKFormItem {
    let feverAnswerFormat = ORKAnswerFormat.continuousScale(
      withMaximumValue: 42,
      minimumValue: 35,
      defaultValue: 37,
      maximumFractionDigits: 2,
      vertical: true,
      maximumValueDescription: "°C",
      minimumValueDescription: "°C")
    let feverItem = ORKFormItem(
      identifier: IdentifierModel.checkinFever.rawValue,
      text: "What is your body temprature?",
      answerFormat: feverAnswerFormat)
    feverItem.isOptional = false
    return feverItem
  }

Here you add another form item for fever, but this time it’s vertical, and you have a temperature as a scale in the centigrade. And last item is nausea item:

  private static var nauseaItem: ORKFormItem {
    let nauseaAnswerFormat = ORKAnswerFormat.scale(
      withMaximumValue: 5,
      minimumValue: 0,
      defaultValue: 2,
      step: 1,
      vertical: false,
      maximumValueDescription: nil,
      minimumValueDescription: nil)
    let nauseaItem = ORKFormItem(
      identifier: IdentifierModel.checkinNausea.rawValue,
      text: "How would you rate your nausea?",
      answerFormat: nauseaAnswerFormat)
    nauseaItem.isOptional = true
    return nauseaItem
  }

You add the same form item to get the scale from 0 to 5. Now it’s time to make a survey itself. add this function to make it ready:

  static func checkInSurvey() -> ORKTask {
    let formStep = ORKFormStep(
      identifier: IdentifierModel.checkinForm.rawValue,
      title: "Check In",
      text: "Please answer the following questions.")
    formStep.formItems = [tirednessItem, headacheItem, musclePainItem, feverItem, nauseaItem]
    formStep.isOptional = false
    let surveyTask = ORKOrderedTask(identifier: IdentifierModel.checkinStep.rawValue, steps: [formStep])
    return surveyTask
  }

Here you made an ORKFormStep and added all the form items into it. Next, you create an ORKOrderedTask and add only one step: a form step.

Now, in the project navigator inside the Models folder, open TaskModels and add a new case to the TaskModel right after // Add CheckIn Task comment:

  case checkIn

So when you add this case, Xcode start complaining about usage of this enum in the TaskViewModel class, so open it from the project navigator inside of ViewModels folder and fulfill the switch case by adding the .checkIn case right after // Make CheckIn ViewController

    case .checkIn:
      let viewController = OCKSurveyTaskViewController(
        taskID: TaskModel.checkIn.rawValue,
        eventQuery: OCKEventQuery(for: date),
        storeManager: storeManager,
        survey: SurveyManager.checkInSurvey(),
        extractOutcome: { _ in return [OCKOutcomeValue(Date())] })
      viewController.surveyDelegate = delegate

      listViewController.appendViewController(viewController, animated: false)
    }

Here you make a viewController as a type of OCKSurveyTaskViewController and put the SurveyManager.checkInSurvey() as one of the inputs.

Next is to stop user to do the checkin tasks from the future also all other tasks so, add a varable like this to check the future and add it inside all the cases.

    // Check the Date for future blocker
    let isFuture = Calendar.current.compare(date, to: Date(), toGranularity: .day) == .orderedDescending
          viewController.view.isUserInteractionEnabled = !isFuture
          viewController.view.alpha = isFuture ? 0.4 : 1.0

You checked the date to see if the calendar date is in the future or not; just make sure you add these two lines for all the cases right after surveyDelegate.

The last step is to open TaskViewContoller and add a ViewController right after // Ask ViewModel to Make CheckIn ViewController comment:

TaskViewModel.checkIfInputTaskIsComplete(
      input: .vaccinationCheck,
      storeManager: self.storeManager) { vaccinationIsComplete in
        if vaccinationIsComplete {
          TaskViewModel.makeTaskViewController(
            input: .checkIn,
            date: date,
            storeManager: self.storeManager,
            listViewController: listViewController,
            delegate: self)
        }
      }

You check if the vaccinationCheck task was completed, then you add a checkIn task to the list. Build and run the project to see how it looks, and just keep in mind, for now, you keep the storeManager on the memory, which means every time you run the app, the storeManager is empty, and you start fresh.