Pattern · Sheets and Alerts

New

Schedule Sheet SwiftUI Block

Pick when something happens: quick picks with real times, a calendar and time picker, repeat rules and Schedule.

The sheet for send later, a reminder or a booking. Quick picks resolve to real times and hide once they pass, Pick date and time opens a graphical calendar and a time picker in place, and Repeat covers Never, Daily, Weekdays, Weekly and custom days. Schedule names the chosen moment, runs your closure with a Schedule value and shows working, Scheduled and failed.

  • SwiftUI
  • iOS 17.0+
  • schedule-sheet
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • Later today, Tonight, Tomorrow morning and Next week with their times
  • Picks that have passed are hidden, even while the sheet is open
  • A graphical calendar and a time picker that open in place
  • Repeat: Never, Daily, Weekdays, Weekly or custom days of the week
  • Schedule returns a Schedule value and shows working, Scheduled and failed

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

Quick picks list the usual moments with the time each resolves to: Later today (three hours on, on the hour), Tonight (8 PM), Tomorrow morning (9 AM) and Next week (Monday 9 AM). A pick that has already passed is hidden, and the list keeps itself current while the sheet is open. Pick date and time opens a graphical calendar and a time picker in place, starting on tomorrow morning, and reads the chosen moment once it closes. Repeat offers Never, Daily, Weekdays, Weekly and Custom, where Custom shows the days of the week as toggles. A note names the time zone the times are in. Schedule waits in a quiet fill until a moment is picked, then carries it in its label ("Schedule for Sat 9:00 AM"), runs your closure with a Schedule value, shows progress, then "Scheduled", and closes the sheet; a thrown error shows its message under the button. A custom time that has passed says so and holds the button.

Notes

  • ScheduleSheet(actionTitle:initial:quickPicks:showsRepeat:onSchedule:onDone:) needs only onSchedule. It is the sheet's content: no scroll view, background or padding of its own, so present it in a .sheet (the large detent fits the open calendar) inside a ScrollView with 20 point margins, or place it inline.
  • actionTitle is the button's verb: "Schedule", "Send later", "Remind me".
  • ScheduleSheet.Schedule is the date of the first occurrence, a repeatRule and the timeZone it was picked in. Pass one as initial to edit it; its date opens selected in the calendar.
  • ScheduleSheet.Repeat is .never, .daily, .weekdays (Monday to Friday), .weekly (on the first date's weekday) or .custom(Set<Int>), weekdays numbered as Calendar does (1 is Sunday). Custom starts on the chosen date's weekday and always keeps one day on.
  • ScheduleSheet.QuickPick is .laterToday, .tonight, .tomorrowMorning or .nextWeek, each with a title, a symbol and date(after:calendar:), which returns nil once the moment has passed. Later today stops at 8 PM and Tonight an hour before. Pass quickPicks to choose and order them.
  • showsRepeat: false hides Repeat for one-off moments.
  • onSchedule(Schedule) is async throws. Throw CancellationError() to go back to rest quietly, or a LocalizedError to show its errorDescription. onDone runs a moment after "Scheduled"; without it the block dismisses the presenting sheet.
  • Dates follow the environment's calendar and timeZone, so the first weekday, the day names and the zone note match the person's settings.
  • Haptics: a selection tick on each pick, success when scheduled, an error when it fails.
  • VoiceOver reads each quick pick with its full date ("Tomorrow morning, Saturday, October 24 at 9:00 AM") and its selected state, Repeat as a menu with its value, and announces "Scheduled for ...". At accessibility sizes the symbol column steps aside and times drop under their titles.
  • Reduce Motion turns the calendar opening and state changes into short fades.
  • ScheduleSheetExample at the end of ScheduleSheet.swift is a message draft with the sheet open; Schedule waits a moment, then succeeds and shows the time under the draft. Pass wrapsInNavigationStack: false to push it in your own stack.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • The When and Repeat cards are color.surface at radius.lg, rows at least 52 points with separator hairlines inset to the text; groups sit 24 points apart (space.xl).
  • Rows use type.body in textPrimary with textSecondary symbols in a 24 point column; times are type.subhead in textSecondary with monospaced digits; the chevron is textTertiary. The selected pick's check is textPrimary.
  • The calendar and time picker are tinted textPrimary. Custom days are fill circles, textPrimary with surface letters when on.
  • The zone note is type.footnote in textSecondary.
  • Schedule is the only accent: accent with accentOn in type.headline at radius.md once a moment is picked, fill with textTertiary before. Errors are danger.
  • The calendar opens with motion.smooth; picks and states change with motion.snappy.