Building Tiempo: A Journey into WatchOS

By

Ivan Koop

·

July 27th, 2023

Ivan is a full stack developer from Asunción, Paraguay

I am thrilled to share some details with you about Tiempo, a SwiftUI-based workout tracker for watchOS, co-created with Santiago Villalba, an ingenious designer. Santiago and I first crossed paths seven years ago when we collaborated on creating a banking frontend for Vision Banco, one of the most important banks in the country, and the website and mobile applications for one of the most popular news outlets in the country. Fast-forward to today, our paths have crossed again, this time on the development of Tiempo.

1: Seizing the Opportunity

A few weeks ago, Santiago got in touch with me and proposed working together on Tiempo. The timing was impeccable; I was in the process of transitioning jobs and had some extra time on my hands. After talking about the app and evaluating its potential, I was amazed by the design and concept. And so, my journey towards creating Tiempo began.

2: Revisiting the Basics

Even though I have significant experience in iOS development, my last native iOS project was two years ago. Hence, there was a need for me to revisit the platform, refresh my knowledge, and familiarize myself with the recent updates in SwiftUI.

3: First Hurdle: The StepsCircle Component

The initial challenge was to create a distinctive feature of Tiempo — the ‘StepsCircle’ component. This visual workout progression indicator was complex due to its multiple rounded corners, and the need to distinctly separate each step with a break indicator. Undeterred by the challenge, I embarked on crafting the first draft of this component.

4: Into the Code

The ‘StepsCircle’ SwiftUI view primarily renders a segmented circle, each segment representing a step in a workout. Each step can be in different states such as ‘rest’, ‘active’, or ‘pending’, and the state is visually communicated through color. The geometry of the circle, including the gaps between the segments, is meticulously calculated based on the number of repetitions in the workout. The rotation effect and animations applied to the circle bring it to life, making it intuitive and responsive for the users.

The StepsCircle struct is a SwiftUI view. Here's what each part of the code does:

import Foundation
import SwiftUI

struct StepsCircle: View {

