From e4a295ba84816f3ac3ab780a7caf4dd285531a06 Mon Sep 17 00:00:00 2001 From: Kyle Date: Fri, 2 Jan 2026 19:02:17 +0800 Subject: [PATCH] Add notify API and add test case for ViewGraphGeometryObservers --- .../Graph/ViewGraphGeometryObservers.swift | 18 +++++++++++++++++- .../ViewGraphGeometryObserversTests.swift | 17 ++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Sources/OpenSwiftUICore/View/Graph/ViewGraphGeometryObservers.swift b/Sources/OpenSwiftUICore/View/Graph/ViewGraphGeometryObservers.swift index c6f4e890e..a43b483eb 100644 --- a/Sources/OpenSwiftUICore/View/Graph/ViewGraphGeometryObservers.swift +++ b/Sources/OpenSwiftUICore/View/Graph/ViewGraphGeometryObservers.swift @@ -77,6 +77,22 @@ package struct ViewGraphGeometryObservers where Measurer: ViewGraphGeo return result } + // [?] + mutating func notify() { + let keys = store.keys + for proposal in keys { + guard var observer = store[proposal] else { continue } + guard case let .pending(oldSize, pending: newSize) = observer.storage else { + continue + } + if oldSize != newSize { + observer.callback(oldSize, newSize) + } + observer.storage = .value(newSize) + store[proposal] = observer + } + } + /// Adds an observer for a specific layout proposal. /// /// - Parameters: @@ -202,7 +218,7 @@ package struct ViewGraphGeometryObservers where Measurer: ViewGraphGeo return true case let .pending(value, _): guard size != value else { - self = .value(size) + self = .value(size) // ? return false } self = .pending(value, pending: size) diff --git a/Tests/OpenSwiftUICoreTests/View/Graph/ViewGraphGeometryObserversTests.swift b/Tests/OpenSwiftUICoreTests/View/Graph/ViewGraphGeometryObserversTests.swift index eff03ca45..a38fd71f6 100644 --- a/Tests/OpenSwiftUICoreTests/View/Graph/ViewGraphGeometryObserversTests.swift +++ b/Tests/OpenSwiftUICoreTests/View/Graph/ViewGraphGeometryObserversTests.swift @@ -10,12 +10,14 @@ private struct TestMeasurer: ViewGraphGeometryMeasurer { typealias Proposal = CGSize typealias Size = CGFloat + static var mockValue: CGFloat? + static func measure(given proposal: CGSize, in graph: ViewGraph) -> CGFloat { - max(proposal.width, proposal.height) + mockValue ?? max(proposal.width, proposal.height) } static func measure(proposal: CGSize, layoutComputer: LayoutComputer, insets: EdgeInsets) -> CGFloat { - max(proposal.width, proposal.height) + mockValue ?? max(proposal.width, proposal.height) } static var invalidValue: CGFloat = .nan @@ -28,14 +30,19 @@ struct ViewGraphGeometryObserversTests { @MainActor @Test func observeCallback() async throws { - // TODO: when the callback got called. - await confirmation(expectedCount: 0) { confirm in + await confirmation(expectedCount: 1) { confirm in var observers = Observers() - observers.addObserver(for: CGSize(width: 10, height: 20)) { _, _ in + observers.addObserver(for: CGSize(width: 10, height: 20)) { oldSize, newSize in confirm() + #expect(oldSize.isApproximatelyEqual(to: 20.0)) + #expect(newSize.isApproximatelyEqual(to: 30.0)) } let emptyViewGraph = ViewGraph(rootViewType: EmptyView.self) _ = observers.needsUpdate(graph: emptyViewGraph) + TestMeasurer.mockValue = 30.0 + defer { TestMeasurer.mockValue = nil } + _ = observers.needsUpdate(graph: emptyViewGraph) + observers.notify() } } #endif