BTraitsObserver: protocol-driven unified trait observation#4
Conversation
Show only directories instead of enumerating individual files. Add missing BroadwayTestHost and BroadwayTesting to README. Made-with: Cursor
Add BTraitsValueObserver protocol and associated type to BTraitsValue so each trait declares its own observer. BTraitsObserver coordinates them behind a single start/stop interface, simplifying BRootViewController. Remove BAccessibility.observe(_:) factory in favor of direct Observer init. Made-with: Cursor
BTraits now owns the set of registered trait types via register<V>() and a .system factory. BTraitsObserver reads registrations and the UIViewController hierarchy from the BTraits instance instead of hardcoding types. initialValue replaced with currentValue(from:) for future injectability. EquatableIgnored gains Hashable conformance. Made-with: Cursor
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f4b306ccf5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Defer child VC creation, trait observation, and context setup until the controller enters a valid view hierarchy (viewIsAppearing). Replace the XCTestCase extension with standalone free functions compatible with Swift Testing. Made-with: Cursor
…e BAccessibility trait conformance into the BAccessibility file.
…ewController Move BTraits, BTraitsObserver, and BAccessibility into BroadwayCore/Sources/Traits/. Extract trait value conformances into Values/. Add BTraits+Overrides for override support and BTraitOverridesViewController for propagating trait overrides through the view hierarchy. Made-with: Cursor
…gnored for caches Flatten BStylesheets to store traits/themes directly instead of through a Config struct. Mark cache and creating arrays with @EquatableIgnored so equality is based solely on traits and themes. Add @unchecked Sendable to EquatableIgnored and mark stylesheets as @EquatableIgnored on BContext. Made-with: Cursor
…troller fix Pass UIViewController through to BTraitsValue.makeObserver so VC-scoped traits can use registerForTraitChanges. Add UIViewControllerTraitObserver as a reusable observer for UIKit trait-backed values. Wire BMode and BContentSizeCategory to read from UITraitCollection and observe changes. Fix BTraitOverridesViewController with proper child containment and lazy setup. Bridge BContext into SwiftUI via UITraitBridgedEnvironmentKey and add bTraitOverrides/bMode/ bContentSizeCategory view modifiers. Made-with: Cursor
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f0a2f072a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7f0a2f0. Configure here.
- Merge main agent tooling (sync-agents, nested AGENTS.md, external skills) - Resolve AGENTS.md and README.md conflicts with flat layout trees - Keep README Targets table; document AI skills via sync-agents Made-with: Cursor
- Seed BStylesheets with merged traits when BContext init takes overrides. - Apply trait overrides from inherited parent bContext and republish full context. - Prefer parent traitCollection when resolving inherited BContext during viewIsAppearing. - Make BTraitsObserver.start/stop idempotent at the coordinator level. - Add BContext and show()-based BroadwayUI tests for the above. Made-with: Cursor
- Align BMode.currentValue with BContentSizeCategory via BMode.from(_: UIUserInterfaceStyle). - Require explicit BTraitsValue.makeObserver (drop NeverObserver default extension); update ScaleFactor tests. - Make BStylesheets traits storage private; sync via updateTraits from BContext only; stop reading traits from tests. - BTraitsObserverTests: use show() with a retained anchor VC; assert coordinator double-start only calls underlying start once (CountingStartSpy). - BTraitOverridesViewController: apply overrides from didMove(toParent:) when embedded. - Restore BroadwayTesting dependency on .xctest (matches main). Made-with: Cursor
- Make themes storage private; add updateThemes like updateTraits. - Theme propagation test resolves theme via lazy TestStylesheet get(). Made-with: Cursor
- Mark updateTraits/updateThemes as package; document Tuist -package-name. - Apply OTHER_SWIFT_FLAGS -package-name Broadway to all first-party targets so package symbols compile outside a SwiftPM Package.swift layout. Made-with: Cursor
- Add Package.swift with BroadwayCore, BroadwayUI, BroadwayTesting (iOS 26 + Mac Catalyst); target paths use */Sources so Tests stay out of libraries. - Tuist Project.swift: local package at repo root; Catalog/TestHost/CoreTests/UITests/CatalogTests depend on package products; drop generated framework targets and -package-name flags. - Sendable: BMode/BContentSizeCategory; SettingsProvider + @unchecked Sendable system/mock providers for SPM concurrency checks. - Update AGENTS.md and README for hybrid SPM + Tuist workflows and scheme names. Made-with: Cursor
…gthen stop test - Remove redundant stylesheet get in BContext merged-traits test (kyleve) - Note why BroadwayTesting no longer links .xctest under Tuist+SPM - BTraitOverridesViewController: document didMove vs viewIsAppearing roles - NeverObserver doc: reflect explicit makeObserver requirement - BTraitsObserverTests: SeqTrait + NotificationCenter proves stop removes subscriptions; fix CountingStartSpy static storage; isolate NC per hosted VC Made-with: Cursor
Made-with: Cursor

Summary
BTraitsValuedeclares anObserverassociated type conforming toBTraitsValueObserver.BTraitsObservercoordinates per-type observers fromBTraitsregistrations, usingcurrentValue(from:)andmakeObserver(with:onChange:), with idempotentstart()/stop()at the coordinator.BTraitsValueimplementsmakeObserver(no protocol default).NeverObserverremains available for traits with nothing live to subscribe to.BTraitsregistration:.system,register(_:), andreadCurrentValues(from:)centralize which types participate.BContext: SeparatesbaseTraitsand subtreetraitOverrides; mergedtraitsdrives equality and stylesheet config.BStylesheetskeeps private trait/theme storage;BContextsyncs viaupdateTraits/updateThemes(package-visible from the Swift package boundary).BRootViewController: Lazy setup inviewIsAppearing; oneBTraitsObserver(traits: .system, from: self)replaces ad hoc accessibility wiring.BTraitOverridesViewController: Applies overrides from the full inherited context (parenttraitCollection.bContextwhen embedded); refreshes indidMove(toParent:)and on trait changes; child creation still deferred toviewIsAppearing.BMode,BContentSizeCategory,UIViewControllerTraitObserver), SwiftUI environment and modifiers forBContext/ overrides.BAccessibility.Observer: Internal initializer only (no publicobservefactory); review chose to keep construction package-internal until a public API is needed.Package.swiftships BroadwayCore, BroadwayUI, and BroadwayTesting (sources under*/Sources). Tuist generates the Xcode workspace for BroadwayCatalog, BroadwayTestHost, and.xctestbundles that depend on those products. BroadwayTesting in SPM links UIKit only (no.xctestlink on the library); seeProject.swiftcomment near the local package.Sendable/@unchecked Sendablewhere required for Swift 6 (e.g.BMode,BContentSizeCategory,SettingsProviderusage).AGENTS.md/README.mddescribe hybrid SPM + Tuist workflows and how to run tests.Test plan
mise exec -- tuist test BroadwayCoreTests(trait observer, context, accessibility observer, stylesheets)BTraitsObserverTests:show()-hosted lifecycle, double-startidempotency (CountingStartSpy), stop tears down notification subscription (SeqTrait+ dedicatedNotificationCenter)BRootViewControllerTests/ trait-override container tests for inherited context andtraitOverrides.bContextBAccessibilityObserverTestscoverObserverlifecycle and injectedNotificationCenterbehaviorMade with Cursor