Skip to content

Commit

Permalink
Update SwiftUICropView (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
shima11 committed Mar 4, 2024
1 parent ab19684 commit 31fc81a
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Dev/Brightroom.xcodeproj/project.pbxproj
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
0451857F2B8F4A9E00A74713 /* DemoCropView2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0451857E2B8F4A9E00A74713 /* DemoCropView2.swift */; };
4B135F6E26136B5D003B5152 /* RendererOrientationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B135F6D26136B5D003B5152 /* RendererOrientationTests.swift */; };
4B2324E42B763D4A00662EB8 /* GeometryPlayground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2324E32B763D4A00662EB8 /* GeometryPlayground.swift */; };
4B2A1107266B7B3000B0C885 /* test-image-10 in Resources */ = {isa = PBXBuildFile; fileRef = 4B2A10FA266B7B3000B0C885 /* test-image-10 */; };
Expand Down Expand Up @@ -568,6 +569,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
0451857E2B8F4A9E00A74713 /* DemoCropView2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoCropView2.swift; sourceTree = "<group>"; };
4B135F6D26136B5D003B5152 /* RendererOrientationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RendererOrientationTests.swift; sourceTree = "<group>"; };
4B2324E32B763D4A00662EB8 /* GeometryPlayground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeometryPlayground.swift; sourceTree = "<group>"; };
4B254FE6260BB32600F77E9A /* orientation_left_mirrored.HEIC */ = {isa = PBXFileReference; lastKnownFileType = file; path = orientation_left_mirrored.HEIC; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1254,6 +1256,7 @@
4B8CAF6825FFCD720075032A /* IsolatedEditingView.swift */,
4B8CAF7225FFD13D0075032A /* BlurryMaskingViewWrapper.swift */,
4B75113F25F13276002D804A /* DemoCropView.swift */,
0451857E2B8F4A9E00A74713 /* DemoCropView2.swift */,
4B98CCC425EFF31400E4F61F /* Info.plist */,
4B98CCC125EFF31400E4F61F /* Preview Content */,
4BB9180B25F5460000C446B8 /* Launch Screen.storyboard */,
Expand Down Expand Up @@ -2430,6 +2433,7 @@
4BA9896F2B70BF2000EB7983 /* RenderedResultView.swift in Sources */,
4B98CCBE25EFF31300E4F61F /* ContentView.swift in Sources */,
4B75114025F13276002D804A /* DemoCropView.swift in Sources */,
0451857F2B8F4A9E00A74713 /* DemoCropView2.swift in Sources */,
4B9325832B6A923400DDABAC /* RotateScrollView.swift in Sources */,
4B98CCBC25EFF31300E4F61F /* SwiftUIDemoApp.swift in Sources */,
4B98CCE725EFF4EF00E4F61F /* Mocks.swift in Sources */,
Expand Down
Expand Up @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/FluidGroup/PrecisionLevelSlider",
"state" : {
"revision" : "6a6d1cbe962225d097012f47038f536c72e26c91",
"version" : "2.0.2"
"revision" : "3e460c1cea5ec916f7185948bc0a4e093e20f7a5",
"version" : "2.1.0"
}
},
{
Expand Down Expand Up @@ -140,8 +140,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/VergeGroup/Verge.git",
"state" : {
"revision" : "790f1ef9af22f62fc7944f924ef4466dde071c2a",
"version" : "12.1.0"
"revision" : "a338c22b82c9a686a7131b54fa84ddad773f5c2a",
"version" : "12.0.0-beta.4"
}
}
],
Expand Down
110 changes: 110 additions & 0 deletions Dev/Sources/SwiftUIDemo/DemoCropView2.swift
@@ -0,0 +1,110 @@
//
// DemoCropView2.swift
// SwiftUIDemo
//
// Created by Jinsei Shima on 2024/02/28.
// Copyright 漏 2024 muukii. All rights reserved.
//

import BrightroomEngine
import BrightroomUI
import BrightroomUIPhotosCrop
import SwiftUI
import UIKit
import SwiftUISupport

struct DemoCropView2: View {

@StateObject var editingStack: EditingStack
@State var resultImage: ResultImage?

init(
editingStack: @escaping () -> EditingStack
) {
self._editingStack = .init(wrappedValue: editingStack())
}

var body: some View {
ZStack {

VStack {

Spacer()

SwiftUICropView(
editingStack: editingStack,
isGuideInteractionEnabled: false,
contentInset: .init(top: 20, left: 20, bottom: 20, right: 20),
cropInsideOverlay: { kind in
ViewHost(instantiated: CropView.RuleOfThirdsView(lineColor: .white))
.overlay {
Rectangle()
.fill(kind == nil ? Color.white : Color.white.opacity(0.6))
.overlay {
RoundedRectangle(cornerRadius: 24, style: .continuous)
.blendMode(.destinationOut)
}
.compositingGroup()
}
},
cropOutsideOverlay: { kind in
Rectangle()
.fill(kind == nil ? Color.white : Color.white.opacity(0.6))
}
)
.frame(height: 500)
.clipped()

Spacer()

}

VStack {
HStack {
Spacer()
Button("Done") {
let image = try! editingStack.makeRenderer().render().cgImage
self.resultImage = .init(cgImage: image)
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.tint(.yellow)
.foregroundColor(.black)
}
Spacer()
}
.padding(.horizontal, 30)
.padding(.vertical, 15)
.ignoresSafeArea()

}
.onAppear {
editingStack.start()
}
.sheet(item: $resultImage) {
RenderedResultView(result: $0)
}
}

}

#Preview("local") {
DemoCropView2(
editingStack: { Mocks.makeEditingStack(image: Mocks.imageHorizontal()) }
)
}

