Week 2 - Metrics, Colors & Core Data

This week I created Core Data entities and queries, a 24 color palette, managed HealthKit permissions flow, and loaded the initial health data.

Metrics and goals

I started working on reading health data, defining goals and visualizing daily progress. I picked ten health metrics to start: stepswalking distancesleepstand hoursexercisemindful minutesactive energyheart rateresting heart rate and weight.

For each metric, you can set a goal that defines the optimal range for that metric. For example, ideally, you would want to walk at least 8000 steps and have your average resting heart rate between 50 and 80 bpm and sleep 7-9 hours. You can have a goal in Active Me for each objective. This goal can be daily, weekly or monthly (the last two will be on average daily values).

In Active Me, the user will see a circle or a heart (for Heart Rate and Resting Heart Rate) representing the current value relative to the goal. A single full view means that the user managed to complete the goal for the desired interval. A smaller circle or heart, bordered by a line shape, means that the value was lower than expected, and a full circle or heart surrounded by a darker border means that the value was higher than expected. I wanted to keep this view simple and straightforward but also suggestive. I hope I succeeded.

Color palette

I was thinking about the app theme, and it makes sense to use multiple colors for the health metrics and goals. My first option was to let the user pick any color using the ColorPicker. The risk here is to have backgrounds and texts with low contrast, which might be hard to read. I decided eventually to define a color palette consisting of 24 nuances. Each has two darker versions for when the goal value is exceeded, one for light mode and one even darker to use on dark mode. I found that using a single color didn't look suitable for either the dark or light appearance, so I wanted to have something similar to what Apple does for their SwiftUI predefined colors. I spent more than a day trying to figure out the best colors. A great discovery tool was Aurora, created by Shihab Mehboob, which lets you get color details for live images or pictures and offers many predefined colors from four different sources with info like RGB value, luminance and related colors palettes.

The above views are randomly generated, one for each color, simulating that the goals are achieved or failed (with values lower and higher than expected), using both circles and hearts on light and dark appearance.

Core Data

As mentioned last week, I am using Core Data for storing goals and health data aggregation used to determine if the user achieved an objective. I think this is the best solution since (most probably) it won't have any costs, as opposed to creating my server or using some 3rd party alternatives. It also lifts a cause of stress for the app users and me as their data will be safe, encrypted and not accessible to anyone, not even me.

Here is a super simple schema of it:

IMG_7729.jpg


I created the entities and relationships in CoreData. I also added an AppGroup to make it available later to use in Widgets and Shortcuts. I defined some classes with methods for creating the objects and a few queries that I know I'm going to use.

Asking for permissions

For an app to have access to health data, it needs to have the user's permission. I want to request the minimum amount of permission as possible, so in the intro, I let the user pick the health metrics that she intends to track/improve and ask permission only for those metrics. If she wants to add later a new metric, I will ask for permission for that metric separately when it's the case.

About the intro, I want to make one inspired by this article by Antoine van der Lee. Kudos for creating and sharing this valuable piece of code! 🙏🏻

Keeping track of HealthKit data

When the user starts using the app during the onboarding process, he will choose which metrics he wants to see in Active Me. After receiving the permission, the app will begin fetching samples previous to the current date. I will store in core data daily aggregates for each metric. The aggregation is specific for the metric:

  • cumulative for steps, walking distance, sleep, stand hours, exercise, mindful minutes and active energy. For sleep, I will look from entries that start at 8 p.m. the previous day until 8 p.m. the current day;

  • averages for heart rate and resting heart rate (To have an accurate value for the day, I will do an average for the samples for each hour, and then a final average for the 24 or less hourly averages. It seems more accurate as an average, especially for situations in which the user exercises and might have more samples in that period);

  • the minimum value for weight.

In order to query the values, I used HealthKit Anchor Object Query. This query returns an anchor, an object that is used to determine all the changes that occurred since the previous query if passed as input. For the initial query, I set it to nil to get all the HealthKit samples for a particular metric, and for the subsequent requests, I store the returned anchor and use it to get just the changes.

For now, I will display a loading screen with progress info while the data is loaded. I am thinking of doing it async / in the background, but I'm not sure how to keep track of the changes if the user closes the app while the data is still loading.

I am using a sheet for the onboarding screen, and I don't want it to be dismissed while loading the initial health data. In SwiftUI, a sheet can be dismissed by dragging it down, which can be prevented by default. Fortunately, I found a great solution on Stack Overflow.

My first user

My first and most important user is my wife, Paula 🥰. She had some great suggestions regarding the onboarding flow and spent hours talking about Active Me, supporting me, and giving great feedback. I am lucky to have her around. She likes drawing and making digital art, and she offered to create some custom icons that I plan to use for Active Me as images and SF Symbols. More about this in the following weeks

Previous
Previous

Week 3 - Onboarding completed

Next
Next

Week 1 - New App, New Icon, New Goals