stanfordspezi/spezischeduler
This source file is part of the Stanford Spezi open-source project.
Overview
The Scheduler module helps you create and manage recurring tasks that users need to complete, such as daily questionnaires, medication reminders, or health measurements. It can also be used for internal application logic and automated processes.
Key Concepts
- Task: A repeatable action users should perform (e.g., "Take daily medication")
- Schedule: Defines when and how often a task repeats (e.g., daily, weekly, monthly)
- Event: A single instance when a task should be completed (e.g., "Take medication today at 8 AM")
The module automatically handles task persistence and versioning. When you update a task's schedule or details, it creates a new version without affecting previously completed events. This ensures your historical data remains intact.
You create tasks using createOrUpdateTask(), and the module takes care of generating the appropriate events based on your schedule.
Setup
You need to add the Spezi Scheduler Swift package to your app in Xcode or Swift package.
[!IMPORTANT] If your application is not yet configured to use Spezi, follow the Spezi setup article to set up the core Spezi infrastructure.
Below is an example on how to create your own Module to manage your tasks and ensure they are always up to date.
import Spezi
import SpeziScheduler
class MySchedulerModule: Module {
@Dependency(Scheduler.self)
private var scheduler
init() {}
func configure() {
do {
try scheduler.createOrUpdateTask(
id: "my-daily-task",
title: "Daily Questionnaire",
instructions: "Please fill out the Questionnaire every day.",
category: .questionnaire,
schedule: .daily(hour: 9, minute: 0, startingAt: .today)
)
} catch {
// handle error (e.g., visualize in your UI)
}
}
}Creating and Managing Tasks
Then, configure the Scheduler module and your custom module in your SpeziAppDelegate:
class ExampleAppDelegate: SpeziAppDelegate {
override var configuration: Configuration {
Configuration(standard: ExampleStandard()) {
MySchedulerModule()
Scheduler()
}
}
}The Scheduler supports various scheduling patterns using the Schedule type.
Task Categories and Metadata
Tasks support categories, tags, and custom metadata. To attach custom metadata, first extend Task.Context using the @Property macro, then set it in the with closure:
extension Task.Context {
@Property var questionnaireIdentifier: String?
}
try scheduler.createOrUpdateTask(
id: "my-questionnaire",
title: "Daily Questionnaire",
instructions: "Please fill out the questionnaire.",
category: .questionnaire,
schedule: .daily(hour: 9, minute: 0, startingAt: .today),
tags: ["questionnaire", "daily"]
) { context in
context.questionnaireIdentifier = "phq-9"
}Notifications
To send a notification for each scheduled event, pass scheduleNotifications: true to createOrUpdateTask. By default the notification fires at the start of the event; use notificationTime to specify a different time of day:
try scheduler.createOrUpdateTask(
id: "my-daily-task",
title: "Daily Questionnaire",
instructions: "Please fill out the Questionnaire every day.",
category: .questionnaire,
schedule: .daily(hour: 9, minute: 0, startingAt: .today),
scheduleNotifications: true,
notificationTime: NotificationTime(hour: 8, minute: 30)
)For advanced notification features, see the SchedulerNotifications documentation.
Querying Tasks and Events
You can query tasks and events using various methods:
// Query events for today
let todayEvents = try scheduler.queryEvents(for: Calendar.current.rangeOfDay(for: .now))
// Query events for a specific task today
let taskEvents = try scheduler.queryEvents(forTaskWithId: "my-daily-task", in: Calendar.current.rangeOfDay(for: .now))
// Query tasks for the next 7 days
let tasks = try scheduler.queryTasks(for: .today..<.nextWeek)User Interface Components
The SpeziSchedulerUI module provides ready-to-use SwiftUI components for displaying scheduled tasks and events in your app.
<table> <tr> <td>
[Schedule Today] [Schedule Today]
Use EventScheduleList and InstructionsTile to present the user's schedule
</td> <td>
[Schedule Today Center] [Schedule Today Center]
A schedule view with center aligned InstructionsTile
</td> <td>
[Schedule Tomorrow] [Schedule Tomorrow]
Use EventScheduleList to display schedules for arbitrary dates
</td> </tr> </table>
Displaying Events in Lists
Use EventScheduleList to display all events for a specific day. It automatically handles empty states and provides a clean, organized view of scheduled tasks:
import SpeziSchedulerUI
struct ScheduleView: View {
var body: some View {
NavigationStack {
EventScheduleList { event in
InstructionsTile(event) {
event.complete()
}
}
.navigationTitle("Today's Schedule")
}
}
}You can also display events for different dates:
EventScheduleList(date: .tomorrow) { event in
InstructionsTile(event) {
event.complete()
}
}Task Cards with InstructionsTile
The InstructionsTile component provides a polished card interface for individual tasks:
// Basic tile with completion button
InstructionsTile(event) {
event.complete()
}
// Tile with additional information sheet
InstructionsTile(event) {
event.complete()
} more: {
VStack(alignment: .leading, spacing: 16) {
Text("Detailed Instructions")
.font(.headline)
Text("Step-by-step guide on how to complete this task...")
}
.padding()
}
// Centered alignment for featured tasks
InstructionsTile(event, alignment: .center) {
event.complete()
}Customizing Task Appearance
You can customize how different task categories appear in the UI using the taskCategoryAppearance modifier:
EventScheduleList { event in
InstructionsTile(event) {
event.complete()
}
}
.taskCategoryAppearance(for: .questionnaire, label: "Survey", image: .system("list.clipboard.fill"))
.taskCategoryAppearance(for: .medication, label: "Medication", image: .system("pills.fill"))
.taskCategoryAppearance(for: .measurement, label: "Measurement", image: .system("ruler.fill"))The Spezi Template Application
The Spezi Template Application provides a great starting point and example using the Spezi Scheduler module.
Contributing
Contributions to this project are welcome. Please make sure to read the contribution guidelines and the contributor covenant code of conduct first.
License
This project is licensed under the MIT License. See Licenses for more information.
[Spezi Footer] [Spezi Footer]
Package Metadata
Repository: stanfordspezi/spezischeduler
Default branch: main
README: README.md