Skip to content

Commit d9148de

Browse files
committed
WIP
1 parent 68c82fd commit d9148de

File tree

18 files changed

+243
-309
lines changed

18 files changed

+243
-309
lines changed

CLAUDE.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,24 @@ Brightroom is a composable image editor library for iOS, powered by Metal for hi
88

99
## Build Commands
1010

11-
### Running Demo Apps
11+
### Building via Xcode Project (Recommended)
1212
```bash
13-
# Open the development workspace
14-
open Dev/Brightroom.xcodeproj
13+
# Build BrightroomUI (includes BrightroomEngine)
14+
cd Dev && xcodebuild -scheme BrightroomUI -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
15+
16+
# Build Demo app
17+
cd Dev && xcodebuild -scheme Demo -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
1518

16-
# Build using Fastlane
17-
fastlane ios build_demo_apps
19+
# Build SwiftUI Demo
20+
cd Dev && xcodebuild -scheme SwiftUIDemo -destination 'platform=iOS Simulator,name=iPhone 15 Pro' build
1821
```
1922

20-
### Building the Package
23+
Note: `swift build` does not work due to macOS version constraints. Always use `xcodebuild` with the Dev/Brightroom.xcodeproj.
24+
25+
### Running Demo Apps
2126
```bash
22-
# Build the Swift package
23-
swift build
27+
# Open the development workspace
28+
open Dev/Brightroom.xcodeproj
2429
```
2530

2631
## Architecture