#Preview("remote") {
DemoCropView2(
editingStack: {
EditingStack(
imageProvider: .init(
editableRemoteURL: URL(
string:
"https://images.unsplash.com/photo-1604456930969-37f67bcd6e1e?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1"
)!
)
)
}
)
}
Expand Up @@ -7,11 +7,12 @@
//

import UIKit
import SwiftUI

extension CropView {

open class CropOutsideOverlayBase: PixelEditorCodeBasedView {

open func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {

}
Expand Down Expand Up @@ -74,4 +75,59 @@ extension CropView {
}
}

@available(iOS 14, *)
open class SwiftUICropOutsideOverlay<Content: View>: CropOutsideOverlayBase {

private let controller: UIHostingController<Container>
private let proxy: Proxy

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

self.proxy = .init()
self.controller = .init(rootView: Container(proxy: proxy, content: content))

controller.view.backgroundColor = .clear
controller.view.preservesSuperviewLayoutMargins = false

super.init(frame: .zero)

addSubview(controller.view)
AutoLayoutTools.setEdge(controller.view, self)
}

open override func didBeginAdjustment(kind: CropView.State.AdjustmentKind) {
proxy.activeKind = kind
}

open override func didEndAdjustment(kind: CropView.State.AdjustmentKind) {
proxy.activeKind = nil
}

private final class Proxy: ObservableObject {

@Published var activeKind: CropView.State.AdjustmentKind?

}

private struct Container: View {

@ObservedObject var proxy: Proxy

private let content: (CropView.State.AdjustmentKind?) -> Content

public init(
proxy: Proxy,
content: @escaping (CropView.State.AdjustmentKind?) -> Content
) {
self.content = content
self.proxy = proxy
}

var body: some View {
content(proxy.activeKind)
}
}

}

}
35 changes: 30 additions & 5 deletions Sources/BrightroomUI/Shared/Components/Crop/SwiftUICropView.swift
Expand Up @@ -70,6 +70,8 @@ public struct SwiftUICropView: UIViewControllerRepresentable {
public typealias UIViewControllerType = _PixelEditor_WrapperViewController<CropView>

private let cropInsideOverlay: ((CropView.State.AdjustmentKind?) -> AnyView)?
private let cropOutsideOverlay: ((CropView.State.AdjustmentKind?) -> AnyView)?

private let editingStack: EditingStack

private var _rotation: EditingCrop.Rotation?
Expand All @@ -78,38 +80,61 @@ public struct SwiftUICropView: UIViewControllerRepresentable {
private var _resetAction: ResetAction?

private let stateHandler: @MainActor (Verge.Changes<CropView.State>) -> Void
private let isGuideInteractionEnabled: Bool
private let contentInset: UIEdgeInsets?

public init<InsideOverlay: View>(
public init<InsideOverlay: View, OutsideOverlay: View>(
editingStack: EditingStack,
isGuideInteractionEnabled: Bool = true,
contentInset: UIEdgeInsets? = nil,
@ViewBuilder cropInsideOverlay: @escaping (CropView.State.AdjustmentKind?) -> InsideOverlay,
@ViewBuilder cropOutsideOverlay: @escaping (CropView.State.AdjustmentKind?) -> OutsideOverlay,
stateHandler: @escaping @MainActor (Verge.Changes<CropView.State>) -> Void = { _ in }
) {
self.editingStack = editingStack
self.isGuideInteractionEnabled = isGuideInteractionEnabled
self.contentInset = contentInset
self.cropInsideOverlay = { AnyView(cropInsideOverlay($0)) }
self.cropOutsideOverlay = { AnyView(cropOutsideOverlay($0)) }
self.stateHandler = stateHandler
}

public init(
editingStack: EditingStack,
isGuideInteractionEnabled: Bool = true,
contentInset: UIEdgeInsets? = nil,
stateHandler: @escaping @MainActor (Verge.Changes<CropView.State>) -> Void = { _ in }
) {
self.cropInsideOverlay = nil
self.cropOutsideOverlay = nil
self.editingStack = editingStack
self.isGuideInteractionEnabled = isGuideInteractionEnabled
self.contentInset = contentInset
self.stateHandler = stateHandler
}

public func makeUIViewController(context: Context) -> _PixelEditor_WrapperViewController<CropView> {

let view = CropView(editingStack: editingStack)
let view: CropView
if let contentInset {
view = .init(editingStack: editingStack, contentInset: contentInset)
} else {
view = .init(editingStack: editingStack)
}

view.isAutoApplyEditingStackEnabled = true
view.isGuideInteractionEnabled = isGuideInteractionEnabled

let controller = _PixelEditor_WrapperViewController.init(bodyView: view)

if let cropInsideOverlay = cropInsideOverlay {
if let cropInsideOverlay {
view.setCropInsideOverlay(CropView.SwiftUICropInsideOverlay(content: cropInsideOverlay))
}

if let cropOutsideOverlay {
view.setCropOutsideOverlay(CropView.SwiftUICropOutsideOverlay(content: cropOutsideOverlay))
}

let controller = _PixelEditor_WrapperViewController.init(bodyView: view)

return controller
}

Expand Down
Expand Up @@ -212,7 +212,7 @@ public struct PhotosCropRotating: View {
source.rounded(.toNearestOrEven)
}
),
centerLevel: { value in
centerLevel: { value, _ in
HStack {
Spacer()
VStack {
Expand All @@ -225,7 +225,7 @@ public struct PhotosCropRotating: View {
}
.foregroundStyle(.tint)
},
track: { value in
track: { value, _ in
VStack {
HStack {
Spacer()
Expand Down

0 comments on commit 31fc81a

Please sign in to comment.