Repository navigation
feat!: restore the widget components library and prepare 2.0.0 - #28
Merged
Merged
Conversation
The Enterprise, Integration, Analytics, Widgets and LiveData folders, the demo app, examples, templates and the Documentation folder were not included by any target in Package.swift, and much of the code referenced types that do not exist. The Quick/Nimble tests in Tests/Unit belonged to the only test target, which did not compile because Quick and Nimble were never declared as dependencies; that test target is removed with them and a new one is added together with the first new tests. The podspec, Turkish README stub and support files described APIs that are not in the package.
Drops the swift-async-algorithms dependency, which no source file used.
- Remove the no-op WidgetDevelopmentKit singleton, the hard-coded version constant and the WidgetConfiguration struct, which shadowed SwiftUI's WidgetConfiguration protocol for any file importing both modules. - Remove TimelinePrewarmer: it only called reloadTimelines and did not do the usage-based scheduling its documentation described. - Remove WidgetGallery; the restored template views cover the same cases.
…eMachine - Drop the print call, which logged a literal "\(newState)" because the interpolation was escaped. - Throw StateMachineError.invalidTransition(from:to:) with typed throws so callers can see which transition was rejected. - Store allowed transitions as sets, expose currentState as a read-only property instead of getCurrentState(), and add canTransition(to:) and allowedNextStates().
- Clamp the selected index to the entry range, so the view cannot index out of bounds when the entries array shrinks. - Hide the slider when there is only one entry instead of building a 0...0 slider. - Allow a custom preview size instead of a fixed 158 x 158 frame. - Show the entry date with a short date format, and replace the deprecated foregroundColor and cornerRadius modifiers.
WidgetMath, WidgetFormat, MonthGrid and CountdownComponents hold the arithmetic the views need (progress fractions, zero totals, reversed timer ranges, locale-aware month grids) so it can be unit tested. Tests use a fixed Gregorian calendar and cover NaN, negative and zero inputs, Monday-first weeks, a leap month and a DST transition. Adds the WidgetDevelopmentKitTests target for these tests.
Restores the chart views that were outside every build target and fixes: sparkline x values no longer depend on Date(), progress ring no longer force-unwraps an empty colour list or divides by a zero total, multi-line series use a stable order, horizontal bars clamp their width, and the activity heat map computes its maximum once and uses discrete levels.
Accessory families are unavailable on macOS, so the views compile for iOS and watchOS only. Timer views no longer build a reversed date range (which traps), countdowns count calendar days from the timeline entry date, progress values are clamped and duplicate labels no longer collide as ForEach identifiers.
The month grid now follows the calendar's first weekday and uses unique column identifiers, fitness rings guard against zero goals, and the countdown is computed from the timeline entry date instead of Date(), dropping the seconds column a static widget snapshot cannot update.
Split into themed files. Fixes a string literal that did not compile, zero-goal and zero-duration divisions, a force-unwrapped fallback URL in the shortcuts widget and the water tracker's fixed eight-glass row. Adds tests for the habit streak and water tracker arithmetic.
Reworked from the TimelineManager removed in e3bcc65. Kept the ideas that hold up and fixed their bugs: - WidgetUpdatePolicy uses calendar arithmetic for next-hour and next-day reloads instead of adding 3600/86400 seconds, and maps to a WidgetKit TimelineReloadPolicy. - TimelineBuilder is a value type and sorts entries by date. - TimelineSchedule generates evenly spaced or boundary-aligned dates. - WidgetSnapshotStore replaces TimelineCacheManager: Codable values with an expiry in injectable UserDefaults (no hard-coded App Group). Dropped SmartTimelineProvider (its placeholder force-cast nil to the data type), the Timer-based reload manager, which cannot run in a widget extension, and the battery and metrics helpers.
Reworked from the orphaned WidgetConfiguration.swift: - WidgetDeepLink builds and parses widget URLs as a value type, with sorted query items, scheme checking and first-wins duplicate keys, replacing the non-Sendable handler-registry singleton. - HexColor validates 3, 6 and 8 digit input; the old initializer accepted partial matches and ignored alpha, and hexString indexed past the end of grayscale colour components. - RefreshIntervalOption and AccentColorOption keep the AppEntity choices, plus an AppIntentsPackage so apps can register them. Dropped the storage and migration singletons with hard-coded App Group names; WidgetSnapshotStore covers persistence.
Reworked from the orphaned NetworkDataProvider.swift. The old provider retried every non-2xx status (including 404), waited for connectivity inside a widget extension and used non-Sendable singletons. Now: - WidgetDataLoader retries only transient errors (5xx, 408, timeouts, offline) with doubling backoff, and takes an injectable transport and sleep so the retry logic is unit tested. - URLSession.widgetDefault is ephemeral with short timeouts. - Endpoint replaces APIEndpointBuilder as a value type with encoded path segments and ordered query items. Dropped the polling, sync and background-refresh singletons.
The orphaned intents wrote to a hard-coded App Group that no app owns, and ActionIntent posted a NotificationCenter notification inside the widget extension, where the app never receives it. Now: - WidgetStateStore holds flags, counters and a pending-action queue in the App Group named by the WidgetDevelopmentKitAppGroup Info.plist key. - ToggleIntent, IncrementIntent, SetValueIntent, RecordActionIntent and RefreshWidgetIntent use that store; counters saturate and can be clamped at zero. - The rating, water, timer and quick-action widgets use these intents, and the rating view no longer traps for a maximum below one.
Restores ten ActivityAttributes types (delivery, order, ride, flight, timer, workout, parking, sports, now playing, meeting) with their Lock Screen and Dynamic Island compact views. The files compile only where ActivityKit exists (iOS). LiveActivityManager becomes a LiveActivities namespace without a singleton, with optional stale dates; the unused LiveActivityTemplate protocol is removed and time labels use WidgetFormat.playbackTime.
SwiftUI views are main-actor isolated in the iOS SDK, so the tests produced isolation warnings when built for the simulator.
scripts/render-screenshots.sh runs an opt-in test suite on an iOS simulator that renders home screen templates, charts and lock screen widgets in light and dark mode into docs/images. The suite is skipped unless WDK_SCREENSHOT_DIR is set.
ReadmeExamplesTests holds the code shown in the README (timeline provider, widget, interactive button, networking) so it is compiled and the provider's timeline is checked on every test run.
The old workflows pinned Xcode 15.2, ran SwiftLint with || true, and included a README guard, link checkers, a Pages deploy and a release job that overwrote release notes with the commit list. None of them built the package successfully. The new workflow runs swift build and swift test on macOS, xcodebuild test on an iOS simulator and xcodebuild docbuild, with checkout pinned to a commit SHA and read-only permissions. Also drops the duplicate Markdown issue templates, points CODEOWNERS at the maintainer and limits Dependabot to GitHub Actions.
…ticles Also completes parameter documentation so xcodebuild docbuild reports no warnings.
Replaces the ASCII banner, static shields, comparison table and template counts that did not match the code with: a feature table counted from the sources, requirements and installation that match Package.swift, compiled usage examples, rendered screenshots, an architecture note, test instructions and a short project history.
The previous file listed releases 1.0.0 to 3.2.0 dated 2023-2024; the repository was created in 2025 and only v1.0.0 was ever tagged. The new file records this work under Unreleased and notes that v1.0.0 does not build.
The library target at the previous main built; only the v1.0.0 manifest failed to load. What did not work was the test target, whose Quick/Nimble tests used packages the manifest never declared, and most of the Swift code, which was outside every target.
The AppIntentsPackage example declared includedPackages as a stored static property, which Swift 6 reports as not concurrency-safe; it is now a computed property, and the example is compiled in the test target. The getting-started example falls back to standard defaults instead of force-unwrapping the App Group suite, as the README does.
xcodebuild stops with "multiple devices matched" when two simulators share a name. The script now also accepts a UDID, or a full destination in the DESTINATION environment variable.
The header always read "7 Day Streak", even when the streaks shown in the rows were 4, 1 and 0. The seven dots are the last seven days, so the header now says that.
"Xcode 16 or later" was not verified; the package has only been built and tested with Xcode 27. The requirement now names the manifest's tools version and the tested Xcode instead.
The iOS simulator runs 77 tests; the 3 screenshot tests are skipped unless scripts/render-screenshots.sh runs them.
The first commit is from August 2025; the license said 2024.
SwiftLint could not parse .swiftlint.yml: the unquoted "*/Generated/*" entry is a YAML alias, so every run fell back to the default rules. - Drop the excluded paths that do not exist in this package (Pods, DerivedData, Generated, Package.swift) and lint Sources and Tests only. - Add Tests/.swiftlint.yml that turns off force_unwrapping for the tests, which unwrap fixed URLs and dates they create themselves. swiftlint lint now reports 0 violations.
Replace the repository's own CI with callers of the reusable workflows in muhittincamdali/.github, pinned to commit 5d3c443: - ci.yml: swift-ci.yml runs swift build --build-tests and swift test on macOS, builds the package for iOS and macOS with xcodebuild, and runs the tests on an iOS simulator (test-on-simulator: true). - docs.yml: docc-pages.yml builds the DocC archive for the iOS Simulator, so the Lock Screen and Live Activity symbols are included, and deploys it to GitHub Pages on pushes to main. - quality.yml: link check (lychee), wording scan of files and commit messages, and the README translation check with strict: true. - .lychee.toml: the shared link check settings. All jobs use GitHub's macos-26 image with its default Xcode, or ubuntu-24.04.
.swiftlint.yml was only used locally. Lint runs SwiftLint 0.63.2 in its official container image, pinned by digest, with --strict so a warning fails the job.
Built with the branding script of the repository kit (muhittincamdali/.github) from .github/brand.json: - banner in light and dark, with the tagline in all ten README languages; - badges for platforms, Swift tools version and license, read from Package.swift and LICENSE. The release badge is turned off (badgeOverrides.version) because the only tag, v1.0.0, does not build; - Get started, Documentation and Examples buttons in ten languages; - social preview (1280 x 640) as SVG and PNG. docs/social-preview.png is the copy to upload in the repository settings. All graphics are SVG files served from this repository; the CI badge is GitHub's own badge.svg.
Examples/WidgetKitExample is an iOS 17 app with a widget extension that uses the package through a local package reference, so it builds against the code in the same commit. - LaunchCountdownWidget: TimelineSchedule entry dates and CountdownWidget, the code the README quick start shows. - StepsWidget: a provider that reads WidgetSnapshotStore and builds its timeline with TimelineBuilder, rendered with WidgetProgressRing. - WaterWidget: InteractiveWaterWidget, whose button runs IncrementIntent and writes to the App Group store. - The app saves the step count for the widgets, previews the steps timeline with WidgetTimelineScrubber and shows the water counter. The project is generated from project.yml with XcodeGen and committed, so building it needs only Xcode. The new Examples workflow builds it for the iOS Simulator on every push and pull request, and SwiftLint now covers Examples/ too.
- Explain how to add a widget extension target, and list the Add Package Dependencies steps with the dialog's button and column names. - Say that the App Groups capability is needed on both targets. - Note that WidgetSnapshotStore and WidgetStateStore keep values in unencrypted UserDefaults, so they must not hold secrets. This moves the note from the repository's SECURITY.md into the documentation. - Use the App Group name of the example app and point to Examples/WidgetKitExample, which contains the article's code. - Show the WidgetTimelineScrubber call the example app uses.
GitHub falls back to the files in muhittincamdali/.github when a
repository has none, so remove the local copies:
- CODE_OF_CONDUCT.md: same Contributor Covenant text as the shared one.
- SECURITY.md: the shared policy adds private reporting through the
Security tab. Its note about unencrypted widget storage is now in the
Getting Started article.
- Issue forms and the pull request template: the local ones were generic
("Change 1 / Change 2", emoji link labels).
- FUNDING.yml: it pointed at a GitHub Sponsors profile that does not exist.
CONTRIBUTING.md stays, since it has this package's build and test steps.
CODEOWNERS and dependabot.yml stay, since they are not inherited.
Follow the shared README layout of the repository kit: - Generated header: banner, language selector, badges and buttons. The shields.io license badge is replaced by a badge served from this repository. - Highlights with the counts from the code (20 Home Screen templates, 15 Lock Screen and 7 StandBy views, 5 App Intents, 8 interactive views, 10 ActivityAttributes types). - Quick start in three steps, with the Xcode menu path, the Add Package dialog and a complete countdown widget taken from Examples/WidgetKitExample. - Usage examples taken from the example app, or from ReadmeExamplesTests.swift. The README used to say all of them were copied from ReadmeExamplesTests.swift, which was not true for the store.save snippet. The networking example no longer force-unwraps the URL, and the examples use the App Group of the example app. - Links to the DocC site on GitHub Pages and its two articles. - Requirements, architecture, roadmap, contributing and license sections. The test commands no longer carry test counts, which change with every new test.
ReadmeSyncTests reads README.md and fails when a Swift block does not appear, line by line, in a Swift file under Examples/ (built by the Examples workflow) or in ReadmeExamplesTests.swift (built with the tests). Indentation and blank lines are ignored; only the Package.swift fragment is exempt. Two more tests cover the block extraction and the matching. ReadmeExamplesTests now uses the example app's App Group, unwraps the example URL with guard instead of !, and its header comment says which README examples it holds.
README.tr.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's tr strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.zh-CN.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's zh-CN strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.ja.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's ja strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.ko.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's ko strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.es.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's es strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.de.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's de strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.fr.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's fr strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.pt-BR.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's pt-BR strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
README.ru.md translates README.md at blob 21d649e: same sections, code blocks and links, headings and fixed sentences from the kit's ru strings. Stamped status=reviewed, so the translation check in quality.yml reports it as current.
…UTING - Add the commands that build the example app and run SwiftLint the way CI does. - Say that README Swift code must come from Examples/ or ReadmeExamplesTests.swift, and how the translations record which README.md they follow. - List the workflows a pull request has to pass, and point to the shared community files in muhittincamdali/.github.
…elog Under Unreleased: the example app, ReadmeSyncTests, the README translations, CI through the shared workflows plus the Examples and Lint workflows, the SwiftLint configuration fix and the removal of the local community files. The added-tests entry no longer gives test counts.
The README, its nine translations and the DocC Getting Started article told readers to depend on `main` until a tagged release that builds existed. With 2.0.0 that release exists, so the Package.swift snippets now use `from: "2.0.0"` and the paragraph below them says that releases start at 2.0.0 and that the older v1.0.0 tag does not build. Each translation's i18n-source marker moves to the new README.md blob, since the only English change is translated in the same commit.
Move the Unreleased notes into a 2.0.0 section dated 2026-10-14, state that this is the major version the notes asked for, and add the Keep a Changelog comparison links for 2.0.0 and the new Unreleased section. The note about removed changelog entries now says that the old 2.x and 3.x entries have nothing to do with this release.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
v1.0.0manifest does not load, and onmainthe library target held only about 240 lines; most of the Swift code sat outside every target and the test target did not compile. This branch restores the views and helpers from history into theWidgetDevelopmentKittarget, reworks the parts that were broken, removes the code that could not work, adds tests, documentation, an example app and CI, and prepares the 2.0.0 release.Changes
WidgetUpdatePolicy,TimelineBuilder,TimelineScheduleandWidgetSnapshotStore, reworked fromTimelineManager.WidgetDataLoader,RetryPolicyandEndpoint; 4xx responses are no longer retried and requests no longer wait for connectivity inside the extension.WidgetDeepLink,HexColor, App Entities for refresh interval and accent color,WidgetStateStore,SetValueIntentandRecordActionIntent.LiveActivityManagerbecomes theLiveActivitiesnamespace;LiveActivityStateMachineuses typed throws; a paused timer shows a fixed remaining time.NaNprogress, force-unwrapped colors and URLs, a trap when an end date precedes the start date, calendar-day counting, month grids that ignored the first weekday, duplicateForEachidentifiers, and a.swiftlint.ymlthat did not parse.Sources/Enterprise,Sources/Integration,Sources/Analytics,Sources/WidgetsandSources/LiveDatathat no target compiled, the Quick/Nimble tests, the old demo app, examples andDocumentation/folder, and ten workflows that did not build the package.ReadmeSyncTestskeeps README code blocks in line with compiled code.CONTRIBUTING.mdupdated. Installation instructions now usefrom: "2.0.0".Examples/WidgetKitExample, an iOS app with a widget extension that builds against the package in the same commit.muhittincamdali/.github(build and test on macOS, iOS simulator tests, DocC to Pages, links, wording, translations), plus SwiftLint and the example app build.CHANGELOG.mdmoves the notes into a2.0.0section.Testing
Run locally with Xcode 27.0 and Swift 6.4:
swift build --build-testsswift testxcodebuild teston an iOS 27 simulatorxcodebuild docbuildxcodebuild buildofExamples/WidgetKitExampleswiftlint lint --strict(0.63.2)actionlintswift build --build-testson every code commitThe GitHub runners use
macos-26with its default Xcode, which the local runs did not cover; the checks on this pull request are the first run with that toolchain.Breaking changes
The public API changes substantially, so the next release is 2.0.0.
WidgetConfiguration(it shadowed SwiftUI's protocol), theWidgetDevelopmentKitsingleton,TimelinePrewarmer,WidgetGallery,SmartTimelineProvider,ActionIntent(useRecordActionIntent) and the Enterprise, Integration and Analytics sources.LiveActivityManageris now theLiveActivitiesnamespace without a singleton.referenceDate;LockScreenTimerWidgettakesstartTimeandendTime.Screenshots
Rendered by
scripts/render-screenshots.shfrom the views in this branch.