I'm trying to use my CoreData entity 'Item' to show decorations on a calendar (using UIcalendarview in iOS16). I have my view called CalView calling the CalendarHelper struct (where the UICalendarView is coded and setup). It is showing decorations on every day currently, but I want to only show decorations on the days where there is a CoreData entry, and then enable navigation when you click on those days to the detail view. The problem is that I can't figure out how to get the CoreData entity into the CalendarHelper and UICalendarView to use it. It's currently giving me an error stating that I can't pass a FetchedResult in to an expected ObservedResult. But when I change them all to FetchedResult on that function, it gives me an error saying it's expecting a type of Item.
NOTE: I posted this over here as well but I think I messed up that post by deleting the original when I updated it. https://stackoverflow.com/questions/75138925/pass-coredata-into-uicalendarview-to-show-decorations-and-click-on-date-for-deta
CALVIEW:
struct CalView: View {
var body: some View {
ZStack {
VStack {
HStack {
CalendarHelper(interval: DateInterval(start: .distantPast, end: .distantFuture))
}
}
}
}
}
CALENDARHELPER:
struct CalendarHelper: UIViewRepresentable {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: SleepSort.default.descriptors,
animation: .default)
private var items: FetchedResults<Item>
let interval: DateInterval
func makeUIView(context: Context) -> UICalendarView {
let calView = UICalendarView()
calView.delegate = context.coordinator
calView.calendar = Calendar(identifier: .gregorian)
calView.availableDateRange = interval
calView.fontDesign = .rounded
let dateSelection = UICalendarSelectionSingleDate(delegate: context.coordinator)
calView.selectionBehavior = dateSelection
calView.wantsDateDecorations = true
return calView
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self, items: items)
}
func updateUIView(_ uiView: UICalendarView, context: Context) {
}
class Coordinator: NSObject, UICalendarViewDelegate, UICalendarSelectionSingleDateDelegate {
var parent: CalendarHelper
@ObservedObject var items: Item
init(parent: CalendarHelper, items: ObservedObject<Item>) {
self.parent = parent
self._items = items
}
@MainActor
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
let font = UIFont.systemFont(ofSize: 10)
let configuration = UIImage.SymbolConfiguration(font: font)
let image = UIImage(systemName: "star.fill", withConfiguration: configuration)?.withRenderingMode(.alwaysOriginal)
return .image(image)
}
func dateSelection(_ selection: UICalendarSelectionSingleDate,
didSelectDate dateComponents: DateComponents?) {
}
func dateSelection(_ selection: UICalendarSelectionSingleDate,
canSelectDate dateComponents: DateComponents?) -> Bool {
return true
}
}
}
Finally got around to messing with this and solved it this way:
@MainActor
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
let foundSleep = sleepItems.filter {$0.awakeDate?.startOfDay == dateComponents.date?.startOfDay}
if foundSleep.isEmpty { return nil }
let today = Calendar.current.startOfDay(for: Date())
// return UICalendarView.Decoration(__color: .red, size: .large)
return .customView {
let scoreCalView = UILabel()
scoreCalView.text = "🛏️"
return scoreCalView
}
}
extension Date {
var startOfDay: Date {
Calendar.current.startOfDay(for: self)
}
}