Settings panes
Your droplet's own page inside Droppy's Settings.
A droplet with anything to configure provides a settings pane. It is rendered on the droplet's page in Droppy's Settings window, in the same content column every native page uses.
Build it from the SDK's settings components and it matches the rest of the app — including after Droppy's styling moves, because those components are kept in step with the host.
Providing one
extension WorldClockDroplet: SettingsPaneProviding {
public func makeSettingsPane(context: SettingsPaneContext) -> AnyView {
AnyView(WorldClockSettings(droplet: self))
}
public var settingsSearchEntries: [SettingsSearchEntry] {
[SettingsSearchEntry(title: "Show seconds", keywords: ["time", "clock"])]
}
}settingsSearchEntries puts your rows in Droppy's Settings search, so a user who types "seconds" lands on your pane instead of failing to find it.
The components
VStack(alignment: .leading, spacing: DroppySpacing.lg) {
DropletSettingsCard {
DropletToggleRow(
title: "Show seconds",
subtitle: "Ticks the shelf widget every second instead of every minute.",
isOn: droplet.showsSecondsBinding
)
DropletSettingsDivider()
DropletSliderRow(
title: "Refresh",
value: "\(Int(interval))s",
binding: $interval,
range: 1...60
)
DropletSettingsDivider()
DropletControlRow(title: "Clocks") {
DropletValuePill(text: "\(droplet.clockCount)")
}
}
}| Component | For |
|---|---|
DropletSettingsCard | The card every group of rows sits in |
DropletControlRow | A title with a trailing control |
DropletToggleRow | A switch |
DropletSliderRow | A value with a slider |
DropletStackedRow | A title over full-width content |
DropletGroupedPickerRow | A segmented picker inside a card |
DropletSettingsDivider | The hairline between rows |
DropletValuePill | A read-only value |
Sentence case
Section headers and row titles are sentence case: only the first word is capitalised, and proper nouns keep their capitals wherever they appear. Droppy enforces this on its own pages, and a droplet in Title Case is visibly a guest.
Picker rows sit in a group
DropletGroupedPickerRow takes a SettingsGroupPosition describing where it sits in its card — .only, .top, .middle, or .bottom. Pass the right one: the selected segment's highlight rounds its outer corners to match, and a .bottom picker with a divider and another row beneath it renders a curve against a straight edge.
Storage
Rows bind to DropletPreferencesService, which namespaces every key to your droplet:
var showsSecondsBinding: Binding<Bool> {
Binding(
get: { self.host?.preferences.value(forKey: "showsSeconds", default: true) ?? true },
set: { self.host?.preferences.setValue($0, forKey: "showsSeconds") }
)
}