  let gapAngle: Double = 4
  let gap: Double = 0.04
  var steps: [WorkOutStep]
  var size: CGFloat = 150

This part of the code declares the StepsCircle struct and defines some properties. gapAngle and gap are used to define the size of the space between the workout segments. steps is an array of WorkOutStep objects, each of which represents a step in the workout. size represents the diameter of the circle.

var rotationAngle: Angle {
    // ...
}

var restItemPosModifier: Double {
    // ...
}

rotationAngle and restItemPosModifier are computed properties that define the rotation of the circle and the position of the rest indicators, respectively. The values are calculated based on the number of steps (reps.count) in the workout.

var body: some View {

    ZStack {
      ForEach(steps.enumerated().map({ $0 }), id: \.element.id) { index, rep in

The body property is where the actual view is constructed. ZStack is used to overlay several items, creating a layered visual effect. The ForEach loop iterates over the steps array. For each step, it creates a Circle view, applying different properties based on the step's properties.

 Circle()
       .trim(
            from: CGFloat(index) / CGFloat(steps.count) + CGFloat(gap / 2),
            to: CGFloat(index + 1) / CGFloat(steps.count) - CGFloat(gap / 2)
       )
       .stroke(
            step.getColor(),
            style: StrokeStyle(lineWidth: 5, lineCap: .round)
       )
       .rotationEffect(.degrees(360.0 / Double(steps.count) / 2))

Another circle is created to indicate rest periods. This circle is filled with a color that is fetched using the getRestColor function from the step object, and a rotation effect is applied so it is in the correct position. The circle's visibility and animations change based on the state of the step. The entire ZStack is rotated according to the rotationAngle and is constrained to a square frame with dimensions given by size.

This SwiftUI view demonstrates a powerful way of representing complex, dynamic data in a user-friendly, visual manner.

5: Conclusion

In conclusion, our journey into the creation of Tiempo has rekindled the excitement of native iOS development and unlocked the powerful capabilities of SwiftUI. The process is still ongoing, and I look forward to sharing more insights from our progress in future posts.

Each challenge, like crafting the StepsCircle component, has been an opportunity to expand our knowledge and skills. Stay tuned for more updates as we delve further into the fascinating world of WatchOS development with Tiempo.

Here’s to the adventure ahead!

Building Tiempo: A Journey into WatchOS

By

Ivan Koop

·

July 27th, 2023

Ivan is a full stack developer from Asunción, Paraguay

I am thrilled to share some details with you about Tiempo, a SwiftUI-based workout tracker for watchOS, co-created with Santiago Villalba, an ingenious designer. Santiago and I first crossed paths seven years ago when we collaborated on creating a banking frontend for Vision Banco, one of the most important banks in the country, and the website and mobile applications for one of the most popular news outlets in the country. Fast-forward to today, our paths have crossed again, this time on the development of Tiempo.

1: Seizing the Opportunity

A few weeks ago, Santiago got in touch with me and proposed working together on Tiempo. The timing was impeccable; I was in the process of transitioning jobs and had some extra time on my hands. After talking about the app and evaluating its potential, I was amazed by the design and concept. And so, my journey towards creating Tiempo began.

2: Revisiting the Basics

Even though I have significant experience in iOS development, my last native iOS project was two years ago. Hence, there was a need for me to revisit the platform, refresh my knowledge, and familiarize myself with the recent updates in SwiftUI.

3: First Hurdle: The StepsCircle Component

The initial challenge was to create a distinctive feature of Tiempo — the ‘StepsCircle’ component. This visual workout progression indicator was complex due to its multiple rounded corners, and the need to distinctly separate each step with a break indicator. Undeterred by the challenge, I embarked on crafting the first draft of this component.

4: Into the Code

The ‘StepsCircle’ SwiftUI view primarily renders a segmented circle, each segment representing a step in a workout. Each step can be in different states such as ‘rest’, ‘active’, or ‘pending’, and the state is visually communicated through color. The geometry of the circle, including the gaps between the segments, is meticulously calculated based on the number of repetitions in the workout. The rotation effect and animations applied to the circle bring it to life, making it intuitive and responsive for the users.

The StepsCircle struct is a SwiftUI view. Here's what each part of the code does:

import Foundation
import SwiftUI

struct StepsCircle: View {

  let gapAngle: Double = 4
  let gap: Double = 0.04
  var steps: [WorkOutStep]
  var size: CGFloat = 150

This part of the code declares the StepsCircle struct and defines some properties. gapAngle and gap are used to define the size of the space between the workout segments. steps is an array of WorkOutStep objects, each of which represents a step in the workout. size represents the diameter of the circle.

var rotationAngle: Angle {
    // ...
}

var restItemPosModifier: Double {
    // ...
}

rotationAngle and restItemPosModifier are computed properties that define the rotation of the circle and the position of the rest indicators, respectively. The values are calculated based on the number of steps (reps.count) in the workout.

var body: some View {

    ZStack {
      ForEach(steps.enumerated().map({ $0 }), id: \.element.id) { index, rep in

The body property is where the actual view is constructed. ZStack is used to overlay several items, creating a layered visual effect. The ForEach loop iterates over the steps array. For each step, it creates a Circle view, applying different properties based on the step's properties.

 Circle()
       .trim(
            from: CGFloat(index) / CGFloat(steps.count) + CGFloat(gap / 2),
            to: CGFloat(index + 1) / CGFloat(steps.count) - CGFloat(gap / 2)
       )
       .stroke(
            step.getColor(),
            style: StrokeStyle(lineWidth: 5, lineCap: .round)
       )
       .rotationEffect(.degrees(360.0 / Double(steps.count) / 2))

Another circle is created to indicate rest periods. This circle is filled with a color that is fetched using the getRestColor function from the step object, and a rotation effect is applied so it is in the correct position. The circle's visibility and animations change based on the state of the step. The entire ZStack is rotated according to the rotationAngle and is constrained to a square frame with dimensions given by size.

This SwiftUI view demonstrates a powerful way of representing complex, dynamic data in a user-friendly, visual manner.

5: Conclusion

In conclusion, our journey into the creation of Tiempo has rekindled the excitement of native iOS development and unlocked the powerful capabilities of SwiftUI. The process is still ongoing, and I look forward to sharing more insights from our progress in future posts.

Each challenge, like crafting the StepsCircle component, has been an opportunity to expand our knowledge and skills. Stay tuned for more updates as we delve further into the fascinating world of WatchOS development with Tiempo.

Here’s to the adventure ahead!