Dev/Sources/SwiftUIDemo/DemoCropView2.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct DemoCropView2: View {
2121
@State var angle: EditingCrop.AdjustmentAngle = .zero
2222
@State var baselineAngle: EditingCrop.AdjustmentAngle = .zero
2323
@State var isDragging: Bool = false
24+
@State var previousAdjustmentKind: CropView.StateModel.AdjustmentKind?
2425

2526
init(
2627
editingStack: EditingStack
@@ -56,13 +57,14 @@ struct DemoCropView2: View {
5657
Rectangle()
5758
.fill(kind == nil ? Color.white : Color.white.opacity(0.6))
5859
},
59-
stateHandler: { state, previous in
60-
if state.adjustmentKind != previous?.adjustmentKind {
60+
stateHandler: { state in
61+
if state.adjustmentKind != previousAdjustmentKind {
6162
if state.adjustmentKind.isEmpty {
6263
isDragging = false
6364
} else {
6465
isDragging = true
6566
}
67+
previousAdjustmentKind = state.adjustmentKind
6668
}
6769
}
6870
)

Sources/BrightroomEngine/Core/EditingStack.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import CoreImage
2323
import MetalKit
2424
import SwiftUI
2525
import UIKit
26+
import Combine
2627
import StateGraph
2728

2829
public enum EditingStackError: Error, Sendable {
@@ -209,7 +210,7 @@ open class EditingStack: Hashable {
209210

210211
private let filterPresets: [FilterPreset]
211212

212-
private var subscriptions: [Any] = []
213+
private var subscriptions: Set<AnyCancellable> = .init()
213214
private var imageProviderSubscription: Any?
214215

215216
public var cropModifier: CropModifier
@@ -277,15 +278,15 @@ open class EditingStack: Hashable {
277278
hasStartedEditing = true
278279

279280
// Set up state observation on background queue
280-
let subscription = withGraphTracking { [weak self] in
281+
withGraphTracking { [weak self] in
281282
withGraphTrackingGroup {
282283
guard let self = self else { return }
283284
self.backgroundQueue.async {
284285
self.receiveInBackground()
285286
}
286287
}
287288
}
288-
subscriptions.append(subscription)
289+
.store(in: &subscriptions)
289290

290291
/**
291292
Start downloading image
@@ -296,15 +297,13 @@ open class EditingStack: Hashable {
296297
}
297298

298299
// Observe image provider's loaded image
299-
let imageProviderSub = withGraphTracking { [weak self] in
300-
withGraphTrackingMap {
301-
self?.imageProvider.loadedImage
302-
} onChange: { [weak self] image in
303-
guard let self = self, let image = image else { return }
300+
let imageProviderSub = withGraphTracking {
301+
withGraphTrackingMap(from: self, map: { $0.imageProvider.loadedImage }, onChange: { [weak self] image in
302+
guard let self, let image else { return }
304303
self.backgroundQueue.async {
305304
self.handleImageLoaded(image: image, onPreparationCompleted: onPreparationCompleted)
306305
}
307-
}
306+
})
308307
}
309308
imageProviderSubscription = imageProviderSub
310309
}

Sources/BrightroomEngine/DataSource/ImageProvider.swift

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// THE SOFTWARE.
2121

2222
import UIKit
23-
23+
import Combine
2424
import CoreImage
2525
import StateGraph
2626

@@ -360,20 +360,3 @@ public final class ImageProvider: Equatable {
360360
}
361361
}
362362

363-
// MARK: - AnyCancellable
364-
365-
public final class AnyCancellable {
366-
private let onCancel: () -> Void
367-
368-
public init(_ onCancel: @escaping () -> Void) {
369-
self.onCancel = onCancel
370-
}
371-
372-
public func cancel() {
373-
onCancel()
374-
}
375-
376-
deinit {
377-
onCancel()
378-
}
379-
}

Sources/BrightroomUI/Shared/Components/Crop/CropView.CropInsideOverlay.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ extension CropView {
118118
super.init(frame: .zero)
119119
}
120120

121-
open func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
121+
open func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
122122

123123
}
124124

125-
open func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
125+
open func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
126126

127127
}
128128

@@ -134,7 +134,7 @@ extension CropView {
134134
private let controller: UIHostingController<Container>
135135
private let proxy: Proxy
136136

137-
public init(@ViewBuilder content: @escaping (CropView.State.AdjustmentKind?) -> Content) {
137+
public init(@ViewBuilder content: @escaping (CropView.StateModel.AdjustmentKind?) -> Content) {
138138

139139
self.proxy = .init()
140140
self.controller = .init(rootView: Container(proxy: proxy, content: content))
@@ -147,29 +147,29 @@ extension CropView {
147147
AutoLayoutTools.setEdge(controller.view, self)
148148
}
149149

150-
open override func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
150+
open override func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
151151
proxy.activeKind = kind
152152
}
153153

154-
open override func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
154+
open override func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
155155
proxy.activeKind = nil
156156
}
157157

158158
private final class Proxy: ObservableObject {
159159

160-
@Published var activeKind: CropView.State.AdjustmentKind?
160+
@Published var activeKind: CropView.StateModel.AdjustmentKind?
161161

162162
}
163163

164164
private struct Container: View {
165165

166166
@ObservedObject var proxy: Proxy
167167

168-
private let content: (CropView.State.AdjustmentKind?) -> Content
168+
private let content: (CropView.StateModel.AdjustmentKind?) -> Content
169169

170170
public init(
171171
proxy: Proxy,
172-
content: @escaping (CropView.State.AdjustmentKind?) -> Content
172+
content: @escaping (CropView.StateModel.AdjustmentKind?) -> Content
173173
) {
174174
self.content = content
175175
self.proxy = proxy
@@ -267,7 +267,7 @@ extension CropView {
267267
guideView.alpha = 0
268268
}
269269

270-
public override func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
270+
public override func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
271271
currentAnimator?.stopAnimation(true)
272272
currentAnimator = UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) { [weak self] in
273273
self?.guideView.alpha = 1
@@ -276,7 +276,7 @@ extension CropView {
276276
}
277277
}
278278

279-
public override func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
279+
public override func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
280280
currentAnimator?.stopAnimation(true)
281281
currentAnimator = UIViewPropertyAnimator(duration: 0.6, dampingRatio: 1) { [weak self] in
282282
self?.guideView.alpha = 0

Sources/BrightroomUI/Shared/Components/Crop/CropView.CropOutsideOverlay.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ extension CropView {
1313

1414
open class CropOutsideOverlayBase: PixelEditorCodeBasedView {
1515

16-
open func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
16+
open func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
1717

1818
}
1919

20-
open func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
20+
open func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
2121

2222
}
2323

@@ -49,7 +49,7 @@ extension CropView {
4949
AutoLayoutTools.setEdge(effectView, self)
5050
}
5151

52-
public override func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
52+
public override func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
5353

5454
if kind == .guide {
5555

@@ -62,7 +62,7 @@ extension CropView {
6262
}
6363
}
6464

65-
public override func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
65+
public override func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
6666

6767
if kind == .guide {
6868
currentAnimator?.stopAnimation(true)
@@ -81,7 +81,7 @@ extension CropView {
8181
private let controller: UIHostingController<Container>
8282
private let proxy: Proxy
8383

84-
public init(@ViewBuilder content: @escaping (CropView.State.AdjustmentKind?) -> Content) {
84+
public init(@ViewBuilder content: @escaping (CropView.StateModel.AdjustmentKind?) -> Content) {
8585

8686
self.proxy = .init()
8787
self.controller = .init(rootView: Container(proxy: proxy, content: content))
@@ -95,29 +95,29 @@ extension CropView {
9595
AutoLayoutTools.setEdge(controller.view, self)
9696
}
9797

98-
open override func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
98+
open override func didBeginAdjustment(kind: CropView.StateModel.AdjustmentKind) {
9999
proxy.activeKind = kind
100100
}
101101

102-
open override func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
102+
open override func didEndAdjustment(kind: CropView.StateModel.AdjustmentKind) {
103103
proxy.activeKind = nil
104104
}
105105

106106
private final class Proxy: ObservableObject {
107107

108-
@Published var activeKind: CropView.State.AdjustmentKind?
108+
@Published var activeKind: CropView.StateModel.AdjustmentKind?
109109

110110
}
111111

112112
private struct Container: View {
113113

114114
@ObservedObject var proxy: Proxy
115115

116-
private let content: (CropView.State.AdjustmentKind?) -> Content
116+
private let content: (CropView.StateModel.AdjustmentKind?) -> Content
117117

118118
public init(
119119
proxy: Proxy,
120-
content: @escaping (CropView.State.AdjustmentKind?) -> Content
120+
content: @escaping (CropView.StateModel.AdjustmentKind?) -> Content
121121
) {
122122
self.content = content
123123
self.proxy = proxy

Sources/BrightroomUI/Shared/Components/Crop/CropView._InteractiveCropGuideView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ extension CropView {
4848
var updating: () -> Void = {}
4949
var didChange: () -> Void = {}
5050

51-
var didUpdateAdjustmentKind: (CropView.State.AdjustmentKind) -> Void = { _ in }
51+
var didUpdateAdjustmentKind: (CropView.StateModel.AdjustmentKind) -> Void = { _ in }
5252

5353
private let topLeftControlPointView = TapExpandedView(horizontal: 16, vertical: 16)
5454
private let topRightControlPointView = TapExpandedView(horizontal: 16, vertical: 16)

0 commit comments

Comments
 (0)