DEV Community

Yugo
Yugo

Posted on

Building Calendar ToDo: Turning Calendar Events into a Done List with SwiftUI and EventKit

Sometimes I want to look back at my calendar and know not only what I planned, but what I actually did.

For example:

  • Did I finish my study session?
  • Did I actually go to the gym?
  • Which scheduled tasks did I complete this week?
  • What kind of rhythm do I have in my daily schedule?

Calendar apps are great for managing future plans.

But I felt they were not very good at showing whether those plans were actually completed.

So I started building an iOS app called Calendar ToDo.

It is an app that lets you mark calendar events as done and turn your calendar into a personal execution log.

App Store: Calendar ToDo

Calendar ToDo

What is Calendar ToDo?

Calendar ToDo is an iOS app that adds completion history to your existing calendar events.

Calendar ToDo - Design

The main idea is simple:

Your calendar already contains your plans.

Calendar ToDo helps you turn those plans into a done list.

The app can:

  • Show today’s calendar events
  • Mark events as done
  • Show today’s completion rate
  • Keep a timeline of completed events
  • Visualize your execution rhythm with a heatmap
  • Send a notification when an event ends
  • Let you mark an event as done from the notification
  • Sync completion history with iCloud / CloudKit

The important design decision is this:

Calendar ToDo does not edit your original calendar events.

It reads calendar data using EventKit, then stores completion records separately inside the app.

Why not just edit the calendar title?

One simple way to manage completed calendar events is to add a checkmark to the event title.

For example:

✅ Study SwiftUI
✅ Workout
✅ Write blog post
Enter fullscreen mode Exit fullscreen mode

This works for a small personal calendar, but it has some problems.

Editing calendar titles Calendar ToDo
Modifies the original calendar Keeps the calendar read-only
Mixes plans and results Stores completion history separately
Can be risky with shared calendars Does not touch shared calendar data
Can break with recurring events Tracks each occurrence separately

For work calendars, shared calendars, and recurring events, editing the original event title can feel unsafe.

I wanted Calendar ToDo to behave more like a layer on top of the calendar.

The calendar remains the source of planned events.

The app stores only the execution result.

Basic architecture

The app is built with SwiftUI, EventKit, Core Data, and CloudKit.

A simplified data flow looks like this:

SwiftUI
  ↓
EventKit
  ↓
Read calendar events
  ↓
Core Data / CloudKit
  ↓
Store completion history
  ↓
Notifications / Widgets / Reports
Enter fullscreen mode Exit fullscreen mode

EventKit is used to read calendar events.

Core Data and CloudKit are used to store and sync the app’s own completion records.

The key separation is:

  • Calendar events: fetched from EventKit
  • Completion records: stored by Calendar ToDo

This separation keeps the user’s calendar safe.

Reading events with EventKit

Fetching today’s events with EventKit looks roughly like this:

let eventStore = EKEventStore()

let calendars = eventStore.calendars(for: .event)

let predicate = eventStore.predicateForEvents(
    withStart: startOfDay,
    end: endOfDay,
    calendars: calendars
)

let events = eventStore.events(matching: predicate)
Enter fullscreen mode Exit fullscreen mode

The fetched EKEvent objects are displayed in SwiftUI.

But the app does not modify them directly.

That rule is important because the calendar may contain work events, shared events, recurring events, or events created by other apps.

Storing completion history separately

Instead of writing completion state back to EKEvent, the app creates its own completion record.

A simplified model looks like this:

struct CompletionRecord {
    let occurrenceKey: String
    let status: CompletionStatus
    let completedAt: Date
}

enum CompletionStatus {
    case done
    case skipped
    case partial
}
Enter fullscreen mode Exit fullscreen mode

The actual implementation has more fields, but the core idea is the same:

Do not change the calendar event.

Store the result separately.

This makes the app more privacy-friendly and safer to use with existing calendars.

The difficult part: matching events and records

At first, it seems easy to connect a completion record with an EventKit event.

You might think:

event.eventIdentifier
Enter fullscreen mode Exit fullscreen mode

But in practice, this is not enough.

Calendar data is more complicated than it looks.

Some examples:

  • Recurring events can share identifiers
  • A single occurrence can be moved
  • Events can be deleted and recreated
  • Start and end times can change
  • iCloud sync can create timing differences
  • The same event may appear on multiple devices

So the app needs a way to identify “this specific event on this specific day.”

A simplified key might look like this:

struct OccurrenceKey: Hashable {
    let calendarItemIdentifier: String
    let startDate: Date
    let endDate: Date
}
Enter fullscreen mode Exit fullscreen mode

This is one of the hardest parts of the app.

A calendar looks simple in the UI, but once you try to build reliable history on top of it, you need to think carefully about recurring events, time zones, updates, and sync behavior.

Completing events from notifications

Another important feature is the ability to record completion without opening the app.

When an event ends, Calendar ToDo can send a notification.

The notification has actions such as:

  • Done
  • Snooze for 1 hour

This matters because recording should be lightweight.

If users need to open the app every time, many records will be missed.

A small notification action can make the difference between:

“I planned this.”

and:

“I actually did this.”

Why build this as a calendar-based app?

Traditional to-do apps are great for managing tasks.

But I think calendars have one strong advantage:

Calendar events already contain time context.

A task says what you need to do.

A calendar event says when you planned to do it.

That time context is useful for reflection.

For example:

  • Which time of day do I complete the most tasks?
  • Are morning plans easier to finish?
  • Do I often leave evening events unfinished?
  • Which recurring events are stable?
  • Which scheduled activities tend to move or disappear?

This is why I think Calendar ToDo is not just a to-do app.

It is closer to an execution log built on top of your calendar.

Design principles

While building the app, I try to follow three principles.

1. Do not break the calendar

The app should not add, edit, or delete calendar events.

Many users already rely on their calendar for work, school, family, or shared schedules.

The app should respect that.

2. Make recording easy

The value of the app depends on whether users can keep recording.

So completion should be fast.

Notification actions, simple buttons, and lightweight states are more important than complex input forms.

3. Return value to the user

If the app stores completion history, that data should be useful to the user.

The goal is not just to collect records.

The goal is to help users see their rhythm, understand their schedule, and reflect with less effort.

Future ideas

I am currently exploring features such as:

  • Partial progress records
    • a little progress
    • halfway done
    • almost done
  • Reflection tags
  • Daily schedule load visualization
  • Schedule change detection
  • Weekly reports
  • Widgets
  • Better ways to summarize execution patterns

Not every scheduled event is simply “done” or “not done.”

Sometimes you made progress.

Sometimes the event was too large.

Sometimes the timing was wrong.

Sometimes the environment was not good.

I want Calendar ToDo to capture those states in a positive and lightweight way.

What I learned

The biggest thing I learned is that calendars are much more complex than they look.

Reading events is easy.

Building a reliable history layer on top of calendar events is much harder.

You need to think about:

  • Event identity
  • Recurring events
  • Time zones
  • Deleted events
  • Changed start times
  • Cloud sync
  • Notification timing
  • Privacy
  • User trust

But I still think this idea is worth exploring.

A calendar should not only be a place for future plans.

It can also become a record of what you actually did.

Conclusion

I built Calendar ToDo because I wanted to mark calendar events as done without modifying the original calendar.

The main idea is:

Keep the calendar read-only.

Store completion history separately.

Turn scheduled events into an execution log.

If you are building an iOS app with EventKit, SwiftUI, Core Data, or CloudKit, I hope this article gives you some useful ideas.

You can try Calendar ToDo here:

https://apps.apple.com/us/app/calendar-todo/id6756511434

Thanks for reading.

Top comments (0)