Kia ora koutou!
I've been working on showing some CoreData
using a UICalendarView
, but am having trouble getting my data model which is an @ObservedObject to update the decorations on the calendar. My file looks like this:
//
// CalendarView.swift
// mInr
//
// Created by Finn LeSueur on 2/03/23.
//
import SwiftUI
struct CalendarView: UIViewRepresentable {
let interval: DateInterval
@ObservedObject var dataModel = DataManager.shared
@AppStorage("lightAccentColour") var lightAccentColour: Color = .red
@AppStorage("darkAccentColour") var darkAccentColour: Color = .yellow
func makeUIView(context: Context) -> UICalendarView {
let view = UICalendarView()
view.delegate = context.coordinator
view.availableDateRange = interval
view.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return view
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func updateUIView(_ uiView: UICalendarView, context: Context) {
print("updateUIView called")
context.coordinator.antiCoagulantDoses = dataModel.antiCoagulantDoses
}
class Coordinator: NSObject, UICalendarViewDelegate, UICalendarSelectionSingleDateDelegate {
var parent: CalendarView
var antiCoagulantDoses: [AntiCoagulantDose]
init(parent: CalendarView) {
self.parent = parent
self.antiCoagulantDoses = self.parent.dataModel.antiCoagulantDoses
}
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
print("Running calendarView")
// Don't decorate future dates.
if dateComponents.date?.timeIntervalSinceNow.sign == FloatingPointSign.plus {
return nil
}
let antiCoagulantDose = antiCoagulantDoses.first(where: { $0.timestamp?.startOfDay == dateComponents.date?.startOfDay })
let font = UIFont.systemFont(ofSize: 12)
let configuration = UIImage.SymbolConfiguration(font: font)
if antiCoagulantDose == nil {
let image = UIImage(systemName: "exclamationmark.triangle", withConfiguration: configuration)?
.withRenderingMode(.alwaysOriginal)
.withTintColor(.red)
return .image(image)
}
return .customView {
let label = UILabel()
label.text = "\(antiCoagulantDose!.dose)g"
label.font = UIFont.systemFont(ofSize: UIFont.smallSystemFontSize)
return label
}
}
func dateSelection(_ selection: UICalendarSelectionSingleDate,
didSelectDate dateComponents: DateComponents?) {
}
func dateSelection(_ selection: UICalendarSelectionSingleDate,
canSelectDate dateComponents: DateComponents?) -> Bool {
return true
}
}
}
I've done a lot of searching about this, and I haven't made much progress. The @ObservedObject is working excellently for my other views (adding/deleting/updating/viewing/rendering a chart) – it's just this one!
I've set it up that I pass in the relevant data and update the coordinator
with fresh data when changes occur. I can definitely see changes occuring in my logs:
Updating anticoagulant doses.
Updating anticoagulant doses.
Start: 2022-12-20 08:48:27 +0000. End: 2023-03-31 08:48:27 +0000
Start: 2022-12-20 08:48:27 +0000. End: 2023-03-31 08:48:27 +0000
updateUIView called
updateUIView called
But it seems like calendarView
never gets called again – which is odd. If I change the rotation of the device or scroll back many months then it refreshes the decorations, but I can't seem to make it go manually.
Any advice would be much appreciated!