Apparently I like coding with the Course Deadline Counter app, now renamed to Course Deadlines app. I really, really should stop doing this, and focus on something else more acute and important — that’s why the call for help. I need to be stopped!
[I am aware of this being my own responsibility, thank you so much, so plz do not send halp.]
As a new feature, the app now has a timeline View:

Where you can view the deadlines of courses currently ongoing. The view does not show courses that haven’t yet begun or courses where the last deadline already passed.
For a student user, viewing all ongoing courses is more important, to be able to view the deadlines of the courses she is currently taking and how they relate between all the work she needs to do.
For a teacher, it is more relevant to show the deadlines to students in a single course. So limiting the view to just that one course is more important, using the drop down list at the top of the view.
Considering the needs and usage patterns of different groups of users is taught in our GUI design and programming course (Programming 4). So obviously I have to be able to do this stuff myself. Consider that done, at least in this case.
For drawing the course and course deadlines, I used the SwiftUI Canvas
and for the gradient background, MeshGradient
. I should still test the colors with both light and dark modes and find a usable combination of colors and an overlay to mute the colors when and if they are in disagreement with the text.
Drawing on the canvas is just simple drawing operations using the GraphicsContext
, plotting the text and symbols on calculated coordinates. For example, if there are no ongoing courses, the code draws only the text “No courses to show”, in the middle of the view:
Canvas { context, size in
var origin = CGPoint(x: 0, y: 0)
let text = Text("No courses to show").font(.title).bold()
let resolved = context.resolve(text)
if coursesToPlot.isEmpty {
// Draw info that there is no ongoing courses to show
var textSize = size
textSize = resolved.measure(in: size)
origin.x = size.width / 2 - textSize.width / 2
origin.y = size.height / 2 - textSize.height / 2
let rect = CGRect(origin: origin, size: textSize)
context.draw(resolved, in: rect)
} else {
// ...
With the Picker
, choosing to show all courses or just one, I searched for different solutions from the internet, and chose this one:
@State private var selectedCourse: Course? = nil
// ...
Picker("Show ongoing courses", selection: $selectedCourse) {
Text("All").tag(Optional<Course>(nil))
ForEach(deadlines.ongoing, id: \.self) { course in
Text(course.name).tag(Optional(course))
}
}
So there is the “show all” option where the course selection is then set to nil
. Otherwise, the selection is the selected course. This enables “no selection” or as it is handled in this case, “all are selected”.
I think I got to use the Swift if
expression (different from the usual if
conditional statement) here the first time, handling the above picker selection:
let coursesToPlot = if let selectedCourse {
[selectedCourse]
} else {
deadlines.ongoing.sorted(by: { $0.startDate < $1.startDate } )
}
In plain English: if the selectedCourse
is not null, let the coursesToPlot
be an array containing only the selectedCourse
. Otherwise, get all the ongoing courses from the deadlines
, sorted by starting date ascending, and let the coursesToPlot
be those courses.
The next time I touch this app should really be in the end of August or beginning of September, when I decide on the deadlines of the courses I am responsible for.
In the other news, I was today awarded as the Distinguished Teacher of the Year (again) by the study program student guild Blanko. Thank you! I am so humbled to receive this appreciation for the work we are doing here.