Adding Events to the Calendar in SwiftUI Using Default UI (Calendar Series Part III)

In this post, we learn how to use the default view to add an event to the calendar without creating a new one, if we don’t need a customized view. I mean this (sorry, today I’m lazy and don’t want to change my phone’s language to English).

I advise you to take a look at the first post of this series to understand the fundamentals (I won’t repeat them here).

The first step is to create a controller for the view:

class EventUIController: UIViewController, EKEventEditViewDelegate {
    let eventStore = EKEventStore()
    
    func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
        controller.dismiss(animated: true, completion: nil)
        parent?.dismiss(animated: true, completion: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        Task {
            let response = try await self.eventStore.requestFullAccessToEvents()
            if response {
                let eventController = EKEventEditViewController()
                eventController.eventStore = self.eventStore
                eventController.editViewDelegate = self
                eventController.modalPresentationStyle = .overCurrentContext
                eventController.modalTransitionStyle = .crossDissolve
                self.present(eventController, animated: true, completion: nil)
            }
        }
    }
}

In the viewDidLoad method, we check for authorizations, and if everything is okay, we create the controller, assign the eventStore, set the delegate to itself, and finally, the view is displayed. Note that in this function, we use Task to allow the call of an async action. In another function, eventEditViewController, the dismiss action is managed.

To allow this controller to be used in SwiftUI, we need to have a UIViewControllerRepresentable:

struct EventRepresentable: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> EventUIController {
        return EventUIController()
    }
    
    func updateUIViewController(_ uiViewController: EventUIController, context: Context) {
        // Only to be conform to the protocol
    }
}

Now we can call it from SwiftUI.

struct ContentView: View {
    @State var eventsManager = EventStoreManager()
    @State var isPresented = false
    
    var body: some View {
        NavigationStack {
            VStack {
                List(eventsManager.events, id:\.self) { event in
                    Text(event.title)
                }
            }
            .padding()
            .toolbar(content: {
                ToolbarItem(placement: .confirmationAction) {
                    Button("+") {
                        isPresented = true
                    }.font(.largeTitle)
                }
            })
            .sheet(isPresented: $isPresented, content: {
                EventRepresentable()
            })
        }.onAppear {
            Task {
                await loadEvents()
            }
        }.onChange(of: isPresented) {
            if !isPresented {
                Task {
                    await loadEvents()
                }
            }
        }
    }
    
    func loadEvents() async {
        do {
            try await eventsManager.setEventDate(date: Date())
        } catch {
            print("Error")
        }
    }
}

The code is 99% similar to that of the previous post; the only thing that changes is that now the sheet presents the default view instead of our custom view.

With this post, this series is complete (at least for now). Always remember to add permissions in the info.plist. Lastly, if you want to get the list of calendars in the calendar application, simply call the calendars function of the eventStore (this is necessary if you want to add an event to a particular calendar).

The code https://github.com/niqt/CalendarAppExample/tree/defaultEventView

To subscribe to my newsletter [https://nicoladefilippo.com/#mailinglist]

Note: English is not my native language, so I apologize for any errors. I use AI solely to generate the banner of the post; the content is human-generated.

share this post with friends

Picture of Nicola De filippo

Nicola De filippo

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve

Leave a comment

Your email address will not be published. Required fields are marked *

Who I am

I'm a software engineer who adds to the passion for technologies the wisdom and the experience without losing the wonder for the world. I love to create new projects and to help people and teams to improve.

Follow Me Here

Get The Latest Updates

Periodically receive my super contents on coding and programming

join the family;)

Recent Posts