Greetings, traveler!
We continue our series about SwiftUI Week Calendar View. This is the second part. If you just want to check out the complete source code, here it is.
First, let’s create models for our task.
# Week Position
As we mentioned before, we will use a TabView
. Even though we have an infinite Week Calendar, we will use only three tabs. We will update them in time to represent three generated weeks. So, there will be three positions for every week: left, middle, and right. Let’s create an appropriate model, then.
public enum WeekPosition {
case left
case middle
case right
}
The difference between these weeks is simple. The first day of each week is a certain distance from the other two. We will start counting from the middle one. So, we can add a rawValue
for our enum cases.
public enum WeekPosition: Int {
case left = -7
case middle = 0
case right = 7
}
# Week
Now, we can create a Week
model. This model has two variables. The first one will represent a date, from which we will start to calculate. The second one will hold all weekdays as an array of Dates.
public struct Week {
public let dates: [Date]
public let referenceDate: Date
public init(dates: [Date], referenceDate: Date) {
self.dates = dates
self.referenceDate = referenceDate
}
}
To generate weeks for every position, we must be able to compose this array based on the WeekPosition’s rawValue
. Since we have a reference date, we can calculate the same day at the desired position. After that, we can calculate the start of the week and add another six days to our array.
# Same day in another week and Week generation
We can use the Foundation’s Calendar
to calculate the same day in another week. Since we will use it more than once, let’s create an extension for Date
. It will be safer to get the date and calculate the start of the day. We can do it with Calendar
, too.
extension Date {
var startOfTheDay: Date {
Calendar.current.startOfDay(for: self)
}
func sameDay(at position: WeekPosition) -> Date {
(Calendar.current.date(byAdding: .day, value: position.rawValue, to: self) ?? .now).startOfTheDay
}
}
We can use it in our function now. For convenience, we will place this function in our Week
model.
public struct Week {
public let dates: [Date]
public let referenceDate: Date
public init(dates: [Date], referenceDate: Date) {
self.dates = dates
self.referenceDate = referenceDate
}
public static func week(
for date: Date,
at position: WeekPosition
) -> Self {
let date = date.sameDay(at: position)
let startOfWeek = Calendar.current.date(from: Calendar.current.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date))
let weekDates = (0...6).compactMap {
Calendar.current.date(
byAdding: .day,
value: $0,
to: startOfWeek ?? .now
)
}
return Week(
dates: weekDates,
referenceDate: date
)
}
}
Conclusion
Our models are almost ready. We will add some additional functionality when it is needed. Meanwhile, I invite you to the third part of our Week Calendar series.
If you enjoyed this article, please feel free to follow me on my social media: