An Entry is a snapshot of data at a specific point in time.
It tells the widget what to display and when.
Every widget must have one.
A type conforming to TimelineEntry must provide:
1. date: Date ← only required property
Everything else is custom — you design the struct around whatever your widget needs.
struct SimpleEntry: TimelineEntry {
let date: Date
let title: String
let value: String
let subtitle: String
let icon: String
let accentColor: Color
let stateIndex: Int
let totalStates: Int
}
Provider builds Entry
→ System schedules it by date
→ EntryView reads it
→ Widget renders
Entry is a dumb data container — no logic, no functions, just properties.
makeEntry()Problem: placeholder(), snapshot(), and timeline() all need
to create a SimpleEntry — repeating the same code 3 times.
Solution: one helper function that builds it for all three.
private func makeEntry(from state: (String, String, String, String, Color), index: Int, date: Date) -> SimpleEntry {
SimpleEntry(
date: date,
title: state.0,
value: state.1,
subtitle: state.2,
icon: state.3,
accentColor: state.4,
stateIndex: index,
totalStates: FocusState.all.count
)
}
placeholder() — shown while widget loads for the first time
func placeholder(in context: Context) -> SimpleEntry {
makeEntry(from: FocusState.all[0], index: 0, date: Date())
}
Hardcoded → doesn't need to be dynamic
System shows a blurred version of whatever you return
snapshot() — shown in the widget gallery
func snapshot(for configuration: FocusWidgetIntent, in context: Context) async -> SimpleEntry {
let index = selectedIndex(for: configuration.session)
return makeEntry(from: FocusState.all[index], index: index, date: Date())
}
Reads the user's intent config → returns one entry instantly