@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +328 -329
- package/package.json +2 -2
- package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
- package/pipeline/scripts/_notices.mjs +12 -1
- package/pipeline/scripts/gen-skills-index.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +106 -106
- package/pipeline/skills/shared/README.md +71 -71
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
- package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/council/SKILL.md +1 -0
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
- package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
- package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
- package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
- package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
- package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
- package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
- package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
- package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
- package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
- package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,591 +1,541 @@
|
|
|
1
|
-
# AlarmKit
|
|
1
|
+
# AlarmKit patterns
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Longer, end-to-end examples. Everything here targets iOS 26 and iPadOS 26 with
|
|
4
|
+
Swift 6.3. Code that uses the stopButton-free
|
|
5
|
+
`AlarmPresentation.Alert(title:secondaryButton:secondaryButtonBehavior:)`
|
|
6
|
+
initializer is marked `@available(iOS 26.1, *)`.
|
|
7
7
|
|
|
8
8
|
## Contents
|
|
9
|
-
- Complete Alarm Scheduling Flow
|
|
10
|
-
- Complete Countdown Timer Flow
|
|
11
|
-
- Authorization Manager
|
|
12
|
-
- State Observation with Async Sequences
|
|
13
|
-
- Live Activity Widget Extension for Alarms
|
|
14
|
-
- Recurring Alarm Patterns
|
|
15
|
-
- Snooze and Dismiss Handling
|
|
16
|
-
- Info.plist Configuration
|
|
17
|
-
- Error Handling
|
|
18
|
-
- Apple Documentation Links
|
|
19
9
|
|
|
20
|
-
|
|
10
|
+
- [Full alarm flow with intents](#full-alarm-flow-with-intents)
|
|
11
|
+
- [Full timer flow](#full-timer-flow)
|
|
12
|
+
- [Authorization manager](#authorization-manager)
|
|
13
|
+
- [State store with async sequences](#state-store-with-async-sequences)
|
|
14
|
+
- [Widget extension for countdown and paused UI](#widget-extension-for-countdown-and-paused-ui)
|
|
15
|
+
- [Recurrence](#recurrence)
|
|
16
|
+
- [Snooze and custom secondary actions](#snooze-and-custom-secondary-actions)
|
|
17
|
+
- [Info.plist](#infoplist)
|
|
18
|
+
- [Error handling](#error-handling)
|
|
19
|
+
- [Apple documentation](#apple-documentation)
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
## Full alarm flow with intents
|
|
22
|
+
|
|
23
|
+
Stop and snooze intents are `LiveActivityIntent` types from AppIntents. Each one
|
|
24
|
+
receives the alarm ID as a string parameter and calls back into `AlarmManager`.
|
|
23
25
|
|
|
24
26
|
```swift
|
|
25
27
|
import AlarmKit
|
|
26
28
|
import AppIntents
|
|
29
|
+
import SwiftUI
|
|
30
|
+
|
|
31
|
+
struct DismissMedicineAlarm: LiveActivityIntent {
|
|
32
|
+
static let title: LocalizedStringResource = "Dismiss medicine reminder"
|
|
33
|
+
|
|
34
|
+
@Parameter(title: "Alarm ID")
|
|
35
|
+
var alarmID: String
|
|
27
36
|
|
|
28
|
-
struct StopAlarmIntent: LiveActivityIntent {
|
|
29
|
-
static var title: LocalizedStringResource = "Stop Alarm"
|
|
30
|
-
@Parameter(title: "Alarm ID") var alarmID: String
|
|
31
37
|
init() {}
|
|
32
|
-
init(alarmID:
|
|
38
|
+
init(alarmID: UUID) { self.alarmID = alarmID.uuidString }
|
|
39
|
+
|
|
33
40
|
func perform() async throws -> some IntentResult {
|
|
34
|
-
|
|
41
|
+
if let id = UUID(uuidString: alarmID) {
|
|
42
|
+
try AlarmManager.shared.stop(id: id)
|
|
43
|
+
}
|
|
35
44
|
return .result()
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
struct
|
|
40
|
-
static
|
|
41
|
-
|
|
48
|
+
struct RemindAgainIntent: LiveActivityIntent {
|
|
49
|
+
static let title: LocalizedStringResource = "Remind again"
|
|
50
|
+
|
|
51
|
+
@Parameter(title: "Alarm ID")
|
|
52
|
+
var alarmID: String
|
|
53
|
+
|
|
42
54
|
init() {}
|
|
43
|
-
init(alarmID:
|
|
55
|
+
init(alarmID: UUID) { self.alarmID = alarmID.uuidString }
|
|
56
|
+
|
|
44
57
|
func perform() async throws -> some IntentResult {
|
|
45
|
-
|
|
58
|
+
if let id = UUID(uuidString: alarmID) {
|
|
59
|
+
try AlarmManager.shared.countdown(id: id)
|
|
60
|
+
}
|
|
46
61
|
return .result()
|
|
47
62
|
}
|
|
48
63
|
}
|
|
49
64
|
|
|
50
|
-
struct
|
|
51
|
-
var
|
|
65
|
+
struct DoseInfo: AlarmMetadata {
|
|
66
|
+
var medicine: String
|
|
67
|
+
var doseLabel: String
|
|
52
68
|
}
|
|
53
69
|
|
|
70
|
+
enum DoseAlarmError: Error {
|
|
71
|
+
case accessNotGranted
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@available(iOS 26.1, *)
|
|
54
75
|
@MainActor
|
|
55
|
-
func
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
76
|
+
func scheduleDoseReminder(hour: Int, minute: Int, medicine: String) async throws -> Alarm {
|
|
77
|
+
let center = AlarmManager.shared
|
|
78
|
+
guard try await center.requestAuthorization() == .authorized else {
|
|
79
|
+
throw DoseAlarmError.accessNotGranted
|
|
80
|
+
}
|
|
61
81
|
|
|
62
82
|
let alert = AlarmPresentation.Alert(
|
|
63
|
-
title: LocalizedStringResource(stringLiteral:
|
|
64
|
-
secondaryButton: AlarmButton(
|
|
65
|
-
text: "Snooze", textColor: .white, systemImageName: "bell.slash"
|
|
66
|
-
),
|
|
83
|
+
title: LocalizedStringResource(stringLiteral: "Time for \(medicine)"),
|
|
84
|
+
secondaryButton: AlarmButton(text: "In 5 min", textColor: .white, systemImageName: "clock.arrow.circlepath"),
|
|
67
85
|
secondaryButtonBehavior: .countdown
|
|
68
86
|
)
|
|
69
|
-
let presentation = AlarmPresentation(alert: alert)
|
|
70
87
|
let attributes = AlarmAttributes(
|
|
71
|
-
presentation:
|
|
72
|
-
metadata:
|
|
88
|
+
presentation: AlarmPresentation(alert: alert),
|
|
89
|
+
metadata: DoseInfo(medicine: medicine, doseLabel: "1 tablet"),
|
|
73
90
|
tintColor: .indigo
|
|
74
91
|
)
|
|
75
92
|
|
|
93
|
+
let doseTime = Alarm.Schedule.Relative.Time(hour: hour, minute: minute)
|
|
76
94
|
let id = UUID()
|
|
77
|
-
let snooze = Alarm.CountdownDuration(preAlert: nil, postAlert: 300)
|
|
78
95
|
let config = AlarmManager.AlarmConfiguration(
|
|
79
|
-
countdownDuration:
|
|
80
|
-
schedule: .relative(.init(
|
|
81
|
-
time: .init(hour: hour, minute: minute), repeats: .never
|
|
82
|
-
)),
|
|
96
|
+
countdownDuration: Alarm.CountdownDuration(preAlert: nil, postAlert: 5 * 60),
|
|
97
|
+
schedule: .relative(.init(time: doseTime)),
|
|
83
98
|
attributes: attributes,
|
|
84
|
-
stopIntent:
|
|
85
|
-
secondaryIntent:
|
|
99
|
+
stopIntent: DismissMedicineAlarm(alarmID: id),
|
|
100
|
+
secondaryIntent: RemindAgainIntent(alarmID: id),
|
|
86
101
|
sound: .default
|
|
87
102
|
)
|
|
88
|
-
return try await
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
enum AlarmSchedulingError: Error {
|
|
92
|
-
case notAuthorized
|
|
103
|
+
return try await center.schedule(id: id, configuration: config)
|
|
93
104
|
}
|
|
94
105
|
```
|
|
95
106
|
|
|
96
|
-
|
|
107
|
+
Generate the `UUID` first. Both intents need to carry the same ID string that
|
|
108
|
+
`schedule(id:configuration:)` will use, so the ID must exist before the intents
|
|
109
|
+
are built. Remember the intents themselves are optional; this example passes
|
|
110
|
+
them only to show the wiring. Declare the intent's `title` with `static let`:
|
|
111
|
+
in the Swift 6 language mode a `static var` is rejected as unprotected global
|
|
112
|
+
mutable state.
|
|
97
113
|
|
|
98
|
-
|
|
114
|
+
## Full timer flow
|
|
99
115
|
|
|
100
116
|
```swift
|
|
101
117
|
import AlarmKit
|
|
102
|
-
import
|
|
103
|
-
|
|
104
|
-
struct StopTimerIntent: LiveActivityIntent {
|
|
105
|
-
static var title: LocalizedStringResource = "Stop Timer"
|
|
106
|
-
@Parameter(title: "Timer ID") var timerID: String
|
|
107
|
-
init() {}
|
|
108
|
-
init(timerID: String) { self.timerID = timerID }
|
|
109
|
-
func perform() async throws -> some IntentResult {
|
|
110
|
-
try AlarmManager.shared.stop(id: UUID(uuidString: timerID)!)
|
|
111
|
-
return .result()
|
|
112
|
-
}
|
|
113
|
-
}
|
|
118
|
+
import SwiftUI
|
|
114
119
|
|
|
115
|
-
struct
|
|
116
|
-
var
|
|
117
|
-
var
|
|
120
|
+
struct BakeStep: AlarmMetadata {
|
|
121
|
+
var loafName: String
|
|
122
|
+
var stage: String
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
@available(iOS 26.1, *)
|
|
120
126
|
@MainActor
|
|
121
|
-
func
|
|
122
|
-
durationSeconds: TimeInterval, recipeName: String, step: String
|
|
123
|
-
) async throws -> Alarm {
|
|
124
|
-
let manager = AlarmManager.shared
|
|
125
|
-
let authState = try await manager.requestAuthorization()
|
|
126
|
-
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
127
|
-
|
|
128
|
-
let alert = AlarmPresentation.Alert(
|
|
129
|
-
title: LocalizedStringResource(stringLiteral: "\(recipeName): \(step)"),
|
|
130
|
-
secondaryButton: nil, secondaryButtonBehavior: nil
|
|
131
|
-
)
|
|
132
|
-
let countdown = AlarmPresentation.Countdown(
|
|
133
|
-
title: LocalizedStringResource(stringLiteral: recipeName),
|
|
134
|
-
pauseButton: AlarmButton(
|
|
135
|
-
text: "Pause", textColor: .orange, systemImageName: "pause.fill"
|
|
136
|
-
)
|
|
137
|
-
)
|
|
138
|
-
let paused = AlarmPresentation.Paused(
|
|
139
|
-
title: "Paused",
|
|
140
|
-
resumeButton: AlarmButton(
|
|
141
|
-
text: "Resume", textColor: .green, systemImageName: "play.fill"
|
|
142
|
-
)
|
|
143
|
-
)
|
|
127
|
+
func startProofingTimer(minutes: Double) async throws -> Alarm {
|
|
144
128
|
let presentation = AlarmPresentation(
|
|
145
|
-
alert:
|
|
129
|
+
alert: AlarmPresentation.Alert(title: "Dough has proofed", secondaryButton: nil, secondaryButtonBehavior: nil),
|
|
130
|
+
countdown: AlarmPresentation.Countdown(
|
|
131
|
+
title: "Proofing",
|
|
132
|
+
pauseButton: AlarmButton(text: "Pause", textColor: .brown, systemImageName: "pause.fill")
|
|
133
|
+
),
|
|
134
|
+
paused: AlarmPresentation.Paused(
|
|
135
|
+
title: "Proofing paused",
|
|
136
|
+
resumeButton: AlarmButton(text: "Resume", textColor: .brown, systemImageName: "play.fill")
|
|
137
|
+
)
|
|
146
138
|
)
|
|
147
139
|
let attributes = AlarmAttributes(
|
|
148
140
|
presentation: presentation,
|
|
149
|
-
metadata:
|
|
141
|
+
metadata: BakeStep(loafName: "Rye", stage: "Second rise"),
|
|
150
142
|
tintColor: .orange
|
|
151
143
|
)
|
|
152
|
-
|
|
153
|
-
let id = UUID()
|
|
154
144
|
let config = AlarmManager.AlarmConfiguration.timer(
|
|
155
|
-
duration:
|
|
145
|
+
duration: minutes * 60,
|
|
156
146
|
attributes: attributes,
|
|
157
|
-
stopIntent:
|
|
147
|
+
stopIntent: nil,
|
|
158
148
|
sound: .default
|
|
159
149
|
)
|
|
160
|
-
|
|
150
|
+
let center = AlarmManager.shared
|
|
151
|
+
return try await center.schedule(id: UUID(), configuration: config)
|
|
161
152
|
}
|
|
162
153
|
```
|
|
163
154
|
|
|
164
|
-
## Authorization
|
|
165
|
-
|
|
166
|
-
Observable pattern for centralized authorization management.
|
|
155
|
+
## Authorization manager
|
|
167
156
|
|
|
168
157
|
```swift
|
|
169
158
|
import AlarmKit
|
|
170
159
|
import Observation
|
|
160
|
+
import SwiftUI
|
|
171
161
|
|
|
172
162
|
@Observable
|
|
173
163
|
@MainActor
|
|
174
|
-
final class
|
|
175
|
-
private let
|
|
176
|
-
private(set) var
|
|
177
|
-
private(set) var authState: AlarmManager.AuthorizationState = .notDetermined
|
|
164
|
+
final class AlarmAccess {
|
|
165
|
+
private let center = AlarmManager.shared
|
|
166
|
+
private(set) var state: AlarmManager.AuthorizationState
|
|
178
167
|
|
|
179
168
|
init() {
|
|
180
|
-
|
|
181
|
-
isAuthorized = authState == .authorized
|
|
169
|
+
state = AlarmManager.shared.authorizationState
|
|
182
170
|
}
|
|
183
171
|
|
|
184
|
-
func
|
|
185
|
-
guard
|
|
186
|
-
let
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return isAuthorized
|
|
172
|
+
func askIfNeeded() async {
|
|
173
|
+
guard state == .notDetermined else { return }
|
|
174
|
+
if let answer = try? await AlarmManager.shared.requestAuthorization() {
|
|
175
|
+
state = answer
|
|
176
|
+
}
|
|
190
177
|
}
|
|
191
178
|
|
|
192
|
-
func
|
|
193
|
-
for await
|
|
194
|
-
|
|
195
|
-
isAuthorized = state == .authorized
|
|
179
|
+
func follow() async {
|
|
180
|
+
for await next in center.authorizationUpdates {
|
|
181
|
+
state = next
|
|
196
182
|
}
|
|
197
183
|
}
|
|
198
184
|
}
|
|
199
185
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
@State private var authManager = AlarmAuthorizationManager()
|
|
186
|
+
struct AlarmAccessView: View {
|
|
187
|
+
@State private var access = AlarmAccess()
|
|
203
188
|
|
|
204
189
|
var body: some View {
|
|
205
190
|
Group {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
191
|
+
switch access.state {
|
|
192
|
+
case .authorized:
|
|
193
|
+
Text("Alarms are on")
|
|
194
|
+
case .denied:
|
|
209
195
|
ContentUnavailableView(
|
|
210
|
-
"Alarms
|
|
211
|
-
|
|
196
|
+
"Alarms are off",
|
|
197
|
+
systemImage: "alarm",
|
|
198
|
+
description: Text("Turn them on in Settings > this app > Alarms & Timers.")
|
|
212
199
|
)
|
|
213
|
-
|
|
214
|
-
Button("
|
|
215
|
-
Task {
|
|
200
|
+
default:
|
|
201
|
+
Button("Allow alarms") {
|
|
202
|
+
Task { await access.askIfNeeded() }
|
|
216
203
|
}
|
|
217
204
|
}
|
|
218
205
|
}
|
|
219
|
-
.task { await
|
|
206
|
+
.task { await access.follow() }
|
|
220
207
|
}
|
|
221
208
|
}
|
|
222
209
|
```
|
|
223
210
|
|
|
224
|
-
|
|
211
|
+
The path users follow to recover from a denial is Settings, then the app's own
|
|
212
|
+
page, then Alarms & Timers.
|
|
225
213
|
|
|
226
|
-
|
|
214
|
+
`askIfNeeded()` reads `AlarmManager.shared` at the call instead of the stored
|
|
215
|
+
`center`. `AlarmManager` is a non-`Sendable` class and `requestAuthorization()`
|
|
216
|
+
is a nonisolated `async` method, so calling it on a property of a main-actor
|
|
217
|
+
object sends main-actor state off the actor, and Swift 6 rejects that in its
|
|
218
|
+
region-isolation pass ("sending 'self.center' risks causing data races").
|
|
219
|
+
|
|
220
|
+
## State store with async sequences
|
|
227
221
|
|
|
228
222
|
```swift
|
|
229
223
|
import AlarmKit
|
|
230
224
|
import Observation
|
|
225
|
+
import SwiftUI
|
|
231
226
|
|
|
232
227
|
@Observable
|
|
233
228
|
@MainActor
|
|
234
|
-
final class
|
|
235
|
-
private let
|
|
236
|
-
private(set) var
|
|
229
|
+
final class AlarmBoard {
|
|
230
|
+
private let center = AlarmManager.shared
|
|
231
|
+
private(set) var items: [Alarm] = []
|
|
237
232
|
|
|
238
|
-
func
|
|
239
|
-
|
|
233
|
+
func reload() throws {
|
|
234
|
+
items = try center.alarms
|
|
240
235
|
}
|
|
241
236
|
|
|
242
|
-
func
|
|
243
|
-
for await
|
|
244
|
-
|
|
237
|
+
func observe() async {
|
|
238
|
+
for await snapshot in center.alarmUpdates {
|
|
239
|
+
items = snapshot
|
|
245
240
|
}
|
|
246
241
|
}
|
|
247
242
|
|
|
248
|
-
func
|
|
249
|
-
|
|
243
|
+
func item(for id: Alarm.ID) -> Alarm? {
|
|
244
|
+
items.first { $0.id == id }
|
|
245
|
+
}
|
|
250
246
|
|
|
251
|
-
func
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
func
|
|
247
|
+
func items(in state: Alarm.State) -> [Alarm] {
|
|
248
|
+
items.filter { $0.state == state }
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
func cancel(_ alarmID: Alarm.ID) throws { try center.cancel(id: alarmID) }
|
|
252
|
+
func pause(_ alarmID: Alarm.ID) throws { try center.pause(id: alarmID) }
|
|
253
|
+
func resume(_ alarmID: Alarm.ID) throws { try center.resume(id: alarmID) }
|
|
254
|
+
func stop(_ alarmID: Alarm.ID) throws { try center.stop(id: alarmID) }
|
|
255
|
+
func snooze(_ alarmID: Alarm.ID) throws { try center.countdown(id: alarmID) }
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
@State private var store = AlarmStore()
|
|
258
|
+
struct AlarmBoardView: View {
|
|
259
|
+
@State private var board = AlarmBoard()
|
|
261
260
|
|
|
262
261
|
var body: some View {
|
|
263
|
-
List(
|
|
262
|
+
List(board.items) { alarm in
|
|
264
263
|
HStack {
|
|
265
|
-
Text(alarm.id.uuidString.prefix(
|
|
264
|
+
Text(alarm.id.uuidString.prefix(6))
|
|
266
265
|
Spacer()
|
|
267
266
|
switch alarm.state {
|
|
268
267
|
case .scheduled:
|
|
269
|
-
Button("Cancel"
|
|
268
|
+
Button("Cancel") { try? board.cancel(alarm.id) }
|
|
270
269
|
case .countdown:
|
|
271
|
-
Button("Pause") { try?
|
|
270
|
+
Button("Pause") { try? board.pause(alarm.id) }
|
|
272
271
|
case .paused:
|
|
273
|
-
Button("Resume") { try?
|
|
272
|
+
Button("Resume") { try? board.resume(alarm.id) }
|
|
274
273
|
case .alerting:
|
|
275
|
-
Button("Stop") { try?
|
|
274
|
+
Button("Stop") { try? board.stop(alarm.id) }
|
|
276
275
|
@unknown default:
|
|
277
276
|
EmptyView()
|
|
278
277
|
}
|
|
279
278
|
}
|
|
280
279
|
}
|
|
281
280
|
.task {
|
|
282
|
-
try?
|
|
283
|
-
await
|
|
281
|
+
try? board.reload()
|
|
282
|
+
await board.observe()
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
285
|
}
|
|
287
286
|
```
|
|
288
287
|
|
|
289
|
-
##
|
|
288
|
+
## Widget extension for countdown and paused UI
|
|
290
289
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
The system only falls back to its own countdown UI in narrow situations, such as
|
|
291
|
+
a device that restarted and has not been unlocked yet. Anything that shows a
|
|
292
|
+
countdown should ship this extension.
|
|
294
293
|
|
|
295
294
|
```swift
|
|
296
|
-
import
|
|
297
|
-
import SwiftUI
|
|
295
|
+
import ActivityKit
|
|
298
296
|
import AlarmKit
|
|
297
|
+
import SwiftUI
|
|
298
|
+
import WidgetKit
|
|
299
299
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
var body: some Widget {
|
|
304
|
-
AlarmLiveActivityWidget()
|
|
305
|
-
}
|
|
300
|
+
struct LapInfo: AlarmMetadata {
|
|
301
|
+
var routeName: String
|
|
302
|
+
var segment: String
|
|
306
303
|
}
|
|
307
304
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
struct AlarmLiveActivityWidget: Widget {
|
|
305
|
+
struct LapAlarmActivity: Widget {
|
|
311
306
|
var body: some WidgetConfiguration {
|
|
312
|
-
ActivityConfiguration(for: AlarmAttributes<
|
|
313
|
-
|
|
307
|
+
ActivityConfiguration(for: AlarmAttributes<LapInfo>.self) { context in
|
|
308
|
+
LapLockScreenView(context: context)
|
|
314
309
|
} dynamicIsland: { context in
|
|
315
310
|
DynamicIsland {
|
|
316
311
|
DynamicIslandExpandedRegion(.leading) {
|
|
317
|
-
Image(systemName: "
|
|
318
|
-
.font(.title2)
|
|
312
|
+
Image(systemName: "figure.run")
|
|
319
313
|
.foregroundStyle(context.attributes.tintColor)
|
|
320
314
|
}
|
|
321
315
|
DynamicIslandExpandedRegion(.trailing) {
|
|
322
|
-
|
|
323
|
-
.
|
|
316
|
+
remainingLabel(for: context.state.mode)
|
|
317
|
+
.monospacedDigit()
|
|
324
318
|
}
|
|
325
319
|
DynamicIslandExpandedRegion(.center) {
|
|
326
|
-
Text(context.attributes.metadata?.
|
|
327
|
-
.font(.headline)
|
|
320
|
+
Text(context.attributes.metadata?.routeName ?? "Run")
|
|
328
321
|
}
|
|
329
322
|
DynamicIslandExpandedRegion(.bottom) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
323
|
+
Text(context.attributes.metadata?.segment ?? "")
|
|
324
|
+
.font(.caption)
|
|
333
325
|
}
|
|
334
326
|
} compactLeading: {
|
|
335
|
-
Image(systemName: "
|
|
327
|
+
Image(systemName: "figure.run")
|
|
336
328
|
} compactTrailing: {
|
|
337
|
-
|
|
338
|
-
.
|
|
329
|
+
remainingLabel(for: context.state.mode)
|
|
330
|
+
.monospacedDigit()
|
|
331
|
+
.frame(maxWidth: 44)
|
|
339
332
|
} minimal: {
|
|
340
|
-
Image(systemName: "
|
|
333
|
+
Image(systemName: "figure.run")
|
|
341
334
|
}
|
|
342
335
|
.keylineTint(context.attributes.tintColor)
|
|
343
336
|
}
|
|
344
337
|
}
|
|
345
338
|
}
|
|
346
339
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
struct AlarmLockScreenView: View {
|
|
350
|
-
let context: ActivityViewContext<AlarmAttributes<CookingTimerMetadata>>
|
|
340
|
+
struct LapLockScreenView: View {
|
|
341
|
+
let context: ActivityViewContext<AlarmAttributes<LapInfo>>
|
|
351
342
|
|
|
352
343
|
var body: some View {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
.font(.headline)
|
|
359
|
-
Spacer()
|
|
360
|
-
AlarmCountdownText(state: context.state)
|
|
361
|
-
.font(.title3.monospacedDigit().bold())
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
switch context.state.mode {
|
|
365
|
-
case .countdown(let info):
|
|
366
|
-
ProgressView(
|
|
367
|
-
value: info.previouslyElapsedDuration,
|
|
368
|
-
total: info.totalCountdownDuration
|
|
369
|
-
)
|
|
370
|
-
.tint(context.attributes.tintColor)
|
|
371
|
-
case .paused:
|
|
372
|
-
Label("Paused", systemImage: "pause.fill")
|
|
373
|
-
.font(.subheadline).foregroundStyle(.secondary)
|
|
374
|
-
case .alert:
|
|
375
|
-
EmptyView() // System handles alerting UI
|
|
376
|
-
@unknown default:
|
|
377
|
-
EmptyView()
|
|
344
|
+
switch context.state.mode {
|
|
345
|
+
case .countdown(let run):
|
|
346
|
+
VStack(alignment: .leading) {
|
|
347
|
+
Text(context.attributes.presentation.countdown?.title ?? "Running")
|
|
348
|
+
ProgressView(value: run.previouslyElapsedDuration, total: run.totalCountdownDuration)
|
|
378
349
|
}
|
|
350
|
+
.padding()
|
|
351
|
+
case .paused:
|
|
352
|
+
Label("Paused", systemImage: "pause.circle").padding()
|
|
353
|
+
case .alert:
|
|
354
|
+
EmptyView()
|
|
355
|
+
@unknown default:
|
|
356
|
+
EmptyView()
|
|
379
357
|
}
|
|
380
|
-
.padding()
|
|
381
358
|
}
|
|
382
359
|
}
|
|
383
360
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
let
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
case .alert(let info):
|
|
397
|
-
Text("\(info.time.hour):\(String(format: "%02d", info.time.minute))")
|
|
398
|
-
@unknown default:
|
|
399
|
-
Text("--:--")
|
|
400
|
-
}
|
|
361
|
+
@ViewBuilder
|
|
362
|
+
func remainingLabel(for mode: AlarmPresentationState.Mode) -> some View {
|
|
363
|
+
switch mode {
|
|
364
|
+
case .countdown(let run):
|
|
365
|
+
Text(run.fireDate, style: .timer)
|
|
366
|
+
case .paused(let hold):
|
|
367
|
+
let left = hold.totalCountdownDuration - hold.previouslyElapsedDuration
|
|
368
|
+
Text(Duration.seconds(left).formatted(.time(pattern: .minuteSecond)))
|
|
369
|
+
case .alert(let ring):
|
|
370
|
+
Text(String(format: "%02d:%02d", ring.time.hour, ring.time.minute))
|
|
371
|
+
@unknown default:
|
|
372
|
+
EmptyView()
|
|
401
373
|
}
|
|
402
374
|
}
|
|
403
375
|
```
|
|
404
376
|
|
|
405
|
-
|
|
377
|
+
The alert case renders `EmptyView()` on the Lock Screen because the system draws
|
|
378
|
+
the ringing UI itself.
|
|
379
|
+
|
|
380
|
+
Fields by mode:
|
|
381
|
+
|
|
382
|
+
| Mode | Fields |
|
|
383
|
+
|---|---|
|
|
384
|
+
| `.countdown` | `fireDate`, `previouslyElapsedDuration`, `totalCountdownDuration` |
|
|
385
|
+
| `.paused` | `previouslyElapsedDuration`, `totalCountdownDuration` |
|
|
386
|
+
| `.alert` | `time` (`hour`, `minute`) |
|
|
387
|
+
|
|
388
|
+
## Recurrence
|
|
406
389
|
|
|
407
390
|
```swift
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
let
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
)
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
repeats: .weekly([.saturday, .sunday])
|
|
425
|
-
))
|
|
426
|
-
|
|
427
|
-
// One-time alarm at a specific Date
|
|
428
|
-
let targetDate = Calendar.current.date(
|
|
429
|
-
from: DateComponents(year: 2026, month: 6, day: 15, hour: 14, minute: 30)
|
|
430
|
-
)!
|
|
431
|
-
let fixedSchedule = Alarm.Schedule.fixed(targetDate)
|
|
391
|
+
import AlarmKit
|
|
392
|
+
import Foundation
|
|
393
|
+
|
|
394
|
+
let allWeek: [Locale.Weekday] = [.monday, .tuesday, .wednesday, .thursday, .friday, .saturday, .sunday]
|
|
395
|
+
let officeDays: [Locale.Weekday] = [.monday, .tuesday, .wednesday, .thursday, .friday]
|
|
396
|
+
let restDays: [Locale.Weekday] = [.saturday, .sunday]
|
|
397
|
+
|
|
398
|
+
let bedtime = Alarm.Schedule.relative(.init(time: .init(hour: 21, minute: 30), repeats: .weekly(allWeek)))
|
|
399
|
+
let commute = Alarm.Schedule.relative(.init(time: .init(hour: 7, minute: 15), repeats: .weekly(officeDays)))
|
|
400
|
+
let lazyMorning = Alarm.Schedule.relative(.init(time: .init(hour: 9, minute: 45), repeats: .weekly(restDays)))
|
|
401
|
+
|
|
402
|
+
func examMorning() -> Alarm.Schedule? {
|
|
403
|
+
let parts = DateComponents(calendar: .current, year: 2027, month: 1, day: 8, hour: 6, minute: 50)
|
|
404
|
+
guard let when = Calendar.current.date(from: parts) else { return nil }
|
|
405
|
+
return .fixed(when)
|
|
406
|
+
}
|
|
432
407
|
```
|
|
433
408
|
|
|
434
|
-
|
|
409
|
+
"Every day" is simply `.weekly` with all seven weekdays. A single calendar date
|
|
410
|
+
is a `Date` built from `DateComponents` and passed to `.fixed`.
|
|
435
411
|
|
|
436
|
-
|
|
412
|
+
## Snooze and custom secondary actions
|
|
437
413
|
|
|
438
|
-
|
|
414
|
+
For a standard snooze, give the alert a `.countdown` secondary button and set
|
|
415
|
+
`postAlert`; that value is the snooze length. A `Countdown` presentation is
|
|
416
|
+
what the user sees while the snooze runs. Metadata can be `nil`; give the
|
|
417
|
+
compiler the type (`Optional<NapInfo>.none`, or `nil as NapInfo?`) when it
|
|
418
|
+
cannot infer the generic parameter.
|
|
439
419
|
|
|
440
420
|
```swift
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
),
|
|
450
|
-
secondaryButtonBehavior: .countdown // tapping Snooze restarts countdown
|
|
451
|
-
)
|
|
452
|
-
// postAlert defines the snooze duration
|
|
453
|
-
let countdown = Alarm.CountdownDuration(
|
|
454
|
-
preAlert: nil, postAlert: snoozeDurationSeconds
|
|
455
|
-
)
|
|
456
|
-
let countdownPresentation = AlarmPresentation.Countdown(
|
|
457
|
-
title: "Snoozing...", pauseButton: nil
|
|
458
|
-
)
|
|
421
|
+
import AlarmKit
|
|
422
|
+
import AppIntents
|
|
423
|
+
import SwiftUI
|
|
424
|
+
|
|
425
|
+
struct NapInfo: AlarmMetadata {}
|
|
426
|
+
|
|
427
|
+
@available(iOS 26.1, *)
|
|
428
|
+
func napWithSnooze() -> AlarmManager.AlarmConfiguration<NapInfo> {
|
|
459
429
|
let presentation = AlarmPresentation(
|
|
460
|
-
alert:
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
metadata: nil as WakeUpMetadata?,
|
|
465
|
-
tintColor: .purple
|
|
430
|
+
alert: .init(title: "Nap over",
|
|
431
|
+
secondaryButton: AlarmButton(text: "5 more", textColor: .white, systemImageName: "moon.zzz"),
|
|
432
|
+
secondaryButtonBehavior: .countdown),
|
|
433
|
+
countdown: .init(title: "Snoozing", pauseButton: nil)
|
|
466
434
|
)
|
|
467
|
-
let
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
)),
|
|
435
|
+
let attributes = AlarmAttributes(presentation: presentation, metadata: Optional<NapInfo>.none, tintColor: .purple)
|
|
436
|
+
return AlarmManager.AlarmConfiguration(
|
|
437
|
+
countdownDuration: .init(preAlert: nil, postAlert: 300),
|
|
438
|
+
schedule: .fixed(Date(timeIntervalSinceNow: 1_200)),
|
|
472
439
|
attributes: attributes,
|
|
473
|
-
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
474
|
-
secondaryIntent: SnoozeAlarmIntent(alarmID: id.uuidString),
|
|
475
440
|
sound: .default
|
|
476
441
|
)
|
|
477
|
-
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
478
442
|
}
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### Custom secondary action (open app)
|
|
482
443
|
|
|
483
|
-
|
|
484
|
-
|
|
444
|
+
struct ShowPackingList: LiveActivityIntent {
|
|
445
|
+
static let title: LocalizedStringResource = "Show packing list"
|
|
446
|
+
static let openAppWhenRun = true
|
|
485
447
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
func perform() async throws -> some IntentResult { .result() }
|
|
448
|
+
func perform() async -> some IntentResult {
|
|
449
|
+
.result()
|
|
450
|
+
}
|
|
490
451
|
}
|
|
491
452
|
|
|
492
|
-
|
|
493
|
-
|
|
453
|
+
@available(iOS 26.1, *)
|
|
454
|
+
func departureAlarm() -> AlarmManager.AlarmConfiguration<NapInfo> {
|
|
494
455
|
let alert = AlarmPresentation.Alert(
|
|
495
|
-
title: "
|
|
496
|
-
secondaryButton: AlarmButton(
|
|
497
|
-
|
|
498
|
-
),
|
|
499
|
-
secondaryButtonBehavior: .custom // triggers secondaryIntent
|
|
500
|
-
)
|
|
501
|
-
let presentation = AlarmPresentation(alert: alert)
|
|
502
|
-
let attributes = AlarmAttributes<WakeUpMetadata>(
|
|
503
|
-
presentation: presentation, metadata: nil, tintColor: .blue
|
|
456
|
+
title: "Leave for the airport",
|
|
457
|
+
secondaryButton: AlarmButton(text: "Checklist", textColor: .white, systemImageName: "list.bullet"),
|
|
458
|
+
secondaryButtonBehavior: .custom
|
|
504
459
|
)
|
|
505
|
-
let
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
)),
|
|
460
|
+
let attributes = AlarmAttributes<NapInfo>(presentation: .init(alert: alert), tintColor: .blue)
|
|
461
|
+
return .alarm(
|
|
462
|
+
schedule: .fixed(Date(timeIntervalSinceNow: 7_200)),
|
|
509
463
|
attributes: attributes,
|
|
510
|
-
stopIntent:
|
|
511
|
-
secondaryIntent:
|
|
464
|
+
stopIntent: nil,
|
|
465
|
+
secondaryIntent: ShowPackingList(),
|
|
512
466
|
sound: .default
|
|
513
467
|
)
|
|
514
|
-
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
515
468
|
}
|
|
516
469
|
```
|
|
517
470
|
|
|
518
|
-
|
|
471
|
+
With `.custom`, pressing the secondary button runs `secondaryIntent` instead of
|
|
472
|
+
starting a countdown.
|
|
519
473
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
```xml
|
|
523
|
-
<key>NSAlarmKitUsageDescription</key>
|
|
524
|
-
<string>We schedule alerts for alarms and timers you create.</string>
|
|
525
|
-
```
|
|
474
|
+
## Info.plist
|
|
526
475
|
|
|
527
|
-
|
|
528
|
-
|
|
476
|
+
| Key | Type | Notes |
|
|
477
|
+
|---|---|---|
|
|
478
|
+
| `NSAlarmKitUsageDescription` | String | Required. Without a non-empty value every `schedule(id:configuration:)` call fails, so the app cannot create alarms at all. |
|
|
529
479
|
|
|
530
|
-
|
|
480
|
+
- Put it in the containing app's Info.plist, not the extension's.
|
|
481
|
+
- Apple does not list `NSSupportsLiveActivities` as part of AlarmKit setup.
|
|
482
|
+
- Using countdown presentation means adding a widget extension target.
|
|
531
483
|
|
|
532
|
-
|
|
533
|
-
custom Live Activity UI. Keep `NSAlarmKitUsageDescription` in the host app's
|
|
534
|
-
Info.plist; Apple does not document `NSSupportsLiveActivities` as an AlarmKit
|
|
535
|
-
setup key.
|
|
484
|
+
## Error handling
|
|
536
485
|
|
|
537
|
-
|
|
486
|
+
`AlarmManager.AlarmConfiguration` is generic over the metadata type, written in
|
|
487
|
+
full as `AlarmManager.AlarmConfiguration<Metadata>`.
|
|
538
488
|
|
|
539
489
|
```swift
|
|
540
490
|
import AlarmKit
|
|
541
491
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
492
|
+
enum ScheduleOutcome {
|
|
493
|
+
case scheduled(Alarm)
|
|
494
|
+
case needsAccess
|
|
495
|
+
case tooMany
|
|
496
|
+
case failed(Error)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
func trySchedule<M: AlarmMetadata>(_ config: AlarmManager.AlarmConfiguration<M>) async -> ScheduleOutcome {
|
|
500
|
+
let center = AlarmManager.shared
|
|
501
|
+
guard center.authorizationState == .authorized else { return .needsAccess }
|
|
550
502
|
do {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
print("Scheduled alarm: \(alarm.id), state: \(alarm.state)")
|
|
555
|
-
} catch let error as AlarmManager.AlarmError {
|
|
556
|
-
switch error {
|
|
503
|
+
return .scheduled(try await center.schedule(id: UUID(), configuration: config))
|
|
504
|
+
} catch let limitError as AlarmManager.AlarmError {
|
|
505
|
+
switch limitError {
|
|
557
506
|
case .maximumLimitReached:
|
|
558
|
-
|
|
507
|
+
return .tooMany
|
|
559
508
|
@unknown default:
|
|
560
|
-
|
|
509
|
+
return .failed(limitError)
|
|
561
510
|
}
|
|
562
511
|
} catch {
|
|
563
|
-
|
|
512
|
+
return .failed(error)
|
|
564
513
|
}
|
|
565
514
|
}
|
|
566
515
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
catch {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
func pauseAlarmSafely(id: Alarm.ID) {
|
|
574
|
-
// Only valid when alarm is in .countdown state
|
|
575
|
-
do { try AlarmManager.shared.pause(id: id) }
|
|
576
|
-
catch { print("Cannot pause: \(error)") }
|
|
516
|
+
func holdCountdown(_ alarmID: Alarm.ID) {
|
|
517
|
+
do {
|
|
518
|
+
try AlarmManager.shared.pause(id: alarmID)
|
|
519
|
+
} catch {
|
|
520
|
+
// pause(id:) only succeeds while the alarm is in .countdown
|
|
521
|
+
}
|
|
577
522
|
}
|
|
578
523
|
```
|
|
579
524
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
- [
|
|
588
|
-
- [
|
|
589
|
-
- [
|
|
590
|
-
- [
|
|
591
|
-
- [
|
|
525
|
+
When `.maximumLimitReached` comes back, ask the user to remove an existing
|
|
526
|
+
alarm before adding another. The transition calls (`cancel`, `pause`,
|
|
527
|
+
`resume`, `stop`, `countdown`) throw when the alarm is in the wrong state, so
|
|
528
|
+
wrap them in `do/catch`; for example `pause` is valid only in `.countdown`.
|
|
529
|
+
|
|
530
|
+
## Apple documentation
|
|
531
|
+
|
|
532
|
+
- [AlarmKit](https://developer.apple.com/documentation/alarmkit)
|
|
533
|
+
- [AlarmManager](https://developer.apple.com/documentation/alarmkit/alarmmanager)
|
|
534
|
+
- [AlarmAttributes](https://developer.apple.com/documentation/alarmkit/alarmattributes)
|
|
535
|
+
- [AlarmPresentation](https://developer.apple.com/documentation/alarmkit/alarmpresentation)
|
|
536
|
+
- [AlarmPresentationState](https://developer.apple.com/documentation/alarmkit/alarmpresentationstate)
|
|
537
|
+
- [AlarmButton](https://developer.apple.com/documentation/alarmkit/alarmbutton)
|
|
538
|
+
- [Alarm](https://developer.apple.com/documentation/alarmkit/alarm)
|
|
539
|
+
- [Alarm.Schedule](https://developer.apple.com/documentation/alarmkit/alarm/schedule)
|
|
540
|
+
- [Alarm.CountdownDuration](https://developer.apple.com/documentation/alarmkit/alarm/countdownduration)
|
|
541
|
+
- [Apple sample: scheduling alarms](https://developer.apple.com/documentation/alarmkit/scheduling-an-alarm-with-alarmkit)
|